From 3365832ce3be6e301c379067dfafb5aca8fccb68 Mon Sep 17 00:00:00 2001 From: khlieng Date: Wed, 29 Apr 2015 23:54:44 +0200 Subject: [PATCH] Add message logging and search server side --- .gitignore | 4 +- Godeps/Godeps.json | 53 + .../github.com/blevesearch/bleve/.gitignore | 17 + .../github.com/blevesearch/bleve/.travis.yml | 19 + .../src/github.com/blevesearch/bleve/LICENSE | 202 + .../github.com/blevesearch/bleve/README.md | 61 + .../custom_analyzer/custom_analyzer.go | 130 + .../detect_lang_analyzer.go | 49 + .../keyword_analyzer/keyword_analyzer.go | 33 + .../simple_analyzer/simple_analyzer.go | 41 + .../standard_analyzer/standard_analyzer.go | 47 + .../ignore/ignore_byte_array_converter.go | 33 + .../json/json_byte_array_converter.go | 40 + .../string/string_byte_array_conveter.go | 33 + .../html_char_filter/html_char_filter.go | 31 + .../regexp_char_filter/regexp_char_filter.go | 58 + .../regexp_char_filter_test.go | 82 + .../zero_width_non_joiner_char_filter.go | 31 + .../datetime_optional/datetime_optional.go | 40 + .../flexible_go/flexible_go.go | 59 + .../flexible_go/flexible_go_test.go | 84 + .../blevesearch/bleve/analysis/freq.go | 88 + .../blevesearch/bleve/analysis/freq_test.go | 167 + .../bleve/analysis/language/ar/analyzer_ar.go | 59 + .../analysis/language/ar/analyzer_ar_test.go | 179 + .../analysis/language/ar/arabic_normalize.go | 80 + .../language/ar/arabic_normalize_test.go | 229 + .../bleve/analysis/language/ar/stemmer_ar.go | 113 + .../analysis/language/ar/stemmer_ar_test.go | 392 + .../analysis/language/ar/stop_filter_ar.go | 28 + .../analysis/language/ar/stop_words_ar.go | 149 + .../analysis/language/bg/stop_filter_bg.go | 28 + .../analysis/language/bg/stop_words_bg.go | 217 + .../bleve/analysis/language/ca/articles_ca.go | 30 + .../bleve/analysis/language/ca/elision_ca.go | 32 + .../analysis/language/ca/elision_ca_test.go | 56 + .../analysis/language/ca/stop_filter_ca.go | 28 + .../analysis/language/ca/stop_words_ca.go | 244 + .../analysis/language/cjk/analyzer_cjk.go | 49 + .../language/cjk/analyzer_cjk_test.go | 620 ++ .../bleve/analysis/language/cjk/cjk_bigram.go | 166 + .../analysis/language/cjk/cjk_bigram_test.go | 420 + .../analysis/language/ckb/analyzer_ckb.go | 58 + .../language/ckb/analyzer_ckb_test.go | 74 + .../analysis/language/ckb/sorani_normalize.go | 113 + .../language/ckb/sorani_normalize_test.go | 318 + .../language/ckb/sorani_stemmer_filter.go | 143 + .../ckb/sorani_stemmer_filter_test.go | 294 + .../analysis/language/ckb/stop_filter_ckb.go | 28 + .../analysis/language/ckb/stop_words_ckb.go | 160 + .../analysis/language/cs/stop_filter_cs.go | 28 + .../analysis/language/cs/stop_words_cs.go | 196 + .../bleve/analysis/language/da/analyzer_da.go | 54 + .../analysis/language/da/analyzer_da_test.go | 69 + .../bleve/analysis/language/da/stemmer_da.go | 28 + .../analysis/language/da/stop_filter_da.go | 28 + .../analysis/language/da/stop_words_da.go | 134 + .../bleve/analysis/language/de/analyzer_de.go | 59 + .../analysis/language/de/analyzer_de_test.go | 97 + .../analysis/language/de/german_normalize.go | 94 + .../language/de/german_normalize_test.go | 98 + .../bleve/analysis/language/de/stemmer_de.go | 28 + .../analysis/language/de/stop_filter_de.go | 28 + .../analysis/language/de/stop_words_de.go | 318 + .../analysis/language/el/stop_filter_el.go | 28 + .../analysis/language/el/stop_words_el.go | 102 + .../bleve/analysis/language/en/analyzer_en.go | 57 + .../analysis/language/en/analyzer_en_test.go | 100 + .../language/en/possessive_filter_en.go | 57 + .../language/en/possessive_filter_en_test.go | 86 + .../bleve/analysis/language/en/stemmer_en.go | 28 + .../analysis/language/en/stemmer_en_test.go | 72 + .../analysis/language/en/stop_filter_en.go | 28 + .../analysis/language/en/stop_words_en.go | 343 + .../bleve/analysis/language/es/analyzer_es.go | 54 + .../analysis/language/es/analyzer_es_test.go | 64 + .../bleve/analysis/language/es/stemmer_es.go | 28 + .../analysis/language/es/stop_filter_es.go | 28 + .../analysis/language/es/stop_words_es.go | 380 + .../analysis/language/eu/stop_filter_eu.go | 28 + .../analysis/language/eu/stop_words_eu.go | 123 + .../bleve/analysis/language/fa/analyzer_fa.go | 67 + .../analysis/language/fa/analyzer_fa_test.go | 681 ++ .../analysis/language/fa/persian_normalize.go | 72 + .../language/fa/persian_normalize_test.go | 125 + .../analysis/language/fa/stop_filter_fa.go | 28 + .../analysis/language/fa/stop_words_fa.go | 337 + .../bleve/analysis/language/fi/analyzer_fi.go | 54 + .../analysis/language/fi/analyzer_fi_test.go | 68 + .../bleve/analysis/language/fi/stemmer_fi.go | 28 + .../analysis/language/fi/stop_filter_fi.go | 28 + .../analysis/language/fi/stop_words_fi.go | 121 + .../bleve/analysis/language/fr/analyzer_fr.go | 56 + .../analysis/language/fr/analyzer_fr_test.go | 196 + .../bleve/analysis/language/fr/articles_fr.go | 37 + .../bleve/analysis/language/fr/elision_fr.go | 32 + .../analysis/language/fr/elision_fr_test.go | 50 + .../analysis/language/fr/light_stemmer_fr.go | 308 + .../language/fr/light_stemmer_fr_test.go | 997 ++ .../language/fr/minimal_stemmer_fr.go | 81 + .../language/fr/minimal_stemmer_fr_test.go | 134 + .../bleve/analysis/language/fr/stemmer_fr.go | 28 + .../analysis/language/fr/stop_filter_fr.go | 28 + .../analysis/language/fr/stop_words_fr.go | 210 + .../bleve/analysis/language/ga/articles_ga.go | 27 + .../bleve/analysis/language/ga/elision_ga.go | 32 + .../analysis/language/ga/elision_ga_test.go | 50 + .../analysis/language/ga/stop_filter_ga.go | 28 + .../analysis/language/ga/stop_words_ga.go | 134 + .../analysis/language/gl/stop_filter_gl.go | 28 + .../analysis/language/gl/stop_words_gl.go | 185 + .../bleve/analysis/language/hi/analyzer_hi.go | 62 + .../analysis/language/hi/analyzer_hi_test.go | 61 + .../analysis/language/hi/hindi_normalize.go | 133 + .../language/hi/hindi_normalize_test.go | 246 + .../language/hi/hindi_stemmer_filter.go | 144 + .../language/hi/hindi_stemmer_filter_test.go | 303 + .../analysis/language/hi/stop_filter_hi.go | 28 + .../analysis/language/hi/stop_words_hi.go | 259 + .../bleve/analysis/language/hu/analyzer_hu.go | 54 + .../analysis/language/hu/analyzer_hu_test.go | 68 + .../bleve/analysis/language/hu/stemmer_hu.go | 28 + .../analysis/language/hu/stop_filter_hu.go | 28 + .../analysis/language/hu/stop_words_hu.go | 235 + .../analysis/language/hy/stop_filter_hy.go | 28 + .../analysis/language/hy/stop_words_hy.go | 70 + .../analysis/language/id/stop_filter_id.go | 28 + .../analysis/language/id/stop_words_id.go | 383 + .../analysis/language/in/indic_normalize.go | 43 + .../language/in/indic_normalize_test.go | 133 + .../bleve/analysis/language/in/scripts.go | 291 + .../bleve/analysis/language/it/analyzer_it.go | 56 + .../analysis/language/it/analyzer_it_test.go | 82 + .../bleve/analysis/language/it/articles_it.go | 45 + .../bleve/analysis/language/it/elision_it.go | 32 + .../analysis/language/it/elision_it_test.go | 50 + .../analysis/language/it/light_stemmer_it.go | 96 + .../language/it/light_stemmer_it_test.go | 62 + .../bleve/analysis/language/it/stemmer_it.go | 28 + .../analysis/language/it/stop_filter_it.go | 28 + .../analysis/language/it/stop_words_it.go | 327 + .../bleve/analysis/language/ja/analyzer_ja.go | 39 + .../analysis/language/ja/analyzer_ja_test.go | 71 + .../analysis/language/ja/ja_morph_kagome.go | 80 + .../language/ja/ja_morph_kagome_test.go | 56 + .../bleve/analysis/language/nl/analyzer_nl.go | 54 + .../analysis/language/nl/analyzer_nl_test.go | 68 + .../bleve/analysis/language/nl/stemmer_nl.go | 28 + .../analysis/language/nl/stop_filter_nl.go | 28 + .../analysis/language/nl/stop_words_nl.go | 143 + .../bleve/analysis/language/no/analyzer_no.go | 54 + .../analysis/language/no/analyzer_no_test.go | 68 + .../bleve/analysis/language/no/stemmer_no.go | 28 + .../analysis/language/no/stop_filter_no.go | 28 + .../analysis/language/no/stop_words_no.go | 218 + .../language/porter/stemmer_porter.go | 28 + .../bleve/analysis/language/pt/analyzer_pt.go | 51 + .../analysis/language/pt/analyzer_pt_test.go | 65 + .../analysis/language/pt/light_stemmer_pt.go | 190 + .../language/pt/light_stemmer_pt_test.go | 399 + .../bleve/analysis/language/pt/stemmer_pt.go | 28 + .../analysis/language/pt/stop_filter_pt.go | 28 + .../analysis/language/pt/stop_words_pt.go | 277 + .../bleve/analysis/language/ro/analyzer_ro.go | 54 + .../analysis/language/ro/analyzer_ro_test.go | 68 + .../bleve/analysis/language/ro/stemmer_ro.go | 28 + .../analysis/language/ro/stop_filter_ro.go | 28 + .../analysis/language/ro/stop_words_ro.go | 257 + .../bleve/analysis/language/ru/analyzer_ru.go | 54 + .../analysis/language/ru/analyzer_ru_test.go | 98 + .../bleve/analysis/language/ru/stemmer_ru.go | 28 + .../analysis/language/ru/stop_filter_ru.go | 28 + .../analysis/language/ru/stop_words_ru.go | 267 + .../bleve/analysis/language/sv/analyzer_sv.go | 54 + .../analysis/language/sv/analyzer_sv_test.go | 68 + .../bleve/analysis/language/sv/stemmer_sv.go | 28 + .../analysis/language/sv/stop_filter_sv.go | 28 + .../analysis/language/sv/stop_words_sv.go | 157 + .../bleve/analysis/language/th/analyzer_th.go | 47 + .../analysis/language/th/analyzer_th_test.go | 119 + .../analysis/language/th/stop_filter_th.go | 28 + .../analysis/language/th/stop_words_th.go | 143 + .../language/th/unicode_tokenizer_th.go | 28 + .../bleve/analysis/language/tr/analyzer_tr.go | 60 + .../analysis/language/tr/analyzer_tr_test.go | 88 + .../bleve/analysis/language/tr/stemmer_tr.go | 28 + .../analysis/language/tr/stop_filter_tr.go | 28 + .../analysis/language/tr/stop_words_tr.go | 236 + .../blevesearch/bleve/analysis/test_words.txt | 7 + .../apostrophe_filter/apostrophe_filter.go | 49 + .../apostrophe_filter_test.go | 94 + .../analysis/token_filters/cld2/README.md | 33 + .../token_filters/cld2/cld2_filter.cc | 44 + .../token_filters/cld2/cld2_filter.go | 67 + .../analysis/token_filters/cld2/cld2_filter.h | 18 + .../token_filters/cld2/cld2_filter_test.go | 123 + .../token_filters/cld2/compile_cld2.sh | 10 + .../analysis/token_filters/compound/dict.go | 136 + .../token_filters/compound/dict_test.go | 182 + .../edge_ngram_filter/edge_ngram_filter.go | 120 + .../edge_ngram_filter_test.go | 142 + .../elision_filter/elision_filter.go | 67 + .../elision_filter/elision_filter_test.go | 68 + .../keyword_marker_filter.go | 56 + .../keyword_marker_filter_test.go | 68 + .../length_filter/length_filter.go | 72 + .../length_filter/length_filter_test.go | 94 + .../lower_case_filter/lower_case_filter.go | 80 + .../lower_case_filter_test.go | 155 + .../ngram_filter/ngram_filter.go | 90 + .../ngram_filter/ngram_filter_test.go | 132 + .../analysis/token_filters/porter/porter.go | 44 + .../token_filters/porter/porter_test.go | 58 + .../analysis/token_filters/shingle/shingle.go | 157 + .../token_filters/shingle/shingle_test.go | 330 + .../token_filters/stemmer_filter/README.md | 18 + .../stemmer_filter/stemmer_filter.go | 80 + .../stemmer_filter/stemmer_filter_test.go | 63 + .../stop_tokens_filter/stop_tokens_filter.go | 58 + .../stop_tokens_filter_test.go | 73 + .../truncate_token_filter.go | 62 + .../truncate_token_filter_test.go | 74 + .../unicode_normalize/unicode_normalize.go | 74 + .../unicode_normalize_test.go | 157 + .../blevesearch/bleve/analysis/token_map.go | 65 + .../bleve/analysis/token_map/custom.go | 46 + .../bleve/analysis/token_map_test.go | 38 + .../tokenizers/exception/exception.go | 121 + .../tokenizers/exception/exception_test.go | 157 + .../bleve/analysis/tokenizers/icu/boundary.go | 138 + .../analysis/tokenizers/icu/boundary_test.go | 191 + .../regexp_tokenizer/regexp_tokenizer.go | 77 + .../regexp_tokenizer/regexp_tokenizer_test.go | 115 + .../tokenizers/single_token/single_token.go | 44 + .../single_token/single_token_test.go | 71 + .../analysis/tokenizers/unicode/unicode.go | 72 + .../tokenizers/unicode/unicode_test.go | 197 + .../whitespace_tokenizer.go | 30 + .../whitespace_tokenizer_test.go | 150 + .../blevesearch/bleve/analysis/type.go | 85 + .../blevesearch/bleve/analysis/util.go | 69 + .../blevesearch/bleve/analysis/util_test.go | 71 + .../github.com/blevesearch/bleve/config.go | 167 + .../blevesearch/bleve/config_cld2.go | 20 + .../blevesearch/bleve/config_cznicb.go | 16 + .../blevesearch/bleve/config_forestdb.go | 16 + .../blevesearch/bleve/config_icu.go | 16 + .../blevesearch/bleve/config_kagome.go | 16 + .../blevesearch/bleve/config_leveldb.go | 21 + .../blevesearch/bleve/config_metrics.go | 16 + .../blevesearch/bleve/config_rocksdb.go | 16 + .../blevesearch/bleve/config_stemmer.go | 17 + .../src/github.com/blevesearch/bleve/doc.go | 33 + .../blevesearch/bleve/docs/bleve.png | Bin 0 -> 6727 bytes .../blevesearch/bleve/docs/build_children.sh | 11 + .../bleve/docs/merge-coverprofile.go | 45 + .../bleve/docs/old_build_script.txt | 29 + .../bleve/docs/project-code-coverage.sh | 51 + .../blevesearch/bleve/document/document.go | 56 + .../blevesearch/bleve/document/field.go | 22 + .../bleve/document/field_composite.go | 86 + .../bleve/document/field_datetime.go | 130 + .../bleve/document/field_numeric.go | 116 + .../bleve/document/field_numeric_test.go | 25 + .../blevesearch/bleve/document/field_text.go | 106 + .../bleve/document/indexing_options.go | 50 + .../bleve/document/indexing_options_test.go | 69 + .../src/github.com/blevesearch/bleve/error.go | 51 + .../blevesearch/bleve/examples_test.go | 485 + .../blevesearch/bleve/http/alias.go | 65 + .../blevesearch/bleve/http/debug.go | 74 + .../blevesearch/bleve/http/doc_count.go | 56 + .../blevesearch/bleve/http/doc_delete.go | 67 + .../blevesearch/bleve/http/doc_get.go | 107 + .../blevesearch/bleve/http/doc_index.go | 75 + .../blevesearch/bleve/http/fields.go | 58 + .../blevesearch/bleve/http/handlers_test.go | 704 ++ .../blevesearch/bleve/http/index_create.go | 78 + .../blevesearch/bleve/http/index_delete.go | 70 + .../blevesearch/bleve/http/index_get.go | 54 + .../blevesearch/bleve/http/index_list.go | 33 + .../blevesearch/bleve/http/registry.go | 120 + .../blevesearch/bleve/http/search.go | 84 + .../github.com/blevesearch/bleve/http/util.go | 46 + .../src/github.com/blevesearch/bleve/index.go | 146 + .../blevesearch/bleve/index/index.go | 146 + .../blevesearch/bleve/index/store/batch.go | 69 + .../bleve/index/store/boltdb/iterator.go | 58 + .../bleve/index/store/boltdb/reader.go | 47 + .../bleve/index/store/boltdb/store.go | 112 + .../bleve/index/store/boltdb/store_test.go | 272 + .../bleve/index/store/boltdb/writer.go | 50 + .../bleve/index/store/cznicb/batch.go | 88 + .../bleve/index/store/cznicb/cznicb.go | 111 + .../bleve/index/store/cznicb/cznicb_test.go | 133 + .../bleve/index/store/cznicb/iterator.go | 113 + .../bleve/index/store/cznicb/reader.go | 44 + .../bleve/index/store/cznicb/writer.go | 55 + .../bleve/index/store/forestdb/batch.go | 86 + .../bleve/index/store/forestdb/iterator.go | 117 + .../bleve/index/store/forestdb/reader.go | 57 + .../bleve/index/store/forestdb/store.go | 297 + .../bleve/index/store/forestdb/store_test.go | 636 ++ .../bleve/index/store/forestdb/writer.go | 71 + .../bleve/index/store/goleveldb/batch.go | 53 + .../bleve/index/store/goleveldb/iterator.go | 75 + .../bleve/index/store/goleveldb/reader.go | 47 + .../bleve/index/store/goleveldb/store.go | 172 + .../bleve/index/store/goleveldb/store_test.go | 296 + .../bleve/index/store/goleveldb/util.go | 26 + .../bleve/index/store/goleveldb/writer.go | 63 + .../bleve/index/store/gorocksdb/batch.go | 43 + .../bleve/index/store/gorocksdb/iterator.go | 76 + .../bleve/index/store/gorocksdb/reader.go | 48 + .../bleve/index/store/gorocksdb/store.go | 146 + .../bleve/index/store/gorocksdb/store_test.go | 298 + .../bleve/index/store/gorocksdb/util.go | 28 + .../bleve/index/store/gorocksdb/writer.go | 64 + .../bleve/index/store/gtreap/gtreap.go | 95 + .../bleve/index/store/gtreap/gtreap_test.go | 259 + .../bleve/index/store/gtreap/iterator.go | 132 + .../bleve/index/store/gtreap/reader.go | 44 + .../bleve/index/store/gtreap/writer.go | 72 + .../bleve/index/store/inmem/iterator.go | 70 + .../bleve/index/store/inmem/reader.go | 40 + .../bleve/index/store/inmem/store.go | 106 + .../bleve/index/store/inmem/store_test.go | 254 + .../bleve/index/store/inmem/writer.go | 57 + .../blevesearch/bleve/index/store/kvstore.go | 53 + .../bleve/index/store/leveldb/batch.go | 55 + .../bleve/index/store/leveldb/iterator.go | 78 + .../bleve/index/store/leveldb/reader.go | 48 + .../bleve/index/store/leveldb/store.go | 174 + .../bleve/index/store/leveldb/store_test.go | 298 + .../bleve/index/store/leveldb/util.go | 28 + .../bleve/index/store/leveldb/writer.go | 65 + .../blevesearch/bleve/index/store/merge.go | 120 + .../bleve/index/store/metrics/metrics.go | 475 + .../bleve/index/store/metrics/metrics_test.go | 368 + .../bleve/index/store/null/null.go | 173 + .../bleve/index/store/null/null_test.go | 88 + .../bleve/index/upside_down/analysis_pool.go | 121 + .../bleve/index/upside_down/benchmark_all.sh | 8 + .../upside_down/benchmark_boltdb_test.go | 77 + .../upside_down/benchmark_common_test.go | 143 + .../upside_down/benchmark_cznicb_test.go | 75 + .../upside_down/benchmark_forestdb_test.go | 86 + .../upside_down/benchmark_goleveldb_test.go | 80 + .../upside_down/benchmark_gorocksdb_test.go | 82 + .../upside_down/benchmark_gtreap_test.go | 75 + .../index/upside_down/benchmark_inmem_test.go | 75 + .../upside_down/benchmark_leveldb_test.go | 82 + .../index/upside_down/benchmark_null_test.go | 75 + .../bleve/index/upside_down/dump.go | 177 + .../bleve/index/upside_down/dump_test.go | 127 + .../bleve/index/upside_down/field_dict.go | 86 + .../index/upside_down/field_dict_test.go | 180 + .../index/upside_down/field_index_cache.go | 69 + .../bleve/index/upside_down/index_reader.go | 164 + .../bleve/index/upside_down/reader.go | 187 + .../bleve/index/upside_down/reader_test.go | 297 + .../bleve/index/upside_down/row.go | 641 ++ .../bleve/index/upside_down/row_merge.go | 70 + .../bleve/index/upside_down/row_test.go | 329 + .../bleve/index/upside_down/stats.go | 31 + .../bleve/index/upside_down/upside_down.go | 720 ++ .../bleve/index/upside_down/upside_down.pb.go | 98 + .../bleve/index/upside_down/upside_down.proto | 14 + .../index/upside_down/upside_down_test.go | 1177 +++ .../blevesearch/bleve/index_alias.go | 32 + .../blevesearch/bleve/index_alias_impl.go | 576 ++ .../bleve/index_alias_impl_test.go | 790 ++ .../blevesearch/bleve/index_impl.go | 739 ++ .../blevesearch/bleve/index_meta.go | 81 + .../blevesearch/bleve/index_meta_test.go | 54 + .../blevesearch/bleve/index_stats.go | 39 + .../blevesearch/bleve/index_test.go | 609 ++ .../blevesearch/bleve/mapping_document.go | 374 + .../blevesearch/bleve/mapping_field.go | 155 + .../blevesearch/bleve/mapping_index.go | 455 + .../blevesearch/bleve/mapping_test.go | 246 + .../blevesearch/bleve/numeric_util/float.go | 29 + .../bleve/numeric_util/float_test.go | 59 + .../bleve/numeric_util/prefix_coded.go | 74 + .../bleve/numeric_util/prefix_coded_test.go | 98 + .../src/github.com/blevesearch/bleve/query.go | 211 + .../blevesearch/bleve/query_boolean.go | 210 + .../blevesearch/bleve/query_conjunction.go | 94 + .../blevesearch/bleve/query_date_range.go | 117 + .../blevesearch/bleve/query_disjunction.go | 119 + .../blevesearch/bleve/query_fuzzy.go | 88 + .../blevesearch/bleve/query_match.go | 128 + .../blevesearch/bleve/query_match_all.go | 53 + .../blevesearch/bleve/query_match_none.go | 53 + .../blevesearch/bleve/query_match_phrase.go | 114 + .../blevesearch/bleve/query_numeric_range.go | 81 + .../blevesearch/bleve/query_phrase.go | 108 + .../blevesearch/bleve/query_prefix.go | 62 + .../blevesearch/bleve/query_regexp.go | 75 + .../blevesearch/bleve/query_string.go | 59 + .../blevesearch/bleve/query_string.nex | 41 + .../blevesearch/bleve/query_string.nn.go | 1362 +++ .../blevesearch/bleve/query_string.y | 217 + .../blevesearch/bleve/query_string.y.go | 563 + .../blevesearch/bleve/query_string_parser.go | 76 + .../bleve/query_string_parser_test.go | 247 + .../blevesearch/bleve/query_term.go | 61 + .../blevesearch/bleve/query_test.go | 220 + .../blevesearch/bleve/query_wildcard.go | 102 + .../github.com/blevesearch/bleve/reflect.go | 79 + .../blevesearch/bleve/registry/analyzer.go | 78 + .../bleve/registry/byte_array_converter.go | 47 + .../blevesearch/bleve/registry/char_filter.go | 78 + .../bleve/registry/datetime_parser.go | 78 + .../bleve/registry/fragment_formatter.go | 78 + .../blevesearch/bleve/registry/fragmenter.go | 78 + .../blevesearch/bleve/registry/highlighter.go | 78 + .../blevesearch/bleve/registry/registry.go | 176 + .../blevesearch/bleve/registry/store.go | 46 + .../bleve/registry/token_filter.go | 78 + .../blevesearch/bleve/registry/token_maps.go | 78 + .../blevesearch/bleve/registry/tokenizer.go | 78 + .../github.com/blevesearch/bleve/search.go | 297 + .../blevesearch/bleve/search/collector.go | 24 + .../search/collectors/collector_top_score.go | 135 + .../collectors/collector_top_score_test.go | 249 + .../bleve/search/collectors/search_test.go | 60 + .../blevesearch/bleve/search/explanation.go | 29 + .../bleve/search/facets/benchmark_data.txt | 2909 ++++++ .../search/facets/facet_builder_datetime.go | 147 + .../search/facets/facet_builder_numeric.go | 120 + .../facets/facet_builder_numeric_test.go | 49 + .../search/facets/facet_builder_terms.go | 86 + .../search/facets/facet_builder_terms_test.go | 58 + .../bleve/search/facets_builder.go | 212 + .../bleve/search/facets_builder_test.go | 301 + .../ansi/fragment_formatter_ansi.go | 100 + .../html/fragment_formatter_html.go | 80 + .../html/fragment_formatter_html_test.go | 87 + .../fragmenters/simple/fragmenter_simple.go | 138 + .../simple/fragmenter_simple_test.go | 295 + .../bleve/search/highlight/highlighter.go | 58 + .../simple/fragment_scorer_simple.go | 44 + .../simple/fragment_scorer_simple_test.go | 77 + .../highlighters/simple/highlighter_simple.go | 208 + .../simple/highlighter_simple_test.go | 164 + .../bleve/search/highlight/term_locations.go | 70 + .../search/highlight/term_locations_test.go | 173 + .../blevesearch/bleve/search/levenshtein.go | 91 + .../bleve/search/levenshtein_test.go | 114 + .../search/scorers/scorer_conjunction.go | 59 + .../bleve/search/scorers/scorer_constant.go | 103 + .../search/scorers/scorer_constant_test.go | 118 + .../search/scorers/scorer_disjunction.go | 71 + .../bleve/search/scorers/scorer_term.go | 169 + .../bleve/search/scorers/scorer_term_test.go | 241 + .../bleve/search/scorers/sqrt_cache.go | 25 + .../blevesearch/bleve/search/search.go | 81 + .../bleve/search/searchers/base_test.go | 80 + .../searchers/ordered_searchers_list.go | 30 + .../bleve/search/searchers/search_boolean.go | 335 + .../search/searchers/search_boolean_test.go | 364 + .../search/searchers/search_conjunction.go | 197 + .../searchers/search_conjunction_test.go | 212 + .../search/searchers/search_disjunction.go | 189 + .../searchers/search_disjunction_test.go | 168 + .../bleve/search/searchers/search_fuzzy.go | 112 + .../search/searchers/search_match_all.go | 89 + .../search/searchers/search_match_all_test.go | 134 + .../search/searchers/search_match_none.go | 53 + .../searchers/search_match_none_test.go | 76 + .../search/searchers/search_numeric_range.go | 214 + .../searchers/search_numeric_range_test.go | 55 + .../bleve/search/searchers/search_phrase.go | 197 + .../search/searchers/search_phrase_test.go | 93 + .../bleve/search/searchers/search_regexp.go | 108 + .../search/searchers/search_regexp_test.go | 110 + .../bleve/search/searchers/search_term.go | 95 + .../search/searchers/search_term_prefix.go | 81 + .../search/searchers/search_term_test.go | 195 + .../blevesearch/bleve/search/util.go | 37 + .../blevesearch/bleve/search/util_test.go | 86 + .../blevesearch/bleve/search_test.go | 117 + .../blevesearch/bleve/test/integration.go | 22 + .../bleve/test/integration_test.go | 163 + .../bleve/test/tests/basic/data/a.json | 7 + .../bleve/test/tests/basic/data/b.json | 7 + .../bleve/test/tests/basic/data/c.json | 7 + .../bleve/test/tests/basic/data/d.json | 7 + .../bleve/test/tests/basic/mapping.json | 27 + .../bleve/test/tests/basic/searches.json | 406 + .../bleve/test/tests/facet/data/a.json | 6 + .../bleve/test/tests/facet/data/b.json | 6 + .../bleve/test/tests/facet/data/c.json | 6 + .../bleve/test/tests/facet/data/d.json | 6 + .../bleve/test/tests/facet/data/e.json | 6 + .../bleve/test/tests/facet/data/f.json | 6 + .../bleve/test/tests/facet/data/g.json | 6 + .../bleve/test/tests/facet/data/h.json | 6 + .../bleve/test/tests/facet/data/i.json | 6 + .../bleve/test/tests/facet/data/j.json | 6 + .../bleve/test/tests/facet/mapping.json | 1 + .../bleve/test/tests/facet/searches.json | 144 + .../fosdem/data/3311@FOSDEM15@fosdem.org.json | 4 + .../fosdem/data/3492@FOSDEM15@fosdem.org.json | 4 + .../fosdem/data/3496@FOSDEM15@fosdem.org.json | 4 + .../fosdem/data/3505@FOSDEM15@fosdem.org.json | 4 + .../fosdem/data/3507@FOSDEM15@fosdem.org.json | 4 + .../bleve/test/tests/fosdem/mapping.json | 76 + .../bleve/test/tests/fosdem/searches.json | 105 + .../bleve/test/tests/phrase/data/a.json | 3 + .../bleve/test/tests/phrase/mapping.json | 23 + .../bleve/test/tests/phrase/searches.json | 326 + .../bleve/utils/bleve_bulkindex/main.go | 104 + .../bleve/utils/bleve_create/main.go | 58 + .../bleve/utils/bleve_dump/main.go | 73 + .../bleve/utils/bleve_index/main.go | 115 + .../bleve/utils/bleve_query/main.go | 85 + .../bleve/utils/bleve_registry/main.go | 82 + .../blevesearch/go-porterstemmer/.gitignore | 8 + .../blevesearch/go-porterstemmer/.travis.yml | 16 + .../blevesearch/go-porterstemmer/LICENSE | 19 + .../blevesearch/go-porterstemmer/README.md | 118 + .../go-porterstemmer/porterstemmer.go | 839 ++ .../porterstemmer_contains_vowel_test.go | 57 + .../porterstemmer_fixes_test.go | 20 + .../porterstemmer_fuzz_test.go | 59 + ...has_repeat_double_consonant_suffix_test.go | 42 + .../porterstemmer_has_suffix_test.go | 432 + .../porterstemmer_is_consontant_test.go | 74 + .../porterstemmer_measure_test.go | 99 + .../porterstemmer_stem_string_test.go | 118 + ...rstemmer_stem_without_lower_casing_test.go | 56 + .../porterstemmer_step1a_test.go | 70 + .../porterstemmer_step1b_test.go | 112 + .../porterstemmer_step1c_test.go | 60 + .../porterstemmer_step2_test.go | 132 + .../porterstemmer_step3_test.go | 76 + .../porterstemmer_step4_test.go | 124 + .../porterstemmer_step5a_test.go | 60 + .../porterstemmer_step5b_test.go | 56 + .../github.com/blevesearch/segment/.gitignore | 9 + .../blevesearch/segment/.travis.yml | 16 + .../github.com/blevesearch/segment/LICENSE | 202 + .../github.com/blevesearch/segment/Makefile | 9 + .../github.com/blevesearch/segment/README.md | 61 + .../src/github.com/blevesearch/segment/doc.go | 45 + .../blevesearch/segment/export_test.go | 20 + .../blevesearch/segment/maketables.go | 279 + .../blevesearch/segment/maketesttables.go | 212 + .../github.com/blevesearch/segment/segment.go | 244 + .../blevesearch/segment/segment_test.go | 241 + .../blevesearch/segment/segment_words.go | 326 + .../blevesearch/segment/segment_words_test.go | 360 + .../github.com/blevesearch/segment/tables.go | 5093 +++++++++ .../blevesearch/segment/tables_test.go | 9097 +++++++++++++++++ .../_workspace/src/github.com/cznic/b/AUTHORS | 11 + .../src/github.com/cznic/b/CONTRIBUTORS | 11 + .../_workspace/src/github.com/cznic/b/LICENSE | 27 + .../src/github.com/cznic/b/Makefile | 53 + .../src/github.com/cznic/b/README.md | 10 + .../src/github.com/cznic/b/all_test.go | 1300 +++ .../src/github.com/cznic/b/btree.go | 981 ++ .../src/github.com/cznic/b/example/Makefile | 35 + .../github.com/cznic/b/example/all_test.go | 1126 ++ .../src/github.com/cznic/b/example/int.go | 921 ++ .../github.com/golang/protobuf/proto/Makefile | 43 + .../golang/protobuf/proto/all_test.go | 2071 ++++ .../github.com/golang/protobuf/proto/clone.go | 197 + .../golang/protobuf/proto/clone_test.go | 226 + .../golang/protobuf/proto/decode.go | 821 ++ .../golang/protobuf/proto/encode.go | 1288 +++ .../github.com/golang/protobuf/proto/equal.go | 256 + .../golang/protobuf/proto/equal_test.go | 191 + .../golang/protobuf/proto/extensions.go | 362 + .../golang/protobuf/proto/extensions_test.go | 153 + .../github.com/golang/protobuf/proto/lib.go | 790 ++ .../golang/protobuf/proto/message_set.go | 287 + .../golang/protobuf/proto/message_set_test.go | 66 + .../golang/protobuf/proto/pointer_reflect.go | 479 + .../golang/protobuf/proto/pointer_unsafe.go | 266 + .../golang/protobuf/proto/properties.go | 742 ++ .../protobuf/proto/proto3_proto/proto3.proto | 68 + .../golang/protobuf/proto/proto3_test.go | 125 + .../golang/protobuf/proto/size2_test.go | 63 + .../golang/protobuf/proto/size_test.go | 142 + .../golang/protobuf/proto/testdata/Makefile | 50 + .../protobuf/proto/testdata/golden_test.go | 86 + .../golang/protobuf/proto/testdata/test.pb.go | 2397 +++++ .../golang/protobuf/proto/testdata/test.proto | 435 + .../github.com/golang/protobuf/proto/text.go | 789 ++ .../golang/protobuf/proto/text_parser.go | 757 ++ .../golang/protobuf/proto/text_parser_test.go | 511 + .../golang/protobuf/proto/text_test.go | 435 + .../ryszard/goskiplist/skiplist/skiplist.go | 635 ++ .../goskiplist/skiplist/skiplist_test.go | 924 ++ .../src/github.com/steveyen/gtreap/.gitignore | 5 + .../src/github.com/steveyen/gtreap/LICENSE | 20 + .../src/github.com/steveyen/gtreap/README.md | 90 + .../src/github.com/steveyen/gtreap/treap.go | 187 + .../github.com/steveyen/gtreap/treap_test.go | 225 + .../syndtr/goleveldb/leveldb/batch.go | 252 + .../syndtr/goleveldb/leveldb/batch_test.go | 120 + .../syndtr/goleveldb/leveldb/bench2_test.go | 58 + .../syndtr/goleveldb/leveldb/bench_test.go | 464 + .../goleveldb/leveldb/cache/bench2_test.go | 30 + .../syndtr/goleveldb/leveldb/cache/cache.go | 676 ++ .../goleveldb/leveldb/cache/cache_test.go | 554 + .../syndtr/goleveldb/leveldb/cache/lru.go | 195 + .../syndtr/goleveldb/leveldb/comparer.go | 75 + .../leveldb/comparer/bytes_comparer.go | 51 + .../goleveldb/leveldb/comparer/comparer.go | 57 + .../syndtr/goleveldb/leveldb/corrupt_test.go | 500 + .../github.com/syndtr/goleveldb/leveldb/db.go | 945 ++ .../syndtr/goleveldb/leveldb/db_compaction.go | 835 ++ .../syndtr/goleveldb/leveldb/db_iter.go | 350 + .../syndtr/goleveldb/leveldb/db_snapshot.go | 183 + .../syndtr/goleveldb/leveldb/db_state.go | 211 + .../syndtr/goleveldb/leveldb/db_test.go | 2665 +++++ .../syndtr/goleveldb/leveldb/db_util.go | 100 + .../syndtr/goleveldb/leveldb/db_write.go | 311 + .../syndtr/goleveldb/leveldb/doc.go | 90 + .../syndtr/goleveldb/leveldb/errors.go | 18 + .../syndtr/goleveldb/leveldb/errors/errors.go | 76 + .../syndtr/goleveldb/leveldb/external_test.go | 58 + .../syndtr/goleveldb/leveldb/filter.go | 31 + .../syndtr/goleveldb/leveldb/filter/bloom.go | 116 + .../goleveldb/leveldb/filter/bloom_test.go | 142 + .../syndtr/goleveldb/leveldb/filter/filter.go | 60 + .../goleveldb/leveldb/iterator/array_iter.go | 184 + .../leveldb/iterator/array_iter_test.go | 30 + .../leveldb/iterator/indexed_iter.go | 242 + .../leveldb/iterator/indexed_iter_test.go | 83 + .../syndtr/goleveldb/leveldb/iterator/iter.go | 131 + .../leveldb/iterator/iter_suite_test.go | 11 + .../goleveldb/leveldb/iterator/merged_iter.go | 304 + .../leveldb/iterator/merged_iter_test.go | 60 + .../goleveldb/leveldb/journal/journal.go | 520 + .../goleveldb/leveldb/journal/journal_test.go | 818 ++ .../syndtr/goleveldb/leveldb/key.go | 142 + .../syndtr/goleveldb/leveldb/key_test.go | 133 + .../goleveldb/leveldb/leveldb_suite_test.go | 11 + .../goleveldb/leveldb/memdb/bench_test.go | 75 + .../syndtr/goleveldb/leveldb/memdb/memdb.go | 468 + .../leveldb/memdb/memdb_suite_test.go | 11 + .../goleveldb/leveldb/memdb/memdb_test.go | 135 + .../syndtr/goleveldb/leveldb/opt/options.go | 639 ++ .../syndtr/goleveldb/leveldb/options.go | 92 + .../syndtr/goleveldb/leveldb/session.go | 455 + .../goleveldb/leveldb/session_record.go | 313 + .../goleveldb/leveldb/session_record_test.go | 64 + .../syndtr/goleveldb/leveldb/session_util.go | 248 + .../goleveldb/leveldb/storage/file_storage.go | 534 + .../leveldb/storage/file_storage_plan9.go | 52 + .../leveldb/storage/file_storage_solaris.go | 68 + .../leveldb/storage/file_storage_test.go | 142 + .../leveldb/storage/file_storage_unix.go | 63 + .../leveldb/storage/file_storage_windows.go | 69 + .../goleveldb/leveldb/storage/mem_storage.go | 203 + .../leveldb/storage/mem_storage_test.go | 66 + .../goleveldb/leveldb/storage/storage.go | 157 + .../syndtr/goleveldb/leveldb/storage_test.go | 539 + .../syndtr/goleveldb/leveldb/table.go | 521 + .../goleveldb/leveldb/table/block_test.go | 139 + .../syndtr/goleveldb/leveldb/table/reader.go | 1106 ++ .../syndtr/goleveldb/leveldb/table/table.go | 177 + .../leveldb/table/table_suite_test.go | 11 + .../goleveldb/leveldb/table/table_test.go | 122 + .../syndtr/goleveldb/leveldb/table/writer.go | 378 + .../syndtr/goleveldb/leveldb/testutil/db.go | 222 + .../goleveldb/leveldb/testutil/ginkgo.go | 21 + .../syndtr/goleveldb/leveldb/testutil/iter.go | 327 + .../syndtr/goleveldb/leveldb/testutil/kv.go | 352 + .../goleveldb/leveldb/testutil/kvtest.go | 187 + .../goleveldb/leveldb/testutil/storage.go | 586 ++ .../syndtr/goleveldb/leveldb/testutil/util.go | 171 + .../syndtr/goleveldb/leveldb/testutil_test.go | 63 + .../syndtr/goleveldb/leveldb/util.go | 91 + .../syndtr/goleveldb/leveldb/util/buffer.go | 293 + .../goleveldb/leveldb/util/buffer_pool.go | 238 + .../goleveldb/leveldb/util/buffer_test.go | 369 + .../syndtr/goleveldb/leveldb/util/crc32.go | 30 + .../syndtr/goleveldb/leveldb/util/hash.go | 48 + .../syndtr/goleveldb/leveldb/util/pool.go | 21 + .../goleveldb/leveldb/util/pool_legacy.go | 33 + .../syndtr/goleveldb/leveldb/util/range.go | 32 + .../syndtr/goleveldb/leveldb/util/util.go | 73 + .../syndtr/goleveldb/leveldb/version.go | 457 + .../syndtr/gosnappy/snappy/decode.go | 292 + .../syndtr/gosnappy/snappy/encode.go | 258 + .../syndtr/gosnappy/snappy/snappy.go | 68 + .../syndtr/gosnappy/snappy/snappy_test.go | 364 + .../src/github.com/willf/bitset/.gitignore | 22 + .../src/github.com/willf/bitset/CHANGELOG | 10 + .../src/github.com/willf/bitset/LICENSE.txt | 27 + .../src/github.com/willf/bitset/README.md | 44 + .../src/github.com/willf/bitset/bitset.go | 614 ++ .../github.com/willf/bitset/bitset_test.go | 767 ++ .../src/github.com/willf/bitset/popcnt.go | 53 + .../github.com/willf/bitset/popcnt_amd64.s | 103 + .../src/github.com/willf/bitset/popcnt_asm.go | 64 + .../github.com/willf/bitset/popcnt_generic.go | 23 + .../x/text/transform/examples_test.go | 37 + .../golang.org/x/text/transform/transform.go | 616 ++ .../x/text/transform/transform_test.go | 1082 ++ .../golang.org/x/text/unicode/norm/Makefile | 23 + .../x/text/unicode/norm/composition.go | 514 + .../x/text/unicode/norm/composition_test.go | 130 + .../x/text/unicode/norm/example_iter_test.go | 82 + .../x/text/unicode/norm/forminfo.go | 256 + .../x/text/unicode/norm/forminfo_test.go | 54 + .../golang.org/x/text/unicode/norm/input.go | 105 + .../golang.org/x/text/unicode/norm/iter.go | 450 + .../x/text/unicode/norm/iter_test.go | 98 + .../x/text/unicode/norm/maketables.go | 1033 ++ .../x/text/unicode/norm/norm_test.go | 14 + .../x/text/unicode/norm/normalize.go | 524 + .../x/text/unicode/norm/normalize_test.go | 1086 ++ .../x/text/unicode/norm/normregtest.go | 318 + .../x/text/unicode/norm/readwriter.go | 126 + .../x/text/unicode/norm/readwriter_test.go | 56 + .../golang.org/x/text/unicode/norm/tables.go | 7549 ++++++++++++++ .../x/text/unicode/norm/transform.go | 88 + .../x/text/unicode/norm/transform_test.go | 101 + .../golang.org/x/text/unicode/norm/trie.go | 54 + .../golang.org/x/text/unicode/norm/triegen.go | 117 + args/args.go | 14 + bindata.go | 36 +- client/src/js/components/Connect.jsx | 2 +- irc.go | 4 +- main.go | 42 +- message_handler.go | 4 + session.go | 2 +- storage/init.go | 36 - storage/storage.go | 53 + storage/user.go | 156 +- websocket.go | 4 +- websocket_handler.go | 42 +- 738 files changed, 143131 insertions(+), 112 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/.gitignore create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/LICENSE create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/README.md create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer/custom_analyzer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/detect_lang_analyzer/detect_lang_analyzer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/keyword_analyzer/keyword_analyzer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/simple_analyzer/simple_analyzer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/standard_analyzer/standard_analyzer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/ignore/ignore_byte_array_converter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/json/json_byte_array_converter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/string/string_byte_array_conveter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/html_char_filter/html_char_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/zero_width_non_joiner/zero_width_non_joiner_char_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/datetime_optional/datetime_optional.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_filter_ar.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_words_ar.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_filter_bg.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_words_bg.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/articles_ca.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_filter_ca.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_words_ca.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_filter_ckb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_words_ckb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_filter_cs.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_words_cs.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stemmer_da.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_filter_da.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_words_da.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stemmer_de.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_filter_de.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_words_de.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_filter_el.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_words_el.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_filter_en.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_words_en.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stemmer_es.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_filter_es.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_words_es.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_filter_eu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_words_eu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_filter_fa.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_words_fa.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stemmer_fi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_filter_fi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_words_fi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/articles_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stemmer_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_filter_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_words_fr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/articles_ga.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_filter_ga.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_words_ga.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_filter_gl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_words_gl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_filter_hi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_words_hi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stemmer_hu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_filter_hu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_words_hu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_filter_hy.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_words_hy.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_filter_id.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_words_id.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/scripts.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/articles_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stemmer_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_filter_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_words_it.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stemmer_nl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_filter_nl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_words_nl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stemmer_no.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_filter_no.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_words_no.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/porter/stemmer_porter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stemmer_pt.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_filter_pt.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_words_pt.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stemmer_ro.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_filter_ro.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_words_ro.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stemmer_ru.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_filter_ru.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_words_ru.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stemmer_sv.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_filter_sv.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_words_sv.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_filter_th.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_words_th.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/unicode_tokenizer_th.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stemmer_tr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_filter_tr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_words_tr.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/test_words.txt create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/README.md create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.cc create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.h create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/compile_cld2.sh create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/README.md create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map/custom.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/type.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_cld2.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_cznicb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_forestdb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_icu.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_kagome.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_leveldb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_metrics.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_rocksdb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/config_stemmer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/doc.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/docs/bleve.png create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/docs/build_children.sh create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/docs/merge-coverprofile.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/docs/old_build_script.txt create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/docs/project-code-coverage.sh create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/document.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/field.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_composite.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_datetime.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_text.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/error.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/examples_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/alias.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/debug.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_count.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_delete.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_get.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_index.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/fields.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/handlers_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_create.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_delete.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_get.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_list.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/registry.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/search.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/http/util.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/index.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/batch.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/batch.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/batch.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/batch.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/util.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/batch.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/util.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/kvstore.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/batch.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/iterator.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/util.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/writer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/merge.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/analysis_pool.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_all.sh create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_boltdb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_common_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_cznicb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_forestdb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_goleveldb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gorocksdb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gtreap_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_inmem_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_leveldb_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_null_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_index_cache.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/index_reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_merge.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/stats.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.pb.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.proto create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_impl.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_stats.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/index_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_document.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_field.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_index.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_boolean.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_conjunction.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_date_range.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_disjunction.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_fuzzy.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_match.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_all.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_none.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_phrase.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_numeric_range.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_phrase.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_prefix.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_regexp.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nex create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nn.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_term.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/query_wildcard.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/reflect.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/analyzer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/byte_array_converter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/char_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/datetime_parser.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragment_formatter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragmenter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/highlighter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/registry.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/store.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_filter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_maps.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/registry/tokenizer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/collector.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/search_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/explanation.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/benchmark_data.txt create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_datetime.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi/fragment_formatter_ansi.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighter.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_conjunction.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_disjunction.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/sqrt_cache.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/search.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/base_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/ordered_searchers_list.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_fuzzy.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_prefix.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/util.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search/util_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/search_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/a.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/b.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/c.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/d.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/mapping.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/searches.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/a.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/b.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/c.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/d.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/e.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/f.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/g.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/h.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/i.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/j.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/mapping.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/searches.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3311@FOSDEM15@fosdem.org.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3492@FOSDEM15@fosdem.org.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3496@FOSDEM15@fosdem.org.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3505@FOSDEM15@fosdem.org.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3507@FOSDEM15@fosdem.org.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/mapping.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/searches.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/data/a.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/mapping.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/searches.json create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_bulkindex/main.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_create/main.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_dump/main.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_index/main.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_query/main.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_registry/main.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.gitignore create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/LICENSE create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/README.md create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_contains_vowel_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fixes_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fuzz_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_repeat_double_consonant_suffix_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_suffix_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_is_consontant_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_measure_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_string_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_without_lower_casing_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1a_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1b_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1c_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step2_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step3_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step4_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5a_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5b_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/.gitignore create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/LICENSE create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/Makefile create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/README.md create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/doc.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/export_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/maketables.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/maketesttables.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/segment.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/segment_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/segment_words.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/segment_words_test.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/tables.go create mode 100644 Godeps/_workspace/src/github.com/blevesearch/segment/tables_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/b/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/b/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/b/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/b/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/b/README.md create mode 100644 Godeps/_workspace/src/github.com/cznic/b/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/b/btree.go create mode 100644 Godeps/_workspace/src/github.com/cznic/b/example/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/b/example/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/b/example/int.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go create mode 100644 Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go create mode 100644 Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist.go create mode 100644 Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist_test.go create mode 100644 Godeps/_workspace/src/github.com/steveyen/gtreap/.gitignore create mode 100644 Godeps/_workspace/src/github.com/steveyen/gtreap/LICENSE create mode 100644 Godeps/_workspace/src/github.com/steveyen/gtreap/README.md create mode 100644 Godeps/_workspace/src/github.com/steveyen/gtreap/treap.go create mode 100644 Godeps/_workspace/src/github.com/steveyen/gtreap/treap_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/doc.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/filter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/db.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/iter.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kv.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/crc32.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/hash.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool_legacy.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/util.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go create mode 100644 Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/.gitignore create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/CHANGELOG create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/LICENSE.txt create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/README.md create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/bitset.go create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/bitset_test.go create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/popcnt.go create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/popcnt_amd64.s create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/popcnt_asm.go create mode 100644 Godeps/_workspace/src/github.com/willf/bitset/popcnt_generic.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/transform/examples_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/transform/transform.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/transform/transform_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/Makefile create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/example_iter_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/input.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/maketables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/norm_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/normregtest.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/tables.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform_test.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/trie.go create mode 100644 Godeps/_workspace/src/golang.org/x/text/unicode/norm/triegen.go create mode 100644 args/args.go delete mode 100644 storage/init.go create mode 100644 storage/storage.go diff --git a/.gitignore b/.gitignore index bebc1e38..d9f28a1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -bin/ client/dist/ -client/node_modules/ -data.db \ No newline at end of file +client/node_modules/ \ No newline at end of file diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 0904e45d..f4722b4c 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,19 +1,72 @@ { "ImportPath": "github.com/khlieng/name_pending", "GoVersion": "go1.4", + "Packages": [ + "./..." + ], "Deps": [ + { + "ImportPath": "github.com/blevesearch/bleve", + "Rev": "16f538d7b76dd85c935a3104c390307cae5cbf79" + }, + { + "ImportPath": "github.com/blevesearch/go-porterstemmer", + "Comment": "v1.0.1-9-g23a2c8e", + "Rev": "23a2c8e5cf1f380f27722c6d2ae8896431dc7d0e" + }, + { + "ImportPath": "github.com/blevesearch/segment", + "Rev": "9588637ce3caba8516208ccc17193ddedd741418" + }, { "ImportPath": "github.com/boltdb/bolt", "Comment": "v1.0-43-gcf33c9e", "Rev": "cf33c9e0ca0a23509b8bb8edfc63e4776bb1a330" }, + { + "ImportPath": "github.com/cznic/b", + "Rev": "c4adf3a58579a2d57cd3097f455dcdf75edcdfd8" + }, + { + "ImportPath": "github.com/golang/protobuf/proto", + "Rev": "655cdfa588ea190e901bc5590e65d5621688847c" + }, { "ImportPath": "github.com/julienschmidt/httprouter", "Rev": "b428fda53bb0a764fea9c76c9413512eda291dec" }, + { + "ImportPath": "github.com/ryszard/goskiplist/skiplist", + "Rev": "2dfbae5fcf46374f166f8969cb07e167f1be6273" + }, + { + "ImportPath": "github.com/steveyen/gtreap", + "Rev": "72cd76f34c91f8d64a031af97b499e4a0b1a6e0c" + }, + { + "ImportPath": "github.com/syndtr/goleveldb/leveldb", + "Rev": "4875955338b0a434238a31165cb87255ab6e9e4a" + }, + { + "ImportPath": "github.com/syndtr/gosnappy/snappy", + "Rev": "156a073208e131d7d2e212cb749feae7c339e846" + }, + { + "ImportPath": "github.com/willf/bitset", + "Comment": "v1.0.0-17-g4b22041", + "Rev": "4b220417a489359f934045d0509d941a7a2a1038" + }, { "ImportPath": "golang.org/x/net/websocket", "Rev": "3d87fd621ca9a824c5cff17216ce44769456cb3f" + }, + { + "ImportPath": "golang.org/x/text/transform", + "Rev": "c92eb3cd6e70951a111680995e651ea4b2c35539" + }, + { + "ImportPath": "golang.org/x/text/unicode/norm", + "Rev": "c92eb3cd6e70951a111680995e651ea4b2c35539" } ] } diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/.gitignore b/Godeps/_workspace/src/github.com/blevesearch/bleve/.gitignore new file mode 100644 index 00000000..97f0415d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/.gitignore @@ -0,0 +1,17 @@ +#* +*.sublime-* +*~ +.#* +.project +.settings +.DS_Store +/analysis/token_filters/cld2/cld2-read-only +/analysis/token_filters/cld2/libcld2_full.a +/utils/bleve_create/bleve_create +/utils/bleve_dump/bleve_dump +/utils/bleve_index/bleve_index +/utils/bleve_bulkindex/bleve_bulkindex +/utils/bleve_index/index.bleve/ +/utils/bleve_query/bleve_query +/utils/bleve_registry/bleve_registry +/y.output diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/.travis.yml b/Godeps/_workspace/src/github.com/blevesearch/bleve/.travis.yml new file mode 100644 index 00000000..27f309a3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/.travis.yml @@ -0,0 +1,19 @@ +language: go + +go: + - 1.4 + +script: + - go get golang.org/x/tools/cmd/vet + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - go get github.com/kisielk/errcheck + - go test -v ./... + - go vet ./... + - errcheck ./... + - docs/project-code-coverage.sh + - docs/build_children.sh + +notifications: + email: + - marty.schoch@gmail.com diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/LICENSE b/Godeps/_workspace/src/github.com/blevesearch/bleve/LICENSE new file mode 100644 index 00000000..7a4a3ea2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/README.md b/Godeps/_workspace/src/github.com/blevesearch/bleve/README.md new file mode 100644 index 00000000..4289dc2f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/README.md @@ -0,0 +1,61 @@ +# ![bleve](docs/bleve.png) bleve + +[![Build Status](https://travis-ci.org/blevesearch/bleve.svg?branch=master)](https://travis-ci.org/blevesearch/bleve) [![Coverage Status](https://coveralls.io/repos/blevesearch/bleve/badge.png?branch=master)](https://coveralls.io/r/blevesearch/bleve?branch=master) [![GoDoc](https://godoc.org/github.com/blevesearch/bleve?status.svg)](https://godoc.org/github.com/blevesearch/bleve) [![Join the chat at https://gitter.im/blevesearch/bleve](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/blevesearch/bleve?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +modern text indexing in go - [blevesearch.com](http://www.blevesearch.com/) + +Try out bleve live by [searching our wiki](http://wikisearch.blevesearch.com/search/). + +## Features + +* Index any go data structure (including JSON) +* Intelligent defaults backed up by powerful configuration +* Supported field types: + * Text, Numeric, Date +* Supported query types: + * Term, Phrase, Match, Match Phrase, Prefix + * Conjunction, Disjunction, Boolean + * Numeric Range, Date Range + * Simple query [syntax](https://github.com/blevesearch/bleve/wiki/Query-String-Query) for human entry +* tf-idf Scoring +* Search result match highlighting +* Supports Aggregating Facets: + * Terms Facet + * Numeric Range Facet + * Date Range Facet + +## Discussion + +Discuss usage and development of bleve in the [google group](https://groups.google.com/forum/#!forum/bleve). + +## Indexing + + message := struct{ + Id string + From string + Body string + }{ + Id: "example", + From: "marty.schoch@gmail.com", + Body: "bleve indexing is easy", + } + + mapping := bleve.NewIndexMapping() + index, err := bleve.New("example.bleve", mapping) + if err != nil { + panic(err) + } + index.Index(message.Id, message) + +## Querying + + index, _ := bleve.Open("example.bleve") + query := bleve.NewQueryStringQuery("bleve") + searchRequest := bleve.NewSearchRequest(query) + searchResult, _ := index.Search(searchRequest) + +## License + +Apache License Version 2.0 + + diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer/custom_analyzer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer/custom_analyzer.go new file mode 100644 index 00000000..ba327f7b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer/custom_analyzer.go @@ -0,0 +1,130 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package standard_analyzer + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "custom" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + + var err error + var charFilters []analysis.CharFilter + charFiltersNames, ok := config["char_filters"].([]string) + if ok { + charFilters, err = getCharFilters(charFiltersNames, cache) + if err != nil { + return nil, err + } + } else { + charFiltersNamesInterfaceSlice, ok := config["char_filters"].([]interface{}) + if ok { + charFiltersNames, err := convertInterfaceSliceToStringSlice(charFiltersNamesInterfaceSlice, "char filter") + if err != nil { + return nil, err + } + charFilters, err = getCharFilters(charFiltersNames, cache) + if err != nil { + return nil, err + } + } + } + + tokenizerName, ok := config["tokenizer"].(string) + if !ok { + return nil, fmt.Errorf("must specify tokenizer") + } + + tokenizer, err := cache.TokenizerNamed(tokenizerName) + if err != nil { + return nil, err + } + + var tokenFilters []analysis.TokenFilter + tokenFiltersNames, ok := config["token_filters"].([]string) + if ok { + tokenFilters, err = getTokenFilters(tokenFiltersNames, cache) + if err != nil { + return nil, err + } + } else { + tokenFiltersNamesInterfaceSlice, ok := config["token_filters"].([]interface{}) + if ok { + tokenFiltersNames, err := convertInterfaceSliceToStringSlice(tokenFiltersNamesInterfaceSlice, "token filter") + if err != nil { + return nil, err + } + tokenFilters, err = getTokenFilters(tokenFiltersNames, cache) + if err != nil { + return nil, err + } + } + } + + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + } + if charFilters != nil { + rv.CharFilters = charFilters + } + if tokenFilters != nil { + rv.TokenFilters = tokenFilters + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(Name, AnalyzerConstructor) +} + +func getCharFilters(charFilterNames []string, cache *registry.Cache) ([]analysis.CharFilter, error) { + charFilters := make([]analysis.CharFilter, len(charFilterNames)) + for i, charFilterName := range charFilterNames { + charFilter, err := cache.CharFilterNamed(charFilterName) + if err != nil { + return nil, err + } + charFilters[i] = charFilter + } + + return charFilters, nil +} + +func getTokenFilters(tokenFilterNames []string, cache *registry.Cache) ([]analysis.TokenFilter, error) { + tokenFilters := make([]analysis.TokenFilter, len(tokenFilterNames)) + for i, tokenFilterName := range tokenFilterNames { + tokenFilter, err := cache.TokenFilterNamed(tokenFilterName) + if err != nil { + return nil, err + } + tokenFilters[i] = tokenFilter + } + + return tokenFilters, nil +} + +func convertInterfaceSliceToStringSlice(interfaceSlice []interface{}, objType string) ([]string, error) { + stringSlice := make([]string, len(interfaceSlice)) + for i, interfaceObj := range interfaceSlice { + stringObj, ok := interfaceObj.(string) + if ok { + stringSlice[i] = stringObj + } else { + return nil, fmt.Errorf(objType + " name must be a string") + } + } + + return stringSlice, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/detect_lang_analyzer/detect_lang_analyzer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/detect_lang_analyzer/detect_lang_analyzer.go new file mode 100644 index 00000000..8b2f2b85 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/detect_lang_analyzer/detect_lang_analyzer.go @@ -0,0 +1,49 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build cld2 full + +package detect_lang_analyzer + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "detect_lang" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + keywordTokenizer, err := cache.TokenizerNamed(single_token.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + detectLangFilter, err := cache.TokenFilterNamed(cld2.Name) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: keywordTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + detectLangFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(Name, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/keyword_analyzer/keyword_analyzer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/keyword_analyzer/keyword_analyzer.go new file mode 100644 index 00000000..57827035 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/keyword_analyzer/keyword_analyzer.go @@ -0,0 +1,33 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package keyword_analyzer + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "keyword" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + keywordTokenizer, err := cache.TokenizerNamed(single_token.Name) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: keywordTokenizer, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(Name, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/simple_analyzer/simple_analyzer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/simple_analyzer/simple_analyzer.go new file mode 100644 index 00000000..b7ffd770 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/simple_analyzer/simple_analyzer.go @@ -0,0 +1,41 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple_analyzer + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "simple" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(Name, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/standard_analyzer/standard_analyzer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/standard_analyzer/standard_analyzer.go new file mode 100644 index 00000000..ab551da1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/standard_analyzer/standard_analyzer.go @@ -0,0 +1,47 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package standard_analyzer + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "standard" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopEnFilter, err := cache.TokenFilterNamed(en.StopName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopEnFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(Name, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/ignore/ignore_byte_array_converter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/ignore/ignore_byte_array_converter.go new file mode 100644 index 00000000..413d8781 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/ignore/ignore_byte_array_converter.go @@ -0,0 +1,33 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ignore_byte_array_converter + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +type IgnoreByteArrayConverter struct{} + +func NewIgnoreByteArrayConverter() *IgnoreByteArrayConverter { + return &IgnoreByteArrayConverter{} +} + +func (c *IgnoreByteArrayConverter) Convert(in []byte) (interface{}, error) { + return nil, nil +} + +func Constructor(config map[string]interface{}, cache *registry.Cache) (analysis.ByteArrayConverter, error) { + return NewIgnoreByteArrayConverter(), nil +} + +func init() { + registry.RegisterByteArrayConverter("ignore", Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/json/json_byte_array_converter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/json/json_byte_array_converter.go new file mode 100644 index 00000000..d64221fa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/json/json_byte_array_converter.go @@ -0,0 +1,40 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package json_byte_array_converter + +import ( + "encoding/json" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +type JSONByteArrayConverter struct{} + +func NewJSONByteArrayConverter() *JSONByteArrayConverter { + return &JSONByteArrayConverter{} +} + +func (c *JSONByteArrayConverter) Convert(in []byte) (interface{}, error) { + var rv map[string]interface{} + err := json.Unmarshal(in, &rv) + if err != nil { + return nil, err + } + return rv, nil +} + +func Constructor(config map[string]interface{}, cache *registry.Cache) (analysis.ByteArrayConverter, error) { + return NewJSONByteArrayConverter(), nil +} + +func init() { + registry.RegisterByteArrayConverter("json", Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/string/string_byte_array_conveter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/string/string_byte_array_conveter.go new file mode 100644 index 00000000..7f170d1c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/string/string_byte_array_conveter.go @@ -0,0 +1,33 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package string_byte_array_converter + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +type StringByteArrayConverter struct{} + +func NewStringByteArrayConverter() *StringByteArrayConverter { + return &StringByteArrayConverter{} +} + +func (c *StringByteArrayConverter) Convert(in []byte) (interface{}, error) { + return string(in), nil +} + +func Constructor(config map[string]interface{}, cache *registry.Cache) (analysis.ByteArrayConverter, error) { + return NewStringByteArrayConverter(), nil +} + +func init() { + registry.RegisterByteArrayConverter("string", Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/html_char_filter/html_char_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/html_char_filter/html_char_filter.go new file mode 100644 index 00000000..521f5dd0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/html_char_filter/html_char_filter.go @@ -0,0 +1,31 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package html_char_filter + +import ( + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "html" + +var htmlCharFilterRegexp = regexp.MustCompile(`\s]+))?)+\s*|\s*)/?>`) + +func CharFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.CharFilter, error) { + replaceBytes := []byte(" ") + return regexp_char_filter.NewRegexpCharFilter(htmlCharFilterRegexp, replaceBytes), nil +} + +func init() { + registry.RegisterCharFilter(Name, CharFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter.go new file mode 100644 index 00000000..ee7fcc41 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package regexp_char_filter + +import ( + "bytes" + "fmt" + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "regexp" + +type RegexpCharFilter struct { + r *regexp.Regexp + replacement []byte +} + +func NewRegexpCharFilter(r *regexp.Regexp, replacement []byte) *RegexpCharFilter { + return &RegexpCharFilter{ + r: r, + replacement: replacement, + } +} + +func (s *RegexpCharFilter) Filter(input []byte) []byte { + return s.r.ReplaceAllFunc(input, func(in []byte) []byte { return bytes.Repeat(s.replacement, len(in)) }) +} + +func RegexpCharFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.CharFilter, error) { + regexpStr, ok := config["regexp"].(string) + if !ok { + return nil, fmt.Errorf("must specify regexp") + } + r, err := regexp.Compile(regexpStr) + if err != nil { + return nil, fmt.Errorf("unable to build regexp char filter: %v", err) + } + replaceBytes := []byte(" ") + replaceStr, ok := config["replace"].(string) + if ok { + replaceBytes = []byte(replaceStr) + } + return NewRegexpCharFilter(r, replaceBytes), nil +} + +func init() { + registry.RegisterCharFilter(Name, RegexpCharFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter_test.go new file mode 100644 index 00000000..d51ed78c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter/regexp_char_filter_test.go @@ -0,0 +1,82 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package regexp_char_filter + +import ( + "reflect" + "regexp" + "testing" +) + +func TestRegexpCharFilter(t *testing.T) { + + htmlTagPattern := `\s]+))?)+\s*|\s*)/?>` + htmlRegex := regexp.MustCompile(htmlTagPattern) + + tests := []struct { + input []byte + output []byte + }{ + { + input: []byte(` + + + +

My First Heading

+ +

My first paragraph.

+ + +`), + output: []byte(` + + + + My First Heading + + My first paragraph. + + + `), + }, + } + + for _, test := range tests { + filter := NewRegexpCharFilter(htmlRegex, []byte{' '}) + output := filter.Filter(test.input) + if !reflect.DeepEqual(output, test.output) { + t.Errorf("Expected:\n`%s`\ngot:\n`%s`\nfor:\n`%s`\n", string(test.output), string(output), string(test.input)) + } + } +} + +func TestZeroWidthNonJoinerCharFilter(t *testing.T) { + + zeroWidthNonJoinerPattern := `\x{200C}` + zeroWidthNonJoinerRegex := regexp.MustCompile(zeroWidthNonJoinerPattern) + + tests := []struct { + input []byte + output []byte + }{ + { + input: []byte("water\u200Cunder\u200Cthe\u200Cbridge"), + output: []byte("water under the bridge"), + }, + } + + for _, test := range tests { + filter := NewRegexpCharFilter(zeroWidthNonJoinerRegex, []byte{' '}) + output := filter.Filter(test.input) + if !reflect.DeepEqual(output, test.output) { + t.Errorf("Expected:\n`%s`\ngot:\n`%s`\nfor:\n`%s`\n", string(test.output), string(output), string(test.input)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/zero_width_non_joiner/zero_width_non_joiner_char_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/zero_width_non_joiner/zero_width_non_joiner_char_filter.go new file mode 100644 index 00000000..8e2c290a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/zero_width_non_joiner/zero_width_non_joiner_char_filter.go @@ -0,0 +1,31 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package zero_width_non_joiner + +import ( + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "zero_width_spaces" + +var zeroWidthNonJoinerRegexp = regexp.MustCompile(`\x{200C}`) + +func CharFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.CharFilter, error) { + replaceBytes := []byte(" ") + return regexp_char_filter.NewRegexpCharFilter(zeroWidthNonJoinerRegexp, replaceBytes), nil +} + +func init() { + registry.RegisterCharFilter(Name, CharFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/datetime_optional/datetime_optional.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/datetime_optional/datetime_optional.go new file mode 100644 index 00000000..0ea96a3f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/datetime_optional/datetime_optional.go @@ -0,0 +1,40 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package html_char_filter + +import ( + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "dateTimeOptional" + +const rfc3339NoTimezone = "2006-01-02T15:04:05" +const rfc3339NoTimezoneNoT = "2006-01-02 15:04:05" +const rfc3339NoTime = "2006-01-02" + +var layouts = []string{ + time.RFC3339Nano, + time.RFC3339, + rfc3339NoTimezone, + rfc3339NoTimezoneNoT, + rfc3339NoTime, +} + +func DateTimeParserConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.DateTimeParser, error) { + return flexible_go.NewFlexibleGoDateTimeParser(layouts), nil +} + +func init() { + registry.RegisterDateTimeParser(Name, DateTimeParserConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go.go new file mode 100644 index 00000000..e5431042 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go.go @@ -0,0 +1,59 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package flexible_go + +import ( + "fmt" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "flexiblego" + +type FlexibleGoDateTimeParser struct { + layouts []string +} + +func NewFlexibleGoDateTimeParser(layouts []string) *FlexibleGoDateTimeParser { + return &FlexibleGoDateTimeParser{ + layouts: layouts, + } +} + +func (p *FlexibleGoDateTimeParser) ParseDateTime(input string) (time.Time, error) { + for _, layout := range p.layouts { + rv, err := time.Parse(layout, input) + if err == nil { + return rv, nil + } + } + return time.Time{}, analysis.ErrInvalidDateTime +} + +func FlexibleGoDateTimeParserConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.DateTimeParser, error) { + layouts, ok := config["layouts"].([]interface{}) + if !ok { + return nil, fmt.Errorf("must specify layouts") + } + layoutStrs := make([]string, 0) + for _, layout := range layouts { + layoutStr, ok := layout.(string) + if ok { + layoutStrs = append(layoutStrs, layoutStr) + } + } + return NewFlexibleGoDateTimeParser(layoutStrs), nil +} + +func init() { + registry.RegisterDateTimeParser(Name, FlexibleGoDateTimeParserConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go_test.go new file mode 100644 index 00000000..70150ff6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go/flexible_go_test.go @@ -0,0 +1,84 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package flexible_go + +import ( + "reflect" + "testing" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestFlexibleDateTimeParser(t *testing.T) { + testLocation := time.FixedZone("", -8*60*60) + + tests := []struct { + input string + expectedTime time.Time + expectedError error + }{ + { + input: "2014-08-03", + expectedTime: time.Date(2014, 8, 3, 0, 0, 0, 0, time.UTC), + expectedError: nil, + }, + { + input: "2014-08-03T15:59:30", + expectedTime: time.Date(2014, 8, 3, 15, 59, 30, 0, time.UTC), + expectedError: nil, + }, + { + input: "2014-08-03 15:59:30", + expectedTime: time.Date(2014, 8, 3, 15, 59, 30, 0, time.UTC), + expectedError: nil, + }, + { + input: "2014-08-03T15:59:30-08:00", + expectedTime: time.Date(2014, 8, 3, 15, 59, 30, 0, testLocation), + expectedError: nil, + }, + { + input: "2014-08-03T15:59:30.999999999-08:00", + expectedTime: time.Date(2014, 8, 3, 15, 59, 30, 999999999, testLocation), + expectedError: nil, + }, + { + input: "not a date time", + expectedTime: time.Time{}, + expectedError: analysis.ErrInvalidDateTime, + }, + } + + rfc3339NoTimezone := "2006-01-02T15:04:05" + rfc3339NoTimezoneNoT := "2006-01-02 15:04:05" + rfc3339NoTime := "2006-01-02" + + dateOptionalTimeParser := NewFlexibleGoDateTimeParser( + []string{ + time.RFC3339Nano, + time.RFC3339, + rfc3339NoTimezone, + rfc3339NoTimezoneNoT, + rfc3339NoTime, + }) + + for _, test := range tests { + actualTime, actualErr := dateOptionalTimeParser.ParseDateTime(test.input) + if actualErr != test.expectedError { + t.Errorf("expected error %#v, got %#v", test.expectedError, actualErr) + continue + } + if !reflect.DeepEqual(actualTime, test.expectedTime) { + t.Errorf("expected time %#v, got %#v", test.expectedTime, actualTime) + t.Errorf("expected location %#v,\n got %#v", test.expectedTime.Location(), actualTime.Location()) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq.go new file mode 100644 index 00000000..1cf96414 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq.go @@ -0,0 +1,88 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +type TokenLocation struct { + Field string + Start int + End int + Position int +} + +type TokenFreq struct { + Term []byte + Locations []*TokenLocation +} + +type TokenFrequencies []*TokenFreq + +func (tfs TokenFrequencies) MergeAll(remoteField string, other TokenFrequencies) TokenFrequencies { + // put existing tokens into a map + index := make(map[string]*TokenFreq) + for _, tf := range tfs { + index[string(tf.Term)] = tf + } + // walk the new token frequencies + for _, tf := range other { + // set the remoteField value in incoming token freqs + for _, l := range tf.Locations { + l.Field = remoteField + } + existingTf, exists := index[string(tf.Term)] + if exists { + existingTf.Locations = append(existingTf.Locations, tf.Locations...) + } else { + index[string(tf.Term)] = tf + } + } + // flatten map back to array + rv := make(TokenFrequencies, len(index)) + i := 0 + for _, tf := range index { + rv[i] = tf + i++ + } + return rv +} + +func TokenFrequency(tokens TokenStream) TokenFrequencies { + index := make(map[string]*TokenFreq) + + for _, token := range tokens { + curr, ok := index[string(token.Term)] + if ok { + curr.Locations = append(curr.Locations, &TokenLocation{ + Start: token.Start, + End: token.End, + Position: token.Position, + }) + } else { + index[string(token.Term)] = &TokenFreq{ + Term: token.Term, + Locations: []*TokenLocation{ + &TokenLocation{ + Start: token.Start, + End: token.End, + Position: token.Position, + }, + }, + } + } + } + + rv := make(TokenFrequencies, len(index)) + i := 0 + for _, tf := range index { + rv[i] = tf + i++ + } + + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq_test.go new file mode 100644 index 00000000..02c945ba --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/freq_test.go @@ -0,0 +1,167 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +import ( + "reflect" + "testing" +) + +func TestTokenFrequency(t *testing.T) { + tokens := TokenStream{ + &Token{ + Term: []byte("water"), + Position: 1, + Start: 0, + End: 5, + }, + &Token{ + Term: []byte("water"), + Position: 2, + Start: 6, + End: 11, + }, + } + expectedResult := TokenFrequencies{ + &TokenFreq{ + Term: []byte("water"), + Locations: []*TokenLocation{ + &TokenLocation{ + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Position: 2, + Start: 6, + End: 11, + }, + }, + }, + } + result := TokenFrequency(tokens) + if !reflect.DeepEqual(result, expectedResult) { + t.Errorf("expected %#v, got %#v", expectedResult, result) + } +} + +func TestTokenFrequenciesMergeAll(t *testing.T) { + tf1 := TokenFrequencies{ + &TokenFreq{ + Term: []byte("water"), + Locations: []*TokenLocation{ + &TokenLocation{ + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Position: 2, + Start: 6, + End: 11, + }, + }, + }, + } + tf2 := TokenFrequencies{ + &TokenFreq{ + Term: []byte("water"), + Locations: []*TokenLocation{ + &TokenLocation{ + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Position: 2, + Start: 6, + End: 11, + }, + }, + }, + } + expectedResult := TokenFrequencies{ + &TokenFreq{ + Term: []byte("water"), + Locations: []*TokenLocation{ + &TokenLocation{ + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Position: 2, + Start: 6, + End: 11, + }, + &TokenLocation{ + Field: "tf2", + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Field: "tf2", + Position: 2, + Start: 6, + End: 11, + }, + }, + }, + } + tf1.MergeAll("tf2", tf2) + if !reflect.DeepEqual(tf1, expectedResult) { + t.Errorf("expected %#v, got %#v", expectedResult, tf1) + } +} + +func TestTokenFrequenciesMergeAllLeftEmpty(t *testing.T) { + tf1 := TokenFrequencies{} + tf2 := TokenFrequencies{ + &TokenFreq{ + Term: []byte("water"), + Locations: []*TokenLocation{ + &TokenLocation{ + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Position: 2, + Start: 6, + End: 11, + }, + }, + }, + } + expectedResult := TokenFrequencies{ + &TokenFreq{ + Term: []byte("water"), + Locations: []*TokenLocation{ + &TokenLocation{ + Field: "tf2", + Position: 1, + Start: 0, + End: 5, + }, + &TokenLocation{ + Field: "tf2", + Position: 2, + Start: 6, + End: 11, + }, + }, + }, + } + result := tf1.MergeAll("tf2", tf2) + if !reflect.DeepEqual(result, expectedResult) { + t.Errorf("expected %#v, got %#v", expectedResult, result) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar.go new file mode 100644 index 00000000..c41d4ae9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar.go @@ -0,0 +1,59 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "ar" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + normalizeFilter := unicode_normalize.MustNewUnicodeNormalizeFilter(unicode_normalize.NFKC) + stopArFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + normalizeArFilter, err := cache.TokenFilterNamed(NormalizeName) + if err != nil { + return nil, err + } + stemmerArFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + normalizeFilter, + stopArFilter, + normalizeArFilter, + stemmerArFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar_test.go new file mode 100644 index 00000000..963d4000 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/analyzer_ar_test.go @@ -0,0 +1,179 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestArabicAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + input: []byte("كبير"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كبير"), + Position: 1, + Start: 0, + End: 8, + }, + }, + }, + // feminine marker + { + input: []byte("كبيرة"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كبير"), + Position: 1, + Start: 0, + End: 10, + }, + }, + }, + { + input: []byte("مشروب"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("مشروب"), + Position: 1, + Start: 0, + End: 10, + }, + }, + }, + // plural -at + { + input: []byte("مشروبات"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("مشروب"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + // plural -in + { + input: []byte("أمريكيين"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("امريك"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + // singular with bare alif + { + input: []byte("امريكي"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("امريك"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { + input: []byte("كتاب"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كتاب"), + Position: 1, + Start: 0, + End: 8, + }, + }, + }, + // definite article + { + input: []byte("الكتاب"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كتاب"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { + input: []byte("ما ملكت أيمانكم"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ملكت"), + Position: 2, + Start: 5, + End: 13, + }, + &analysis.Token{ + Term: []byte("ايمانكم"), + Position: 3, + Start: 14, + End: 28, + }, + }, + }, + // stopwords + { + input: []byte("الذين ملكت أيمانكم"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ملكت"), + Position: 2, + Start: 11, + End: 19, + }, + &analysis.Token{ + Term: []byte("ايمانكم"), + Position: 3, + Start: 20, + End: 34, + }, + }, + }, + // presentation form normalization + { + input: []byte("ﺍﻟﺴﻼﻢ"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلام"), + Position: 1, + Start: 0, + End: 15, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize.go new file mode 100644 index 00000000..a310ea96 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const NormalizeName = "normalize_ar" + +const ( + Alef = '\u0627' + AlefMadda = '\u0622' + AlefHamzaAbove = '\u0623' + AlefHamzaBelow = '\u0625' + Yeh = '\u064A' + DotlessYeh = '\u0649' + TehMarbuta = '\u0629' + Heh = '\u0647' + Tatweel = '\u0640' + Fathatan = '\u064B' + Dammatan = '\u064C' + Kasratan = '\u064D' + Fatha = '\u064E' + Damma = '\u064F' + Kasra = '\u0650' + Shadda = '\u0651' + Sukun = '\u0652' +) + +type ArabicNormalizeFilter struct { +} + +func NewArabicNormalizeFilter() *ArabicNormalizeFilter { + return &ArabicNormalizeFilter{} +} + +func (s *ArabicNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + term := normalize(token.Term) + token.Term = term + } + return input +} + +func normalize(input []byte) []byte { + runes := bytes.Runes(input) + for i := 0; i < len(runes); i++ { + switch runes[i] { + case AlefMadda, AlefHamzaAbove, AlefHamzaBelow: + runes[i] = Alef + case DotlessYeh: + runes[i] = Yeh + case TehMarbuta: + runes[i] = Heh + case Tatweel, Kasratan, Dammatan, Fathatan, Fatha, Damma, Kasra, Shadda, Sukun: + runes = analysis.DeleteRune(runes, i) + i-- + } + } + return analysis.BuildTermFromRunes(runes) +} + +func NormalizerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewArabicNormalizeFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(NormalizeName, NormalizerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize_test.go new file mode 100644 index 00000000..20aa97ff --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/arabic_normalize_test.go @@ -0,0 +1,229 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestArabicNormalizeFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // AlifMadda + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("آجن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("اجن"), + }, + }, + }, + // AlifHamzaAbove + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("أحمد"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("احمد"), + }, + }, + }, + // AlifHamzaBelow + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("إعاذ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("اعاذ"), + }, + }, + }, + // AlifMaksura + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بنى"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بني"), + }, + }, + }, + // TehMarbuta + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("فاطمة"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("فاطمه"), + }, + }, + }, + // Tatweel + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("روبرـــــت"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("روبرت"), + }, + }, + }, + // Fatha + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("مَبنا"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("مبنا"), + }, + }, + }, + // Kasra + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("علِي"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("علي"), + }, + }, + }, + // Damma + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بُوات"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بوات"), + }, + }, + }, + // Fathatan + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ولداً"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ولدا"), + }, + }, + }, + // Kasratan + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ولدٍ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ولد"), + }, + }, + }, + // Dammatan + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ولدٌ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ولد"), + }, + }, + }, + // Sukun + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("نلْسون"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("نلسون"), + }, + }, + }, + // Shaddah + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هتميّ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هتمي"), + }, + }, + }, + // empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + arabicNormalizeFilter := NewArabicNormalizeFilter() + for _, test := range tests { + actual := arabicNormalizeFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar.go new file mode 100644 index 00000000..6d762fbd --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar.go @@ -0,0 +1,113 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_ar" + +// These were obtained from org.apache.lucene.analysis.ar.ArabicStemmer +var prefixes = [][]rune{ + []rune("ال"), + []rune("وال"), + []rune("بال"), + []rune("كال"), + []rune("فال"), + []rune("لل"), + []rune("و"), +} +var suffixes = [][]rune{ + []rune("ها"), + []rune("ان"), + []rune("ات"), + []rune("ون"), + []rune("ين"), + []rune("يه"), + []rune("ية"), + []rune("ه"), + []rune("ة"), + []rune("ي"), +} + +type ArabicStemmerFilter struct{} + +func NewArabicStemmerFilter() *ArabicStemmerFilter { + return &ArabicStemmerFilter{} +} + +func (s *ArabicStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + term := stem(token.Term) + token.Term = term + } + return input +} + +func canStemPrefix(input, prefix []rune) bool { + // Wa- prefix requires at least 3 characters. + if len(prefix) == 1 && len(input) < 4 { + return false + } + // Other prefixes require only 2. + if len(input)-len(prefix) < 2 { + return false + } + for i := range prefix { + if prefix[i] != input[i] { + return false + } + } + return true +} + +func canStemSuffix(input, suffix []rune) bool { + // All suffixes require at least 2 characters after stemming. + if len(input)-len(suffix) < 2 { + return false + } + stemEnd := len(input) - len(suffix) + for i := range suffix { + if suffix[i] != input[stemEnd+i] { + return false + } + } + return true +} + +func stem(input []byte) []byte { + runes := bytes.Runes(input) + // Strip a single prefix. + for _, p := range prefixes { + if canStemPrefix(runes, p) { + runes = runes[len(p):] + break + } + } + // Strip off multiple suffixes, in their order in the suffixes array. + for _, s := range suffixes { + if canStemSuffix(runes, s) { + runes = runes[:len(runes)-len(s)] + } + } + return analysis.BuildTermFromRunes(runes) +} + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewArabicStemmerFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar_test.go new file mode 100644 index 00000000..3e37f2c8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stemmer_ar_test.go @@ -0,0 +1,392 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestArabicStemmerFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // AlPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("الحسن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("حسن"), + }, + }, + }, + // WalPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("والحسن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("حسن"), + }, + }, + }, + // BalPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بالحسن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("حسن"), + }, + }, + }, + // KalPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كالحسن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("حسن"), + }, + }, + }, + // FalPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("فالحسن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("حسن"), + }, + }, + }, + // LlPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("للاخر"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("اخر"), + }, + }, + }, + // WaPrefix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("وحسن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("حسن"), + }, + }, + }, + // AhSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("زوجها"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("زوج"), + }, + }, + }, + // AnSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدان"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // AtSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدات"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // WnSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدون"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // YnSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدين"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // YhSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهديه"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // YpSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدية"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // HSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهده"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // PSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدة"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // YSuffix + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدي"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // ComboPrefSuf + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("وساهدون"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // ComboSuf + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهدهات"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ساهد"), + }, + }, + }, + // ShouldntStem + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("الو"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("الو"), + }, + }, + }, + // NonArabic + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("English"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("English"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلام"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلام"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("السلام"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلام"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلامة"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلام"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("السلامة"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سلام"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("الوصل"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("وصل"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("والصل"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("صل"), + }, + }, + }, + // Empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + arabicStemmerFilter := NewArabicStemmerFilter() + for _, test := range tests { + actual := arabicStemmerFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_filter_ar.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_filter_ar.go new file mode 100644 index 00000000..e567e191 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_filter_ar.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ar + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_words_ar.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_words_ar.go new file mode 100644 index 00000000..20755f50 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar/stop_words_ar.go @@ -0,0 +1,149 @@ +package ar + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_ar" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis +// ` was changed to ' to allow for literal string + +var ArabicStopWords = []byte(`# This file was created by Jacques Savoy and is distributed under the BSD license. +# See http://members.unine.ch/jacques.savoy/clef/index.html. +# Also see http://www.opensource.org/licenses/bsd-license.html +# Cleaned on October 11, 2009 (not normalized, so use before normalization) +# This means that when modifying this list, you might need to add some +# redundant entries, for example containing forms with both أ and ا +من +ومن +منها +منه +في +وفي +فيها +فيه +و +ف +ثم +او +أو +ب +بها +به +ا +أ +اى +اي +أي +أى +لا +ولا +الا +ألا +إلا +لكن +ما +وما +كما +فما +عن +مع +اذا +إذا +ان +أن +إن +انها +أنها +إنها +انه +أنه +إنه +بان +بأن +فان +فأن +وان +وأن +وإن +التى +التي +الذى +الذي +الذين +الى +الي +إلى +إلي +على +عليها +عليه +اما +أما +إما +ايضا +أيضا +كل +وكل +لم +ولم +لن +ولن +هى +هي +هو +وهى +وهي +وهو +فهى +فهي +فهو +انت +أنت +لك +لها +له +هذه +هذا +تلك +ذلك +هناك +كانت +كان +يكون +تكون +وكانت +وكان +غير +بعض +قد +نحو +بين +بينما +منذ +ضمن +حيث +الان +الآن +خلال +بعد +قبل +حتى +عند +عندما +لدى +جميع +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(ArabicStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_filter_bg.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_filter_bg.go new file mode 100644 index 00000000..9a198225 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_filter_bg.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bg + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_words_bg.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_words_bg.go new file mode 100644 index 00000000..ee3eeac8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg/stop_words_bg.go @@ -0,0 +1,217 @@ +package bg + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_bg" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var BulgarianStopWords = []byte(`# This file was created by Jacques Savoy and is distributed under the BSD license. +# See http://members.unine.ch/jacques.savoy/clef/index.html. +# Also see http://www.opensource.org/licenses/bsd-license.html +а +аз +ако +ала +бе +без +беше +би +бил +била +били +било +близо +бъдат +бъде +бяха +в +вас +ваш +ваша +вероятно +вече +взема +ви +вие +винаги +все +всеки +всички +всичко +всяка +във +въпреки +върху +г +ги +главно +го +д +да +дали +до +докато +докога +дори +досега +доста +е +едва +един +ето +за +зад +заедно +заради +засега +затова +защо +защото +и +из +или +им +има +имат +иска +й +каза +как +каква +какво +както +какъв +като +кога +когато +което +които +кой +който +колко +която +къде +където +към +ли +м +ме +между +мен +ми +мнозина +мога +могат +може +моля +момента +му +н +на +над +назад +най +направи +напред +например +нас +не +него +нея +ни +ние +никой +нито +но +някои +някой +няма +обаче +около +освен +особено +от +отгоре +отново +още +пак +по +повече +повечето +под +поне +поради +после +почти +прави +пред +преди +през +при +пък +първо +с +са +само +се +сега +си +скоро +след +сме +според +сред +срещу +сте +съм +със +също +т +тази +така +такива +такъв +там +твой +те +тези +ти +тн +то +това +тогава +този +той +толкова +точно +трябва +тук +тъй +тя +тях +у +харесва +ч +че +често +чрез +ще +щом +я +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(BulgarianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/articles_ca.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/articles_ca.go new file mode 100644 index 00000000..516d8946 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/articles_ca.go @@ -0,0 +1,30 @@ +package ca + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ArticlesName = "articles_ca" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis + +var CatalanArticles = []byte(` +d +l +m +n +s +t +`) + +func ArticlesTokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(CatalanArticles) + return rv, err +} + +func init() { + registry.RegisterTokenMap(ArticlesName, ArticlesTokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca.go new file mode 100644 index 00000000..8110edfc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca.go @@ -0,0 +1,32 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ca + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ElisionName = "elision_ca" + +func ElisionFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + articlesTokenMap, err := cache.TokenMapNamed(ArticlesName) + if err != nil { + return nil, fmt.Errorf("error building elision filter: %v", err) + } + return elision_filter.NewElisionFilter(articlesTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(ElisionName, ElisionFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca_test.go new file mode 100644 index 00000000..49aff361 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/elision_ca_test.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ca + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFrenchElision(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("l'Institut"), + }, + &analysis.Token{ + Term: []byte("d'Estudis"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Institut"), + }, + &analysis.Token{ + Term: []byte("Estudis"), + }, + }, + }, + } + + cache := registry.NewCache() + elisionFilter, err := cache.TokenFilterNamed(ElisionName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := elisionFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_filter_ca.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_filter_ca.go new file mode 100644 index 00000000..8597808e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_filter_ca.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ca + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_words_ca.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_words_ca.go new file mode 100644 index 00000000..063a43bb --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca/stop_words_ca.go @@ -0,0 +1,244 @@ +package ca + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_ca" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var CatalanStopWords = []byte(`# Catalan stopwords from http://github.com/vcl/cue.language (Apache 2 Licensed) +a +abans +ací +ah +així +això +al +als +aleshores +algun +alguna +algunes +alguns +alhora +allà +allí +allò +altra +altre +altres +amb +ambdós +ambdues +apa +aquell +aquella +aquelles +aquells +aquest +aquesta +aquestes +aquests +aquí +baix +cada +cadascú +cadascuna +cadascunes +cadascuns +com +contra +d'un +d'una +d'unes +d'uns +dalt +de +del +dels +des +després +dins +dintre +donat +doncs +durant +e +eh +el +els +em +en +encara +ens +entre +érem +eren +éreu +es +és +esta +està +estàvem +estaven +estàveu +esteu +et +etc +ets +fins +fora +gairebé +ha +han +has +havia +he +hem +heu +hi +ho +i +igual +iguals +ja +l'hi +la +les +li +li'n +llavors +m'he +ma +mal +malgrat +mateix +mateixa +mateixes +mateixos +me +mentre +més +meu +meus +meva +meves +molt +molta +moltes +molts +mon +mons +n'he +n'hi +ne +ni +no +nogensmenys +només +nosaltres +nostra +nostre +nostres +o +oh +oi +on +pas +pel +pels +per +però +perquè +poc +poca +pocs +poques +potser +propi +qual +quals +quan +quant +que +què +quelcom +qui +quin +quina +quines +quins +s'ha +s'han +sa +semblant +semblants +ses +seu +seus +seva +seva +seves +si +sobre +sobretot +sóc +solament +sols +son +són +sons +sota +sou +t'ha +t'han +t'he +ta +tal +també +tampoc +tan +tant +tanta +tantes +teu +teus +teva +teves +ton +tons +tot +tota +totes +tots +un +una +unes +uns +us +va +vaig +vam +van +vas +veu +vosaltres +vostra +vostre +vostres +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(CatalanStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk.go new file mode 100644 index 00000000..f29bb5c7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk.go @@ -0,0 +1,49 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package cjk + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "cjk" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + whitespaceTokenizer, err := cache.TokenizerNamed(whitespace_tokenizer.Name) + if err != nil { + return nil, err + } + normalizeFilter := unicode_normalize.MustNewUnicodeNormalizeFilter(unicode_normalize.NFKD) + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + bigramFilter, err := cache.TokenFilterNamed(BigramName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: whitespaceTokenizer, + TokenFilters: []analysis.TokenFilter{ + normalizeFilter, + toLowerFilter, + bigramFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk_test.go new file mode 100644 index 00000000..80af6ab0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/analyzer_cjk_test.go @@ -0,0 +1,620 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package cjk + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestCJKAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + input: []byte("こんにちは世界"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こん"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("んに"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("にち"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("ちは"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("は世"), + Type: analysis.Double, + Position: 5, + Start: 12, + End: 18, + }, + &analysis.Token{ + Term: []byte("世界"), + Type: analysis.Double, + Position: 6, + Start: 15, + End: 21, + }, + }, + }, + { + input: []byte("一二三四五六七八九十"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("一二"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("二三"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("三四"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("四五"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("五六"), + Type: analysis.Double, + Position: 5, + Start: 12, + End: 18, + }, + &analysis.Token{ + Term: []byte("六七"), + Type: analysis.Double, + Position: 6, + Start: 15, + End: 21, + }, + &analysis.Token{ + Term: []byte("七八"), + Type: analysis.Double, + Position: 7, + Start: 18, + End: 24, + }, + &analysis.Token{ + Term: []byte("八九"), + Type: analysis.Double, + Position: 8, + Start: 21, + End: 27, + }, + &analysis.Token{ + Term: []byte("九十"), + Type: analysis.Double, + Position: 9, + Start: 24, + End: 30, + }, + }, + }, + { + input: []byte("一 二三四 五六七八九 十"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("一"), + Type: analysis.Single, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("二三"), + Type: analysis.Double, + Position: 2, + Start: 4, + End: 10, + }, + &analysis.Token{ + Term: []byte("三四"), + Type: analysis.Double, + Position: 3, + Start: 7, + End: 13, + }, + &analysis.Token{ + Term: []byte("五六"), + Type: analysis.Double, + Position: 5, + Start: 14, + End: 20, + }, + &analysis.Token{ + Term: []byte("六七"), + Type: analysis.Double, + Position: 6, + Start: 17, + End: 23, + }, + &analysis.Token{ + Term: []byte("七八"), + Type: analysis.Double, + Position: 7, + Start: 20, + End: 26, + }, + &analysis.Token{ + Term: []byte("八九"), + Type: analysis.Double, + Position: 8, + Start: 23, + End: 29, + }, + &analysis.Token{ + Term: []byte("十"), + Type: analysis.Single, + Position: 10, + Start: 30, + End: 33, + }, + }, + }, + { + input: []byte("abc defgh ijklmn opqrstu vwxy z"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abc"), + Type: analysis.AlphaNumeric, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("defgh"), + Type: analysis.AlphaNumeric, + Position: 2, + Start: 4, + End: 9, + }, + &analysis.Token{ + Term: []byte("ijklmn"), + Type: analysis.AlphaNumeric, + Position: 3, + Start: 10, + End: 16, + }, + &analysis.Token{ + Term: []byte("opqrstu"), + Type: analysis.AlphaNumeric, + Position: 4, + Start: 17, + End: 24, + }, + &analysis.Token{ + Term: []byte("vwxy"), + Type: analysis.AlphaNumeric, + Position: 5, + Start: 25, + End: 29, + }, + &analysis.Token{ + Term: []byte("z"), + Type: analysis.AlphaNumeric, + Position: 6, + Start: 30, + End: 31, + }, + }, + }, + { + input: []byte("あい"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("あい"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + }, + }, + { + input: []byte("あい "), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("あい"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + }, + }, + { + input: []byte("test"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("test"), + Type: analysis.AlphaNumeric, + Position: 1, + Start: 0, + End: 4, + }, + }, + }, + { + input: []byte("test "), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("test"), + Type: analysis.AlphaNumeric, + Position: 1, + Start: 0, + End: 4, + }, + }, + }, + { + input: []byte("あいtest"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("あい"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("test"), + Type: analysis.AlphaNumeric, + Position: 3, + Start: 6, + End: 10, + }, + }, + }, + { + input: []byte("testあい "), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("test"), + Type: analysis.AlphaNumeric, + Position: 1, + Start: 0, + End: 4, + }, + &analysis.Token{ + Term: []byte("あい"), + Type: analysis.Double, + Position: 2, + Start: 4, + End: 10, + }, + }, + }, + { + input: []byte("あいうえおabcかきくけこ"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("あい"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("いう"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("うえ"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("えお"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("abc"), + Type: analysis.AlphaNumeric, + Position: 6, + Start: 15, + End: 18, + }, + &analysis.Token{ + Term: []byte("かき"), + Type: analysis.Double, + Position: 7, + Start: 18, + End: 24, + }, + &analysis.Token{ + Term: []byte("きく"), + Type: analysis.Double, + Position: 8, + Start: 21, + End: 27, + }, + &analysis.Token{ + Term: []byte("くけ"), + Type: analysis.Double, + Position: 9, + Start: 24, + End: 30, + }, + &analysis.Token{ + Term: []byte("けこ"), + Type: analysis.Double, + Position: 10, + Start: 27, + End: 33, + }, + }, + }, + { + input: []byte("あいうえおabんcかきくけ こ"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("あい"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("いう"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("うえ"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("えお"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("ab"), + Type: analysis.AlphaNumeric, + Position: 6, + Start: 15, + End: 17, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Single, + Position: 7, + Start: 17, + End: 20, + }, + &analysis.Token{ + Term: []byte("c"), + Type: analysis.AlphaNumeric, + Position: 8, + Start: 20, + End: 21, + }, + &analysis.Token{ + Term: []byte("かき"), + Type: analysis.Double, + Position: 9, + Start: 21, + End: 27, + }, + &analysis.Token{ + Term: []byte("きく"), + Type: analysis.Double, + Position: 10, + Start: 24, + End: 30, + }, + &analysis.Token{ + Term: []byte("くけ"), + Type: analysis.Double, + Position: 11, + Start: 27, + End: 33, + }, + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Single, + Position: 13, + Start: 34, + End: 37, + }, + }, + }, + { + input: []byte("一 روبرت موير"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("一"), + Type: analysis.Single, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("روبرت"), + Type: analysis.AlphaNumeric, + Position: 2, + Start: 4, + End: 14, + }, + &analysis.Token{ + Term: []byte("موير"), + Type: analysis.AlphaNumeric, + Position: 3, + Start: 15, + End: 23, + }, + }, + }, + { + input: []byte("一 رُوبرت موير"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("一"), + Type: analysis.Single, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("رُوبرت"), + Type: analysis.AlphaNumeric, + Position: 2, + Start: 4, + End: 16, + }, + &analysis.Token{ + Term: []byte("موير"), + Type: analysis.AlphaNumeric, + Position: 3, + Start: 17, + End: 25, + }, + }, + }, + { + input: []byte("𩬅艱鍟䇹愯瀛"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("𩬅艱"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 7, + }, + &analysis.Token{ + Term: []byte("艱鍟"), + Type: analysis.Double, + Position: 2, + Start: 4, + End: 10, + }, + &analysis.Token{ + Term: []byte("鍟䇹"), + Type: analysis.Double, + Position: 3, + Start: 7, + End: 13, + }, + &analysis.Token{ + Term: []byte("䇹愯"), + Type: analysis.Double, + Position: 4, + Start: 10, + End: 16, + }, + &analysis.Token{ + Term: []byte("愯瀛"), + Type: analysis.Double, + Position: 5, + Start: 13, + End: 19, + }, + }, + }, + { + input: []byte("一"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("一"), + Type: analysis.Single, + Position: 1, + Start: 0, + End: 3, + }, + }, + }, + { + input: []byte("一丁丂"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("一丁"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("丁丂"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + }, + }, + } + + cache := registry.NewCache() + for _, test := range tests { + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram.go new file mode 100644 index 00000000..2e902ccd --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram.go @@ -0,0 +1,166 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package cjk + +import ( + "container/ring" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const BigramName = "cjk_bigram" + +type CJKBigramFilter struct { + outputUnigram bool +} + +func NewCJKBigramFilter(outputUnigram bool) *CJKBigramFilter { + return &CJKBigramFilter{ + outputUnigram: outputUnigram, + } +} + +func (s *CJKBigramFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + r := ring.New(2) + itemsInRing := 0 + + rv := make(analysis.TokenStream, 0, len(input)) + + for _, token := range input { + if token.Type == analysis.Ideographic { + if itemsInRing > 0 { + // if items already buffered + // check to see if this is aligned + curr := r.Value.(*analysis.Token) + if token.Start-curr.End != 0 { + // not aligned flush + flushToken := s.flush(r, &itemsInRing) + if flushToken != nil { + rv = append(rv, flushToken) + } + } + } + // now we can add this token to the buffer + r = r.Next() + r.Value = token + if itemsInRing < 2 { + itemsInRing++ + } + if itemsInRing > 1 && s.outputUnigram { + unigram := s.buildUnigram(r, &itemsInRing) + if unigram != nil { + rv = append(rv, unigram) + } + } + bigramToken := s.outputBigram(r, &itemsInRing) + if bigramToken != nil { + rv = append(rv, bigramToken) + } + } else { + // flush anything already buffered + flushToken := s.flush(r, &itemsInRing) + if flushToken != nil { + rv = append(rv, flushToken) + } + // output this token as is + rv = append(rv, token) + } + } + + // deal with possible trailing unigram + if itemsInRing == 1 || s.outputUnigram { + if itemsInRing == 2 { + r = r.Next() + } + unigram := s.buildUnigram(r, &itemsInRing) + if unigram != nil { + rv = append(rv, unigram) + } + } + return rv +} + +func (s *CJKBigramFilter) flush(r *ring.Ring, itemsInRing *int) *analysis.Token { + var rv *analysis.Token + if *itemsInRing == 1 { + rv = s.buildUnigram(r, itemsInRing) + } + r.Value = nil + *itemsInRing = 0 + return rv +} + +func (s *CJKBigramFilter) outputBigram(r *ring.Ring, itemsInRing *int) *analysis.Token { + if *itemsInRing == 2 { + thisShingleRing := r.Move(-1) + shingledBytes := make([]byte, 0) + + // do first token + prev := thisShingleRing.Value.(*analysis.Token) + shingledBytes = append(shingledBytes, prev.Term...) + + // do second token + thisShingleRing = thisShingleRing.Next() + curr := thisShingleRing.Value.(*analysis.Token) + shingledBytes = append(shingledBytes, curr.Term...) + + token := analysis.Token{ + Type: analysis.Double, + Term: shingledBytes, + Position: prev.Position, + Start: prev.Start, + End: curr.End, + } + return &token + } + return nil +} + +func (s *CJKBigramFilter) buildUnigram(r *ring.Ring, itemsInRing *int) *analysis.Token { + if *itemsInRing == 2 { + thisShingleRing := r.Move(-1) + // do first token + prev := thisShingleRing.Value.(*analysis.Token) + token := analysis.Token{ + Type: analysis.Single, + Term: prev.Term, + Position: prev.Position, + Start: prev.Start, + End: prev.End, + } + return &token + } else if *itemsInRing == 1 { + // do first token + prev := r.Value.(*analysis.Token) + token := analysis.Token{ + Type: analysis.Single, + Term: prev.Term, + Position: prev.Position, + Start: prev.Start, + End: prev.End, + } + return &token + } + return nil +} + +func CJKBigramFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + outputUnigram := false + outVal, ok := config["output_unigram"].(bool) + if ok { + outputUnigram = outVal + } + return NewCJKBigramFilter(outputUnigram), nil +} + +func init() { + registry.RegisterTokenFilter(BigramName, CJKBigramFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram_test.go new file mode 100644 index 00000000..7805e969 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk/cjk_bigram_test.go @@ -0,0 +1,420 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package cjk + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestCJKBigramFilter(t *testing.T) { + + tests := []struct { + outputUnigram bool + input analysis.TokenStream + output analysis.TokenStream + }{ + { + outputUnigram: false, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Ideographic, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Ideographic, + Position: 2, + Start: 5, + End: 7, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Single, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Single, + Position: 2, + Start: 5, + End: 7, + }, + }, + }, + { + outputUnigram: false, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Ideographic, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Ideographic, + Position: 2, + Start: 3, + End: 6, + }, + &analysis.Token{ + Term: []byte("に"), + Type: analysis.Ideographic, + Position: 3, + Start: 6, + End: 9, + }, + &analysis.Token{ + Term: []byte("ち"), + Type: analysis.Ideographic, + Position: 4, + Start: 9, + End: 12, + }, + &analysis.Token{ + Term: []byte("は"), + Type: analysis.Ideographic, + Position: 5, + Start: 12, + End: 15, + }, + &analysis.Token{ + Term: []byte("世"), + Type: analysis.Ideographic, + Position: 6, + Start: 15, + End: 18, + }, + &analysis.Token{ + Term: []byte("界"), + Type: analysis.Ideographic, + Position: 7, + Start: 18, + End: 21, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こん"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("んに"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("にち"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("ちは"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("は世"), + Type: analysis.Double, + Position: 5, + Start: 12, + End: 18, + }, + &analysis.Token{ + Term: []byte("世界"), + Type: analysis.Double, + Position: 6, + Start: 15, + End: 21, + }, + }, + }, + { + outputUnigram: true, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Ideographic, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Ideographic, + Position: 2, + Start: 3, + End: 6, + }, + &analysis.Token{ + Term: []byte("に"), + Type: analysis.Ideographic, + Position: 3, + Start: 6, + End: 9, + }, + &analysis.Token{ + Term: []byte("ち"), + Type: analysis.Ideographic, + Position: 4, + Start: 9, + End: 12, + }, + &analysis.Token{ + Term: []byte("は"), + Type: analysis.Ideographic, + Position: 5, + Start: 12, + End: 15, + }, + &analysis.Token{ + Term: []byte("世"), + Type: analysis.Ideographic, + Position: 6, + Start: 15, + End: 18, + }, + &analysis.Token{ + Term: []byte("界"), + Type: analysis.Ideographic, + Position: 7, + Start: 18, + End: 21, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Single, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("こん"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Single, + Position: 2, + Start: 3, + End: 6, + }, + &analysis.Token{ + Term: []byte("んに"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("に"), + Type: analysis.Single, + Position: 3, + Start: 6, + End: 9, + }, + &analysis.Token{ + Term: []byte("にち"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("ち"), + Type: analysis.Single, + Position: 4, + Start: 9, + End: 12, + }, + &analysis.Token{ + Term: []byte("ちは"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("は"), + Type: analysis.Single, + Position: 5, + Start: 12, + End: 15, + }, + &analysis.Token{ + Term: []byte("は世"), + Type: analysis.Double, + Position: 5, + Start: 12, + End: 18, + }, + &analysis.Token{ + Term: []byte("世"), + Type: analysis.Single, + Position: 6, + Start: 15, + End: 18, + }, + &analysis.Token{ + Term: []byte("世界"), + Type: analysis.Double, + Position: 6, + Start: 15, + End: 21, + }, + &analysis.Token{ + Term: []byte("界"), + Type: analysis.Single, + Position: 7, + Start: 18, + End: 21, + }, + }, + }, + { + outputUnigram: false, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こ"), + Type: analysis.Ideographic, + Position: 1, + Start: 0, + End: 3, + }, + &analysis.Token{ + Term: []byte("ん"), + Type: analysis.Ideographic, + Position: 2, + Start: 3, + End: 6, + }, + &analysis.Token{ + Term: []byte("に"), + Type: analysis.Ideographic, + Position: 3, + Start: 6, + End: 9, + }, + &analysis.Token{ + Term: []byte("ち"), + Type: analysis.Ideographic, + Position: 4, + Start: 9, + End: 12, + }, + &analysis.Token{ + Term: []byte("は"), + Type: analysis.Ideographic, + Position: 5, + Start: 12, + End: 15, + }, + &analysis.Token{ + Term: []byte("cat"), + Type: analysis.AlphaNumeric, + Position: 6, + Start: 12, + End: 15, + }, + &analysis.Token{ + Term: []byte("世"), + Type: analysis.Ideographic, + Position: 7, + Start: 18, + End: 21, + }, + &analysis.Token{ + Term: []byte("界"), + Type: analysis.Ideographic, + Position: 8, + Start: 21, + End: 24, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こん"), + Type: analysis.Double, + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("んに"), + Type: analysis.Double, + Position: 2, + Start: 3, + End: 9, + }, + &analysis.Token{ + Term: []byte("にち"), + Type: analysis.Double, + Position: 3, + Start: 6, + End: 12, + }, + &analysis.Token{ + Term: []byte("ちは"), + Type: analysis.Double, + Position: 4, + Start: 9, + End: 15, + }, + &analysis.Token{ + Term: []byte("cat"), + Type: analysis.AlphaNumeric, + Position: 6, + Start: 12, + End: 15, + }, + &analysis.Token{ + Term: []byte("世界"), + Type: analysis.Double, + Position: 7, + Start: 18, + End: 24, + }, + }, + }, + } + + for _, test := range tests { + cjkBigramFilter := NewCJKBigramFilter(test.outputUnigram) + actual := cjkBigramFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb.go new file mode 100644 index 00000000..48b4bddd --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package ckb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "ckb" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + normCkbFilter, err := cache.TokenFilterNamed(NormalizeName) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopCkbFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerCkbFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + normCkbFilter, + toLowerFilter, + stopCkbFilter, + stemmerCkbFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb_test.go new file mode 100644 index 00000000..c0d6257b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/analyzer_ckb_test.go @@ -0,0 +1,74 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package ckb + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestSoraniAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stop word removal + { + input: []byte("ئەم پیاوە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 2, + Start: 7, + End: 17, + }, + }, + }, + { + input: []byte("پیاوە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 10, + }, + }, + }, + { + input: []byte("پیاو"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 8, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize.go new file mode 100644 index 00000000..f35fd6a0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize.go @@ -0,0 +1,113 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ckb + +import ( + "bytes" + "unicode" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const NormalizeName = "normalize_ckb" + +const ( + Yeh = '\u064A' + DotlessYeh = '\u0649' + FarsiYeh = '\u06CC' + + Kaf = '\u0643' + Keheh = '\u06A9' + + Heh = '\u0647' + Ae = '\u06D5' + Zwnj = '\u200C' + HehDoachashmee = '\u06BE' + TehMarbuta = '\u0629' + + Reh = '\u0631' + Rreh = '\u0695' + RrehAbove = '\u0692' + + Tatweel = '\u0640' + Fathatan = '\u064B' + Dammatan = '\u064C' + Kasratan = '\u064D' + Fatha = '\u064E' + Damma = '\u064F' + Kasra = '\u0650' + Shadda = '\u0651' + Sukun = '\u0652' +) + +type SoraniNormalizeFilter struct { +} + +func NewSoraniNormalizeFilter() *SoraniNormalizeFilter { + return &SoraniNormalizeFilter{} +} + +func (s *SoraniNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + term := normalize(token.Term) + token.Term = term + } + return input +} + +func normalize(input []byte) []byte { + runes := bytes.Runes(input) + for i := 0; i < len(runes); i++ { + switch runes[i] { + case Yeh, DotlessYeh: + runes[i] = FarsiYeh + case Kaf: + runes[i] = Keheh + case Zwnj: + if i > 0 && runes[i-1] == Heh { + runes[i-1] = Ae + } + runes = analysis.DeleteRune(runes, i) + i-- + case Heh: + if i == len(runes)-1 { + runes[i] = Ae + } + case TehMarbuta: + runes[i] = Ae + case HehDoachashmee: + runes[i] = Heh + case Reh: + if i == 0 { + runes[i] = Rreh + } + case RrehAbove: + runes[i] = Rreh + case Tatweel, Kasratan, Dammatan, Fathatan, Fatha, Damma, Kasra, Shadda, Sukun: + runes = analysis.DeleteRune(runes, i) + i-- + default: + if unicode.In(runes[i], unicode.Cf) { + runes = analysis.DeleteRune(runes, i) + i-- + } + } + } + return analysis.BuildTermFromRunes(runes) +} + +func NormalizerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewSoraniNormalizeFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(NormalizeName, NormalizerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize_test.go new file mode 100644 index 00000000..48a8a8f6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_normalize_test.go @@ -0,0 +1,318 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ckb + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestSoraniNormalizeFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // test Y + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u064A"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06CC"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0649"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06CC"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06CC"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06CC"), + }, + }, + }, + // test K + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0643"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06A9"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06A9"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06A9"), + }, + }, + }, + // test H + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0647\u200C"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06D5"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0647\u200C\u06A9"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06D5\u06A9"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06BE"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0647"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0629"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u06D5"), + }, + }, + }, + // test final H + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0647\u0647\u0647"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0647\u0647\u06D5"), + }, + }, + }, + // test RR + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0692"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0695"), + }, + }, + }, + // test initial RR + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0631\u0631\u0631"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0695\u0631\u0631"), + }, + }, + }, + // test remove + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0640"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u064B"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u064C"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u064D"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u064E"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u064F"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0650"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0651"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0652"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u200C"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + // empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + soraniNormalizeFilter := NewSoraniNormalizeFilter() + for _, test := range tests { + actual := soraniNormalizeFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter.go new file mode 100644 index 00000000..6f664d4e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter.go @@ -0,0 +1,143 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ckb + +import ( + "bytes" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_ckb" + +type SoraniStemmerFilter struct { +} + +func NewSoraniStemmerFilter() *SoraniStemmerFilter { + return &SoraniStemmerFilter{} +} + +func (s *SoraniStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + // if not protected keyword, stem it + if !token.KeyWord { + stemmed := stem(token.Term) + token.Term = stemmed + } + } + return input +} + +func stem(input []byte) []byte { + inputLen := utf8.RuneCount(input) + + // postposition + if inputLen > 5 && bytes.HasSuffix(input, []byte("دا")) { + input = truncateRunes(input, 2) + inputLen = utf8.RuneCount(input) + } else if inputLen > 4 && bytes.HasSuffix(input, []byte("نا")) { + input = truncateRunes(input, 1) + inputLen = utf8.RuneCount(input) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("ەوە")) { + input = truncateRunes(input, 3) + inputLen = utf8.RuneCount(input) + } + + // possessive pronoun + if inputLen > 6 && + (bytes.HasSuffix(input, []byte("مان")) || + bytes.HasSuffix(input, []byte("یان")) || + bytes.HasSuffix(input, []byte("تان"))) { + input = truncateRunes(input, 3) + inputLen = utf8.RuneCount(input) + } + + // indefinite singular ezafe + if inputLen > 6 && bytes.HasSuffix(input, []byte("ێکی")) { + return truncateRunes(input, 3) + } else if inputLen > 7 && bytes.HasSuffix(input, []byte("یەکی")) { + return truncateRunes(input, 4) + } + + if inputLen > 5 && bytes.HasSuffix(input, []byte("ێک")) { + // indefinite singular + return truncateRunes(input, 2) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("یەک")) { + // indefinite singular + return truncateRunes(input, 3) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("ەکە")) { + // definite singular + return truncateRunes(input, 3) + } else if inputLen > 5 && bytes.HasSuffix(input, []byte("کە")) { + // definite singular + return truncateRunes(input, 2) + } else if inputLen > 7 && bytes.HasSuffix(input, []byte("ەکان")) { + // definite plural + return truncateRunes(input, 4) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("کان")) { + // definite plural + return truncateRunes(input, 3) + } else if inputLen > 7 && bytes.HasSuffix(input, []byte("یانی")) { + // indefinite plural ezafe + return truncateRunes(input, 4) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("انی")) { + // indefinite plural ezafe + return truncateRunes(input, 3) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("یان")) { + // indefinite plural + return truncateRunes(input, 3) + } else if inputLen > 5 && bytes.HasSuffix(input, []byte("ان")) { + // indefinite plural + return truncateRunes(input, 2) + } else if inputLen > 7 && bytes.HasSuffix(input, []byte("یانە")) { + // demonstrative plural + return truncateRunes(input, 4) + } else if inputLen > 6 && bytes.HasSuffix(input, []byte("انە")) { + // demonstrative plural + return truncateRunes(input, 3) + } else if inputLen > 5 && (bytes.HasSuffix(input, []byte("ایە")) || bytes.HasSuffix(input, []byte("ەیە"))) { + // demonstrative singular + return truncateRunes(input, 2) + } else if inputLen > 4 && bytes.HasSuffix(input, []byte("ە")) { + // demonstrative singular + return truncateRunes(input, 1) + } else if inputLen > 4 && bytes.HasSuffix(input, []byte("ی")) { + // absolute singular ezafe + return truncateRunes(input, 1) + } + return input +} + +func truncateRunes(input []byte, num int) []byte { + runes := bytes.Runes(input) + runes = runes[:len(runes)-num] + out := buildTermFromRunes(runes) + return out +} + +func buildTermFromRunes(runes []rune) []byte { + rv := make([]byte, 0, len(runes)*4) + for _, r := range runes { + runeBytes := make([]byte, utf8.RuneLen(r)) + utf8.EncodeRune(runeBytes, r) + rv = append(rv, runeBytes...) + } + return rv +} + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewSoraniStemmerFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter_test.go new file mode 100644 index 00000000..fab292c5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/sorani_stemmer_filter_test.go @@ -0,0 +1,294 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ckb + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token" +) + +func TestSoraniStemmerFilter(t *testing.T) { + + // in order to match the lucene tests + // we will test with an analyzer, not just the stemmer + analyzer := analysis.Analyzer{ + Tokenizer: single_token.NewSingleTokenTokenizer(), + TokenFilters: []analysis.TokenFilter{ + NewSoraniNormalizeFilter(), + NewSoraniStemmerFilter(), + }, + } + + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { // -ek + input: []byte("پیاوێک"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { // -yek + input: []byte("دەرگایەک"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دەرگا"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + { // -aka + input: []byte("پیاوەكە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -ka + input: []byte("دەرگاكە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دەرگا"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -a + input: []byte("کتاویە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("کتاوی"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { // -ya + input: []byte("دەرگایە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دەرگا"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -An + input: []byte("پیاوان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { // -yAn + input: []byte("دەرگایان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دەرگا"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + { // -akAn + input: []byte("پیاوەکان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + { // -kAn + input: []byte("دەرگاکان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دەرگا"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + { // -Ana + input: []byte("پیاوانە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پیاو"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -yAna + input: []byte("دەرگایانە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دەرگا"), + Position: 1, + Start: 0, + End: 18, + }, + }, + }, + { // Ezafe singular + input: []byte("هۆتیلی"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هۆتیل"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { // Ezafe indefinite + input: []byte("هۆتیلێکی"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هۆتیل"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + { // Ezafe plural + input: []byte("هۆتیلانی"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هۆتیل"), + Position: 1, + Start: 0, + End: 16, + }, + }, + }, + { // -awa + input: []byte("دوورەوە"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("دوور"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -dA + input: []byte("نیوەشەودا"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("نیوەشەو"), + Position: 1, + Start: 0, + End: 18, + }, + }, + }, + { // -A + input: []byte("سۆرانا"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("سۆران"), + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + { // -mAn + input: []byte("پارەمان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پارە"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -tAn + input: []byte("پارەتان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پارە"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // -yAn + input: []byte("پارەیان"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("پارە"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { // empty + input: []byte(""), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + Position: 1, + Start: 0, + End: 0, + }, + }, + }, + } + + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("for input %s(% x)", test.input, test.input) + t.Errorf("\texpected:") + for _, token := range test.output { + t.Errorf("\t\t%v %s(% x)", token, token.Term, token.Term) + } + t.Errorf("\tactual:") + for _, token := range actual { + t.Errorf("\t\t%v %s(% x)", token, token.Term, token.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_filter_ckb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_filter_ckb.go new file mode 100644 index 00000000..46efffac --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_filter_ckb.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ckb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_words_ckb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_words_ckb.go new file mode 100644 index 00000000..55654af8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb/stop_words_ckb.go @@ -0,0 +1,160 @@ +package ckb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_ckb" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var SoraniStopWords = []byte(`# set of kurdish stopwords +# note these have been normalized with our scheme (e represented with U+06D5, etc) +# constructed from: +# * Fig 5 of "Building A Test Collection For Sorani Kurdish" (Esmaili et al) +# * "Sorani Kurdish: A Reference Grammar with selected readings" (Thackston) +# * Corpus-based analysis of 77M word Sorani collection: wikipedia, news, blogs, etc + +# and +و +# which +کە +# of +ی +# made/did +کرد +# that/which +ئەوەی +# on/head +سەر +# two +دوو +# also +هەروەها +# from/that +لەو +# makes/does +دەکات +# some +چەند +# every +هەر + +# demonstratives +# that +ئەو +# this +ئەم + +# personal pronouns +# I +من +# we +ئێمە +# you +تۆ +# you +ئێوە +# he/she/it +ئەو +# they +ئەوان + +# prepositions +# to/with/by +بە +پێ +# without +بەبێ +# along with/while/during +بەدەم +# in the opinion of +بەلای +# according to +بەپێی +# before +بەرلە +# in the direction of +بەرەوی +# in front of/toward +بەرەوە +# before/in the face of +بەردەم +# without +بێ +# except for +بێجگە +# for +بۆ +# on/in +دە +تێ +# with +دەگەڵ +# after +دوای +# except for/aside from +جگە +# in/from +لە +لێ +# in front of/before/because of +لەبەر +# between/among +لەبەینی +# concerning/about +لەبابەت +# concerning +لەبارەی +# instead of +لەباتی +# beside +لەبن +# instead of +لەبرێتی +# behind +لەدەم +# with/together with +لەگەڵ +# by +لەلایەن +# within +لەناو +# between/among +لەنێو +# for the sake of +لەپێناوی +# with respect to +لەرەوی +# by means of/for +لەرێ +# for the sake of +لەرێگا +# on/on top of/according to +لەسەر +# under +لەژێر +# between/among +ناو +# between/among +نێوان +# after +پاش +# before +پێش +# like +وەک +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(SoraniStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_filter_cs.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_filter_cs.go new file mode 100644 index 00000000..8e7e34d5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_filter_cs.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package cs + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_words_cs.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_words_cs.go new file mode 100644 index 00000000..28e1b6c5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs/stop_words_cs.go @@ -0,0 +1,196 @@ +package cs + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_cs" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var CzechStopWords = []byte(`a +s +k +o +i +u +v +z +dnes +cz +tímto +budeš +budem +byli +jseš +můj +svým +ta +tomto +tohle +tuto +tyto +jej +zda +proč +máte +tato +kam +tohoto +kdo +kteří +mi +nám +tom +tomuto +mít +nic +proto +kterou +byla +toho +protože +asi +ho +naši +napište +re +což +tím +takže +svých +její +svými +jste +aj +tu +tedy +teto +bylo +kde +ke +pravé +ji +nad +nejsou +či +pod +téma +mezi +přes +ty +pak +vám +ani +když +však +neg +jsem +tento +článku +články +aby +jsme +před +pta +jejich +byl +ještě +až +bez +také +pouze +první +vaše +která +nás +nový +tipy +pokud +může +strana +jeho +své +jiné +zprávy +nové +není +vás +jen +podle +zde +už +být +více +bude +již +než +který +by +které +co +nebo +ten +tak +má +při +od +po +jsou +jak +další +ale +si +se +ve +to +jako +za +zpět +ze +do +pro +je +na +atd +atp +jakmile +přičemž +já +on +ona +ono +oni +ony +my +vy +jí +ji +mě +mne +jemu +tomu +těm +těmu +němu +němuž +jehož +jíž +jelikož +jež +jakož +načež +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(CzechStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da.go new file mode 100644 index 00000000..f9fe25d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package da + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "da" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopDaFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerDaFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopDaFilter, + stemmerDaFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da_test.go new file mode 100644 index 00000000..2b63d46c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/analyzer_da_test.go @@ -0,0 +1,69 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package da + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestDanishAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("undersøg"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("undersøg"), + Position: 1, + Start: 0, + End: 9, + }, + }, + }, + { + input: []byte("undersøgelse"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("undersøg"), + Position: 1, + Start: 0, + End: 13, + }, + }, + }, + // stop word + { + input: []byte("på"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stemmer_da.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stemmer_da.go new file mode 100644 index 00000000..4b7fc2dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stemmer_da.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package da + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_da" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("da") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_filter_da.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_filter_da.go new file mode 100644 index 00000000..e72c9e31 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_filter_da.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package da + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_words_da.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_words_da.go new file mode 100644 index 00000000..8ae6a539 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da/stop_words_da.go @@ -0,0 +1,134 @@ +package da + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_da" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var DanishStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/danish/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Danish stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + | This is a ranked list (commonest to rarest) of stopwords derived from + | a large text sample. + + +og | and +i | in +jeg | I +det | that (dem. pronoun)/it (pers. pronoun) +at | that (in front of a sentence)/to (with infinitive) +en | a/an +den | it (pers. pronoun)/that (dem. pronoun) +til | to/at/for/until/against/by/of/into, more +er | present tense of "to be" +som | who, as +på | on/upon/in/on/at/to/after/of/with/for, on +de | they +med | with/by/in, along +han | he +af | of/by/from/off/for/in/with/on, off +for | at/for/to/from/by/of/ago, in front/before, because +ikke | not +der | who/which, there/those +var | past tense of "to be" +mig | me/myself +sig | oneself/himself/herself/itself/themselves +men | but +et | a/an/one, one (number), someone/somebody/one +har | present tense of "to have" +om | round/about/for/in/a, about/around/down, if +vi | we +min | my +havde | past tense of "to have" +ham | him +hun | she +nu | now +over | over/above/across/by/beyond/past/on/about, over/past +da | then, when/as/since +fra | from/off/since, off, since +du | you +ud | out +sin | his/her/its/one's +dem | them +os | us/ourselves +op | up +man | you/one +hans | his +hvor | where +eller | or +hvad | what +skal | must/shall etc. +selv | myself/youself/herself/ourselves etc., even +her | here +alle | all/everyone/everybody etc. +vil | will (verb) +blev | past tense of "to stay/to remain/to get/to become" +kunne | could +ind | in +når | when +være | present tense of "to be" +dog | however/yet/after all +noget | something +ville | would +jo | you know/you see (adv), yes +deres | their/theirs +efter | after/behind/according to/for/by/from, later/afterwards +ned | down +skulle | should +denne | this +end | than +dette | this +mit | my/mine +også | also +under | under/beneath/below/during, below/underneath +have | have +dig | you +anden | other +hende | her +mine | my +alt | everything +meget | much/very, plenty of +sit | his, her, its, one's +sine | his, her, its, one's +vor | our +mod | against +disse | these +hvis | if +din | your/yours +nogle | some +hos | by/at +blive | be/become +mange | many +ad | by/through +bliver | present tense of "to be/to become" +hendes | her/hers +været | be +thi | for (conj) +jer | you +sådan | such, like this/like that +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(DanishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de.go new file mode 100644 index 00000000..8d181868 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de.go @@ -0,0 +1,59 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package de + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "de" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopDeFilter, err := cache.TokenFilterNamed(NormalizeName) + if err != nil { + return nil, err + } + normalizeDeFilter, err := cache.TokenFilterNamed(NormalizeName) + if err != nil { + return nil, err + } + stemmerDeFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopDeFilter, + normalizeDeFilter, + stemmerDeFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de_test.go new file mode 100644 index 00000000..e760bf6b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/analyzer_de_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package de + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestGermanAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + input: []byte("Tisch"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("tisch"), + Position: 1, + Start: 0, + End: 5, + }, + }, + }, + { + input: []byte("Tische"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("tisch"), + Position: 1, + Start: 0, + End: 6, + }, + }, + }, + { + input: []byte("Tischen"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("tisch"), + Position: 1, + Start: 0, + End: 7, + }, + }, + }, + // german specials + { + input: []byte("Schaltflächen"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("schaltflach"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + { + input: []byte("Schaltflaechen"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("schaltflach"), + Position: 1, + Start: 0, + End: 14, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize.go new file mode 100644 index 00000000..b67abaf7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize.go @@ -0,0 +1,94 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package de + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const NormalizeName = "normalize_de" + +const ( + N = /* ordinary state */ 0 + V = 1 /* stops 'u' from entering umlaut state */ + U = 2 /* umlaut state, allows e-deletion */ +) + +type GermanNormalizeFilter struct { +} + +func NewGermanNormalizeFilter() *GermanNormalizeFilter { + return &GermanNormalizeFilter{} +} + +func (s *GermanNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + term := normalize(token.Term) + token.Term = term + } + return input +} + +func normalize(input []byte) []byte { + state := N + runes := bytes.Runes(input) + for i := 0; i < len(runes); i++ { + switch runes[i] { + case 'a', 'o': + state = U + case 'u': + if state == N { + state = U + } else { + state = V + } + case 'e': + if state == U { + runes = analysis.DeleteRune(runes, i) + i-- + } + state = V + case 'i', 'q', 'y': + state = V + case 'ä': + runes[i] = 'a' + state = V + case 'ö': + runes[i] = 'o' + state = V + case 'ü': + runes[i] = 'u' + state = V + case 'ß': + runes[i] = 's' + i++ + // newrunes := make([]rune, len(runes)+1) + // copy(newrunes, runes) + // runes = newrunes + // runes[i] = 's' + runes = analysis.InsertRune(runes, i, 's') + state = N + default: + state = N + } + } + return analysis.BuildTermFromRunes(runes) +} + +func NormalizerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewGermanNormalizeFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(NormalizeName, NormalizerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize_test.go new file mode 100644 index 00000000..f9a4c8d1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/german_normalize_test.go @@ -0,0 +1,98 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package de + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestGermanNormalizeFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // Tests that a/o/u + e is equivalent to the umlaut form + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Schaltflächen"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Schaltflachen"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Schaltflaechen"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Schaltflachen"), + }, + }, + }, + // Tests the specific heuristic that ue is not folded after a vowel or q. + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("dauer"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("dauer"), + }, + }, + }, + // Tests german specific folding of sharp-s + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("weißbier"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("weissbier"), + }, + }, + }, + // empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + germanNormalizeFilter := NewGermanNormalizeFilter() + for _, test := range tests { + actual := germanNormalizeFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected %s(% x), got %s(% x)", test.output[0].Term, test.output[0].Term, actual[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stemmer_de.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stemmer_de.go new file mode 100644 index 00000000..3a80ebda --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stemmer_de.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package de + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_de" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("de") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_filter_de.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_filter_de.go new file mode 100644 index 00000000..856eab5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_filter_de.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package de + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_words_de.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_words_de.go new file mode 100644 index 00000000..2168bbc4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de/stop_words_de.go @@ -0,0 +1,318 @@ +package de + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_de" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var GermanStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/german/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A German stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + | The number of forms in this list is reduced significantly by passing it + | through the German stemmer. + + +aber | but + +alle | all +allem +allen +aller +alles + +als | than, as +also | so +am | an + dem +an | at + +ander | other +andere +anderem +anderen +anderer +anderes +anderm +andern +anderr +anders + +auch | also +auf | on +aus | out of +bei | by +bin | am +bis | until +bist | art +da | there +damit | with it +dann | then + +der | the +den +des +dem +die +das + +daß | that + +derselbe | the same +derselben +denselben +desselben +demselben +dieselbe +dieselben +dasselbe + +dazu | to that + +dein | thy +deine +deinem +deinen +deiner +deines + +denn | because + +derer | of those +dessen | of him + +dich | thee +dir | to thee +du | thou + +dies | this +diese +diesem +diesen +dieser +dieses + + +doch | (several meanings) +dort | (over) there + + +durch | through + +ein | a +eine +einem +einen +einer +eines + +einig | some +einige +einigem +einigen +einiger +einiges + +einmal | once + +er | he +ihn | him +ihm | to him + +es | it +etwas | something + +euer | your +eure +eurem +euren +eurer +eures + +für | for +gegen | towards +gewesen | p.p. of sein +hab | have +habe | have +haben | have +hat | has +hatte | had +hatten | had +hier | here +hin | there +hinter | behind + +ich | I +mich | me +mir | to me + + +ihr | you, to her +ihre +ihrem +ihren +ihrer +ihres +euch | to you + +im | in + dem +in | in +indem | while +ins | in + das +ist | is + +jede | each, every +jedem +jeden +jeder +jedes + +jene | that +jenem +jenen +jener +jenes + +jetzt | now +kann | can + +kein | no +keine +keinem +keinen +keiner +keines + +können | can +könnte | could +machen | do +man | one + +manche | some, many a +manchem +manchen +mancher +manches + +mein | my +meine +meinem +meinen +meiner +meines + +mit | with +muss | must +musste | had to +nach | to(wards) +nicht | not +nichts | nothing +noch | still, yet +nun | now +nur | only +ob | whether +oder | or +ohne | without +sehr | very + +sein | his +seine +seinem +seinen +seiner +seines + +selbst | self +sich | herself + +sie | they, she +ihnen | to them + +sind | are +so | so + +solche | such +solchem +solchen +solcher +solches + +soll | shall +sollte | should +sondern | but +sonst | else +über | over +um | about, around +und | and + +uns | us +unse +unsem +unsen +unser +unses + +unter | under +viel | much +vom | von + dem +von | from +vor | before +während | while +war | was +waren | were +warst | wast +was | what +weg | away, off +weil | because +weiter | further + +welche | which +welchem +welchen +welcher +welches + +wenn | when +werde | will +werden | will +wie | how +wieder | again +will | want +wir | we +wird | will +wirst | willst +wo | where +wollen | want +wollte | wanted +würde | would +würden | would +zu | to +zum | zu + dem +zur | zu + der +zwar | indeed +zwischen | between + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(GermanStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_filter_el.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_filter_el.go new file mode 100644 index 00000000..3ce2c1d3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_filter_el.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package el + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_words_el.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_words_el.go new file mode 100644 index 00000000..e2238795 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el/stop_words_el.go @@ -0,0 +1,102 @@ +package el + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_el" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var GreekStopWords = []byte(`# Lucene Greek Stopwords list +# Note: by default this file is used after GreekLowerCaseFilter, +# so when modifying this file use 'σ' instead of 'ς' +ο +η +το +οι +τα +του +τησ +των +τον +την +και +κι +κ +ειμαι +εισαι +ειναι +ειμαστε +ειστε +στο +στον +στη +στην +μα +αλλα +απο +για +προσ +με +σε +ωσ +παρα +αντι +κατα +μετα +θα +να +δε +δεν +μη +μην +επι +ενω +εαν +αν +τοτε +που +πωσ +ποιοσ +ποια +ποιο +ποιοι +ποιεσ +ποιων +ποιουσ +αυτοσ +αυτη +αυτο +αυτοι +αυτων +αυτουσ +αυτεσ +αυτα +εκεινοσ +εκεινη +εκεινο +εκεινοι +εκεινεσ +εκεινα +εκεινων +εκεινουσ +οπωσ +ομωσ +ισωσ +οσο +οτι +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(GreekStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en.go new file mode 100644 index 00000000..40a6cb02 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en.go @@ -0,0 +1,57 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package en + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "en" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + possEnFilter, err := cache.TokenFilterNamed(PossessiveName) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopEnFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerEnFilter, err := cache.TokenFilterNamed(porter.Name) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + possEnFilter, + toLowerFilter, + stopEnFilter, + stemmerEnFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en_test.go new file mode 100644 index 00000000..c2b0c86d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/analyzer_en_test.go @@ -0,0 +1,100 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package en + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestEnglishAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("books"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("book"), + Position: 1, + Start: 0, + End: 5, + }, + }, + }, + { + input: []byte("book"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("book"), + Position: 1, + Start: 0, + End: 4, + }, + }, + }, + // stop word removal + { + input: []byte("the"), + output: analysis.TokenStream{}, + }, + // possessive removal + { + input: []byte("steven's"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("steven"), + Position: 1, + Start: 0, + End: 8, + }, + }, + }, + { + input: []byte("steven\u2019s"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("steven"), + Position: 1, + Start: 0, + End: 10, + }, + }, + }, + { + input: []byte("steven\uFF07s"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("steven"), + Position: 1, + Start: 0, + End: 10, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en.go new file mode 100644 index 00000000..ce6a5dfa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en.go @@ -0,0 +1,57 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package en + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const PossessiveName = "possessive_en" + +const rightSingleQuotationMark = '’' +const apostrophe = '\'' +const fullWidthApostrophe = ''' + +const apostropheChars = rightSingleQuotationMark + apostrophe + fullWidthApostrophe + +type PossessiveFilter struct { +} + +func NewPossessiveFilter() *PossessiveFilter { + return &PossessiveFilter{} +} + +func (s *PossessiveFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + runes := bytes.Runes(token.Term) + if len(runes) >= 2 { + secondToLastRune := runes[len(runes)-2] + lastRune := runes[len(runes)-1] + if (secondToLastRune == rightSingleQuotationMark || + secondToLastRune == apostrophe || + secondToLastRune == fullWidthApostrophe) && + (lastRune == 's' || lastRune == 'S') { + token.Term = analysis.TruncateRunes(token.Term, 2) + } + } + } + return input +} + +func PossessiveFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewPossessiveFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(PossessiveName, PossessiveFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en_test.go new file mode 100644 index 00000000..df055125 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/possessive_filter_en_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package en + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestEnglishPossessiveFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("marty's"), + }, + &analysis.Token{ + Term: []byte("MARTY'S"), + }, + &analysis.Token{ + Term: []byte("marty’s"), + }, + &analysis.Token{ + Term: []byte("MARTY’S"), + }, + &analysis.Token{ + Term: []byte("marty's"), + }, + &analysis.Token{ + Term: []byte("MARTY'S"), + }, + &analysis.Token{ + Term: []byte("m"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("marty"), + }, + &analysis.Token{ + Term: []byte("MARTY"), + }, + &analysis.Token{ + Term: []byte("marty"), + }, + &analysis.Token{ + Term: []byte("MARTY"), + }, + &analysis.Token{ + Term: []byte("marty"), + }, + &analysis.Token{ + Term: []byte("MARTY"), + }, + &analysis.Token{ + Term: []byte("m"), + }, + }, + }, + } + + cache := registry.NewCache() + stemmerFilter, err := cache.TokenFilterNamed(PossessiveName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := stemmerFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en.go new file mode 100644 index 00000000..c778efe8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package en + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_en" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("en") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en_test.go new file mode 100644 index 00000000..95930b4c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stemmer_en_test.go @@ -0,0 +1,72 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package en + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestEnglishStemmer(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walking"), + }, + &analysis.Token{ + Term: []byte("talked"), + }, + &analysis.Token{ + Term: []byte("business"), + }, + &analysis.Token{ + Term: []byte("protected"), + KeyWord: true, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walk"), + }, + &analysis.Token{ + Term: []byte("talk"), + }, + &analysis.Token{ + Term: []byte("busi"), + }, + &analysis.Token{ + Term: []byte("protected"), + KeyWord: true, + }, + }, + }, + } + + cache := registry.NewCache() + stemmerFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := stemmerFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_filter_en.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_filter_en.go new file mode 100644 index 00000000..191d7492 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_filter_en.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package en + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_words_en.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_words_en.go new file mode 100644 index 00000000..a3f94b16 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en/stop_words_en.go @@ -0,0 +1,343 @@ +package en + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_en" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var EnglishStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/english/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | An English stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + | Many of the forms below are quite rare (e.g. "yourselves") but included for + | completeness. + + | PRONOUNS FORMS + | 1st person sing + +i | subject, always in upper case of course + +me | object +my | possessive adjective + | the possessive pronoun 'mine' is best suppressed, because of the + | sense of coal-mine etc. +myself | reflexive + | 1st person plural +we | subject + +| us | object + | care is required here because US = United States. It is usually + | safe to remove it if it is in lower case. +our | possessive adjective +ours | possessive pronoun +ourselves | reflexive + | second person (archaic 'thou' forms not included) +you | subject and object +your | possessive adjective +yours | possessive pronoun +yourself | reflexive (singular) +yourselves | reflexive (plural) + | third person singular +he | subject +him | object +his | possessive adjective and pronoun +himself | reflexive + +she | subject +her | object and possessive adjective +hers | possessive pronoun +herself | reflexive + +it | subject and object +its | possessive adjective +itself | reflexive + | third person plural +they | subject +them | object +their | possessive adjective +theirs | possessive pronoun +themselves | reflexive + | other forms (demonstratives, interrogatives) +what +which +who +whom +this +that +these +those + + | VERB FORMS (using F.R. Palmer's nomenclature) + | BE +am | 1st person, present +is | -s form (3rd person, present) +are | present +was | 1st person, past +were | past +be | infinitive +been | past participle +being | -ing form + | HAVE +have | simple +has | -s form +had | past +having | -ing form + | DO +do | simple +does | -s form +did | past +doing | -ing form + + | The forms below are, I believe, best omitted, because of the significant + | homonym forms: + + | He made a WILL + | old tin CAN + | merry month of MAY + | a smell of MUST + | fight the good fight with all thy MIGHT + + | would, could, should, ought might however be included + + | | AUXILIARIES + | | WILL + |will + +would + + | | SHALL + |shall + +should + + | | CAN + |can + +could + + | | MAY + |may + |might + | | MUST + |must + | | OUGHT + +ought + + | COMPOUND FORMS, increasingly encountered nowadays in 'formal' writing + | pronoun + verb + +i'm +you're +he's +she's +it's +we're +they're +i've +you've +we've +they've +i'd +you'd +he'd +she'd +we'd +they'd +i'll +you'll +he'll +she'll +we'll +they'll + + | verb + negation + +isn't +aren't +wasn't +weren't +hasn't +haven't +hadn't +doesn't +don't +didn't + + | auxiliary + negation + +won't +wouldn't +shan't +shouldn't +can't +cannot +couldn't +mustn't + + | miscellaneous forms + +let's +that's +who's +what's +here's +there's +when's +where's +why's +how's + + | rarer forms + + | daren't needn't + + | doubtful forms + + | oughtn't mightn't + + | ARTICLES +a +an +the + + | THE REST (Overlap among prepositions, conjunctions, adverbs etc is so + | high, that classification is pointless.) +and +but +if +or +because +as +until +while + +of +at +by +for +with +about +against +between +into +through +during +before +after +above +below +to +from +up +down +in +out +on +off +over +under + +again +further +then +once + +here +there +when +where +why +how + +all +any +both +each +few +more +most +other +some +such + +no +nor +not +only +own +same +so +than +too +very + + | Just for the record, the following words are among the commonest in English + + | one + | every + | least + | less + | many + | now + | ever + | never + | say + | says + | said + | also + | get + | go + | goes + | just + | made + | make + | put + | see + | seen + | whether + | like + | well + | back + | even + | still + | way + | take + | since + | another + | however + | two + | three + | four + | five + | first + | second + | new + | old + | high + | long +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(EnglishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es.go new file mode 100644 index 00000000..0fba32f3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package es + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "es" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopEsFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerEsFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopEsFilter, + stemmerEsFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es_test.go new file mode 100644 index 00000000..e322b2ac --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/analyzer_es_test.go @@ -0,0 +1,64 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package es + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestSpanishAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("chicana"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chican"), + Position: 1, + Start: 0, + End: 7, + }, + }, + }, + { + input: []byte("chicano"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chican"), + Position: 1, + Start: 0, + End: 7, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stemmer_es.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stemmer_es.go new file mode 100644 index 00000000..c0f8acf1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stemmer_es.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package es + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_es" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("es") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_filter_es.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_filter_es.go new file mode 100644 index 00000000..9dd1475a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_filter_es.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package es + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_words_es.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_words_es.go new file mode 100644 index 00000000..6ac1a299 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es/stop_words_es.go @@ -0,0 +1,380 @@ +package es + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_es" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var SpanishStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/spanish/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Spanish stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + + | The following is a ranked list (commonest to rarest) of stopwords + | deriving from a large sample of text. + + | Extra words have been added at the end. + +de | from, of +la | the, her +que | who, that +el | the +en | in +y | and +a | to +los | the, them +del | de + el +se | himself, from him etc +las | the, them +por | for, by, etc +un | a +para | for +con | with +no | no +una | a +su | his, her +al | a + el + | es from SER +lo | him +como | how +más | more +pero | pero +sus | su plural +le | to him, her +ya | already +o | or + | fue from SER +este | this + | ha from HABER +sí | himself etc +porque | because +esta | this + | son from SER +entre | between + | está from ESTAR +cuando | when +muy | very +sin | without +sobre | on + | ser from SER + | tiene from TENER +también | also +me | me +hasta | until +hay | there is/are +donde | where + | han from HABER +quien | whom, that + | están from ESTAR + | estado from ESTAR +desde | from +todo | all +nos | us +durante | during + | estados from ESTAR +todos | all +uno | a +les | to them +ni | nor +contra | against +otros | other + | fueron from SER +ese | that +eso | that + | había from HABER +ante | before +ellos | they +e | and (variant of y) +esto | this +mí | me +antes | before +algunos | some +qué | what? +unos | a +yo | I +otro | other +otras | other +otra | other +él | he +tanto | so much, many +esa | that +estos | these +mucho | much, many +quienes | who +nada | nothing +muchos | many +cual | who + | sea from SER +poco | few +ella | she +estar | to be + | haber from HABER +estas | these + | estaba from ESTAR + | estamos from ESTAR +algunas | some +algo | something +nosotros | we + + | other forms + +mi | me +mis | mi plural +tú | thou +te | thee +ti | thee +tu | thy +tus | tu plural +ellas | they +nosotras | we +vosotros | you +vosotras | you +os | you +mío | mine +mía | +míos | +mías | +tuyo | thine +tuya | +tuyos | +tuyas | +suyo | his, hers, theirs +suya | +suyos | +suyas | +nuestro | ours +nuestra | +nuestros | +nuestras | +vuestro | yours +vuestra | +vuestros | +vuestras | +esos | those +esas | those + + | forms of estar, to be (not including the infinitive): +estoy +estás +está +estamos +estáis +están +esté +estés +estemos +estéis +estén +estaré +estarás +estará +estaremos +estaréis +estarán +estaría +estarías +estaríamos +estaríais +estarían +estaba +estabas +estábamos +estabais +estaban +estuve +estuviste +estuvo +estuvimos +estuvisteis +estuvieron +estuviera +estuvieras +estuviéramos +estuvierais +estuvieran +estuviese +estuvieses +estuviésemos +estuvieseis +estuviesen +estando +estado +estada +estados +estadas +estad + + | forms of haber, to have (not including the infinitive): +he +has +ha +hemos +habéis +han +haya +hayas +hayamos +hayáis +hayan +habré +habrás +habrá +habremos +habréis +habrán +habría +habrías +habríamos +habríais +habrían +había +habías +habíamos +habíais +habían +hube +hubiste +hubo +hubimos +hubisteis +hubieron +hubiera +hubieras +hubiéramos +hubierais +hubieran +hubiese +hubieses +hubiésemos +hubieseis +hubiesen +habiendo +habido +habida +habidos +habidas + + | forms of ser, to be (not including the infinitive): +soy +eres +es +somos +sois +son +sea +seas +seamos +seáis +sean +seré +serás +será +seremos +seréis +serán +sería +serías +seríamos +seríais +serían +era +eras +éramos +erais +eran +fui +fuiste +fue +fuimos +fuisteis +fueron +fuera +fueras +fuéramos +fuerais +fueran +fuese +fueses +fuésemos +fueseis +fuesen +siendo +sido + | sed also means 'thirst' + + | forms of tener, to have (not including the infinitive): +tengo +tienes +tiene +tenemos +tenéis +tienen +tenga +tengas +tengamos +tengáis +tengan +tendré +tendrás +tendrá +tendremos +tendréis +tendrán +tendría +tendrías +tendríamos +tendríais +tendrían +tenía +tenías +teníamos +teníais +tenían +tuve +tuviste +tuvo +tuvimos +tuvisteis +tuvieron +tuviera +tuvieras +tuviéramos +tuvierais +tuvieran +tuviese +tuvieses +tuviésemos +tuvieseis +tuviesen +teniendo +tenido +tenida +tenidos +tenidas +tened + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(SpanishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_filter_eu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_filter_eu.go new file mode 100644 index 00000000..83a7cd19 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_filter_eu.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package eu + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_words_eu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_words_eu.go new file mode 100644 index 00000000..7b5afd81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu/stop_words_eu.go @@ -0,0 +1,123 @@ +package eu + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_eu" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var BasqueStopWords = []byte(`# example set of basque stopwords +al +anitz +arabera +asko +baina +bat +batean +batek +bati +batzuei +batzuek +batzuetan +batzuk +bera +beraiek +berau +berauek +bere +berori +beroriek +beste +bezala +da +dago +dira +ditu +du +dute +edo +egin +ere +eta +eurak +ez +gainera +gu +gutxi +guzti +haiei +haiek +haietan +hainbeste +hala +han +handik +hango +hara +hari +hark +hartan +hau +hauei +hauek +hauetan +hemen +hemendik +hemengo +hi +hona +honek +honela +honetan +honi +hor +hori +horiei +horiek +horietan +horko +horra +horrek +horrela +horretan +horri +hortik +hura +izan +ni +noiz +nola +non +nondik +nongo +nor +nora +ze +zein +zen +zenbait +zenbat +zer +zergatik +ziren +zituen +zu +zuek +zuen +zuten +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(BasqueStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa.go new file mode 100644 index 00000000..04e1667f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa.go @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package fa + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/zero_width_non_joiner" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "fa" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + zFilter, err := cache.CharFilterNamed(zero_width_non_joiner.Name) + if err != nil { + return nil, err + } + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + normArFilter, err := cache.TokenFilterNamed(ar.NormalizeName) + if err != nil { + return nil, err + } + normFaFilter, err := cache.TokenFilterNamed(NormalizeName) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopFaFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + CharFilters: []analysis.CharFilter{ + zFilter, + }, + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + normArFilter, + normFaFilter, + stopFaFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa_test.go new file mode 100644 index 00000000..c2495f73 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/analyzer_fa_test.go @@ -0,0 +1,681 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package fa + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestPersianAnalyzerVerbs(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // active present indicative + { + input: []byte("می‌خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active preterite indicative + { + input: []byte("خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active imperfective preterite indicative + { + input: []byte("می‌خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active future indicative + { + input: []byte("خواهد خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active present progressive indicative + { + input: []byte("دارد می‌خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active preterite progressive indicative + { + input: []byte("داشت می‌خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active perfect indicative + { + input: []byte("خورده‌است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective perfect indicative + { + input: []byte("می‌خورده‌است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active pluperfect indicative + { + input: []byte("خورده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective pluperfect indicative + { + input: []byte("می‌خورده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active preterite subjunctive + { + input: []byte("خورده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective preterite subjunctive + { + input: []byte("می‌خورده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active pluperfect subjunctive + { + input: []byte("خورده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective pluperfect subjunctive + { + input: []byte("می‌خورده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive present indicative + { + input: []byte("خورده می‌شود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive preterite indicative + { + input: []byte("خورده شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective preterite indicative + { + input: []byte("خورده می‌شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive perfect indicative + { + input: []byte("خورده شده‌است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective perfect indicative + { + input: []byte("خورده می‌شده‌است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive pluperfect indicative + { + input: []byte("خورده شده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective pluperfect indicative + { + input: []byte("خورده می‌شده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive future indicative + { + input: []byte("خورده خواهد شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive present progressive indicative + { + input: []byte("دارد خورده می‌شود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive preterite progressive indicative + { + input: []byte("داشت خورده می‌شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive present subjunctive + { + input: []byte("خورده شود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive preterite subjunctive + { + input: []byte("خورده شده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective preterite subjunctive + { + input: []byte("خورده می‌شده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive pluperfect subjunctive + { + input: []byte("خورده شده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective pluperfect subjunctive + { + input: []byte("خورده می‌شده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active present subjunctive + { + input: []byte("بخورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بخورد"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} + +func TestPersianAnalyzerVerbsDefective(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // active present indicative + { + input: []byte("مي خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active preterite indicative + { + input: []byte("خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active imperfective preterite indicative + { + input: []byte("مي خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active future indicative + { + input: []byte("خواهد خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active present progressive indicative + { + input: []byte("دارد مي خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active preterite progressive indicative + { + input: []byte("داشت مي خورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورد"), + }, + }, + }, + // active perfect indicative + { + input: []byte("خورده است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective perfect indicative + { + input: []byte("مي خورده است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active pluperfect indicative + { + input: []byte("خورده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective pluperfect indicative + { + input: []byte("مي خورده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active preterite subjunctive + { + input: []byte("خورده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective preterite subjunctive + { + input: []byte("مي خورده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active pluperfect subjunctive + { + input: []byte("خورده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active imperfective pluperfect subjunctive + { + input: []byte("مي خورده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive present indicative + { + input: []byte("خورده مي شود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive preterite indicative + { + input: []byte("خورده شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective preterite indicative + { + input: []byte("خورده مي شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive perfect indicative + { + input: []byte("خورده شده است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective perfect indicative + { + input: []byte("خورده مي شده است"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive pluperfect indicative + { + input: []byte("خورده شده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective pluperfect indicative + { + input: []byte("خورده مي شده بود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive future indicative + { + input: []byte("خورده خواهد شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive present progressive indicative + { + input: []byte("دارد خورده مي شود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive preterite progressive indicative + { + input: []byte("داشت خورده مي شد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive present subjunctive + { + input: []byte("خورده شود"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive preterite subjunctive + { + input: []byte("خورده شده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective preterite subjunctive + { + input: []byte("خورده مي شده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive pluperfect subjunctive + { + input: []byte("خورده شده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // passive imperfective pluperfect subjunctive + { + input: []byte("خورده مي شده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + // active present subjunctive + { + input: []byte("بخورد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("بخورد"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} + +func TestPersianAnalyzerOthers(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // nouns + { + input: []byte("برگ ها"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("برگ"), + }, + }, + }, + { + input: []byte("برگ‌ها"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("برگ"), + }, + }, + }, + // non persian + { + input: []byte("English test."), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("english"), + }, + &analysis.Token{ + Term: []byte("test"), + }, + }, + }, + // others + { + input: []byte("خورده مي شده بوده باشد"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("خورده"), + }, + }, + }, + { + input: []byte("برگ‌ها"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("برگ"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize.go new file mode 100644 index 00000000..6b2aea4f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize.go @@ -0,0 +1,72 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fa + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const NormalizeName = "normalize_fa" + +const ( + Yeh = '\u064A' + FarsiYeh = '\u06CC' + YehBarree = '\u06D2' + Keheh = '\u06A9' + Kaf = '\u0643' + HamzaAbove = '\u0654' + HehYeh = '\u06C0' + HehGoal = '\u06C1' + Heh = '\u0647' +) + +type PersianNormalizeFilter struct { +} + +func NewPersianNormalizeFilter() *PersianNormalizeFilter { + return &PersianNormalizeFilter{} +} + +func (s *PersianNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + term := normalize(token.Term) + token.Term = term + } + return input +} + +func normalize(input []byte) []byte { + runes := bytes.Runes(input) + for i := 0; i < len(runes); i++ { + switch runes[i] { + case FarsiYeh, YehBarree: + runes[i] = Yeh + case Keheh: + runes[i] = Kaf + case HehYeh, HehGoal: + runes[i] = Heh + case HamzaAbove: // necessary for HEH + HAMZA + runes = analysis.DeleteRune(runes, i) + i-- + } + } + return analysis.BuildTermFromRunes(runes) +} + +func NormalizerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewPersianNormalizeFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(NormalizeName, NormalizerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize_test.go new file mode 100644 index 00000000..1861abe3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/persian_normalize_test.go @@ -0,0 +1,125 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fa + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestPersianNormalizeFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // FarsiYeh + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("های"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هاي"), + }, + }, + }, + // YehBarree + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هاے"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("هاي"), + }, + }, + }, + // Keheh + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("کشاندن"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كشاندن"), + }, + }, + }, + // HehYeh + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كتابۀ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كتابه"), + }, + }, + }, + // HehHamzaAbove + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كتابهٔ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("كتابه"), + }, + }, + }, + // HehGoal + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("زادہ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("زاده"), + }, + }, + }, + // empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + persianNormalizeFilter := NewPersianNormalizeFilter() + for _, test := range tests { + actual := persianNormalizeFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_filter_fa.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_filter_fa.go new file mode 100644 index 00000000..f0380820 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_filter_fa.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fa + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_words_fa.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_words_fa.go new file mode 100644 index 00000000..2f320a2f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa/stop_words_fa.go @@ -0,0 +1,337 @@ +package fa + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_fa" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var PersianStopWords = []byte(`# This file was created by Jacques Savoy and is distributed under the BSD license. +# See http://members.unine.ch/jacques.savoy/clef/index.html. +# Also see http://www.opensource.org/licenses/bsd-license.html +# Note: by default this file is used after normalization, so when adding entries +# to this file, use the arabic 'ي' instead of 'ی' +انان +نداشته +سراسر +خياه +ايشان +وي +تاكنون +بيشتري +دوم +پس +ناشي +وگو +يا +داشتند +سپس +هنگام +هرگز +پنج +نشان +امسال +ديگر +گروهي +شدند +چطور +ده +و +دو +نخستين +ولي +چرا +چه +وسط +ه +كدام +قابل +يك +رفت +هفت +همچنين +در +هزار +بله +بلي +شايد +اما +شناسي +گرفته +دهد +داشته +دانست +داشتن +خواهيم +ميليارد +وقتيكه +امد +خواهد +جز +اورده +شده +بلكه +خدمات +شدن +برخي +نبود +بسياري +جلوگيري +حق +كردند +نوعي +بعري +نكرده +نظير +نبايد +بوده +بودن +داد +اورد +هست +جايي +شود +دنبال +داده +بايد +سابق +هيچ +همان +انجا +كمتر +كجاست +گردد +كسي +تر +مردم +تان +دادن +بودند +سري +جدا +ندارند +مگر +يكديگر +دارد +دهند +بنابراين +هنگامي +سمت +جا +انچه +خود +دادند +زياد +دارند +اثر +بدون +بهترين +بيشتر +البته +به +براساس +بيرون +كرد +بعضي +گرفت +توي +اي +ميليون +او +جريان +تول +بر +مانند +برابر +باشيم +مدتي +گويند +اكنون +تا +تنها +جديد +چند +بي +نشده +كردن +كردم +گويد +كرده +كنيم +نمي +نزد +روي +قصد +فقط +بالاي +ديگران +اين +ديروز +توسط +سوم +ايم +دانند +سوي +استفاده +شما +كنار +داريم +ساخته +طور +امده +رفته +نخست +بيست +نزديك +طي +كنيد +از +انها +تمامي +داشت +يكي +طريق +اش +چيست +روب +نمايد +گفت +چندين +چيزي +تواند +ام +ايا +با +ان +ايد +ترين +اينكه +ديگري +راه +هايي +بروز +همچنان +پاعين +كس +حدود +مختلف +مقابل +چيز +گيرد +ندارد +ضد +همچون +سازي +شان +مورد +باره +مرسي +خويش +برخوردار +چون +خارج +شش +هنوز +تحت +ضمن +هستيم +گفته +فكر +بسيار +پيش +براي +روزهاي +انكه +نخواهد +بالا +كل +وقتي +كي +چنين +كه +گيري +نيست +است +كجا +كند +نيز +يابد +بندي +حتي +توانند +عقب +خواست +كنند +بين +تمام +همه +ما +باشند +مثل +شد +اري +باشد +اره +طبق +بعد +اگر +صورت +غير +جاي +بيش +ريزي +اند +زيرا +چگونه +بار +لطفا +مي +درباره +من +ديده +همين +گذاري +برداري +علت +گذاشته +هم +فوق +نه +ها +شوند +اباد +همواره +هر +اول +خواهند +چهار +نام +امروز +مان +هاي +قبل +كنم +سعي +تازه +را +هستند +زير +جلوي +عنوان +بود +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(PersianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi.go new file mode 100644 index 00000000..3b6eaf30 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package fi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "fi" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopFiFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerFiFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopFiFilter, + stemmerFiFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi_test.go new file mode 100644 index 00000000..0557d1d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/analyzer_fi_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package fi + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFinishAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("edeltäjiinsä"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("edeltäj"), + }, + }, + }, + { + input: []byte("edeltäjistään"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("edeltäj"), + }, + }, + }, + // stop word + { + input: []byte("olla"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stemmer_fi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stemmer_fi.go new file mode 100644 index 00000000..fc411309 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stemmer_fi.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package fi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_fi" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("fi") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_filter_fi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_filter_fi.go new file mode 100644 index 00000000..bf6290e6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_filter_fi.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_words_fi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_words_fi.go new file mode 100644 index 00000000..7b83aa90 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi/stop_words_fi.go @@ -0,0 +1,121 @@ +package fi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_fi" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var FinnishStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/finnish/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + +| forms of BE + +olla +olen +olet +on +olemme +olette +ovat +ole | negative form + +oli +olisi +olisit +olisin +olisimme +olisitte +olisivat +olit +olin +olimme +olitte +olivat +ollut +olleet + +en | negation +et +ei +emme +ette +eivät + +|Nom Gen Acc Part Iness Elat Illat Adess Ablat Allat Ess Trans +minä minun minut minua minussa minusta minuun minulla minulta minulle | I +sinä sinun sinut sinua sinussa sinusta sinuun sinulla sinulta sinulle | you +hän hänen hänet häntä hänessä hänestä häneen hänellä häneltä hänelle | he she +me meidän meidät meitä meissä meistä meihin meillä meiltä meille | we +te teidän teidät teitä teissä teistä teihin teillä teiltä teille | you +he heidän heidät heitä heissä heistä heihin heillä heiltä heille | they + +tämä tämän tätä tässä tästä tähän tallä tältä tälle tänä täksi | this +tuo tuon tuotä tuossa tuosta tuohon tuolla tuolta tuolle tuona tuoksi | that +se sen sitä siinä siitä siihen sillä siltä sille sinä siksi | it +nämä näiden näitä näissä näistä näihin näillä näiltä näille näinä näiksi | these +nuo noiden noita noissa noista noihin noilla noilta noille noina noiksi | those +ne niiden niitä niissä niistä niihin niillä niiltä niille niinä niiksi | they + +kuka kenen kenet ketä kenessä kenestä keneen kenellä keneltä kenelle kenenä keneksi| who +ketkä keiden ketkä keitä keissä keistä keihin keillä keiltä keille keinä keiksi | (pl) +mikä minkä minkä mitä missä mistä mihin millä miltä mille minä miksi | which what +mitkä | (pl) + +joka jonka jota jossa josta johon jolla jolta jolle jona joksi | who which +jotka joiden joita joissa joista joihin joilla joilta joille joina joiksi | (pl) + +| conjunctions + +että | that +ja | and +jos | if +koska | because +kuin | than +mutta | but +niin | so +sekä | and +sillä | for +tai | or +vaan | but +vai | or +vaikka | although + + +| prepositions + +kanssa | with +mukaan | according to +noin | about +poikki | across +yli | over, across + +| other + +kun | when +niin | so +nyt | now +itse | self + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(FinnishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr.go new file mode 100644 index 00000000..8ce551b3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "fr" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + elisionFilter, err := cache.TokenFilterNamed(ElisionName) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopFrFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerFrFilter, err := cache.TokenFilterNamed(LightStemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + elisionFilter, + toLowerFilter, + stopFrFilter, + stemmerFrFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr_test.go new file mode 100644 index 00000000..e973ff56 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/analyzer_fr_test.go @@ -0,0 +1,196 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFrenchAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + input: []byte(""), + output: analysis.TokenStream{}, + }, + { + input: []byte("chien chat cheval"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chien"), + }, + &analysis.Token{ + Term: []byte("chat"), + }, + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + { + input: []byte("chien CHAT CHEVAL"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chien"), + }, + &analysis.Token{ + Term: []byte("chat"), + }, + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + { + input: []byte(" chien ,? + = - CHAT /: > CHEVAL"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chien"), + }, + &analysis.Token{ + Term: []byte("chat"), + }, + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + { + input: []byte("chien++"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chien"), + }, + }, + }, + { + input: []byte("mot \"entreguillemet\""), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("mot"), + }, + &analysis.Token{ + Term: []byte("entreguilemet"), + }, + }, + }, + { + input: []byte("Jean-François"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("jean"), + }, + &analysis.Token{ + Term: []byte("francoi"), + }, + }, + }, + // stop words + { + input: []byte("le la chien les aux chat du des à cheval"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chien"), + }, + &analysis.Token{ + Term: []byte("chat"), + }, + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + // nouns and adjectives + { + input: []byte("lances chismes habitable chiste éléments captifs"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("lanc"), + }, + &analysis.Token{ + Term: []byte("chism"), + }, + &analysis.Token{ + Term: []byte("habitabl"), + }, + &analysis.Token{ + Term: []byte("chist"), + }, + &analysis.Token{ + Term: []byte("element"), + }, + &analysis.Token{ + Term: []byte("captif"), + }, + }, + }, + // verbs + { + input: []byte("finissions souffrirent rugissante"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("finision"), + }, + &analysis.Token{ + Term: []byte("soufrirent"), + }, + &analysis.Token{ + Term: []byte("rugisant"), + }, + }, + }, + { + input: []byte("C3PO aujourd'hui oeuf ïâöûàä anticonstitutionnellement Java++ "), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("c3po"), + }, + &analysis.Token{ + Term: []byte("aujourd'hui"), + }, + &analysis.Token{ + Term: []byte("oeuf"), + }, + &analysis.Token{ + Term: []byte("ïaöuaä"), + }, + &analysis.Token{ + Term: []byte("anticonstitutionel"), + }, + &analysis.Token{ + Term: []byte("java"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/articles_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/articles_fr.go new file mode 100644 index 00000000..04340fef --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/articles_fr.go @@ -0,0 +1,37 @@ +package fr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ArticlesName = "articles_fr" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis + +var FrenchArticles = []byte(` +l +m +t +qu +n +s +j +d +c +jusqu +quoiqu +lorsqu +puisqu +`) + +func ArticlesTokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(FrenchArticles) + return rv, err +} + +func init() { + registry.RegisterTokenMap(ArticlesName, ArticlesTokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr.go new file mode 100644 index 00000000..d3ee602c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr.go @@ -0,0 +1,32 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ElisionName = "elision_fr" + +func ElisionFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + articlesTokenMap, err := cache.TokenMapNamed(ArticlesName) + if err != nil { + return nil, fmt.Errorf("error building elision filter: %v", err) + } + return elision_filter.NewElisionFilter(articlesTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(ElisionName, ElisionFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr_test.go new file mode 100644 index 00000000..e68ae93a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/elision_fr_test.go @@ -0,0 +1,50 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFrenchElision(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("l'avion"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("avion"), + }, + }, + }, + } + + cache := registry.NewCache() + elisionFilter, err := cache.TokenFilterNamed(ElisionName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := elisionFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr.go new file mode 100644 index 00000000..fa871c73 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr.go @@ -0,0 +1,308 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "bytes" + "unicode" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const LightStemmerName = "stemmer_fr_light" + +type FrenchLightStemmerFilter struct { +} + +func NewFrenchLightStemmerFilter() *FrenchLightStemmerFilter { + return &FrenchLightStemmerFilter{} +} + +func (s *FrenchLightStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + runes := bytes.Runes(token.Term) + runes = stem(runes) + token.Term = analysis.BuildTermFromRunes(runes) + } + return input +} + +func stem(input []rune) []rune { + + inputLen := len(input) + + if inputLen > 5 && input[inputLen-1] == 'x' { + if input[inputLen-3] == 'a' && input[inputLen-2] == 'u' && input[inputLen-4] != 'e' { + input[inputLen-2] = 'l' + } + input = input[0 : inputLen-1] + inputLen = len(input) + } + + if inputLen > 3 && input[inputLen-1] == 'x' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + + if inputLen > 3 && input[inputLen-1] == 's' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + + if inputLen > 9 && analysis.RunesEndsWith(input, "issement") { + input = input[0 : inputLen-6] + inputLen = len(input) + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "issant") { + input = input[0 : inputLen-4] + inputLen = len(input) + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 6 && analysis.RunesEndsWith(input, "ement") { + input = input[0 : inputLen-4] + inputLen = len(input) + if inputLen > 3 && analysis.RunesEndsWith(input, "ive") { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-1] = 'f' + } + return norm(input) + } + + if inputLen > 11 && analysis.RunesEndsWith(input, "ficatrice") { + input = input[0 : inputLen-5] + inputLen = len(input) + input[inputLen-2] = 'e' + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 10 && analysis.RunesEndsWith(input, "ficateur") { + input = input[0 : inputLen-4] + inputLen = len(input) + input[inputLen-2] = 'e' + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 9 && analysis.RunesEndsWith(input, "catrice") { + input = input[0 : inputLen-3] + inputLen = len(input) + input[inputLen-4] = 'q' + input[inputLen-3] = 'u' + input[inputLen-2] = 'e' + //s[len-1] = 'r' <-- unnecessary, already 'r'. + return norm(input) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "cateur") { + input = input[0 : inputLen-2] + inputLen = len(input) + input[inputLen-4] = 'q' + input[inputLen-3] = 'u' + input[inputLen-2] = 'e' + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "atrice") { + input = input[0 : inputLen-4] + inputLen = len(input) + input[inputLen-2] = 'e' + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 7 && analysis.RunesEndsWith(input, "ateur") { + input = input[0 : inputLen-3] + inputLen = len(input) + input[inputLen-2] = 'e' + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 6 && analysis.RunesEndsWith(input, "trice") { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-3] = 'e' + input[inputLen-2] = 'u' + input[inputLen-1] = 'r' + } + + if inputLen > 5 && analysis.RunesEndsWith(input, "ième") { + return norm(input[0 : inputLen-4]) + } + + if inputLen > 7 && analysis.RunesEndsWith(input, "teuse") { + input = input[0 : inputLen-2] + inputLen = len(input) + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 6 && analysis.RunesEndsWith(input, "teur") { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-1] = 'r' + return norm(input) + } + + if inputLen > 5 && analysis.RunesEndsWith(input, "euse") { + return norm(input[0 : inputLen-2]) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "ère") { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-2] = 'e' + return norm(input) + } + + if inputLen > 7 && analysis.RunesEndsWith(input, "ive") { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-1] = 'f' + return norm(input) + } + + if inputLen > 4 && + (analysis.RunesEndsWith(input, "folle") || + analysis.RunesEndsWith(input, "molle")) { + input = input[0 : inputLen-2] + inputLen = len(input) + input[inputLen-1] = 'u' + return norm(input) + } + + if inputLen > 9 && analysis.RunesEndsWith(input, "nnelle") { + return norm(input[0 : inputLen-5]) + } + + if inputLen > 9 && analysis.RunesEndsWith(input, "nnel") { + return norm(input[0 : inputLen-3]) + } + + if inputLen > 4 && analysis.RunesEndsWith(input, "ète") { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-2] = 'e' + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "ique") { + input = input[0 : inputLen-4] + inputLen = len(input) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "esse") { + return norm(input[0 : inputLen-3]) + } + + if inputLen > 7 && analysis.RunesEndsWith(input, "inage") { + return norm(input[0 : inputLen-3]) + } + + if inputLen > 9 && analysis.RunesEndsWith(input, "isation") { + input = input[0 : inputLen-7] + inputLen = len(input) + if inputLen > 5 && analysis.RunesEndsWith(input, "ual") { + input[inputLen-2] = 'e' + } + return norm(input) + } + + if inputLen > 9 && analysis.RunesEndsWith(input, "isateur") { + return norm(input[0 : inputLen-7]) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "ation") { + return norm(input[0 : inputLen-5]) + } + + if inputLen > 8 && analysis.RunesEndsWith(input, "ition") { + return norm(input[0 : inputLen-5]) + } + + return norm(input) + +} + +func norm(input []rune) []rune { + + inputLen := len(input) + if inputLen > 4 { + for i := 0; i < inputLen; i++ { + switch input[i] { + case 'à', 'á', 'â': + input[i] = 'a' + case 'ô': + input[i] = 'o' + case 'è', 'é', 'ê': + input[i] = 'e' + case 'ù', 'û': + input[i] = 'u' + case 'î': + input[i] = 'i' + case 'ç': + input[i] = 'c' + } + + ch := input[0] + for i := 1; i < inputLen; i++ { + if input[i] == ch && unicode.IsLetter(ch) { + input = analysis.DeleteRune(input, i) + i -= 1 + inputLen = len(input) + } else { + ch = input[i] + } + } + } + } + + if inputLen > 4 && analysis.RunesEndsWith(input, "ie") { + input = input[0 : inputLen-2] + inputLen = len(input) + } + + if inputLen > 4 { + if input[inputLen-1] == 'r' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == 'e' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == 'e' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == input[inputLen-2] && unicode.IsLetter(input[inputLen-1]) { + input = input[0 : inputLen-1] + inputLen = len(input) + } + } + + return input +} + +func FrenchLightStemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewFrenchLightStemmerFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(LightStemmerName, FrenchLightStemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr_test.go new file mode 100644 index 00000000..39180871 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/light_stemmer_fr_test.go @@ -0,0 +1,997 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFrenchLightStemmer(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chevaux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("hiboux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("hibou"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("hibou"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("hibou"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chantés"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chanter"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chante"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baronnes"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("barons"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("peaux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("peau"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("peau"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("peau"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("anneaux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("aneau"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("anneau"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("aneau"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("neveux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("neveu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("neveu"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("neveu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("affreux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("afreu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("affreuse"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("afreu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("investissement"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("investi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("investir"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("investi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("assourdissant"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("asourdi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("assourdir"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("asourdi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("pratiquement"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("pratiqu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("pratique"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("pratiqu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administrativement"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administratif"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administratif"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administratif"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("justificatrice"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("justifi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("justificateur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("justifi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("justifier"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("justifi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("educatrice"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("eduqu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("eduquer"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("eduqu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("communicateur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("comuniqu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("communiquer"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("comuniqu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("accompagnatrice"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("acompagn"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("accompagnateur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("acompagn"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administrateur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administr"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administrer"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("administr"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("productrice"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("product"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("producteur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("product"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("acheteuse"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("achet"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("acheteur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("achet"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("planteur"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("plant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("plante"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("plant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("poreuse"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("poreu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("poreux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("poreu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("plieuse"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("plieu"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("bijoutière"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("bijouti"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("bijoutier"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("bijouti"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("caissière"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("caisi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("caissier"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("caisi"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abrasive"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abrasif"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abrasif"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abrasif"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("folle"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("fou"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("fou"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("fou"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("personnelle"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("person"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("personne"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("person"), + }, + }, + }, + // algo bug: too short length + // { + // input: analysis.TokenStream{ + // &analysis.Token{ + // Term: []byte("personnel"), + // }, + // }, + // output: analysis.TokenStream{ + // &analysis.Token{ + // Term: []byte("person"), + // }, + // }, + // }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("complète"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("complet"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("complet"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("complet"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("aromatique"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("aromat"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("faiblesse"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("faibl"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("faible"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("faibl"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("patinage"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("patin"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("patin"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("patin"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("sonorisation"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("sono"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ritualisation"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("rituel"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("rituel"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("rituel"), + }, + }, + }, + // algo bug: masked by rules above + // { + // input: analysis.TokenStream{ + // &analysis.Token{ + // Term: []byte("colonisateur"), + // }, + // }, + // output: analysis.TokenStream{ + // &analysis.Token{ + // Term: []byte("colon"), + // }, + // }, + // }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("nomination"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("nomin"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("disposition"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("dispos"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("dispose"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("dispos"), + }, + }, + }, + // SOLR-3463 : abusive compression of repeated characters in numbers + // Trailing repeated char elision : + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1234555"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1234555"), + }, + }, + }, + // Repeated char within numbers with more than 4 characters : + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("12333345"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("12333345"), + }, + }, + }, + // Short numbers weren't affected already: + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1234"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1234"), + }, + }, + }, + // Ensure behaviour is preserved for words! + // Trailing repeated char elision : + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcdeff"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcdef"), + }, + }, + }, + // Repeated char within words with more than 4 characters : + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcccddeef"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcdef"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("créées"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("cre"), + }, + }, + }, + // Combined letter and digit repetition + // 10:00pm + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("22hh00"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("22h00"), + }, + }, + }, + } + + cache := registry.NewCache() + filter, err := cache.TokenFilterNamed(LightStemmerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := filter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr.go new file mode 100644 index 00000000..6eef925c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr.go @@ -0,0 +1,81 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const MinimalStemmerName = "stemmer_fr_min" + +type FrenchMinimalStemmerFilter struct { +} + +func NewFrenchMinimalStemmerFilter() *FrenchMinimalStemmerFilter { + return &FrenchMinimalStemmerFilter{} +} + +func (s *FrenchMinimalStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + runes := bytes.Runes(token.Term) + runes = minstem(runes) + token.Term = analysis.BuildTermFromRunes(runes) + } + return input +} + +func minstem(input []rune) []rune { + + inputLen := len(input) + + if inputLen < 6 { + return input + } + + if input[inputLen-1] == 'x' { + if input[inputLen-3] == 'a' && input[inputLen-2] == 'u' { + input[inputLen-2] = 'l' + } + return input[0 : inputLen-1] + } + + if input[inputLen-1] == 's' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == 'r' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == 'e' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == 'é' { + input = input[0 : inputLen-1] + inputLen = len(input) + } + if input[inputLen-1] == input[inputLen-2] { + input = input[0 : inputLen-1] + inputLen = len(input) + } + return input +} + +func FrenchMinimalStemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewFrenchMinimalStemmerFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(MinimalStemmerName, FrenchMinimalStemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr_test.go new file mode 100644 index 00000000..a71ebe35 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/minimal_stemmer_fr_test.go @@ -0,0 +1,134 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFrenchMinimalStemmer(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chevaux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("cheval"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("hiboux"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("hibou"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chantés"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chanter"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chante"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("chant"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baronnes"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("barons"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("baron"), + }, + }, + }, + } + + cache := registry.NewCache() + filter, err := cache.TokenFilterNamed(MinimalStemmerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := filter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stemmer_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stemmer_fr.go new file mode 100644 index 00000000..2db836e5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stemmer_fr.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package fr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_fr" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("fr") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_filter_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_filter_fr.go new file mode 100644 index 00000000..a4ec9e3b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_filter_fr.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package fr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_words_fr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_words_fr.go new file mode 100644 index 00000000..3debc895 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr/stop_words_fr.go @@ -0,0 +1,210 @@ +package fr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_fr" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var FrenchStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/french/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A French stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + +au | a + le +aux | a + les +avec | with +ce | this +ces | these +dans | with +de | of +des | de + les +du | de + le +elle | she +en | 'of them' etc +et | and +eux | them +il | he +je | I +la | the +le | the +leur | their +lui | him +ma | my (fem) +mais | but +me | me +même | same; as in moi-même (myself) etc +mes | me (pl) +moi | me +mon | my (masc) +ne | not +nos | our (pl) +notre | our +nous | we +on | one +ou | where +par | by +pas | not +pour | for +qu | que before vowel +que | that +qui | who +sa | his, her (fem) +se | oneself +ses | his (pl) +son | his, her (masc) +sur | on +ta | thy (fem) +te | thee +tes | thy (pl) +toi | thee +ton | thy (masc) +tu | thou +un | a +une | a +vos | your (pl) +votre | your +vous | you + + | single letter forms + +c | c' +d | d' +j | j' +l | l' +à | to, at +m | m' +n | n' +s | s' +t | t' +y | there + + | forms of être (not including the infinitive): +été +étée +étées +étés +étant +suis +es +est +sommes +êtes +sont +serai +seras +sera +serons +serez +seront +serais +serait +serions +seriez +seraient +étais +était +étions +étiez +étaient +fus +fut +fûmes +fûtes +furent +sois +soit +soyons +soyez +soient +fusse +fusses +fût +fussions +fussiez +fussent + + | forms of avoir (not including the infinitive): +ayant +eu +eue +eues +eus +ai +as +avons +avez +ont +aurai +auras +aura +aurons +aurez +auront +aurais +aurait +aurions +auriez +auraient +avais +avait +avions +aviez +avaient +eut +eûmes +eûtes +eurent +aie +aies +ait +ayons +ayez +aient +eusse +eusses +eût +eussions +eussiez +eussent + + | Later additions (from Jean-Christophe Deschamps) +ceci | this +cela | that +celà | that +cet | this +cette | this +ici | here +ils | they +les | the (pl) +leurs | their (pl) +quel | which +quels | which +quelle | which +quelles | which +sans | without +soi | oneself + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(FrenchStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/articles_ga.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/articles_ga.go new file mode 100644 index 00000000..0c8d4a98 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/articles_ga.go @@ -0,0 +1,27 @@ +package ga + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ArticlesName = "articles_ga" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis + +var IrishArticles = []byte(` +d +m +b +`) + +func ArticlesTokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(IrishArticles) + return rv, err +} + +func init() { + registry.RegisterTokenMap(ArticlesName, ArticlesTokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga.go new file mode 100644 index 00000000..6ea1e113 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga.go @@ -0,0 +1,32 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ga + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ElisionName = "elision_ga" + +func ElisionFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + articlesTokenMap, err := cache.TokenMapNamed(ArticlesName) + if err != nil { + return nil, fmt.Errorf("error building elision filter: %v", err) + } + return elision_filter.NewElisionFilter(articlesTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(ElisionName, ElisionFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga_test.go new file mode 100644 index 00000000..92ea6814 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/elision_ga_test.go @@ -0,0 +1,50 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ga + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestFrenchElision(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("b'fhearr"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("fhearr"), + }, + }, + }, + } + + cache := registry.NewCache() + elisionFilter, err := cache.TokenFilterNamed(ElisionName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := elisionFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_filter_ga.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_filter_ga.go new file mode 100644 index 00000000..af117c28 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_filter_ga.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ga + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_words_ga.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_words_ga.go new file mode 100644 index 00000000..4497024a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga/stop_words_ga.go @@ -0,0 +1,134 @@ +package ga + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_ga" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var IrishStopWords = []byte(` +a +ach +ag +agus +an +aon +ar +arna +as +b' +ba +beirt +bhúr +caoga +ceathair +ceathrar +chomh +chtó +chuig +chun +cois +céad +cúig +cúigear +d' +daichead +dar +de +deich +deichniúr +den +dhá +do +don +dtí +dá +dár +dó +faoi +faoin +faoina +faoinár +fara +fiche +gach +gan +go +gur +haon +hocht +i +iad +idir +in +ina +ins +inár +is +le +leis +lena +lenár +m' +mar +mo +mé +na +nach +naoi +naonúr +ná +ní +níor +nó +nócha +ocht +ochtar +os +roimh +sa +seacht +seachtar +seachtó +seasca +seisear +siad +sibh +sinn +sna +sé +sí +tar +thar +thú +triúr +trí +trína +trínár +tríocha +tú +um +ár +é +éis +í +ó +ón +óna +ónár +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(IrishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_filter_gl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_filter_gl.go new file mode 100644 index 00000000..d5bd8488 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_filter_gl.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package gl + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_words_gl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_words_gl.go new file mode 100644 index 00000000..09afa73c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl/stop_words_gl.go @@ -0,0 +1,185 @@ +package gl + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_gl" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var GalicianStopWords = []byte(`# galican stopwords +a +aínda +alí +aquel +aquela +aquelas +aqueles +aquilo +aquí +ao +aos +as +así +á +ben +cando +che +co +coa +comigo +con +connosco +contigo +convosco +coas +cos +cun +cuns +cunha +cunhas +da +dalgunha +dalgunhas +dalgún +dalgúns +das +de +del +dela +delas +deles +desde +deste +do +dos +dun +duns +dunha +dunhas +e +el +ela +elas +eles +en +era +eran +esa +esas +ese +eses +esta +estar +estaba +está +están +este +estes +estiven +estou +eu +é +facer +foi +foron +fun +había +hai +iso +isto +la +las +lle +lles +lo +los +mais +me +meu +meus +min +miña +miñas +moi +na +nas +neste +nin +no +non +nos +nosa +nosas +noso +nosos +nós +nun +nunha +nuns +nunhas +o +os +ou +ó +ós +para +pero +pode +pois +pola +polas +polo +polos +por +que +se +senón +ser +seu +seus +sexa +sido +sobre +súa +súas +tamén +tan +te +ten +teñen +teño +ter +teu +teus +ti +tido +tiña +tiven +túa +túas +un +unha +unhas +uns +vos +vosa +vosas +voso +vosos +vós +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(GalicianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi.go new file mode 100644 index 00000000..661fa0af --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi.go @@ -0,0 +1,62 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "hi" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + indicNormalizeFilter, err := cache.TokenFilterNamed(in.NormalizeName) + if err != nil { + return nil, err + } + hindiNormalizeFilter, err := cache.TokenFilterNamed(NormalizeName) + if err != nil { + return nil, err + } + stopHiFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerHiFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + indicNormalizeFilter, + hindiNormalizeFilter, + stopHiFilter, + stemmerHiFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi_test.go new file mode 100644 index 00000000..91293a68 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/analyzer_hi_test.go @@ -0,0 +1,61 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestHindiAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // two ways to write 'hindi' itself + { + input: []byte("हिन्दी"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("हिंद"), + Position: 1, + Start: 0, + End: 18, + }, + }, + }, + { + input: []byte("हिंदी"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("हिंद"), + Position: 1, + Start: 0, + End: 15, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize.go new file mode 100644 index 00000000..eb8ee591 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize.go @@ -0,0 +1,133 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const NormalizeName = "normalize_hi" + +type HindiNormalizeFilter struct { +} + +func NewHindiNormalizeFilter() *HindiNormalizeFilter { + return &HindiNormalizeFilter{} +} + +func (s *HindiNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + term := normalize(token.Term) + token.Term = term + } + return input +} + +func normalize(input []byte) []byte { + runes := bytes.Runes(input) + for i := 0; i < len(runes); i++ { + switch runes[i] { + // dead n -> bindu + case '\u0928': + if i+1 < len(runes) && runes[i+1] == '\u094D' { + runes[i] = '\u0902' + runes = analysis.DeleteRune(runes, i+1) + } + // candrabindu -> bindu + case '\u0901': + runes[i] = '\u0902' + // nukta deletions + case '\u093C': + runes = analysis.DeleteRune(runes, i) + i-- + case '\u0929': + runes[i] = '\u0928' + case '\u0931': + runes[i] = '\u0930' + case '\u0934': + runes[i] = '\u0933' + case '\u0958': + runes[i] = '\u0915' + case '\u0959': + runes[i] = '\u0916' + case '\u095A': + runes[i] = '\u0917' + case '\u095B': + runes[i] = '\u091C' + case '\u095C': + runes[i] = '\u0921' + case '\u095D': + runes[i] = '\u0922' + case '\u095E': + runes[i] = '\u092B' + case '\u095F': + runes[i] = '\u092F' + // zwj/zwnj -> delete + case '\u200D', '\u200C': + runes = analysis.DeleteRune(runes, i) + i-- + // virama -> delete + case '\u094D': + runes = analysis.DeleteRune(runes, i) + i-- + // chandra/short -> replace + case '\u0945', '\u0946': + runes[i] = '\u0947' + case '\u0949', '\u094A': + runes[i] = '\u094B' + case '\u090D', '\u090E': + runes[i] = '\u090F' + case '\u0911', '\u0912': + runes[i] = '\u0913' + case '\u0972': + runes[i] = '\u0905' + // long -> short ind. vowels + case '\u0906': + runes[i] = '\u0905' + case '\u0908': + runes[i] = '\u0907' + case '\u090A': + runes[i] = '\u0909' + case '\u0960': + runes[i] = '\u090B' + case '\u0961': + runes[i] = '\u090C' + case '\u0910': + runes[i] = '\u090F' + case '\u0914': + runes[i] = '\u0913' + // long -> short dep. vowels + case '\u0940': + runes[i] = '\u093F' + case '\u0942': + runes[i] = '\u0941' + case '\u0944': + runes[i] = '\u0943' + case '\u0963': + runes[i] = '\u0962' + case '\u0948': + runes[i] = '\u0947' + case '\u094C': + runes[i] = '\u094B' + } + } + return analysis.BuildTermFromRunes(runes) +} + +func NormalizerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewHindiNormalizeFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(NormalizeName, NormalizerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize_test.go new file mode 100644 index 00000000..7aab7823 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_normalize_test.go @@ -0,0 +1,246 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestHindiNormalizeFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // basics + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अँगरेज़ी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अँगरेजी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अँग्रेज़ी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अँग्रेजी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेज़ी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंग्रेज़ी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंग्रेजी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अंगरेजि"), + }, + }, + }, + // test decompositions + // removing nukta dot + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("क़िताब"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताब"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("फ़र्ज़"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("फरज"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("क़र्ज़"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("करज"), + }, + }, + }, + // some other composed nukta forms + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ऱऴख़ग़ड़ढ़य़"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("रळखगडढय"), + }, + }, + }, + // removal of format (ZWJ/ZWNJ) + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("शार्‍मा"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("शारमा"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("शार्‌मा"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("शारमा"), + }, + }, + }, + // removal of chandra + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ॅॆॉॊऍऎऑऒ\u0972"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ेेोोएएओओअ"), + }, + }, + }, + // vowel shortening + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आईऊॠॡऐऔीूॄॣैौ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अइउऋऌएओिुृॢेो"), + }, + }, + }, + // empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + hindiNormalizeFilter := NewHindiNormalizeFilter() + for _, test := range tests { + actual := hindiNormalizeFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter.go new file mode 100644 index 00000000..5f4295f1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter.go @@ -0,0 +1,144 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "bytes" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_hi" + +type HindiStemmerFilter struct { +} + +func NewHindiStemmerFilter() *HindiStemmerFilter { + return &HindiStemmerFilter{} +} + +func (s *HindiStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + // if not protected keyword, stem it + if !token.KeyWord { + stemmed := stem(token.Term) + token.Term = stemmed + } + } + return input +} + +func stem(input []byte) []byte { + inputLen := utf8.RuneCount(input) + + // 5 + if inputLen > 6 && + (bytes.HasSuffix(input, []byte("ाएंगी")) || + bytes.HasSuffix(input, []byte("ाएंगे")) || + bytes.HasSuffix(input, []byte("ाऊंगी")) || + bytes.HasSuffix(input, []byte("ाऊंगा")) || + bytes.HasSuffix(input, []byte("ाइयाँ")) || + bytes.HasSuffix(input, []byte("ाइयों")) || + bytes.HasSuffix(input, []byte("ाइयां"))) { + return analysis.TruncateRunes(input, 5) + } + + // 4 + if inputLen > 5 && + (bytes.HasSuffix(input, []byte("ाएगी")) || + bytes.HasSuffix(input, []byte("ाएगा")) || + bytes.HasSuffix(input, []byte("ाओगी")) || + bytes.HasSuffix(input, []byte("ाओगे")) || + bytes.HasSuffix(input, []byte("एंगी")) || + bytes.HasSuffix(input, []byte("ेंगी")) || + bytes.HasSuffix(input, []byte("एंगे")) || + bytes.HasSuffix(input, []byte("ेंगे")) || + bytes.HasSuffix(input, []byte("ूंगी")) || + bytes.HasSuffix(input, []byte("ूंगा")) || + bytes.HasSuffix(input, []byte("ातीं")) || + bytes.HasSuffix(input, []byte("नाओं")) || + bytes.HasSuffix(input, []byte("नाएं")) || + bytes.HasSuffix(input, []byte("ताओं")) || + bytes.HasSuffix(input, []byte("ताएं")) || + bytes.HasSuffix(input, []byte("ियाँ")) || + bytes.HasSuffix(input, []byte("ियों")) || + bytes.HasSuffix(input, []byte("ियां"))) { + return analysis.TruncateRunes(input, 4) + } + + // 3 + if inputLen > 4 && + (bytes.HasSuffix(input, []byte("ाकर")) || + bytes.HasSuffix(input, []byte("ाइए")) || + bytes.HasSuffix(input, []byte("ाईं")) || + bytes.HasSuffix(input, []byte("ाया")) || + bytes.HasSuffix(input, []byte("ेगी")) || + bytes.HasSuffix(input, []byte("ेगा")) || + bytes.HasSuffix(input, []byte("ोगी")) || + bytes.HasSuffix(input, []byte("ोगे")) || + bytes.HasSuffix(input, []byte("ाने")) || + bytes.HasSuffix(input, []byte("ाना")) || + bytes.HasSuffix(input, []byte("ाते")) || + bytes.HasSuffix(input, []byte("ाती")) || + bytes.HasSuffix(input, []byte("ाता")) || + bytes.HasSuffix(input, []byte("तीं")) || + bytes.HasSuffix(input, []byte("ाओं")) || + bytes.HasSuffix(input, []byte("ाएं")) || + bytes.HasSuffix(input, []byte("ुओं")) || + bytes.HasSuffix(input, []byte("ुएं")) || + bytes.HasSuffix(input, []byte("ुआं"))) { + return analysis.TruncateRunes(input, 3) + } + + // 2 + if inputLen > 3 && + (bytes.HasSuffix(input, []byte("कर")) || + bytes.HasSuffix(input, []byte("ाओ")) || + bytes.HasSuffix(input, []byte("िए")) || + bytes.HasSuffix(input, []byte("ाई")) || + bytes.HasSuffix(input, []byte("ाए")) || + bytes.HasSuffix(input, []byte("ने")) || + bytes.HasSuffix(input, []byte("नी")) || + bytes.HasSuffix(input, []byte("ना")) || + bytes.HasSuffix(input, []byte("ते")) || + bytes.HasSuffix(input, []byte("ीं")) || + bytes.HasSuffix(input, []byte("ती")) || + bytes.HasSuffix(input, []byte("ता")) || + bytes.HasSuffix(input, []byte("ाँ")) || + bytes.HasSuffix(input, []byte("ां")) || + bytes.HasSuffix(input, []byte("ों")) || + bytes.HasSuffix(input, []byte("ें"))) { + return analysis.TruncateRunes(input, 2) + } + + // 1 + if inputLen > 2 && + (bytes.HasSuffix(input, []byte("ो")) || + bytes.HasSuffix(input, []byte("े")) || + bytes.HasSuffix(input, []byte("ू")) || + bytes.HasSuffix(input, []byte("ु")) || + bytes.HasSuffix(input, []byte("ी")) || + bytes.HasSuffix(input, []byte("ि")) || + bytes.HasSuffix(input, []byte("ा"))) { + return analysis.TruncateRunes(input, 1) + } + + return input +} + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewHindiStemmerFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter_test.go new file mode 100644 index 00000000..7d2f0855 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/hindi_stemmer_filter_test.go @@ -0,0 +1,303 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestHindiStemmerFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // masc noun inflections + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडका"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडके"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडकों"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("गुरु"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("गुर"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("गुरुओं"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("गुर"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("दोस्त"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("दोस्त"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("दोस्तों"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("दोस्त"), + }, + }, + }, + // feminine noun inflections + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडकी"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडकियों"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("लडक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताब"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताब"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताबें"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताब"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताबों"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("किताब"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आध्यापीका"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आध्यापीक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आध्यापीकाएं"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आध्यापीक"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आध्यापीकाओं"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आध्यापीक"), + }, + }, + }, + // some verb forms + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खाना"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खा"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खाता"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खा"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खाती"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खा"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खा"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("खा"), + }, + }, + }, + // exceptions + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("कठिनाइयां"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("कठिन"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("कठिन"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("कठिन"), + }, + }, + }, + // empty + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + hindiStemmerFilter := NewHindiStemmerFilter() + for _, test := range tests { + actual := hindiStemmerFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_filter_hi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_filter_hi.go new file mode 100644 index 00000000..87a8a6ff --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_filter_hi.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_words_hi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_words_hi.go new file mode 100644 index 00000000..47d04a1e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi/stop_words_hi.go @@ -0,0 +1,259 @@ +package hi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_hi" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var HindiStopWords = []byte(`# Also see http://www.opensource.org/licenses/bsd-license.html +# See http://members.unine.ch/jacques.savoy/clef/index.html. +# This file was created by Jacques Savoy and is distributed under the BSD license. +# Note: by default this file also contains forms normalized by HindiNormalizer +# for spelling variation (see section below), such that it can be used whether or +# not you enable that feature. When adding additional entries to this list, +# please add the normalized form as well. +अंदर +अत +अपना +अपनी +अपने +अभी +आदि +आप +इत्यादि +इन +इनका +इन्हीं +इन्हें +इन्हों +इस +इसका +इसकी +इसके +इसमें +इसी +इसे +उन +उनका +उनकी +उनके +उनको +उन्हीं +उन्हें +उन्हों +उस +उसके +उसी +उसे +एक +एवं +एस +ऐसे +और +कई +कर +करता +करते +करना +करने +करें +कहते +कहा +का +काफ़ी +कि +कितना +किन्हें +किन्हों +किया +किर +किस +किसी +किसे +की +कुछ +कुल +के +को +कोई +कौन +कौनसा +गया +घर +जब +जहाँ +जा +जितना +जिन +जिन्हें +जिन्हों +जिस +जिसे +जीधर +जैसा +जैसे +जो +तक +तब +तरह +तिन +तिन्हें +तिन्हों +तिस +तिसे +तो +था +थी +थे +दबारा +दिया +दुसरा +दूसरे +दो +द्वारा +न +नहीं +ना +निहायत +नीचे +ने +पर +पर +पहले +पूरा +पे +फिर +बनी +बही +बहुत +बाद +बाला +बिलकुल +भी +भीतर +मगर +मानो +मे +में +यदि +यह +यहाँ +यही +या +यिह +ये +रखें +रहा +रहे +ऱ्वासा +लिए +लिये +लेकिन +व +वर्ग +वह +वह +वहाँ +वहीं +वाले +वुह +वे +वग़ैरह +संग +सकता +सकते +सबसे +सभी +साथ +साबुत +साभ +सारा +से +सो +ही +हुआ +हुई +हुए +है +हैं +हो +होता +होती +होते +होना +होने +# additional normalized forms of the above +अपनि +जेसे +होति +सभि +तिंहों +इंहों +दवारा +इसि +किंहें +थि +उंहों +ओर +जिंहें +वहिं +अभि +बनि +हि +उंहिं +उंहें +हें +वगेरह +एसे +रवासा +कोन +निचे +काफि +उसि +पुरा +भितर +हे +बहि +वहां +कोइ +यहां +जिंहों +तिंहें +किसि +कइ +यहि +इंहिं +जिधर +इंहें +अदि +इतयादि +हुइ +कोनसा +इसकि +दुसरे +जहां +अप +किंहों +उनकि +भि +वरग +हुअ +जेसा +नहिं +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(HindiStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu.go new file mode 100644 index 00000000..2f103d58 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package hu + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "hu" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopHuFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerHuFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopHuFilter, + stemmerHuFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu_test.go new file mode 100644 index 00000000..93a65c6b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/analyzer_hu_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package hu + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestHungarianAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("babakocsi"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("babakocs"), + }, + }, + }, + { + input: []byte("babakocsijáért"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("babakocs"), + }, + }, + }, + // stop word + { + input: []byte("által"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stemmer_hu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stemmer_hu.go new file mode 100644 index 00000000..863e9664 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stemmer_hu.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package hu + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_hu" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("hu") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_filter_hu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_filter_hu.go new file mode 100644 index 00000000..195bd233 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_filter_hu.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hu + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_words_hu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_words_hu.go new file mode 100644 index 00000000..45f01524 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu/stop_words_hu.go @@ -0,0 +1,235 @@ +package hu + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_hu" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var HungarianStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/hungarian/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + +| Hungarian stop word list +| prepared by Anna Tordai + +a +ahogy +ahol +aki +akik +akkor +alatt +által +általában +amely +amelyek +amelyekben +amelyeket +amelyet +amelynek +ami +amit +amolyan +amíg +amikor +át +abban +ahhoz +annak +arra +arról +az +azok +azon +azt +azzal +azért +aztán +azután +azonban +bár +be +belül +benne +cikk +cikkek +cikkeket +csak +de +e +eddig +egész +egy +egyes +egyetlen +egyéb +egyik +egyre +ekkor +el +elég +ellen +elő +először +előtt +első +én +éppen +ebben +ehhez +emilyen +ennek +erre +ez +ezt +ezek +ezen +ezzel +ezért +és +fel +felé +hanem +hiszen +hogy +hogyan +igen +így +illetve +ill. +ill +ilyen +ilyenkor +ison +ismét +itt +jó +jól +jobban +kell +kellett +keresztül +keressünk +ki +kívül +között +közül +legalább +lehet +lehetett +legyen +lenne +lenni +lesz +lett +maga +magát +majd +majd +már +más +másik +meg +még +mellett +mert +mely +melyek +mi +mit +míg +miért +milyen +mikor +minden +mindent +mindenki +mindig +mint +mintha +mivel +most +nagy +nagyobb +nagyon +ne +néha +nekem +neki +nem +néhány +nélkül +nincs +olyan +ott +össze +ő +ők +őket +pedig +persze +rá +s +saját +sem +semmi +sok +sokat +sokkal +számára +szemben +szerint +szinte +talán +tehát +teljes +tovább +továbbá +több +úgy +ugyanis +új +újabb +újra +után +utána +utolsó +vagy +vagyis +valaki +valami +valamint +való +vagyok +van +vannak +volt +voltam +voltak +voltunk +vissza +vele +viszont +volna +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(HungarianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_filter_hy.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_filter_hy.go new file mode 100644 index 00000000..418083ae --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_filter_hy.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package hy + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_words_hy.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_words_hy.go new file mode 100644 index 00000000..8f36d3fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy/stop_words_hy.go @@ -0,0 +1,70 @@ +package hy + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_hy" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var ArmenianStopWords = []byte(`# example set of Armenian stopwords. +այդ +այլ +այն +այս +դու +դուք +եմ +են +ենք +ես +եք +է +էի +էին +էինք +էիր +էիք +էր +ըստ +թ +ի +ին +իսկ +իր +կամ +համար +հետ +հետո +մենք +մեջ +մի +ն +նա +նաև +նրա +նրանք +որ +որը +որոնք +որպես +ու +ում +պիտի +վրա +և +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(ArmenianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_filter_id.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_filter_id.go new file mode 100644 index 00000000..0f42571a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_filter_id.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package id + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_words_id.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_words_id.go new file mode 100644 index 00000000..4f4f1ae8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id/stop_words_id.go @@ -0,0 +1,383 @@ +package id + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_id" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var IndonesianStopWords = []byte(`# from appendix D of: A Study of Stemming Effects on Information +# Retrieval in Bahasa Indonesia +ada +adanya +adalah +adapun +agak +agaknya +agar +akan +akankah +akhirnya +aku +akulah +amat +amatlah +anda +andalah +antar +diantaranya +antara +antaranya +diantara +apa +apaan +mengapa +apabila +apakah +apalagi +apatah +atau +ataukah +ataupun +bagai +bagaikan +sebagai +sebagainya +bagaimana +bagaimanapun +sebagaimana +bagaimanakah +bagi +bahkan +bahwa +bahwasanya +sebaliknya +banyak +sebanyak +beberapa +seberapa +begini +beginian +beginikah +beginilah +sebegini +begitu +begitukah +begitulah +begitupun +sebegitu +belum +belumlah +sebelum +sebelumnya +sebenarnya +berapa +berapakah +berapalah +berapapun +betulkah +sebetulnya +biasa +biasanya +bila +bilakah +bisa +bisakah +sebisanya +boleh +bolehkah +bolehlah +buat +bukan +bukankah +bukanlah +bukannya +cuma +percuma +dahulu +dalam +dan +dapat +dari +daripada +dekat +demi +demikian +demikianlah +sedemikian +dengan +depan +di +dia +dialah +dini +diri +dirinya +terdiri +dong +dulu +enggak +enggaknya +entah +entahlah +terhadap +terhadapnya +hal +hampir +hanya +hanyalah +harus +haruslah +harusnya +seharusnya +hendak +hendaklah +hendaknya +hingga +sehingga +ia +ialah +ibarat +ingin +inginkah +inginkan +ini +inikah +inilah +itu +itukah +itulah +jangan +jangankan +janganlah +jika +jikalau +juga +justru +kala +kalau +kalaulah +kalaupun +kalian +kami +kamilah +kamu +kamulah +kan +kapan +kapankah +kapanpun +dikarenakan +karena +karenanya +ke +kecil +kemudian +kenapa +kepada +kepadanya +ketika +seketika +khususnya +kini +kinilah +kiranya +sekiranya +kita +kitalah +kok +lagi +lagian +selagi +lah +lain +lainnya +melainkan +selaku +lalu +melalui +terlalu +lama +lamanya +selama +selama +selamanya +lebih +terlebih +bermacam +macam +semacam +maka +makanya +makin +malah +malahan +mampu +mampukah +mana +manakala +manalagi +masih +masihkah +semasih +masing +mau +maupun +semaunya +memang +mereka +merekalah +meski +meskipun +semula +mungkin +mungkinkah +nah +namun +nanti +nantinya +nyaris +oleh +olehnya +seorang +seseorang +pada +padanya +padahal +paling +sepanjang +pantas +sepantasnya +sepantasnyalah +para +pasti +pastilah +per +pernah +pula +pun +merupakan +rupanya +serupa +saat +saatnya +sesaat +saja +sajalah +saling +bersama +sama +sesama +sambil +sampai +sana +sangat +sangatlah +saya +sayalah +se +sebab +sebabnya +sebuah +tersebut +tersebutlah +sedang +sedangkan +sedikit +sedikitnya +segala +segalanya +segera +sesegera +sejak +sejenak +sekali +sekalian +sekalipun +sesekali +sekaligus +sekarang +sekarang +sekitar +sekitarnya +sela +selain +selalu +seluruh +seluruhnya +semakin +sementara +sempat +semua +semuanya +sendiri +sendirinya +seolah +seperti +sepertinya +sering +seringnya +serta +siapa +siapakah +siapapun +disini +disinilah +sini +sinilah +sesuatu +sesuatunya +suatu +sesudah +sesudahnya +sudah +sudahkah +sudahlah +supaya +tadi +tadinya +tak +tanpa +setelah +telah +tentang +tentu +tentulah +tentunya +tertentu +seterusnya +tapi +tetapi +setiap +tiap +setidaknya +tidak +tidakkah +tidaklah +toh +waduh +wah +wahai +sewaktu +walau +walaupun +wong +yaitu +yakni +yang +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(IndonesianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize.go new file mode 100644 index 00000000..6968cba2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize.go @@ -0,0 +1,43 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package in + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const NormalizeName = "normalize_in" + +type IndicNormalizeFilter struct { +} + +func NewIndicNormalizeFilter() *IndicNormalizeFilter { + return &IndicNormalizeFilter{} +} + +func (s *IndicNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + runes := bytes.Runes(token.Term) + runes = normalize(runes) + token.Term = analysis.BuildTermFromRunes(runes) + } + return input +} + +func NormalizerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewIndicNormalizeFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(NormalizeName, NormalizerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize_test.go new file mode 100644 index 00000000..b5728b37 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/indic_normalize_test.go @@ -0,0 +1,133 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package in + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestIndicNormalizeFilter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + // basics + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अाॅअाॅ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ऑऑ"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अाॆअाॆ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ऒऒ"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अाेअाे"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ओओ"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अाैअाै"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("औऔ"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अाअा"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("आआ"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("अाैर"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("और"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ত্‍"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ৎ"), + }, + }, + }, + // empty term + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte(""), + }, + }, + }, + } + + indicNormalizeFilter := NewIndicNormalizeFilter() + for _, test := range tests { + actual := indicNormalizeFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + t.Errorf("expected % x, got % x for % x", test.output[0].Term, actual[0].Term, test.input[0].Term) + t.Errorf("expected %s, got %s for %s", test.output[0].Term, actual[0].Term, test.input[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/scripts.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/scripts.go new file mode 100644 index 00000000..6465ff5a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in/scripts.go @@ -0,0 +1,291 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package in + +import ( + "unicode" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/willf/bitset" +) + +type ScriptData struct { + flag rune + base rune + decompMask *bitset.BitSet +} + +var scripts = map[*unicode.RangeTable]*ScriptData{ + unicode.Devanagari: &ScriptData{ + flag: 1, + base: 0x0900, + }, + unicode.Bengali: &ScriptData{ + flag: 2, + base: 0x0980, + }, + unicode.Gurmukhi: &ScriptData{ + flag: 4, + base: 0x0A00, + }, + unicode.Gujarati: &ScriptData{ + flag: 8, + base: 0x0A80, + }, + unicode.Oriya: &ScriptData{ + flag: 16, + base: 0x0B00, + }, + unicode.Tamil: &ScriptData{ + flag: 32, + base: 0x0B80, + }, + unicode.Telugu: &ScriptData{ + flag: 64, + base: 0x0C00, + }, + unicode.Kannada: &ScriptData{ + flag: 128, + base: 0x0C80, + }, + unicode.Malayalam: &ScriptData{ + flag: 256, + base: 0x0D00, + }, +} + +func flag(ub *unicode.RangeTable) rune { + return scripts[ub].flag +} + +var decompositions = [][]rune{ + /* devanagari, gujarati vowel candra O */ + {0x05, 0x3E, 0x45, 0x11, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari short O */ + {0x05, 0x3E, 0x46, 0x12, flag(unicode.Devanagari)}, + /* devanagari, gujarati letter O */ + {0x05, 0x3E, 0x47, 0x13, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari letter AI, gujarati letter AU */ + {0x05, 0x3E, 0x48, 0x14, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari, bengali, gurmukhi, gujarati, oriya AA */ + {0x05, 0x3E, -1, 0x06, flag(unicode.Devanagari) | flag(unicode.Bengali) | flag(unicode.Gurmukhi) | flag(unicode.Gujarati) | flag(unicode.Oriya)}, + /* devanagari letter candra A */ + {0x05, 0x45, -1, 0x72, flag(unicode.Devanagari)}, + /* gujarati vowel candra E */ + {0x05, 0x45, -1, 0x0D, flag(unicode.Gujarati)}, + /* devanagari letter short A */ + {0x05, 0x46, -1, 0x04, flag(unicode.Devanagari)}, + /* gujarati letter E */ + {0x05, 0x47, -1, 0x0F, flag(unicode.Gujarati)}, + /* gurmukhi, gujarati letter AI */ + {0x05, 0x48, -1, 0x10, flag(unicode.Gurmukhi) | flag(unicode.Gujarati)}, + /* devanagari, gujarati vowel candra O */ + {0x05, 0x49, -1, 0x11, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari short O */ + {0x05, 0x4A, -1, 0x12, flag(unicode.Devanagari)}, + /* devanagari, gujarati letter O */ + {0x05, 0x4B, -1, 0x13, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari letter AI, gurmukhi letter AU, gujarati letter AU */ + {0x05, 0x4C, -1, 0x14, flag(unicode.Devanagari) | flag(unicode.Gurmukhi) | flag(unicode.Gujarati)}, + /* devanagari, gujarati vowel candra O */ + {0x06, 0x45, -1, 0x11, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari short O */ + {0x06, 0x46, -1, 0x12, flag(unicode.Devanagari)}, + /* devanagari, gujarati letter O */ + {0x06, 0x47, -1, 0x13, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari letter AI, gujarati letter AU */ + {0x06, 0x48, -1, 0x14, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* malayalam letter II */ + {0x07, 0x57, -1, 0x08, flag(unicode.Malayalam)}, + /* devanagari letter UU */ + {0x09, 0x41, -1, 0x0A, flag(unicode.Devanagari)}, + /* tamil, malayalam letter UU (some styles) */ + {0x09, 0x57, -1, 0x0A, flag(unicode.Tamil) | flag(unicode.Malayalam)}, + /* malayalam letter AI */ + {0x0E, 0x46, -1, 0x10, flag(unicode.Malayalam)}, + /* devanagari candra E */ + {0x0F, 0x45, -1, 0x0D, flag(unicode.Devanagari)}, + /* devanagari short E */ + {0x0F, 0x46, -1, 0x0E, flag(unicode.Devanagari)}, + /* devanagari AI */ + {0x0F, 0x47, -1, 0x10, flag(unicode.Devanagari)}, + /* oriya AI */ + {0x0F, 0x57, -1, 0x10, flag(unicode.Oriya)}, + /* malayalam letter OO */ + {0x12, 0x3E, -1, 0x13, flag(unicode.Malayalam)}, + /* telugu, kannada letter AU */ + {0x12, 0x4C, -1, 0x14, flag(unicode.Telugu) | flag(unicode.Kannada)}, + /* telugu letter OO */ + {0x12, 0x55, -1, 0x13, flag(unicode.Telugu)}, + /* tamil, malayalam letter AU */ + {0x12, 0x57, -1, 0x14, flag(unicode.Tamil) | flag(unicode.Malayalam)}, + /* oriya letter AU */ + {0x13, 0x57, -1, 0x14, flag(unicode.Oriya)}, + /* devanagari qa */ + {0x15, 0x3C, -1, 0x58, flag(unicode.Devanagari)}, + /* devanagari, gurmukhi khha */ + {0x16, 0x3C, -1, 0x59, flag(unicode.Devanagari) | flag(unicode.Gurmukhi)}, + /* devanagari, gurmukhi ghha */ + {0x17, 0x3C, -1, 0x5A, flag(unicode.Devanagari) | flag(unicode.Gurmukhi)}, + /* devanagari, gurmukhi za */ + {0x1C, 0x3C, -1, 0x5B, flag(unicode.Devanagari) | flag(unicode.Gurmukhi)}, + /* devanagari dddha, bengali, oriya rra */ + {0x21, 0x3C, -1, 0x5C, flag(unicode.Devanagari) | flag(unicode.Bengali) | flag(unicode.Oriya)}, + /* devanagari, bengali, oriya rha */ + {0x22, 0x3C, -1, 0x5D, flag(unicode.Devanagari) | flag(unicode.Bengali) | flag(unicode.Oriya)}, + /* malayalam chillu nn */ + {0x23, 0x4D, 0xFF, 0x7A, flag(unicode.Malayalam)}, + /* bengali khanda ta */ + {0x24, 0x4D, 0xFF, 0x4E, flag(unicode.Bengali)}, + /* devanagari nnna */ + {0x28, 0x3C, -1, 0x29, flag(unicode.Devanagari)}, + /* malayalam chillu n */ + {0x28, 0x4D, 0xFF, 0x7B, flag(unicode.Malayalam)}, + /* devanagari, gurmukhi fa */ + {0x2B, 0x3C, -1, 0x5E, flag(unicode.Devanagari) | flag(unicode.Gurmukhi)}, + /* devanagari, bengali yya */ + {0x2F, 0x3C, -1, 0x5F, flag(unicode.Devanagari) | flag(unicode.Bengali)}, + /* telugu letter vocalic R */ + {0x2C, 0x41, 0x41, 0x0B, flag(unicode.Telugu)}, + /* devanagari rra */ + {0x30, 0x3C, -1, 0x31, flag(unicode.Devanagari)}, + /* malayalam chillu rr */ + {0x30, 0x4D, 0xFF, 0x7C, flag(unicode.Malayalam)}, + /* malayalam chillu l */ + {0x32, 0x4D, 0xFF, 0x7D, flag(unicode.Malayalam)}, + /* devanagari llla */ + {0x33, 0x3C, -1, 0x34, flag(unicode.Devanagari)}, + /* malayalam chillu ll */ + {0x33, 0x4D, 0xFF, 0x7E, flag(unicode.Malayalam)}, + /* telugu letter MA */ + {0x35, 0x41, -1, 0x2E, flag(unicode.Telugu)}, + /* devanagari, gujarati vowel sign candra O */ + {0x3E, 0x45, -1, 0x49, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari vowel sign short O */ + {0x3E, 0x46, -1, 0x4A, flag(unicode.Devanagari)}, + /* devanagari, gujarati vowel sign O */ + {0x3E, 0x47, -1, 0x4B, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* devanagari, gujarati vowel sign AU */ + {0x3E, 0x48, -1, 0x4C, flag(unicode.Devanagari) | flag(unicode.Gujarati)}, + /* kannada vowel sign II */ + {0x3F, 0x55, -1, 0x40, flag(unicode.Kannada)}, + /* gurmukhi vowel sign UU (when stacking) */ + {0x41, 0x41, -1, 0x42, flag(unicode.Gurmukhi)}, + /* tamil, malayalam vowel sign O */ + {0x46, 0x3E, -1, 0x4A, flag(unicode.Tamil) | flag(unicode.Malayalam)}, + /* kannada vowel sign OO */ + {0x46, 0x42, 0x55, 0x4B, flag(unicode.Kannada)}, + /* kannada vowel sign O */ + {0x46, 0x42, -1, 0x4A, flag(unicode.Kannada)}, + /* malayalam vowel sign AI (if reordered twice) */ + {0x46, 0x46, -1, 0x48, flag(unicode.Malayalam)}, + /* telugu, kannada vowel sign EE */ + {0x46, 0x55, -1, 0x47, flag(unicode.Telugu) | flag(unicode.Kannada)}, + /* telugu, kannada vowel sign AI */ + {0x46, 0x56, -1, 0x48, flag(unicode.Telugu) | flag(unicode.Kannada)}, + /* tamil, malayalam vowel sign AU */ + {0x46, 0x57, -1, 0x4C, flag(unicode.Tamil) | flag(unicode.Malayalam)}, + /* bengali, oriya vowel sign O, tamil, malayalam vowel sign OO */ + {0x47, 0x3E, -1, 0x4B, flag(unicode.Bengali) | flag(unicode.Oriya) | flag(unicode.Tamil) | flag(unicode.Malayalam)}, + /* bengali, oriya vowel sign AU */ + {0x47, 0x57, -1, 0x4C, flag(unicode.Bengali) | flag(unicode.Oriya)}, + /* kannada vowel sign OO */ + {0x4A, 0x55, -1, 0x4B, flag(unicode.Kannada)}, + /* gurmukhi letter I */ + {0x72, 0x3F, -1, 0x07, flag(unicode.Gurmukhi)}, + /* gurmukhi letter II */ + {0x72, 0x40, -1, 0x08, flag(unicode.Gurmukhi)}, + /* gurmukhi letter EE */ + {0x72, 0x47, -1, 0x0F, flag(unicode.Gurmukhi)}, + /* gurmukhi letter U */ + {0x73, 0x41, -1, 0x09, flag(unicode.Gurmukhi)}, + /* gurmukhi letter UU */ + {0x73, 0x42, -1, 0x0A, flag(unicode.Gurmukhi)}, + /* gurmukhi letter OO */ + {0x73, 0x4B, -1, 0x13, flag(unicode.Gurmukhi)}, +} + +func init() { + for _, scriptData := range scripts { + scriptData.decompMask = bitset.New(0x7d) + for _, decomposition := range decompositions { + ch := decomposition[0] + flags := decomposition[4] + if (flags & scriptData.flag) != 0 { + scriptData.decompMask.Set(uint(ch)) + } + } + } +} + +func lookupScript(r rune) *unicode.RangeTable { + for script, _ := range scripts { + if unicode.Is(script, r) { + return script + } + } + return nil +} + +func normalize(input []rune) []rune { + inputLen := len(input) + for i := 0; i < inputLen; i++ { + r := input[i] + script := lookupScript(r) + if script != nil { + scriptData := scripts[script] + ch := r - scriptData.base + if scriptData.decompMask.Test(uint(ch)) { + input = compose(ch, script, scriptData, input, i, inputLen) + inputLen = len(input) + } + } + } + return input[0:inputLen] +} + +func compose(ch0 rune, script0 *unicode.RangeTable, scriptData *ScriptData, input []rune, pos int, inputLen int) []rune { + if pos+1 >= inputLen { + return input // need at least 2 characters + } + + ch1 := input[pos+1] - scriptData.base + script1 := lookupScript(input[pos+1]) + if script0 != script1 { + return input // need to be same script + } + + ch2 := rune(-1) + if pos+2 < inputLen { + ch2 = input[pos+2] - scriptData.base + script2 := lookupScript(input[pos+2]) + if input[pos+2] == '\u200D' { + ch2 = 0xff // zero width joiner + } else if script2 != script1 { + ch2 = -1 // still allow 2 character match + } + } + + for _, decomposition := range decompositions { + if decomposition[0] == ch0 && + (decomposition[4]&scriptData.flag) != 0 { + if decomposition[1] == ch1 && + (decomposition[2] < 0 || decomposition[2] == ch2) { + input[pos] = scriptData.base + decomposition[3] + input = analysis.DeleteRune(input, pos+1) + if decomposition[2] >= 0 { + input = analysis.DeleteRune(input, pos+1) + } + return input + } + } + } + return input +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it.go new file mode 100644 index 00000000..bb58a2eb --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "it" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + elisionFilter, err := cache.TokenFilterNamed(ElisionName) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopItFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerItFilter, err := cache.TokenFilterNamed(LightStemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + elisionFilter, + toLowerFilter, + stopItFilter, + stemmerItFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it_test.go new file mode 100644 index 00000000..7fcaba83 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/analyzer_it_test.go @@ -0,0 +1,82 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestItalianAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("abbandonata"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abbandonat"), + }, + }, + }, + { + input: []byte("abbandonati"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abbandonat"), + }, + }, + }, + // stop word + { + input: []byte("dallo"), + output: analysis.TokenStream{}, + }, + // contractions + { + input: []byte("dell'Italia"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ital"), + }, + }, + }, + { + input: []byte("l'Italiano"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("italian"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/articles_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/articles_it.go new file mode 100644 index 00000000..edb0ad1d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/articles_it.go @@ -0,0 +1,45 @@ +package it + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ArticlesName = "articles_it" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis + +var ItalianArticles = []byte(` +c +l +all +dall +dell +nell +sull +coll +pell +gl +agl +dagl +degl +negl +sugl +un +m +t +s +v +d +`) + +func ArticlesTokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(ItalianArticles) + return rv, err +} + +func init() { + registry.RegisterTokenMap(ArticlesName, ArticlesTokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it.go new file mode 100644 index 00000000..c5a898a3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it.go @@ -0,0 +1,32 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const ElisionName = "elision_it" + +func ElisionFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + articlesTokenMap, err := cache.TokenMapNamed(ArticlesName) + if err != nil { + return nil, fmt.Errorf("error building elision filter: %v", err) + } + return elision_filter.NewElisionFilter(articlesTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(ElisionName, ElisionFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it_test.go new file mode 100644 index 00000000..5a76ebbf --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/elision_it_test.go @@ -0,0 +1,50 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestItalianElision(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("dell'Italia"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Italia"), + }, + }, + }, + } + + cache := registry.NewCache() + elisionFilter, err := cache.TokenFilterNamed(ElisionName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := elisionFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it.go new file mode 100644 index 00000000..71f4115a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it.go @@ -0,0 +1,96 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const LightStemmerName = "stemmer_it_light" + +type ItalianLightStemmerFilter struct { +} + +func NewItalianLightStemmerFilterFilter() *ItalianLightStemmerFilter { + return &ItalianLightStemmerFilter{} +} + +func (s *ItalianLightStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + runes := bytes.Runes(token.Term) + runes = stem(runes) + token.Term = analysis.BuildTermFromRunes(runes) + } + return input +} + +func stem(input []rune) []rune { + + inputLen := len(input) + + if inputLen < 6 { + return input + } + + for i := 0; i < inputLen; i++ { + switch input[i] { + case 'à', 'á', 'â', 'ä': + input[i] = 'a' + case 'ò', 'ó', 'ô', 'ö': + input[i] = 'o' + case 'è', 'é', 'ê', 'ë': + input[i] = 'e' + case 'ù', 'ú', 'û', 'ü': + input[i] = 'u' + case 'ì', 'í', 'î', 'ï': + input[i] = 'i' + } + } + + switch input[inputLen-1] { + case 'e': + if input[inputLen-2] == 'i' || input[inputLen-2] == 'h' { + return input[0 : inputLen-2] + } else { + return input[0 : inputLen-1] + } + case 'i': + if input[inputLen-2] == 'h' || input[inputLen-2] == 'i' { + return input[0 : inputLen-2] + } else { + return input[0 : inputLen-1] + } + case 'a': + if input[inputLen-2] == 'i' { + return input[0 : inputLen-2] + } else { + return input[0 : inputLen-1] + } + case 'o': + if input[inputLen-2] == 'i' { + return input[0 : inputLen-2] + } else { + return input[0 : inputLen-1] + } + } + + return input +} + +func ItalianLightStemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewItalianLightStemmerFilterFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(LightStemmerName, ItalianLightStemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it_test.go new file mode 100644 index 00000000..3df155d6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/light_stemmer_it_test.go @@ -0,0 +1,62 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestItalianLightStemmer(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ragazzo"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ragazz"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ragazzi"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ragazz"), + }, + }, + }, + } + + cache := registry.NewCache() + filter, err := cache.TokenFilterNamed(LightStemmerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := filter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stemmer_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stemmer_it.go new file mode 100644 index 00000000..a74e75fb --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stemmer_it.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package it + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_it" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("it") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_filter_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_filter_it.go new file mode 100644 index 00000000..d9af6390 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_filter_it.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package it + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_words_it.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_words_it.go new file mode 100644 index 00000000..05a06eb8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it/stop_words_it.go @@ -0,0 +1,327 @@ +package it + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_it" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var ItalianStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/italian/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | An Italian stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + +ad | a (to) before vowel +al | a + il +allo | a + lo +ai | a + i +agli | a + gli +all | a + l' +agl | a + gl' +alla | a + la +alle | a + le +con | with +col | con + il +coi | con + i (forms collo, cogli etc are now very rare) +da | from +dal | da + il +dallo | da + lo +dai | da + i +dagli | da + gli +dall | da + l' +dagl | da + gll' +dalla | da + la +dalle | da + le +di | of +del | di + il +dello | di + lo +dei | di + i +degli | di + gli +dell | di + l' +degl | di + gl' +della | di + la +delle | di + le +in | in +nel | in + el +nello | in + lo +nei | in + i +negli | in + gli +nell | in + l' +negl | in + gl' +nella | in + la +nelle | in + le +su | on +sul | su + il +sullo | su + lo +sui | su + i +sugli | su + gli +sull | su + l' +sugl | su + gl' +sulla | su + la +sulle | su + le +per | through, by +tra | among +contro | against +io | I +tu | thou +lui | he +lei | she +noi | we +voi | you +loro | they +mio | my +mia | +miei | +mie | +tuo | +tua | +tuoi | thy +tue | +suo | +sua | +suoi | his, her +sue | +nostro | our +nostra | +nostri | +nostre | +vostro | your +vostra | +vostri | +vostre | +mi | me +ti | thee +ci | us, there +vi | you, there +lo | him, the +la | her, the +li | them +le | them, the +gli | to him, the +ne | from there etc +il | the +un | a +uno | a +una | a +ma | but +ed | and +se | if +perché | why, because +anche | also +come | how +dov | where (as dov') +dove | where +che | who, that +chi | who +cui | whom +non | not +più | more +quale | who, that +quanto | how much +quanti | +quanta | +quante | +quello | that +quelli | +quella | +quelle | +questo | this +questi | +questa | +queste | +si | yes +tutto | all +tutti | all + + | single letter forms: + +a | at +c | as c' for ce or ci +e | and +i | the +l | as l' +o | or + + | forms of avere, to have (not including the infinitive): + +ho +hai +ha +abbiamo +avete +hanno +abbia +abbiate +abbiano +avrò +avrai +avrà +avremo +avrete +avranno +avrei +avresti +avrebbe +avremmo +avreste +avrebbero +avevo +avevi +aveva +avevamo +avevate +avevano +ebbi +avesti +ebbe +avemmo +aveste +ebbero +avessi +avesse +avessimo +avessero +avendo +avuto +avuta +avuti +avute + + | forms of essere, to be (not including the infinitive): +sono +sei +è +siamo +siete +sia +siate +siano +sarò +sarai +sarà +saremo +sarete +saranno +sarei +saresti +sarebbe +saremmo +sareste +sarebbero +ero +eri +era +eravamo +eravate +erano +fui +fosti +fu +fummo +foste +furono +fossi +fosse +fossimo +fossero +essendo + + | forms of fare, to do (not including the infinitive, fa, fat-): +faccio +fai +facciamo +fanno +faccia +facciate +facciano +farò +farai +farà +faremo +farete +faranno +farei +faresti +farebbe +faremmo +fareste +farebbero +facevo +facevi +faceva +facevamo +facevate +facevano +feci +facesti +fece +facemmo +faceste +fecero +facessi +facesse +facessimo +facessero +facendo + + | forms of stare, to be (not including the infinitive): +sto +stai +sta +stiamo +stanno +stia +stiate +stiano +starò +starai +starà +staremo +starete +staranno +starei +staresti +starebbe +staremmo +stareste +starebbero +stavo +stavi +stava +stavamo +stavate +stavano +stetti +stesti +stette +stemmo +steste +stettero +stessi +stesse +stessimo +stessero +stando +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(ItalianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja.go new file mode 100644 index 00000000..968defe5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja.go @@ -0,0 +1,39 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build kagome full + +package ja + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "ja" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + kagomeTokenizer, err := cache.TokenizerNamed(TokenizerName) + if err != nil { + return nil, err + } + normalizeFilter := unicode_normalize.MustNewUnicodeNormalizeFilter(unicode_normalize.NFKD) + rv := analysis.Analyzer{ + Tokenizer: kagomeTokenizer, + TokenFilters: []analysis.TokenFilter{ + normalizeFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja_test.go new file mode 100644 index 00000000..102a82ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/analyzer_ja_test.go @@ -0,0 +1,71 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build kagome full + +package ja + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestJaAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + input: []byte("こんにちは世界"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こんにちは"), + Type: analysis.Ideographic, + Position: 1, + Start: 0, + End: 15, + }, + &analysis.Token{ + Term: []byte("世界"), + Type: analysis.Ideographic, + Position: 2, + Start: 15, + End: 21, + }, + }, + }, + { + input: []byte("カタカナ"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("カタカナ"), + Type: analysis.Ideographic, + Position: 1, + Start: 0, + End: 12, + }, + }, + }, + } + + cache := registry.NewCache() + for _, test := range tests { + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome.go new file mode 100644 index 00000000..ca5283bc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build kagome full + +package ja + +import ( + "github.com/ikawaha/kagome" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const TokenizerName = "kagome" + +type KagomeMorphTokenizer struct { + tok *kagome.Tokenizer +} + +func NewKagomeMorphTokenizer() *KagomeMorphTokenizer { + return &KagomeMorphTokenizer{ + tok: kagome.NewTokenizer(), + } +} + +func NewKagomeMorphTokenizerWithUserDic(userdic *kagome.UserDic) *KagomeMorphTokenizer { + k := kagome.NewTokenizer() + k.SetUserDic(userdic) + return &KagomeMorphTokenizer{ + tok: k, + } +} + +func (t *KagomeMorphTokenizer) Tokenize(input []byte) analysis.TokenStream { + var ( + morphs []kagome.Token + prevstart int + ) + + rv := make(analysis.TokenStream, 0, len(input)) + if len(input) < 1 { + return rv + } + + morphs = t.tok.Tokenize(string(input)) + + for i, m := range morphs { + if m.Surface == "EOS" || m.Surface == "BOS" { + continue + } + + surfacelen := len(m.Surface) + token := &analysis.Token{ + Term: []byte(m.Surface), + Position: i, + Start: prevstart, + End: prevstart + surfacelen, + Type: analysis.Ideographic, + } + + prevstart = prevstart + surfacelen + rv = append(rv, token) + } + + return rv +} + +func KagomeMorphTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + return NewKagomeMorphTokenizer(), nil +} + +func init() { + registry.RegisterTokenizer(TokenizerName, KagomeMorphTokenizerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome_test.go new file mode 100644 index 00000000..a2cf8610 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja/ja_morph_kagome_test.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build kagome full + +package ja + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestKagome(t *testing.T) { + + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + []byte("こんにちは世界"), + analysis.TokenStream{ + { + Start: 0, + End: 15, + Term: []byte("こんにちは"), + Position: 1, + Type: analysis.Ideographic, + }, + { + Start: 15, + End: 21, + Term: []byte("世界"), + Position: 2, + Type: analysis.Ideographic, + }, + }, + }, + } + + tokenizer := NewKagomeMorphTokenizer() + for _, test := range tests { + actuals := tokenizer.Tokenize(test.input) + + if !reflect.DeepEqual(actuals, test.output) { + t.Errorf("Expected %v, got %v for %s", test.output, actuals, string(test.input)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl.go new file mode 100644 index 00000000..6c567e82 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package nl + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "nl" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopNlFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerNlFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopNlFilter, + stemmerNlFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl_test.go new file mode 100644 index 00000000..7ca9e6f9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/analyzer_nl_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package nl + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestDutchAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("lichamelijk"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("licham"), + }, + }, + }, + { + input: []byte("lichamelijke"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("licham"), + }, + }, + }, + // stop word + { + input: []byte("van"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stemmer_nl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stemmer_nl.go new file mode 100644 index 00000000..bf3d6863 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stemmer_nl.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package nl + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_nl" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("nl") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_filter_nl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_filter_nl.go new file mode 100644 index 00000000..e2157ef7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_filter_nl.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package nl + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_words_nl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_words_nl.go new file mode 100644 index 00000000..39966c36 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl/stop_words_nl.go @@ -0,0 +1,143 @@ +package nl + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_nl" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var DutchStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/dutch/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Dutch stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + | This is a ranked list (commonest to rarest) of stopwords derived from + | a large sample of Dutch text. + + | Dutch stop words frequently exhibit homonym clashes. These are indicated + | clearly below. + +de | the +en | and +van | of, from +ik | I, the ego +te | (1) chez, at etc, (2) to, (3) too +dat | that, which +die | that, those, who, which +in | in, inside +een | a, an, one +hij | he +het | the, it +niet | not, nothing, naught +zijn | (1) to be, being, (2) his, one's, its +is | is +was | (1) was, past tense of all persons sing. of 'zijn' (to be) (2) wax, (3) the washing, (4) rise of river +op | on, upon, at, in, up, used up +aan | on, upon, to (as dative) +met | with, by +als | like, such as, when +voor | (1) before, in front of, (2) furrow +had | had, past tense all persons sing. of 'hebben' (have) +er | there +maar | but, only +om | round, about, for etc +hem | him +dan | then +zou | should/would, past tense all persons sing. of 'zullen' +of | or, whether, if +wat | what, something, anything +mijn | possessive and noun 'mine' +men | people, 'one' +dit | this +zo | so, thus, in this way +door | through by +over | over, across +ze | she, her, they, them +zich | oneself +bij | (1) a bee, (2) by, near, at +ook | also, too +tot | till, until +je | you +mij | me +uit | out of, from +der | Old Dutch form of 'van der' still found in surnames +daar | (1) there, (2) because +haar | (1) her, their, them, (2) hair +naar | (1) unpleasant, unwell etc, (2) towards, (3) as +heb | present first person sing. of 'to have' +hoe | how, why +heeft | present third person sing. of 'to have' +hebben | 'to have' and various parts thereof +deze | this +u | you +want | (1) for, (2) mitten, (3) rigging +nog | yet, still +zal | 'shall', first and third person sing. of verb 'zullen' (will) +me | me +zij | she, they +nu | now +ge | 'thou', still used in Belgium and south Netherlands +geen | none +omdat | because +iets | something, somewhat +worden | to become, grow, get +toch | yet, still +al | all, every, each +waren | (1) 'were' (2) to wander, (3) wares, (3) +veel | much, many +meer | (1) more, (2) lake +doen | to do, to make +toen | then, when +moet | noun 'spot/mote' and present form of 'to must' +ben | (1) am, (2) 'are' in interrogative second person singular of 'to be' +zonder | without +kan | noun 'can' and present form of 'to be able' +hun | their, them +dus | so, consequently +alles | all, everything, anything +onder | under, beneath +ja | yes, of course +eens | once, one day +hier | here +wie | who +werd | imperfect third person sing. of 'become' +altijd | always +doch | yet, but etc +wordt | present third person sing. of 'become' +wezen | (1) to be, (2) 'been' as in 'been fishing', (3) orphans +kunnen | to be able +ons | us/our +zelf | self +tegen | against, towards, at +na | after, near +reeds | already +wil | (1) present tense of 'want', (2) 'will', noun, (3) fender +kon | could; past tense of 'to be able' +niets | nothing +uw | your +iemand | somebody +geweest | been; past participle of 'be' +andere | other +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(DutchStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no.go new file mode 100644 index 00000000..1a2a9b59 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package no + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "no" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopNoFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerNoFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopNoFilter, + stemmerNoFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no_test.go new file mode 100644 index 00000000..870a7979 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/analyzer_no_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package no + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestNorwegianAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("havnedistriktene"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("havnedistrikt"), + }, + }, + }, + { + input: []byte("havnedistrikter"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("havnedistrikt"), + }, + }, + }, + // stop word + { + input: []byte("det"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stemmer_no.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stemmer_no.go new file mode 100644 index 00000000..3ae818c9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stemmer_no.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package no + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_no" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("no") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_filter_no.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_filter_no.go new file mode 100644 index 00000000..747afe87 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_filter_no.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package no + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_words_no.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_words_no.go new file mode 100644 index 00000000..2b0817af --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no/stop_words_no.go @@ -0,0 +1,218 @@ +package no + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_no" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var NorwegianStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/norwegian/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Norwegian stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + | This stop word list is for the dominant bokmål dialect. Words unique + | to nynorsk are marked *. + + | Revised by Jan Bruusgaard , Jan 2005 + +og | and +i | in +jeg | I +det | it/this/that +at | to (w. inf.) +en | a/an +et | a/an +den | it/this/that +til | to +er | is/am/are +som | who/that +på | on +de | they / you(formal) +med | with +han | he +av | of +ikke | not +ikkje | not * +der | there +så | so +var | was/were +meg | me +seg | you +men | but +ett | one +har | have +om | about +vi | we +min | my +mitt | my +ha | have +hadde | had +hun | she +nå | now +over | over +da | when/as +ved | by/know +fra | from +du | you +ut | out +sin | your +dem | them +oss | us +opp | up +man | you/one +kan | can +hans | his +hvor | where +eller | or +hva | what +skal | shall/must +selv | self (reflective) +sjøl | self (reflective) +her | here +alle | all +vil | will +bli | become +ble | became +blei | became * +blitt | have become +kunne | could +inn | in +når | when +være | be +kom | come +noen | some +noe | some +ville | would +dere | you +som | who/which/that +deres | their/theirs +kun | only/just +ja | yes +etter | after +ned | down +skulle | should +denne | this +for | for/because +deg | you +si | hers/his +sine | hers/his +sitt | hers/his +mot | against +å | to +meget | much +hvorfor | why +dette | this +disse | these/those +uten | without +hvordan | how +ingen | none +din | your +ditt | your +blir | become +samme | same +hvilken | which +hvilke | which (plural) +sånn | such a +inni | inside/within +mellom | between +vår | our +hver | each +hvem | who +vors | us/ours +hvis | whose +både | both +bare | only/just +enn | than +fordi | as/because +før | before +mange | many +også | also +slik | just +vært | been +være | to be +båe | both * +begge | both +siden | since +dykk | your * +dykkar | yours * +dei | they * +deira | them * +deires | theirs * +deim | them * +di | your (fem.) * +då | as/when * +eg | I * +ein | a/an * +eit | a/an * +eitt | a/an * +elles | or * +honom | he * +hjå | at * +ho | she * +hoe | she * +henne | her +hennar | her/hers +hennes | hers +hoss | how * +hossen | how * +ikkje | not * +ingi | noone * +inkje | noone * +korleis | how * +korso | how * +kva | what/which * +kvar | where * +kvarhelst | where * +kven | who/whom * +kvi | why * +kvifor | why * +me | we * +medan | while * +mi | my * +mine | my * +mykje | much * +no | now * +nokon | some (masc./neut.) * +noka | some (fem.) * +nokor | some * +noko | some * +nokre | some * +si | his/hers * +sia | since * +sidan | since * +so | so * +somt | some * +somme | some * +um | about* +upp | up * +vere | be * +vore | was * +verte | become * +vort | become * +varte | became * +vart | became * + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(NorwegianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/porter/stemmer_porter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/porter/stemmer_porter.go new file mode 100644 index 00000000..8d3eac14 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/porter/stemmer_porter.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package porter + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_porter_classic" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("porter") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt.go new file mode 100644 index 00000000..ce8aa157 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt.go @@ -0,0 +1,51 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package pt + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "pt" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + tokenizer, err := cache.TokenizerNamed(unicode.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopPtFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerPtFilter, err := cache.TokenFilterNamed(LightStemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: tokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopPtFilter, + stemmerPtFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt_test.go new file mode 100644 index 00000000..9a2d542b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/analyzer_pt_test.go @@ -0,0 +1,65 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package pt + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestPortugueseAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("quilométricas"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("quilometric"), + }, + }, + }, + { + input: []byte("quilométricos"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("quilometric"), + }, + }, + }, + // stop word + { + input: []byte("não"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt.go new file mode 100644 index 00000000..75179cb5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt.go @@ -0,0 +1,190 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package pt + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const LightStemmerName = "stemmer_pt_light" + +type PortugueseLightStemmerFilter struct { +} + +func NewPortugueseLightStemmerFilter() *PortugueseLightStemmerFilter { + return &PortugueseLightStemmerFilter{} +} + +func (s *PortugueseLightStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + runes := bytes.Runes(token.Term) + runes = stem(runes) + token.Term = analysis.BuildTermFromRunes(runes) + } + return input +} + +func stem(input []rune) []rune { + + inputLen := len(input) + + if inputLen < 4 { + return input + } + + input = removeSuffix(input) + inputLen = len(input) + + if inputLen > 3 && input[inputLen-1] == 'a' { + input = normFeminine(input) + inputLen = len(input) + } + + if inputLen > 4 { + switch input[inputLen-1] { + case 'e', 'a', 'o': + input = input[0 : inputLen-1] + inputLen = len(input) + } + } + + for i := 0; i < inputLen; i++ { + switch input[i] { + case 'à', 'á', 'â', 'ä', 'ã': + input[i] = 'a' + case 'ò', 'ó', 'ô', 'ö', 'õ': + input[i] = 'o' + case 'è', 'é', 'ê', 'ë': + input[i] = 'e' + case 'ù', 'ú', 'û', 'ü': + input[i] = 'u' + case 'ì', 'í', 'î', 'ï': + input[i] = 'i' + case 'ç': + input[i] = 'c' + } + } + + return input +} + +func removeSuffix(input []rune) []rune { + + inputLen := len(input) + + if inputLen > 4 && analysis.RunesEndsWith(input, "es") { + switch input[inputLen-3] { + case 'r', 's', 'l', 'z': + return input[0 : inputLen-2] + } + } + + if inputLen > 3 && analysis.RunesEndsWith(input, "ns") { + input[inputLen-2] = 'm' + return input[0 : inputLen-1] + } + + if inputLen > 4 && (analysis.RunesEndsWith(input, "eis") || analysis.RunesEndsWith(input, "éis")) { + input[inputLen-3] = 'e' + input[inputLen-2] = 'l' + return input[0 : inputLen-1] + } + + if inputLen > 4 && analysis.RunesEndsWith(input, "ais") { + input[inputLen-2] = 'l' + return input[0 : inputLen-1] + } + + if inputLen > 4 && analysis.RunesEndsWith(input, "óis") { + input[inputLen-3] = 'o' + input[inputLen-2] = 'l' + return input[0 : inputLen-1] + } + + if inputLen > 4 && analysis.RunesEndsWith(input, "is") { + input[inputLen-1] = 'l' + return input + } + + if inputLen > 3 && + (analysis.RunesEndsWith(input, "ões") || + analysis.RunesEndsWith(input, "ães")) { + input = input[0 : inputLen-1] + inputLen = len(input) + input[inputLen-2] = 'ã' + input[inputLen-1] = 'o' + return input + } + + if inputLen > 6 && analysis.RunesEndsWith(input, "mente") { + return input[0 : inputLen-5] + } + + if inputLen > 3 && input[inputLen-1] == 's' { + return input[0 : inputLen-1] + } + return input +} + +func normFeminine(input []rune) []rune { + inputLen := len(input) + + if inputLen > 7 && + (analysis.RunesEndsWith(input, "inha") || + analysis.RunesEndsWith(input, "iaca") || + analysis.RunesEndsWith(input, "eira")) { + input[inputLen-1] = 'o' + return input + } + + if inputLen > 6 { + if analysis.RunesEndsWith(input, "osa") || + analysis.RunesEndsWith(input, "ica") || + analysis.RunesEndsWith(input, "ida") || + analysis.RunesEndsWith(input, "ada") || + analysis.RunesEndsWith(input, "iva") || + analysis.RunesEndsWith(input, "ama") { + input[inputLen-1] = 'o' + return input + } + + if analysis.RunesEndsWith(input, "ona") { + input[inputLen-3] = 'ã' + input[inputLen-2] = 'o' + return input[0 : inputLen-1] + } + + if analysis.RunesEndsWith(input, "ora") { + return input[0 : inputLen-1] + } + + if analysis.RunesEndsWith(input, "esa") { + input[inputLen-3] = 'ê' + return input[0 : inputLen-1] + } + + if analysis.RunesEndsWith(input, "na") { + input[inputLen-1] = 'o' + return input + } + } + return input +} + +func PortugueseLightStemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewPortugueseLightStemmerFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(LightStemmerName, PortugueseLightStemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt_test.go new file mode 100644 index 00000000..fdb60f4a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/light_stemmer_pt_test.go @@ -0,0 +1,399 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package pt + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestPortugueseLightStemmer(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("doutores"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("doutor"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("doutor"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("doutor"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("homens"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("homem"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("homem"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("homem"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("papéis"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("papel"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("papel"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("papel"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("normais"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("normal"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("normal"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("normal"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("lencóis"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("lencol"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("lencol"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("lencol"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("barris"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("barril"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("barril"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("barril"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("botões"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("bota"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("botão"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("bota"), + }, + }, + }, + // longer + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("o"), + }, + &analysis.Token{ + Term: []byte("debate"), + }, + &analysis.Token{ + Term: []byte("político"), + }, + &analysis.Token{ + Term: []byte("pelo"), + }, + &analysis.Token{ + Term: []byte("menos"), + }, + &analysis.Token{ + Term: []byte("o"), + }, + &analysis.Token{ + Term: []byte("que"), + }, + &analysis.Token{ + Term: []byte("vem"), + }, + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("público"), + }, + &analysis.Token{ + Term: []byte("parece"), + }, + &analysis.Token{ + Term: []byte("de"), + }, + &analysis.Token{ + Term: []byte("modo"), + }, + &analysis.Token{ + Term: []byte("nada"), + }, + &analysis.Token{ + Term: []byte("surpreendente"), + }, + &analysis.Token{ + Term: []byte("restrito"), + }, + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("temas"), + }, + &analysis.Token{ + Term: []byte("menores"), + }, + &analysis.Token{ + Term: []byte("mas"), + }, + &analysis.Token{ + Term: []byte("há"), + }, + &analysis.Token{ + Term: []byte("evidentemente"), + }, + &analysis.Token{ + Term: []byte("grandes"), + }, + &analysis.Token{ + Term: []byte("questões"), + }, + &analysis.Token{ + Term: []byte("em"), + }, + &analysis.Token{ + Term: []byte("jogo"), + }, + &analysis.Token{ + Term: []byte("nas"), + }, + &analysis.Token{ + Term: []byte("eleições"), + }, + &analysis.Token{ + Term: []byte("que"), + }, + &analysis.Token{ + Term: []byte("se"), + }, + &analysis.Token{ + Term: []byte("aproximam"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("o"), + }, + &analysis.Token{ + Term: []byte("debat"), + }, + &analysis.Token{ + Term: []byte("politic"), + }, + &analysis.Token{ + Term: []byte("pelo"), + }, + &analysis.Token{ + Term: []byte("meno"), + }, + &analysis.Token{ + Term: []byte("o"), + }, + &analysis.Token{ + Term: []byte("que"), + }, + &analysis.Token{ + Term: []byte("vem"), + }, + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("public"), + }, + &analysis.Token{ + Term: []byte("parec"), + }, + &analysis.Token{ + Term: []byte("de"), + }, + &analysis.Token{ + Term: []byte("modo"), + }, + &analysis.Token{ + Term: []byte("nada"), + }, + &analysis.Token{ + Term: []byte("surpreendent"), + }, + &analysis.Token{ + Term: []byte("restrit"), + }, + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("tema"), + }, + &analysis.Token{ + Term: []byte("menor"), + }, + &analysis.Token{ + Term: []byte("mas"), + }, + &analysis.Token{ + Term: []byte("há"), + }, + &analysis.Token{ + Term: []byte("evident"), + }, + &analysis.Token{ + Term: []byte("grand"), + }, + &analysis.Token{ + Term: []byte("questa"), + }, + &analysis.Token{ + Term: []byte("em"), + }, + &analysis.Token{ + Term: []byte("jogo"), + }, + &analysis.Token{ + Term: []byte("nas"), + }, + &analysis.Token{ + Term: []byte("eleica"), + }, + &analysis.Token{ + Term: []byte("que"), + }, + &analysis.Token{ + Term: []byte("se"), + }, + &analysis.Token{ + Term: []byte("aproximam"), + }, + }, + }, + } + + cache := registry.NewCache() + filter, err := cache.TokenFilterNamed(LightStemmerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := filter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stemmer_pt.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stemmer_pt.go new file mode 100644 index 00000000..fc589678 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stemmer_pt.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package pt + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_pt" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("pt") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_filter_pt.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_filter_pt.go new file mode 100644 index 00000000..629a02de --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_filter_pt.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package pt + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_words_pt.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_words_pt.go new file mode 100644 index 00000000..4502873e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt/stop_words_pt.go @@ -0,0 +1,277 @@ +package pt + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_pt" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var PortugueseStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/portuguese/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Portuguese stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + + | The following is a ranked list (commonest to rarest) of stopwords + | deriving from a large sample of text. + + | Extra words have been added at the end. + +de | of, from +a | the; to, at; her +o | the; him +que | who, that +e | and +do | de + o +da | de + a +em | in +um | a +para | for + | é from SER +com | with +não | not, no +uma | a +os | the; them +no | em + o +se | himself etc +na | em + a +por | for +mais | more +as | the; them +dos | de + os +como | as, like +mas | but + | foi from SER +ao | a + o +ele | he +das | de + as + | tem from TER +à | a + a +seu | his +sua | her +ou | or + | ser from SER +quando | when +muito | much + | há from HAV +nos | em + os; us +já | already, now + | está from EST +eu | I +também | also +só | only, just +pelo | per + o +pela | per + a +até | up to +isso | that +ela | he +entre | between + | era from SER +depois | after +sem | without +mesmo | same +aos | a + os + | ter from TER +seus | his +quem | whom +nas | em + as +me | me +esse | that +eles | they + | estão from EST +você | you + | tinha from TER + | foram from SER +essa | that +num | em + um +nem | nor +suas | her +meu | my +às | a + as +minha | my + | têm from TER +numa | em + uma +pelos | per + os +elas | they + | havia from HAV + | seja from SER +qual | which + | será from SER +nós | we + | tenho from TER +lhe | to him, her +deles | of them +essas | those +esses | those +pelas | per + as +este | this + | fosse from SER +dele | of him + + | other words. There are many contractions such as naquele = em+aquele, + | mo = me+o, but they are rare. + | Indefinite article plural forms are also rare. + +tu | thou +te | thee +vocês | you (plural) +vos | you +lhes | to them +meus | my +minhas +teu | thy +tua +teus +tuas +nosso | our +nossa +nossos +nossas + +dela | of her +delas | of them + +esta | this +estes | these +estas | these +aquele | that +aquela | that +aqueles | those +aquelas | those +isto | this +aquilo | that + + | forms of estar, to be (not including the infinitive): +estou +está +estamos +estão +estive +esteve +estivemos +estiveram +estava +estávamos +estavam +estivera +estivéramos +esteja +estejamos +estejam +estivesse +estivéssemos +estivessem +estiver +estivermos +estiverem + + | forms of haver, to have (not including the infinitive): +hei +há +havemos +hão +houve +houvemos +houveram +houvera +houvéramos +haja +hajamos +hajam +houvesse +houvéssemos +houvessem +houver +houvermos +houverem +houverei +houverá +houveremos +houverão +houveria +houveríamos +houveriam + + | forms of ser, to be (not including the infinitive): +sou +somos +são +era +éramos +eram +fui +foi +fomos +foram +fora +fôramos +seja +sejamos +sejam +fosse +fôssemos +fossem +for +formos +forem +serei +será +seremos +serão +seria +seríamos +seriam + + | forms of ter, to have (not including the infinitive): +tenho +tem +temos +tém +tinha +tínhamos +tinham +tive +teve +tivemos +tiveram +tivera +tivéramos +tenha +tenhamos +tenham +tivesse +tivéssemos +tivessem +tiver +tivermos +tiverem +terei +terá +teremos +terão +teria +teríamos +teriam +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(PortugueseStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro.go new file mode 100644 index 00000000..7283c25a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package ro + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "ro" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopRoFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerRoFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopRoFilter, + stemmerRoFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro_test.go new file mode 100644 index 00000000..57a2b0c1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/analyzer_ro_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package ro + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestRomanianAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("absenţa"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("absenţ"), + }, + }, + }, + { + input: []byte("absenţi"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("absenţ"), + }, + }, + }, + // stop word + { + input: []byte("îl"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stemmer_ro.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stemmer_ro.go new file mode 100644 index 00000000..26504bdf --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stemmer_ro.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package ro + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_ro" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("ro") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_filter_ro.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_filter_ro.go new file mode 100644 index 00000000..47687cc0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_filter_ro.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ro + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_words_ro.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_words_ro.go new file mode 100644 index 00000000..46379f7b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro/stop_words_ro.go @@ -0,0 +1,257 @@ +package ro + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_ro" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/ +// ` was changed to ' to allow for literal string + +var RomanianStopWords = []byte(`# This file was created by Jacques Savoy and is distributed under the BSD license. +# See http://members.unine.ch/jacques.savoy/clef/index.html. +# Also see http://www.opensource.org/licenses/bsd-license.html +acea +aceasta +această +aceea +acei +aceia +acel +acela +acele +acelea +acest +acesta +aceste +acestea +aceşti +aceştia +acolo +acum +ai +aia +aibă +aici +al +ăla +ale +alea +ălea +altceva +altcineva +am +ar +are +aş +aşadar +asemenea +asta +ăsta +astăzi +astea +ăstea +ăştia +asupra +aţi +au +avea +avem +aveţi +azi +bine +bucur +bună +ca +că +căci +când +care +cărei +căror +cărui +cât +câte +câţi +către +câtva +ce +cel +ceva +chiar +cînd +cine +cineva +cît +cîte +cîţi +cîtva +contra +cu +cum +cumva +curând +curînd +da +dă +dacă +dar +datorită +de +deci +deja +deoarece +departe +deşi +din +dinaintea +dintr +dintre +drept +după +ea +ei +el +ele +eram +este +eşti +eu +face +fără +fi +fie +fiecare +fii +fim +fiţi +iar +ieri +îi +îl +îmi +împotriva +în +înainte +înaintea +încât +încît +încotro +între +întrucât +întrucît +îţi +la +lângă +le +li +lîngă +lor +lui +mă +mâine +mea +mei +mele +mereu +meu +mi +mine +mult +multă +mulţi +ne +nicăieri +nici +nimeni +nişte +noastră +noastre +noi +noştri +nostru +nu +ori +oricând +oricare +oricât +orice +oricînd +oricine +oricît +oricum +oriunde +până +pe +pentru +peste +pînă +poate +pot +prea +prima +primul +prin +printr +sa +să +săi +sale +sau +său +se +şi +sînt +sîntem +sînteţi +spre +sub +sunt +suntem +sunteţi +ta +tăi +tale +tău +te +ţi +ţie +tine +toată +toate +tot +toţi +totuşi +tu +un +una +unde +undeva +unei +unele +uneori +unor +vă +vi +voastră +voastre +voi +voştri +vostru +vouă +vreo +vreun +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(RomanianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru.go new file mode 100644 index 00000000..76e7d2be --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package ru + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "ru" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopRuFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerRuFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopRuFilter, + stemmerRuFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru_test.go new file mode 100644 index 00000000..60b66023 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/analyzer_ru_test.go @@ -0,0 +1,98 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package ru + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestRussianAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // digits safe + { + input: []byte("text 1000"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("text"), + }, + &analysis.Token{ + Term: []byte("1000"), + }, + }, + }, + { + input: []byte("Вместе с тем о силе электромагнитной энергии имели представление еще"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("вмест"), + }, + &analysis.Token{ + Term: []byte("сил"), + }, + &analysis.Token{ + Term: []byte("электромагнитн"), + }, + &analysis.Token{ + Term: []byte("энерг"), + }, + &analysis.Token{ + Term: []byte("имел"), + }, + &analysis.Token{ + Term: []byte("представлен"), + }, + }, + }, + { + input: []byte("Но знание это хранилось в тайне"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("знан"), + }, + &analysis.Token{ + Term: []byte("эт"), + }, + &analysis.Token{ + Term: []byte("хран"), + }, + &analysis.Token{ + Term: []byte("тайн"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stemmer_ru.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stemmer_ru.go new file mode 100644 index 00000000..f7e24eb5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stemmer_ru.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package ru + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_ru" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("ru") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_filter_ru.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_filter_ru.go new file mode 100644 index 00000000..ce46018d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_filter_ru.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ru + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_words_ru.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_words_ru.go new file mode 100644 index 00000000..aea73640 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru/stop_words_ru.go @@ -0,0 +1,267 @@ +package ru + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_ru" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var RussianStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/russian/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | a russian stop word list. comments begin with vertical bar. each stop + | word is at the start of a line. + + | this is a ranked list (commonest to rarest) of stopwords derived from + | a large text sample. + + | letter 'ё' is translated to 'е'. + +и | and +в | in/into +во | alternative form +не | not +что | what/that +он | he +на | on/onto +я | i +с | from +со | alternative form +как | how +а | milder form of 'no' (but) +то | conjunction and form of 'that' +все | all +она | she +так | so, thus +его | him +но | but +да | yes/and +ты | thou +к | towards, by +у | around, chez +же | intensifier particle +вы | you +за | beyond, behind +бы | conditional/subj. particle +по | up to, along +только | only +ее | her +мне | to me +было | it was +вот | here is/are, particle +от | away from +меня | me +еще | still, yet, more +нет | no, there isnt/arent +о | about +из | out of +ему | to him +теперь | now +когда | when +даже | even +ну | so, well +вдруг | suddenly +ли | interrogative particle +если | if +уже | already, but homonym of 'narrower' +или | or +ни | neither +быть | to be +был | he was +него | prepositional form of его +до | up to +вас | you accusative +нибудь | indef. suffix preceded by hyphen +опять | again +уж | already, but homonym of 'adder' +вам | to you +сказал | he said +ведь | particle 'after all' +там | there +потом | then +себя | oneself +ничего | nothing +ей | to her +может | usually with 'быть' as 'maybe' +они | they +тут | here +где | where +есть | there is/are +надо | got to, must +ней | prepositional form of ей +для | for +мы | we +тебя | thee +их | them, their +чем | than +была | she was +сам | self +чтоб | in order to +без | without +будто | as if +человек | man, person, one +чего | genitive form of 'what' +раз | once +тоже | also +себе | to oneself +под | beneath +жизнь | life +будет | will be +ж | short form of intensifer particle 'же' +тогда | then +кто | who +этот | this +говорил | was saying +того | genitive form of 'that' +потому | for that reason +этого | genitive form of 'this' +какой | which +совсем | altogether +ним | prepositional form of 'его', 'они' +здесь | here +этом | prepositional form of 'этот' +один | one +почти | almost +мой | my +тем | instrumental/dative plural of 'тот', 'то' +чтобы | full form of 'in order that' +нее | her (acc.) +кажется | it seems +сейчас | now +были | they were +куда | where to +зачем | why +сказать | to say +всех | all (acc., gen. preposn. plural) +никогда | never +сегодня | today +можно | possible, one can +при | by +наконец | finally +два | two +об | alternative form of 'о', about +другой | another +хоть | even +после | after +над | above +больше | more +тот | that one (masc.) +через | across, in +эти | these +нас | us +про | about +всего | in all, only, of all +них | prepositional form of 'они' (they) +какая | which, feminine +много | lots +разве | interrogative particle +сказала | she said +три | three +эту | this, acc. fem. sing. +моя | my, feminine +впрочем | moreover, besides +хорошо | good +свою | ones own, acc. fem. sing. +этой | oblique form of 'эта', fem. 'this' +перед | in front of +иногда | sometimes +лучше | better +чуть | a little +том | preposn. form of 'that one' +нельзя | one must not +такой | such a one +им | to them +более | more +всегда | always +конечно | of course +всю | acc. fem. sing of 'all' +между | between + + + | b: some paradigms + | + | personal pronouns + | + | я меня мне мной [мною] + | ты тебя тебе тобой [тобою] + | он его ему им [него, нему, ним] + | она ее эи ею [нее, нэи, нею] + | оно его ему им [него, нему, ним] + | + | мы нас нам нами + | вы вас вам вами + | они их им ими [них, ним, ними] + | + | себя себе собой [собою] + | + | demonstrative pronouns: этот (this), тот (that) + | + | этот эта это эти + | этого эты это эти + | этого этой этого этих + | этому этой этому этим + | этим этой этим [этою] этими + | этом этой этом этих + | + | тот та то те + | того ту то те + | того той того тех + | тому той тому тем + | тем той тем [тою] теми + | том той том тех + | + | determinative pronouns + | + | (a) весь (all) + | + | весь вся все все + | всего всю все все + | всего всей всего всех + | всему всей всему всем + | всем всей всем [всею] всеми + | всем всей всем всех + | + | (b) сам (himself etc) + | + | сам сама само сами + | самого саму само самих + | самого самой самого самих + | самому самой самому самим + | самим самой самим [самою] самими + | самом самой самом самих + | + | stems of verbs 'to be', 'to have', 'to do' and modal + | + | быть бы буд быв есть суть + | име + | дел + | мог мож мочь + | уме + | хоч хот + | долж + | можн + | нужн + | нельзя + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(RussianStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv.go new file mode 100644 index 00000000..149ad204 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package sv + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "sv" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopSvFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerSvFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopSvFilter, + stemmerSvFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv_test.go new file mode 100644 index 00000000..5f67cfaa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/analyzer_sv_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package sv + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestSwedishAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("jaktkarlarne"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("jaktkarl"), + }, + }, + }, + { + input: []byte("jaktkarlens"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("jaktkarl"), + }, + }, + }, + // stop word + { + input: []byte("och"), + output: analysis.TokenStream{}, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stemmer_sv.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stemmer_sv.go new file mode 100644 index 00000000..f844665c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stemmer_sv.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package sv + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_sv" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("sv") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_filter_sv.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_filter_sv.go new file mode 100644 index 00000000..2abb8de8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_filter_sv.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package sv + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_words_sv.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_words_sv.go new file mode 100644 index 00000000..6efd70d8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv/stop_words_sv.go @@ -0,0 +1,157 @@ +package sv + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_sv" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var SwedishStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/swedish/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Swedish stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + | This is a ranked list (commonest to rarest) of stopwords derived from + | a large text sample. + + | Swedish stop words occasionally exhibit homonym clashes. For example + | så = so, but also seed. These are indicated clearly below. + +och | and +det | it, this/that +att | to (with infinitive) +i | in, at +en | a +jag | I +hon | she +som | who, that +han | he +på | on +den | it, this/that +med | with +var | where, each +sig | him(self) etc +för | for +så | so (also: seed) +till | to +är | is +men | but +ett | a +om | if; around, about +hade | had +de | they, these/those +av | of +icke | not, no +mig | me +du | you +henne | her +då | then, when +sin | his +nu | now +har | have +inte | inte någon = no one +hans | his +honom | him +skulle | 'sake' +hennes | her +där | there +min | my +man | one (pronoun) +ej | nor +vid | at, by, on (also: vast) +kunde | could +något | some etc +från | from, off +ut | out +när | when +efter | after, behind +upp | up +vi | we +dem | them +vara | be +vad | what +över | over +än | than +dig | you +kan | can +sina | his +här | here +ha | have +mot | towards +alla | all +under | under (also: wonder) +någon | some etc +eller | or (else) +allt | all +mycket | much +sedan | since +ju | why +denna | this/that +själv | myself, yourself etc +detta | this/that +åt | to +utan | without +varit | was +hur | how +ingen | no +mitt | my +ni | you +bli | to be, become +blev | from bli +oss | us +din | thy +dessa | these/those +några | some etc +deras | their +blir | from bli +mina | my +samma | (the) same +vilken | who, that +er | you, your +sådan | such a +vår | our +blivit | from bli +dess | its +inom | within +mellan | between +sådant | such a +varför | why +varje | each +vilka | who, that +ditt | thy +vem | who +vilket | who, that +sitta | his +sådana | such a +vart | each +dina | thy +vars | whose +vårt | our +våra | our +ert | your +era | your +vilkas | whose + +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(SwedishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th.go new file mode 100644 index 00000000..65a67dd3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th.go @@ -0,0 +1,47 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package th + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "th" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + unicodeTokenizer, err := cache.TokenizerNamed(TokenizerName) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopThFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: unicodeTokenizer, + TokenFilters: []analysis.TokenFilter{ + toLowerFilter, + stopThFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th_test.go new file mode 100644 index 00000000..0368c2db --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/analyzer_th_test.go @@ -0,0 +1,119 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package th + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +// tried to adapt these from the lucene tests, most of which either +// use the empty stop dictionary or the english one. + +func TestThaiAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stop words + { + input: []byte("การที่ได้ต้องแสดงว่างานดี"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("แสดง"), + Position: 5, + Start: 39, + End: 51, + }, + &analysis.Token{ + Term: []byte("งาน"), + Position: 7, + Start: 60, + End: 69, + }, + &analysis.Token{ + Term: []byte("ดี"), + Position: 8, + Start: 69, + End: 75, + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %v, got %v", test.output, actual) + } + } +} + +func TestThaiAnalyzerWihtoutOffsets(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stop words + { + input: []byte("บริษัทชื่อ XY&Z - คุยกับ xyz@demo.com"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("บริษัท"), + }, + &analysis.Token{ + Term: []byte("ชื่อ"), + }, + &analysis.Token{ + Term: []byte("xy"), + }, + &analysis.Token{ + Term: []byte("z"), + }, + &analysis.Token{ + Term: []byte("คุย"), + }, + &analysis.Token{ + Term: []byte("xyz"), + }, + &analysis.Token{ + Term: []byte("demo.com"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Errorf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_filter_th.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_filter_th.go new file mode 100644 index 00000000..53d78ad9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_filter_th.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package th + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_words_th.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_words_th.go new file mode 100644 index 00000000..70ee3793 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/stop_words_th.go @@ -0,0 +1,143 @@ +package th + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_th" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var ThaiStopWords = []byte(`# Thai stopwords from: +# "Opinion Detection in Thai Political News Columns +# Based on Subjectivity Analysis" +# Khampol Sukhum, Supot Nitsuwat, and Choochart Haruechaiyasak +ไว้ +ไม่ +ไป +ได้ +ให้ +ใน +โดย +แห่ง +แล้ว +และ +แรก +แบบ +แต่ +เอง +เห็น +เลย +เริ่ม +เรา +เมื่อ +เพื่อ +เพราะ +เป็นการ +เป็น +เปิดเผย +เปิด +เนื่องจาก +เดียวกัน +เดียว +เช่น +เฉพาะ +เคย +เข้า +เขา +อีก +อาจ +อะไร +ออก +อย่าง +อยู่ +อยาก +หาก +หลาย +หลังจาก +หลัง +หรือ +หนึ่ง +ส่วน +ส่ง +สุด +สําหรับ +ว่า +วัน +ลง +ร่วม +ราย +รับ +ระหว่าง +รวม +ยัง +มี +มาก +มา +พร้อม +พบ +ผ่าน +ผล +บาง +น่า +นี้ +นํา +นั้น +นัก +นอกจาก +ทุก +ที่สุด +ที่ +ทําให้ +ทํา +ทาง +ทั้งนี้ +ทั้ง +ถ้า +ถูก +ถึง +ต้อง +ต่างๆ +ต่าง +ต่อ +ตาม +ตั้งแต่ +ตั้ง +ด้าน +ด้วย +ดัง +ซึ่ง +ช่วง +จึง +จาก +จัด +จะ +คือ +ความ +ครั้ง +คง +ขึ้น +ของ +ขอ +ขณะ +ก่อน +ก็ +การ +กับ +กัน +กว่า +กล่าว +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(ThaiStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/unicode_tokenizer_th.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/unicode_tokenizer_th.go new file mode 100644 index 00000000..21e0960f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th/unicode_tokenizer_th.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package th + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const TokenizerName = "icu_th" + +func TokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + return icu.NewUnicodeWordBoundaryCustomLocaleTokenizer("th_TH"), nil +} + +func init() { + registry.RegisterTokenizer(TokenizerName, TokenizerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr.go new file mode 100644 index 00000000..8e920ad6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr.go @@ -0,0 +1,60 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package tr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const AnalyzerName = "tr" + +func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) { + icuTokenizer, err := cache.TokenizerNamed(icu.Name) + if err != nil { + return nil, err + } + aposFilter, err := cache.TokenFilterNamed(apostrophe_filter.Name) + if err != nil { + return nil, err + } + toLowerFilter, err := cache.TokenFilterNamed(lower_case_filter.Name) + if err != nil { + return nil, err + } + stopTrFilter, err := cache.TokenFilterNamed(StopName) + if err != nil { + return nil, err + } + stemmerTrFilter, err := cache.TokenFilterNamed(StemmerName) + if err != nil { + return nil, err + } + rv := analysis.Analyzer{ + Tokenizer: icuTokenizer, + TokenFilters: []analysis.TokenFilter{ + aposFilter, + toLowerFilter, + stopTrFilter, + stemmerTrFilter, + }, + } + return &rv, nil +} + +func init() { + registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr_test.go new file mode 100644 index 00000000..79d8098e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/analyzer_tr_test.go @@ -0,0 +1,88 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full +// +build icu full + +package tr + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestTurkishAnalyzer(t *testing.T) { + tests := []struct { + input []byte + output analysis.TokenStream + }{ + // stemming + { + input: []byte("ağacı"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ağaç"), + }, + }, + }, + { + input: []byte("ağaç"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ağaç"), + }, + }, + }, + // stop word + { + input: []byte("dolayı"), + output: analysis.TokenStream{}, + }, + // apostrophes + { + input: []byte("Kıbrıs'ta"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("kıbrıs"), + }, + }, + }, + { + input: []byte("Van Gölü'ne"), + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("van"), + }, + &analysis.Token{ + Term: []byte("göl"), + }, + }, + }, + } + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed(AnalyzerName) + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + actual := analyzer.Analyze(test.input) + if len(actual) != len(test.output) { + t.Fatalf("expected length: %d, got %d", len(test.output), len(actual)) + } + for i, tok := range actual { + if !reflect.DeepEqual(tok.Term, test.output[i].Term) { + t.Errorf("expected term %s (% x) got %s (% x)", test.output[i].Term, test.output[i].Term, tok.Term, tok.Term) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stemmer_tr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stemmer_tr.go new file mode 100644 index 00000000..27838182 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stemmer_tr.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package tr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StemmerName = "stemmer_tr" + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return stemmer_filter.NewStemmerFilter("tr") +} + +func init() { + registry.RegisterTokenFilter(StemmerName, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_filter_tr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_filter_tr.go new file mode 100644 index 00000000..77983fec --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_filter_tr.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package tr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + tokenMap, err := cache.TokenMapNamed(StopName) + if err != nil { + return nil, err + } + return stop_tokens_filter.NewStopTokensFilter(tokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_words_tr.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_words_tr.go new file mode 100644 index 00000000..a4d54f31 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr/stop_words_tr.go @@ -0,0 +1,236 @@ +package tr + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const StopName = "stop_tr" + +// this content was obtained from: +// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/ +// ` was changed to ' to allow for literal string + +var TurkishStopWords = []byte(`# Turkish stopwords from LUCENE-559 +# merged with the list from "Information Retrieval on Turkish Texts" +# (http://www.users.muohio.edu/canf/papers/JASIST2008offPrint.pdf) +acaba +altmış +altı +ama +ancak +arada +aslında +ayrıca +bana +bazı +belki +ben +benden +beni +benim +beri +beş +bile +bin +bir +birçok +biri +birkaç +birkez +birşey +birşeyi +biz +bize +bizden +bizi +bizim +böyle +böylece +bu +buna +bunda +bundan +bunlar +bunları +bunların +bunu +bunun +burada +çok +çünkü +da +daha +dahi +de +defa +değil +diğer +diye +doksan +dokuz +dolayı +dolayısıyla +dört +edecek +eden +ederek +edilecek +ediliyor +edilmesi +ediyor +eğer +elli +en +etmesi +etti +ettiği +ettiğini +gibi +göre +halen +hangi +hatta +hem +henüz +hep +hepsi +her +herhangi +herkesin +hiç +hiçbir +için +iki +ile +ilgili +ise +işte +itibaren +itibariyle +kadar +karşın +katrilyon +kendi +kendilerine +kendini +kendisi +kendisine +kendisini +kez +ki +kim +kimden +kime +kimi +kimse +kırk +milyar +milyon +mu +mü +mı +nasıl +ne +neden +nedenle +nerde +nerede +nereye +niye +niçin +o +olan +olarak +oldu +olduğu +olduğunu +olduklarını +olmadı +olmadığı +olmak +olması +olmayan +olmaz +olsa +olsun +olup +olur +olursa +oluyor +on +ona +ondan +onlar +onlardan +onları +onların +onu +onun +otuz +oysa +öyle +pek +rağmen +sadece +sanki +sekiz +seksen +sen +senden +seni +senin +siz +sizden +sizi +sizin +şey +şeyden +şeyi +şeyler +şöyle +şu +şuna +şunda +şundan +şunları +şunu +tarafından +trilyon +tüm +üç +üzere +var +vardı +ve +veya +ya +yani +yapacak +yapılan +yapılması +yapıyor +yapmak +yaptı +yaptığı +yaptığını +yaptıkları +yedi +yerine +yetmiş +yine +yirmi +yoksa +yüz +zaten +`) + +func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + err := rv.LoadBytes(TurkishStopWords) + return rv, err +} + +func init() { + registry.RegisterTokenMap(StopName, TokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/test_words.txt b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/test_words.txt new file mode 100644 index 00000000..b86e254b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/test_words.txt @@ -0,0 +1,7 @@ +# full line comment +marty +steve # trailing comment +| different format of comment +dustin +siri | different style trailing comment +multiple words with different whitespace \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter.go new file mode 100644 index 00000000..08ffefae --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter.go @@ -0,0 +1,49 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package apostrophe_filter + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "apostrophe" + +const RightSingleQoutationMark = "’" +const Apostrophe = "'" +const Apostrophes = Apostrophe + RightSingleQoutationMark + +type ApostropheFilter struct{} + +func NewApostropheFilter() *ApostropheFilter { + return &ApostropheFilter{} +} + +func (s *ApostropheFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + firstApostrophe := bytes.IndexAny(token.Term, Apostrophes) + if firstApostrophe >= 0 { + // found an apostrophe + token.Term = token.Term[0:firstApostrophe] + } + } + + return input +} + +func ApostropheFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewApostropheFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(Name, ApostropheFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter_test.go new file mode 100644 index 00000000..55af5ab7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter/apostrophe_filter_test.go @@ -0,0 +1,94 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package apostrophe_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestApostropheFilter(t *testing.T) { + + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Türkiye'de"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Türkiye"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("2003'te"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("2003"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Van"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Van"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Gölü'nü"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Gölü"), + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("gördüm"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("gördüm"), + }, + }, + }, + } + + for _, test := range tests { + apostropheFilter := NewApostropheFilter() + actual := apostropheFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/README.md b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/README.md new file mode 100644 index 00000000..64d71710 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/README.md @@ -0,0 +1,33 @@ +# cld2 token filter + +A bleve token filter which passes the text of each token and passes it to the cld2 library. The library determines what it thinks the language most likely is. The ISO-639 language code replaces the token term. + +In normal usage, you use this with the "single" tokenizer, so there is only one input token. Further, you should precede it with the "to_lower" filter so that the input term is in all lower-case unicode characters. + +# Building + +1. Acquire the source to cld2 in this directory. + + $ svn checkout -r 167 http://cld2.googlecode.com/svn/trunk/ cld2-read-only + +2. Build cld2 + + As dynamic library + + $ cd cld2-read-only/internal/ + $ ./compile_libs.sh + $ cp *.so /usr/local/lib + $ cd ../.. + + Or static library + + $ ./compile_cld2.sh + $ cp *.a /usr/local/lib + +3. Run the unit tests + + $ go test -v + === RUN TestCld2Filter + --- PASS: TestCld2Filter (0.00 seconds) + PASS + ok github.com/couchbaselabs/bleve/analysis/token_filters/cld2 0.033s diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.cc b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.cc new file mode 100644 index 00000000..cb116715 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +#include +#include +#include +#include +#include "cld2_filter.h" +#include "cld2-read-only/public/compact_lang_det.h" + +const char* DetectLang(const char *buffer) { + + bool is_plain_text = true; + CLD2::CLDHints cldhints = {NULL, NULL, 0, CLD2::UNKNOWN_LANGUAGE}; + bool allow_extended_lang = true; + int flags = 0; + CLD2::Language language3[3]; + int percent3[3]; + double normalized_score3[3]; + CLD2::ResultChunkVector resultchunkvector; + int text_bytes; + bool is_reliable; + + CLD2::Language summary_lang = CLD2::UNKNOWN_LANGUAGE; + + summary_lang = CLD2::ExtDetectLanguageSummary(buffer, + strlen(buffer), + is_plain_text, + &cldhints, + flags, + language3, + percent3, + normalized_score3, + &resultchunkvector, + &text_bytes, + &is_reliable); + + return CLD2::LanguageCode(summary_lang); +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.go new file mode 100644 index 00000000..8125c996 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.go @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build cld2 full + +package cld2 + +// #cgo LDFLAGS: -lcld2_full +// #include "cld2_filter.h" +// #include +import "C" + +import ( + "unsafe" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "detect_lang" + +type Cld2Filter struct { +} + +func NewCld2Filter() *Cld2Filter { + return &Cld2Filter{} +} + +func (f *Cld2Filter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + offset := 0 + for _, token := range input { + var err error + token.Term, err = f.detectLanguage(token.Term) + if err != nil { + token.Term = []byte("error") + } + token.Start = offset + token.End = token.Start + len(token.Term) + token.Type = analysis.AlphaNumeric + rv = append(rv, token) + offset = token.End + 1 + } + + return rv +} + +func (f *Cld2Filter) detectLanguage(input []byte) ([]byte, error) { + cstr := C.CString(string(input)) + res := C.DetectLang(cstr) + return C.GoBytes(unsafe.Pointer(res), C.int(C.strlen(res))), nil +} + +func Cld2FilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewCld2Filter(), nil +} + +func init() { + registry.RegisterTokenFilter(Name, Cld2FilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.h b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.h new file mode 100644 index 00000000..8f692986 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter.h @@ -0,0 +1,18 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +#ifdef __cplusplus +extern "C" { +#endif + +const char* DetectLang(const char *buffer); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter_test.go new file mode 100644 index 00000000..12290814 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/cld2_filter_test.go @@ -0,0 +1,123 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build cld2 full + +package cld2 + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestCld2Filter(t *testing.T) { + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the quick brown fox"), + Start: 0, + End: 19, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("en"), + Start: 0, + End: 2, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こんにちは世界"), + Start: 0, + End: 21, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ja"), + Start: 0, + End: 2, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("แยกคำภาษาไทยก็ทำได้นะจ้ะ"), + Start: 0, + End: 72, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("th"), + Start: 0, + End: 2, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("مرحبا، العالم!"), + Start: 0, + End: 26, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ar"), + Start: 0, + End: 2, + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + } + + filter := NewCld2Filter() + for _, test := range tests { + res := filter.Filter(test.input) + if !reflect.DeepEqual(res, test.output) { + t.Errorf("expected:") + for _, token := range test.output { + t.Errorf("%#v - %s", token, token.Term) + } + t.Errorf("got:") + for _, token := range res { + t.Errorf("%#v - %s", token, token.Term) + } + } + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/compile_cld2.sh b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/compile_cld2.sh new file mode 100644 index 00000000..71840bbe --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2/compile_cld2.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +SRC="cldutil cldutil_shared compact_lang_det compact_lang_det_hint_code compact_lang_det_impl debug fixunicodevalue generated_entities generated_language generated_ulscript getonescriptspan lang_script offsetmap scoreonescriptspan tote utf8statetable cld_generated_cjk_uni_prop_80 cld2_generated_cjk_compatible cld_generated_cjk_delta_bi_32 generated_distinct_bi_0 cld2_generated_quad0122 cld2_generated_deltaocta0122 cld2_generated_distinctocta0122 cld_generated_score_quad_octa_0122"; +OBJ=""; +for f in ${SRC}; do + g++ -c -fPIC -O2 -m64 -o "cld2-read-only/internal/${f}.o" "cld2-read-only/internal/${f}.cc"; + OBJ="${OBJ} cld2-read-only/internal/${f}.o"; +done; + +ar rcs libcld2_full.a ${OBJ}; diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict.go new file mode 100644 index 00000000..cf05dc48 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict.go @@ -0,0 +1,136 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package compound + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "dict_compound" + +const defaultMinWordSize = 5 +const defaultMinSubWordSize = 2 +const defaultMaxSubWordSize = 15 +const defaultOnlyLongestMatch = false + +type DictionaryCompoundFilter struct { + dict analysis.TokenMap + minWordSize int + minSubWordSize int + maxSubWordSize int + onlyLongestMatch bool +} + +func NewDictionaryCompoundFilter(dict analysis.TokenMap, minWordSize, minSubWordSize, maxSubWordSize int, onlyLongestMatch bool) *DictionaryCompoundFilter { + return &DictionaryCompoundFilter{ + dict: dict, + minWordSize: minWordSize, + minSubWordSize: minSubWordSize, + maxSubWordSize: maxSubWordSize, + onlyLongestMatch: onlyLongestMatch, + } +} + +func (f *DictionaryCompoundFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + for _, token := range input { + rv = append(rv, token) + tokenLen := utf8.RuneCount(token.Term) + if tokenLen >= f.minWordSize { + newtokens := f.decompose(token) + for _, newtoken := range newtokens { + rv = append(rv, newtoken) + } + } + } + + return rv +} + +func (f *DictionaryCompoundFilter) decompose(token *analysis.Token) []*analysis.Token { + runes := bytes.Runes(token.Term) + rv := make([]*analysis.Token, 0) + rlen := len(runes) + for i := 0; i <= (rlen - f.minSubWordSize); i++ { + var longestMatchToken *analysis.Token + for j := f.minSubWordSize; j <= f.maxSubWordSize; j++ { + if i+j > rlen { + break + } + _, inDict := f.dict[string(runes[i:i+j])] + if inDict { + newtoken := analysis.Token{ + Term: []byte(string(runes[i : i+j])), + Position: token.Position, + Start: token.Start + i, + End: token.Start + i + j, + Type: token.Type, + KeyWord: token.KeyWord, + } + if f.onlyLongestMatch { + if longestMatchToken == nil || utf8.RuneCount(longestMatchToken.Term) < j { + longestMatchToken = &newtoken + } + } else { + rv = append(rv, &newtoken) + } + } + } + if f.onlyLongestMatch && longestMatchToken != nil { + rv = append(rv, longestMatchToken) + } + } + return rv +} + +func DictionaryCompoundFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + + minWordSize := defaultMinWordSize + minSubWordSize := defaultMinSubWordSize + maxSubWordSize := defaultMaxSubWordSize + onlyLongestMatch := defaultOnlyLongestMatch + + minVal, ok := config["min_word_size"].(float64) + if ok { + minWordSize = int(minVal) + } + minSubVal, ok := config["min_subword_size"].(float64) + if ok { + minSubWordSize = int(minSubVal) + } + maxSubVal, ok := config["max_subword_size"].(float64) + if ok { + maxSubWordSize = int(maxSubVal) + } + onlyVal, ok := config["only_longest_match"].(bool) + if ok { + onlyLongestMatch = onlyVal + } + + dictTokenMapName, ok := config["dict_token_map"].(string) + if !ok { + return nil, fmt.Errorf("must specify dict_token_map") + } + dictTokenMap, err := cache.TokenMapNamed(dictTokenMapName) + if err != nil { + return nil, fmt.Errorf("error building dict compound words filter: %v", err) + } + return NewDictionaryCompoundFilter(dictTokenMap, minWordSize, minSubWordSize, maxSubWordSize, onlyLongestMatch), nil +} + +func init() { + registry.RegisterTokenFilter(Name, DictionaryCompoundFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict_test.go new file mode 100644 index 00000000..7617e09a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound/dict_test.go @@ -0,0 +1,182 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package compound + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestStopWordsFilter(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("i"), + Start: 0, + End: 1, + Position: 1, + }, + &analysis.Token{ + Term: []byte("like"), + Start: 2, + End: 6, + Position: 2, + }, + &analysis.Token{ + Term: []byte("to"), + Start: 7, + End: 9, + Position: 3, + }, + &analysis.Token{ + Term: []byte("play"), + Start: 10, + End: 14, + Position: 4, + }, + &analysis.Token{ + Term: []byte("softball"), + Start: 15, + End: 23, + Position: 5, + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("i"), + Start: 0, + End: 1, + Position: 1, + }, + &analysis.Token{ + Term: []byte("like"), + Start: 2, + End: 6, + Position: 2, + }, + &analysis.Token{ + Term: []byte("to"), + Start: 7, + End: 9, + Position: 3, + }, + &analysis.Token{ + Term: []byte("play"), + Start: 10, + End: 14, + Position: 4, + }, + &analysis.Token{ + Term: []byte("softball"), + Start: 15, + End: 23, + Position: 5, + }, + &analysis.Token{ + Term: []byte("soft"), + Start: 15, + End: 19, + Position: 5, + }, + &analysis.Token{ + Term: []byte("ball"), + Start: 19, + End: 23, + Position: 5, + }, + } + + cache := registry.NewCache() + dictListConfig := map[string]interface{}{ + "type": token_map.Name, + "tokens": []interface{}{"factor", "soft", "ball", "team"}, + } + _, err := cache.DefineTokenMap("dict_test", dictListConfig) + if err != nil { + t.Fatal(err) + } + + dictConfig := map[string]interface{}{ + "type": "dict_compound", + "dict_token_map": "dict_test", + } + dictFilter, err := cache.DefineTokenFilter("dict_test", dictConfig) + if err != nil { + t.Fatal(err) + } + + ouputTokenStream := dictFilter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream, ouputTokenStream) + } +} + +func TestStopWordsFilterLongestMatch(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("softestball"), + Start: 0, + End: 11, + Position: 1, + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("softestball"), + Start: 0, + End: 11, + Position: 1, + }, + &analysis.Token{ + Term: []byte("softest"), + Start: 0, + End: 7, + Position: 1, + }, + &analysis.Token{ + Term: []byte("ball"), + Start: 7, + End: 11, + Position: 1, + }, + } + + cache := registry.NewCache() + dictListConfig := map[string]interface{}{ + "type": token_map.Name, + "tokens": []interface{}{"soft", "softest", "ball"}, + } + _, err := cache.DefineTokenMap("dict_test", dictListConfig) + if err != nil { + t.Fatal(err) + } + + dictConfig := map[string]interface{}{ + "type": "dict_compound", + "dict_token_map": "dict_test", + "only_longest_match": true, + } + dictFilter, err := cache.DefineTokenFilter("dict_test", dictConfig) + if err != nil { + t.Fatal(err) + } + + ouputTokenStream := dictFilter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream, ouputTokenStream) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter.go new file mode 100644 index 00000000..5cf107e9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter.go @@ -0,0 +1,120 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package edge_ngram_filter + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "edge_ngram" + +type Side bool + +const BACK Side = true +const FRONT Side = false + +type EdgeNgramFilter struct { + back Side + minLength int + maxLength int +} + +func NewEdgeNgramFilter(side Side, minLength, maxLength int) *EdgeNgramFilter { + return &EdgeNgramFilter{ + back: side, + minLength: minLength, + maxLength: maxLength, + } +} + +func (s *EdgeNgramFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + for _, token := range input { + runeCount := utf8.RuneCount(token.Term) + runes := bytes.Runes(token.Term) + if s.back { + i := runeCount + // index of the starting rune for this token + for ngramSize := s.minLength; ngramSize <= s.maxLength; ngramSize++ { + // build an ngram of this size starting at i + if i-ngramSize > 0 { + ngramTerm := buildTermFromRunes(runes[i-ngramSize : i]) + token := analysis.Token{ + Position: token.Position, + Start: token.Start, + End: token.End, + Type: token.Type, + Term: ngramTerm, + } + rv = append(rv, &token) + } + } + } else { + i := 0 + // index of the starting rune for this token + for ngramSize := s.minLength; ngramSize <= s.maxLength; ngramSize++ { + // build an ngram of this size starting at i + if i+ngramSize <= runeCount { + ngramTerm := buildTermFromRunes(runes[i : i+ngramSize]) + token := analysis.Token{ + Position: token.Position, + Start: token.Start, + End: token.End, + Type: token.Type, + Term: ngramTerm, + } + rv = append(rv, &token) + } + } + } + } + + return rv +} + +func buildTermFromRunes(runes []rune) []byte { + rv := make([]byte, 0, len(runes)*4) + for _, r := range runes { + runeBytes := make([]byte, utf8.RuneLen(r)) + utf8.EncodeRune(runeBytes, r) + rv = append(rv, runeBytes...) + } + return rv +} + +func EdgeNgramFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + side := FRONT + back, ok := config["back"].(bool) + if ok && back { + side = BACK + } + minVal, ok := config["min"].(float64) + if !ok { + return nil, fmt.Errorf("must specify min") + } + min := int(minVal) + maxVal, ok := config["max"].(float64) + if !ok { + return nil, fmt.Errorf("must specify max") + } + max := int(maxVal) + + return NewEdgeNgramFilter(side, min, max), nil +} + +func init() { + registry.RegisterTokenFilter(Name, EdgeNgramFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter_test.go new file mode 100644 index 00000000..78b0d58e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter/edge_ngram_filter_test.go @@ -0,0 +1,142 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package edge_ngram_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestEdgeNgramFilter(t *testing.T) { + + tests := []struct { + side Side + min int + max int + input analysis.TokenStream + output analysis.TokenStream + }{ + { + side: FRONT, + min: 1, + max: 1, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + }, + }, + { + side: BACK, + min: 1, + max: 1, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("e"), + }, + }, + }, + { + side: FRONT, + min: 1, + max: 3, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("ab"), + }, + &analysis.Token{ + Term: []byte("abc"), + }, + }, + }, + { + side: BACK, + min: 1, + max: 3, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("e"), + }, + &analysis.Token{ + Term: []byte("de"), + }, + &analysis.Token{ + Term: []byte("cde"), + }, + }, + }, + { + side: FRONT, + min: 1, + max: 3, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + &analysis.Token{ + Term: []byte("vwxyz"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("ab"), + }, + &analysis.Token{ + Term: []byte("abc"), + }, + &analysis.Token{ + Term: []byte("v"), + }, + &analysis.Token{ + Term: []byte("vw"), + }, + &analysis.Token{ + Term: []byte("vwx"), + }, + }, + }, + } + + for _, test := range tests { + edgeNgramFilter := NewEdgeNgramFilter(test.side, test.min, test.max) + actual := edgeNgramFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter.go new file mode 100644 index 00000000..94548a48 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter.go @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package elision_filter + +import ( + "bytes" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "elision" + +const RightSingleQoutationMark = "’" +const Apostrophe = "'" + +const Apostrophes = Apostrophe + RightSingleQoutationMark + +type ElisionFilter struct { + articles analysis.TokenMap +} + +func NewElisionFilter(articles analysis.TokenMap) *ElisionFilter { + return &ElisionFilter{ + articles: articles, + } +} + +func (s *ElisionFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + firstApostrophe := bytes.IndexAny(token.Term, Apostrophes) + if firstApostrophe >= 0 { + // found an apostrophe + prefix := token.Term[0:firstApostrophe] + // see if the prefix matches one of the articles + _, articleMatch := s.articles[string(prefix)] + if articleMatch { + token.Term = token.Term[firstApostrophe+1:] + } + } + } + return input +} + +func ElisionFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + articlesTokenMapName, ok := config["articles_token_map"].(string) + if !ok { + return nil, fmt.Errorf("must specify articles_token_map") + } + articlesTokenMap, err := cache.TokenMapNamed(articlesTokenMapName) + if err != nil { + return nil, fmt.Errorf("error building elision filter: %v", err) + } + return NewElisionFilter(articlesTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(Name, ElisionFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter_test.go new file mode 100644 index 00000000..7bffc533 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter/elision_filter_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package elision_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestElisionFilter(t *testing.T) { + + tests := []struct { + input analysis.TokenStream + output analysis.TokenStream + }{ + { + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ar'word"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("word"), + }, + }, + }, + } + + cache := registry.NewCache() + + articleListConfig := map[string]interface{}{ + "type": token_map.Name, + "tokens": []interface{}{"ar"}, + } + _, err := cache.DefineTokenMap("articles_test", articleListConfig) + if err != nil { + t.Fatal(err) + } + + elisionConfig := map[string]interface{}{ + "type": "elision", + "articles_token_map": "articles_test", + } + elisionFilter, err := cache.DefineTokenFilter("elision_test", elisionConfig) + if err != nil { + t.Fatal(err) + } + + for _, test := range tests { + + actual := elisionFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter.go new file mode 100644 index 00000000..9a788d2d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package keyword_filter + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "keyword_marker" + +type KeyWordMarkerFilter struct { + keyWords analysis.TokenMap +} + +func NewKeyWordMarkerFilter(keyWords analysis.TokenMap) *KeyWordMarkerFilter { + return &KeyWordMarkerFilter{ + keyWords: keyWords, + } +} + +func (f *KeyWordMarkerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + word := string(token.Term) + _, isKeyWord := f.keyWords[word] + if isKeyWord { + token.KeyWord = true + } + } + return input +} + +func KeyWordMarkerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + keywordsTokenMapName, ok := config["keywords_token_map"].(string) + if !ok { + return nil, fmt.Errorf("must specify keywords_token_map") + } + keywordsTokenMap, err := cache.TokenMapNamed(keywordsTokenMapName) + if err != nil { + return nil, fmt.Errorf("error building keyword marker filter: %v", err) + } + return NewKeyWordMarkerFilter(keywordsTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(Name, KeyWordMarkerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter_test.go new file mode 100644 index 00000000..f5dfa55d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter/keyword_marker_filter_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package keyword_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestKeyWordMarkerFilter(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("walk"), + }, + &analysis.Token{ + Term: []byte("in"), + }, + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("park"), + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("walk"), + KeyWord: true, + }, + &analysis.Token{ + Term: []byte("in"), + }, + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("park"), + KeyWord: true, + }, + } + + keyWordsMap := analysis.NewTokenMap() + keyWordsMap.AddToken("walk") + keyWordsMap.AddToken("park") + + filter := NewKeyWordMarkerFilter(keyWordsMap) + ouputTokenStream := filter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream[0].KeyWord, ouputTokenStream[0].KeyWord) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter.go new file mode 100644 index 00000000..9e16440f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter.go @@ -0,0 +1,72 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package length_filter + +import ( + "fmt" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "length" + +type LengthFilter struct { + min int + max int +} + +func NewLengthFilter(min, max int) *LengthFilter { + return &LengthFilter{ + min: min, + max: max, + } +} + +func (f *LengthFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + for _, token := range input { + wordLen := utf8.RuneCount(token.Term) + if f.min > 0 && f.min > wordLen { + continue + } + if f.max > 0 && f.max < wordLen { + continue + } + rv = append(rv, token) + } + + return rv +} + +func LengthFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + min := 0 + max := 0 + + minVal, ok := config["min"].(float64) + if ok { + min = int(minVal) + } + maxVal, ok := config["max"].(float64) + if ok { + max = int(maxVal) + } + if min == max && max == 0 { + return nil, fmt.Errorf("either min or max must be non-zero") + } + + return NewLengthFilter(min, max), nil +} + +func init() { + registry.RegisterTokenFilter(Name, LengthFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter_test.go new file mode 100644 index 00000000..b7bfcad4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter/length_filter_test.go @@ -0,0 +1,94 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package length_filter + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestLengthFilter(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1"), + }, + &analysis.Token{ + Term: []byte("two"), + }, + &analysis.Token{ + Term: []byte("three"), + }, + } + + lengthFilter := NewLengthFilter(3, 4) + ouputTokenStream := lengthFilter.Filter(inputTokenStream) + if len(ouputTokenStream) != 1 { + t.Fatalf("expected 1 output token") + } + if string(ouputTokenStream[0].Term) != "two" { + t.Errorf("expected term `two`, got `%s`", ouputTokenStream[0].Term) + } +} + +func TestLengthFilterNoMax(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1"), + }, + &analysis.Token{ + Term: []byte("two"), + }, + &analysis.Token{ + Term: []byte("three"), + }, + } + + lengthFilter := NewLengthFilter(3, -1) + ouputTokenStream := lengthFilter.Filter(inputTokenStream) + if len(ouputTokenStream) != 2 { + t.Fatalf("expected 2 output token") + } + if string(ouputTokenStream[0].Term) != "two" { + t.Errorf("expected term `two`, got `%s`", ouputTokenStream[0].Term) + } + if string(ouputTokenStream[1].Term) != "three" { + t.Errorf("expected term `three`, got `%s`", ouputTokenStream[0].Term) + } +} + +func TestLengthFilterNoMin(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1"), + }, + &analysis.Token{ + Term: []byte("two"), + }, + &analysis.Token{ + Term: []byte("three"), + }, + } + + lengthFilter := NewLengthFilter(-1, 4) + ouputTokenStream := lengthFilter.Filter(inputTokenStream) + if len(ouputTokenStream) != 2 { + t.Fatalf("expected 2 output token") + } + if string(ouputTokenStream[0].Term) != "1" { + t.Errorf("expected term `1`, got `%s`", ouputTokenStream[0].Term) + } + if string(ouputTokenStream[1].Term) != "two" { + t.Errorf("expected term `two`, got `%s`", ouputTokenStream[0].Term) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter.go new file mode 100644 index 00000000..73c27ea1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package lower_case_filter + +import ( + "bytes" + "unicode" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "to_lower" + +type LowerCaseFilter struct { +} + +func NewLowerCaseFilter() *LowerCaseFilter { + return &LowerCaseFilter{} +} + +func (f *LowerCaseFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + token.Term = toLowerDeferredCopy(token.Term) + } + return input +} + +func LowerCaseFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewLowerCaseFilter(), nil +} + +func init() { + registry.RegisterTokenFilter(Name, LowerCaseFilterConstructor) +} + +// toLowerDeferredCopy will function exactly like +// bytes.ToLower() only it will reuse (overwrite) +// the original byte array when possible +// NOTE: because its possible that the lower-case +// form of a rune has a different utf-8 encoded +// length, in these cases a new byte array is allocated +func toLowerDeferredCopy(s []byte) []byte { + j := 0 + for i := 0; i < len(s); { + wid := 1 + r := rune(s[i]) + if r >= utf8.RuneSelf { + r, wid = utf8.DecodeRune(s[i:]) + } + l := unicode.ToLower(r) + lwid := utf8.RuneLen(l) + if lwid > wid { + // utf-8 encoded replacement is wider + // for now, punt and defer + // to bytes.ToLower() for the remainder + // only known to happen with chars + // Rune Ⱥ(570) width 2 - Lower ⱥ(11365) width 3 + // Rune Ⱦ(574) width 2 - Lower ⱦ(11366) width 3 + rest := bytes.ToLower(s[i:]) + rv := make([]byte, j+len(rest)) + copy(rv[:j], s[:j]) + copy(rv[j:], rest) + return rv + } else { + utf8.EncodeRune(s[j:], l) + } + i += wid + j += lwid + } + return s[:j] +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter_test.go new file mode 100644 index 00000000..637b51be --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter/lower_case_filter_test.go @@ -0,0 +1,155 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package lower_case_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestLowerCaseFilter(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ONE"), + }, + &analysis.Token{ + Term: []byte("two"), + }, + &analysis.Token{ + Term: []byte("ThReE"), + }, + &analysis.Token{ + Term: []byte("steven's"), + }, + // these characters are chosen in particular + // because the utf-8 encoding of the lower-case + // version has a different length + // Rune İ(304) width 2 - Lower i(105) width 1 + // Rune Ⱥ(570) width 2 - Lower ⱥ(11365) width 3 + // Rune Ⱦ(574) width 2 - Lower ⱦ(11366) width 3 + &analysis.Token{ + Term: []byte("İȺȾCAT"), + }, + &analysis.Token{ + Term: []byte("ȺȾCAT"), + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("one"), + }, + &analysis.Token{ + Term: []byte("two"), + }, + &analysis.Token{ + Term: []byte("three"), + }, + &analysis.Token{ + Term: []byte("steven's"), + }, + &analysis.Token{ + Term: []byte("iⱥⱦcat"), + }, + &analysis.Token{ + Term: []byte("ⱥⱦcat"), + }, + } + + filter := NewLowerCaseFilter() + ouputTokenStream := filter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream, ouputTokenStream) + t.Errorf("expected %s got %s", expectedTokenStream[0].Term, ouputTokenStream[0].Term) + } +} + +func BenchmarkLowerCaseFilter(b *testing.B) { + input := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("A"), + }, + &analysis.Token{ + Term: []byte("boiling"), + }, + &analysis.Token{ + Term: []byte("liquid"), + }, + &analysis.Token{ + Term: []byte("expanding"), + }, + &analysis.Token{ + Term: []byte("vapor"), + }, + &analysis.Token{ + Term: []byte("explosion"), + }, + &analysis.Token{ + Term: []byte("caused"), + }, + &analysis.Token{ + Term: []byte("by"), + }, + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("rupture"), + }, + &analysis.Token{ + Term: []byte("of"), + }, + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("vessel"), + }, + &analysis.Token{ + Term: []byte("containing"), + }, + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("pressurized"), + }, + &analysis.Token{ + Term: []byte("liquid"), + }, + &analysis.Token{ + Term: []byte("above"), + }, + &analysis.Token{ + Term: []byte("its"), + }, + &analysis.Token{ + Term: []byte("boiling"), + }, + &analysis.Token{ + Term: []byte("point"), + }, + &analysis.Token{ + Term: []byte("İȺȾCAT"), + }, + &analysis.Token{ + Term: []byte("ȺȾCAT"), + }, + } + filter := NewLowerCaseFilter() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + filter.Filter(input) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter.go new file mode 100644 index 00000000..8384b81f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter.go @@ -0,0 +1,90 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ngram_filter + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "ngram" + +type NgramFilter struct { + minLength int + maxLength int +} + +func NewNgramFilter(minLength, maxLength int) *NgramFilter { + return &NgramFilter{ + minLength: minLength, + maxLength: maxLength, + } +} + +func (s *NgramFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + for _, token := range input { + runeCount := utf8.RuneCount(token.Term) + runes := bytes.Runes(token.Term) + for i := 0; i < runeCount; i++ { + // index of the starting rune for this token + for ngramSize := s.minLength; ngramSize <= s.maxLength; ngramSize++ { + // build an ngram of this size starting at i + if i+ngramSize <= runeCount { + ngramTerm := buildTermFromRunes(runes[i : i+ngramSize]) + token := analysis.Token{ + Position: token.Position, + Start: token.Start, + End: token.End, + Type: token.Type, + Term: ngramTerm, + } + rv = append(rv, &token) + } + } + } + } + + return rv +} + +func buildTermFromRunes(runes []rune) []byte { + rv := make([]byte, 0, len(runes)*4) + for _, r := range runes { + runeBytes := make([]byte, utf8.RuneLen(r)) + utf8.EncodeRune(runeBytes, r) + rv = append(rv, runeBytes...) + } + return rv +} + +func NgramFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + minVal, ok := config["min"].(float64) + if !ok { + return nil, fmt.Errorf("must specify min") + } + min := int(minVal) + maxVal, ok := config["max"].(float64) + if !ok { + return nil, fmt.Errorf("must specify max") + } + max := int(maxVal) + + return NewNgramFilter(min, max), nil +} + +func init() { + registry.RegisterTokenFilter(Name, NgramFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter_test.go new file mode 100644 index 00000000..cb9e292a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter/ngram_filter_test.go @@ -0,0 +1,132 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ngram_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestNgramFilter(t *testing.T) { + + tests := []struct { + min int + max int + input analysis.TokenStream + output analysis.TokenStream + }{ + { + min: 1, + max: 1, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("b"), + }, + &analysis.Token{ + Term: []byte("c"), + }, + &analysis.Token{ + Term: []byte("d"), + }, + &analysis.Token{ + Term: []byte("e"), + }, + }, + }, + { + min: 2, + max: 2, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ab"), + }, + &analysis.Token{ + Term: []byte("bc"), + }, + &analysis.Token{ + Term: []byte("cd"), + }, + &analysis.Token{ + Term: []byte("de"), + }, + }, + }, + { + min: 1, + max: 3, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("ab"), + }, + &analysis.Token{ + Term: []byte("abc"), + }, + &analysis.Token{ + Term: []byte("b"), + }, + &analysis.Token{ + Term: []byte("bc"), + }, + &analysis.Token{ + Term: []byte("bcd"), + }, + &analysis.Token{ + Term: []byte("c"), + }, + &analysis.Token{ + Term: []byte("cd"), + }, + &analysis.Token{ + Term: []byte("cde"), + }, + &analysis.Token{ + Term: []byte("d"), + }, + &analysis.Token{ + Term: []byte("de"), + }, + &analysis.Token{ + Term: []byte("e"), + }, + }, + }, + } + + for _, test := range tests { + ngramFilter := NewNgramFilter(test.min, test.max) + actual := ngramFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter.go new file mode 100644 index 00000000..a73b4083 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter.go @@ -0,0 +1,44 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package porter + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer" +) + +const Name = "stemmer_porter" + +type PorterStemmer struct { +} + +func NewPorterStemmer() *PorterStemmer { + return &PorterStemmer{} +} + +func (s *PorterStemmer) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + // if it is not a protected keyword, stem it + if !token.KeyWord { + stemmed := porterstemmer.StemString(string(token.Term)) + token.Term = []byte(stemmed) + } + } + return input +} + +func PorterStemmerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + return NewPorterStemmer(), nil +} + +func init() { + registry.RegisterTokenFilter(Name, PorterStemmerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter_test.go new file mode 100644 index 00000000..30dbb784 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/porter/porter_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package porter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestPorterStemmer(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walking"), + }, + &analysis.Token{ + Term: []byte("talked"), + }, + &analysis.Token{ + Term: []byte("business"), + }, + &analysis.Token{ + Term: []byte("protected"), + KeyWord: true, + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walk"), + }, + &analysis.Token{ + Term: []byte("talk"), + }, + &analysis.Token{ + Term: []byte("busi"), + }, + &analysis.Token{ + Term: []byte("protected"), + KeyWord: true, + }, + } + + filter := NewPorterStemmer() + ouputTokenStream := filter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream[3], ouputTokenStream[3]) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle.go new file mode 100644 index 00000000..5d2b1d6f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle.go @@ -0,0 +1,157 @@ +package shingle + +import ( + "container/ring" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "shingle" + +type ShingleFilter struct { + min int + max int + outputOriginal bool + tokenSeparator string + fill string + ring *ring.Ring + itemsInRing int +} + +func NewShingleFilter(min, max int, outputOriginal bool, sep, fill string) *ShingleFilter { + return &ShingleFilter{ + min: min, + max: max, + outputOriginal: outputOriginal, + tokenSeparator: sep, + fill: fill, + ring: ring.New(max), + } +} + +func (s *ShingleFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + currentPosition := 0 + for _, token := range input { + if s.outputOriginal { + rv = append(rv, token) + } + + // if there are gaps, insert filler tokens + offset := token.Position - currentPosition + for offset > 1 { + fillerToken := analysis.Token{ + Position: 0, + Start: -1, + End: -1, + Type: analysis.AlphaNumeric, + Term: []byte(s.fill), + } + s.ring.Value = &fillerToken + if s.itemsInRing < s.max { + s.itemsInRing++ + } + rv = append(rv, s.shingleCurrentRingState()...) + s.ring = s.ring.Next() + offset-- + } + currentPosition = token.Position + + s.ring.Value = token + if s.itemsInRing < s.max { + s.itemsInRing++ + } + rv = append(rv, s.shingleCurrentRingState()...) + s.ring = s.ring.Next() + + } + + return rv +} + +func (s *ShingleFilter) shingleCurrentRingState() analysis.TokenStream { + rv := make(analysis.TokenStream, 0) + for shingleN := s.min; shingleN <= s.max; shingleN++ { + // if there are enough items in the ring + // to produce a shingle of this size + if s.itemsInRing >= shingleN { + thisShingleRing := s.ring.Move(-(shingleN - 1)) + shingledBytes := make([]byte, 0) + pos := 0 + start := -1 + end := 0 + for i := 0; i < shingleN; i++ { + if i != 0 { + shingledBytes = append(shingledBytes, []byte(s.tokenSeparator)...) + } + curr := thisShingleRing.Value.(*analysis.Token) + if pos == 0 && curr.Position != 0 { + pos = curr.Position + } + if start == -1 && curr.Start != -1 { + start = curr.Start + } + if curr.End != -1 { + end = curr.End + } + shingledBytes = append(shingledBytes, curr.Term...) + thisShingleRing = thisShingleRing.Next() + } + token := analysis.Token{ + Type: analysis.Shingle, + Term: shingledBytes, + } + if pos != 0 { + token.Position = pos + } + if start != -1 { + token.Start = start + } + if end != -1 { + token.End = end + } + rv = append(rv, &token) + } + } + return rv +} + +func ShingleFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + minVal, ok := config["min"].(float64) + if !ok { + return nil, fmt.Errorf("must specify min") + } + min := int(minVal) + maxVal, ok := config["max"].(float64) + if !ok { + return nil, fmt.Errorf("must specify max") + } + max := int(maxVal) + + outputOriginal := false + outVal, ok := config["output_original"].(bool) + if ok { + outputOriginal = outVal + } + + sep := " " + sepVal, ok := config["separator"].(string) + if ok { + sep = sepVal + } + + fill := "_" + fillVal, ok := config["filler"].(string) + if ok { + fill = fillVal + } + + return NewShingleFilter(min, max, outputOriginal, sep, fill), nil +} + +func init() { + registry.RegisterTokenFilter(Name, ShingleFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle_test.go new file mode 100644 index 00000000..1548f861 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle/shingle_test.go @@ -0,0 +1,330 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package shingle + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestShingleFilter(t *testing.T) { + + tests := []struct { + min int + max int + outputOriginal bool + separator string + filler string + input analysis.TokenStream + output analysis.TokenStream + }{ + { + min: 2, + max: 2, + outputOriginal: false, + separator: " ", + filler: "_", + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("quick"), + }, + &analysis.Token{ + Term: []byte("brown"), + }, + &analysis.Token{ + Term: []byte("fox"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the quick"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("quick brown"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("brown fox"), + Type: analysis.Shingle, + }, + }, + }, + { + min: 3, + max: 3, + outputOriginal: false, + separator: " ", + filler: "_", + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("quick"), + }, + &analysis.Token{ + Term: []byte("brown"), + }, + &analysis.Token{ + Term: []byte("fox"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the quick brown"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("quick brown fox"), + Type: analysis.Shingle, + }, + }, + }, + { + min: 2, + max: 3, + outputOriginal: false, + separator: " ", + filler: "_", + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("quick"), + }, + &analysis.Token{ + Term: []byte("brown"), + }, + &analysis.Token{ + Term: []byte("fox"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the quick"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("quick brown"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("the quick brown"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("brown fox"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("quick brown fox"), + Type: analysis.Shingle, + }, + }, + }, + { + min: 3, + max: 3, + outputOriginal: false, + separator: " ", + filler: "_", + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ugly"), + Position: 1, + }, + &analysis.Token{ + Term: []byte("quick"), + Position: 3, + }, + &analysis.Token{ + Term: []byte("brown"), + Position: 4, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ugly _ quick"), + Type: analysis.Shingle, + Position: 1, + }, + &analysis.Token{ + Term: []byte("_ quick brown"), + Type: analysis.Shingle, + Position: 3, + }, + }, + }, + { + min: 1, + max: 5, + outputOriginal: false, + separator: " ", + filler: "_", + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("test"), + Position: 1, + }, + &analysis.Token{ + Term: []byte("text"), + Position: 2, + }, + // token 3 removed by stop filter + &analysis.Token{ + Term: []byte("see"), + Position: 4, + }, + &analysis.Token{ + Term: []byte("shingles"), + Position: 5, + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("test"), + Type: analysis.Shingle, + Position: 1, + }, + &analysis.Token{ + Term: []byte("text"), + Type: analysis.Shingle, + Position: 2, + }, + &analysis.Token{ + Term: []byte("test text"), + Type: analysis.Shingle, + Position: 1, + }, + &analysis.Token{ + Term: []byte("_"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("text _"), + Type: analysis.Shingle, + Position: 2, + }, + &analysis.Token{ + Term: []byte("test text _"), + Type: analysis.Shingle, + Position: 1, + }, + &analysis.Token{ + Term: []byte("see"), + Type: analysis.Shingle, + Position: 4, + }, + &analysis.Token{ + Term: []byte("_ see"), + Type: analysis.Shingle, + Position: 4, + }, + &analysis.Token{ + Term: []byte("text _ see"), + Type: analysis.Shingle, + Position: 2, + }, + &analysis.Token{ + Term: []byte("test text _ see"), + Type: analysis.Shingle, + Position: 1, + }, + &analysis.Token{ + Term: []byte("shingles"), + Type: analysis.Shingle, + Position: 5, + }, + &analysis.Token{ + Term: []byte("see shingles"), + Type: analysis.Shingle, + Position: 4, + }, + &analysis.Token{ + Term: []byte("_ see shingles"), + Type: analysis.Shingle, + Position: 4, + }, + &analysis.Token{ + Term: []byte("text _ see shingles"), + Type: analysis.Shingle, + Position: 2, + }, + &analysis.Token{ + Term: []byte("test text _ see shingles"), + Type: analysis.Shingle, + Position: 1, + }, + }, + }, + { + min: 2, + max: 2, + outputOriginal: true, + separator: " ", + filler: "_", + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("quick"), + }, + &analysis.Token{ + Term: []byte("brown"), + }, + &analysis.Token{ + Term: []byte("fox"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("quick"), + }, + &analysis.Token{ + Term: []byte("the quick"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("brown"), + }, + &analysis.Token{ + Term: []byte("quick brown"), + Type: analysis.Shingle, + }, + &analysis.Token{ + Term: []byte("fox"), + }, + &analysis.Token{ + Term: []byte("brown fox"), + Type: analysis.Shingle, + }, + }, + }, + } + + for _, test := range tests { + shingleFilter := NewShingleFilter(test.min, test.max, test.outputOriginal, test.separator, test.filler) + actual := shingleFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/README.md b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/README.md new file mode 100644 index 00000000..56b0e863 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/README.md @@ -0,0 +1,18 @@ +## Languages supported + +"danish", +"dutch", +"english", +"finnish", +"french", +"german", +"hungarian", +"italian", +"norwegian", +"porter", +"portuguese", +"romanian", +"russian", +"spanish", +"swedish", +"turkish" \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter.go new file mode 100644 index 00000000..3eeeba55 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package stemmer_filter + +import ( + "fmt" + + "bitbucket.org/tebeka/snowball" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "stem" + +type StemmerFilter struct { + lang string + stemmerPool chan *snowball.Stemmer +} + +func NewStemmerFilter(lang string) (*StemmerFilter, error) { + stemmerPool := make(chan *snowball.Stemmer, 4) + for i := 0; i < 4; i++ { + stemmer, err := snowball.New(lang) + if err != nil { + return nil, err + } + stemmerPool <- stemmer + } + return &StemmerFilter{ + lang: lang, + stemmerPool: stemmerPool, + }, nil +} + +func MustNewStemmerFilter(lang string) *StemmerFilter { + sf, err := NewStemmerFilter(lang) + if err != nil { + panic(err) + } + return sf +} + +func (s *StemmerFilter) List() []string { + return snowball.LangList() +} + +func (s *StemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + // if it is not a protected keyword, stem it + if !token.KeyWord { + stemmer := <-s.stemmerPool + stemmed := stemmer.Stem(string(token.Term)) + s.stemmerPool <- stemmer + token.Term = []byte(stemmed) + } + } + return input +} + +func StemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + langVal, ok := config["lang"].(string) + if !ok { + return nil, fmt.Errorf("must specify stemmer language") + } + lang := langVal + return NewStemmerFilter(lang) +} + +func init() { + registry.RegisterTokenFilter(Name, StemmerFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter_test.go new file mode 100644 index 00000000..c3d129a2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter/stemmer_filter_test.go @@ -0,0 +1,63 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package stemmer_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestStemmerFilter(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walking"), + }, + &analysis.Token{ + Term: []byte("talked"), + }, + &analysis.Token{ + Term: []byte("business"), + }, + &analysis.Token{ + Term: []byte("protected"), + KeyWord: true, + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walk"), + }, + &analysis.Token{ + Term: []byte("talk"), + }, + &analysis.Token{ + Term: []byte("busi"), + }, + &analysis.Token{ + Term: []byte("protected"), + KeyWord: true, + }, + } + + filter, err := NewStemmerFilter("en") + if err != nil { + t.Fatal(err) + } + ouputTokenStream := filter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream[3], ouputTokenStream[3]) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter.go new file mode 100644 index 00000000..e7af7cad --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package stop_tokens_filter + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "stop_tokens" + +type StopTokensFilter struct { + stopTokens analysis.TokenMap +} + +func NewStopTokensFilter(stopTokens analysis.TokenMap) *StopTokensFilter { + return &StopTokensFilter{ + stopTokens: stopTokens, + } +} + +func (f *StopTokensFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + rv := make(analysis.TokenStream, 0, len(input)) + + for _, token := range input { + _, isStopToken := f.stopTokens[string(token.Term)] + if !isStopToken { + rv = append(rv, token) + } + } + + return rv +} + +func StopTokensFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + stopTokenMapName, ok := config["stop_token_map"].(string) + if !ok { + return nil, fmt.Errorf("must specify stop_token_map") + } + stopTokenMap, err := cache.TokenMapNamed(stopTokenMapName) + if err != nil { + return nil, fmt.Errorf("error building stop words filter: %v", err) + } + return NewStopTokensFilter(stopTokenMap), nil +} + +func init() { + registry.RegisterTokenFilter(Name, StopTokensFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter_test.go new file mode 100644 index 00000000..1998cc45 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter/stop_tokens_filter_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package stop_tokens_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestStopWordsFilter(t *testing.T) { + + inputTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("a"), + }, + &analysis.Token{ + Term: []byte("walk"), + }, + &analysis.Token{ + Term: []byte("in"), + }, + &analysis.Token{ + Term: []byte("the"), + }, + &analysis.Token{ + Term: []byte("park"), + }, + } + + expectedTokenStream := analysis.TokenStream{ + &analysis.Token{ + Term: []byte("walk"), + }, + &analysis.Token{ + Term: []byte("park"), + }, + } + + cache := registry.NewCache() + stopListConfig := map[string]interface{}{ + "type": token_map.Name, + "tokens": []interface{}{"a", "in", "the"}, + } + _, err := cache.DefineTokenMap("stop_test", stopListConfig) + if err != nil { + t.Fatal(err) + } + + stopConfig := map[string]interface{}{ + "type": "stop_tokens", + "stop_token_map": "stop_test", + } + stopFilter, err := cache.DefineTokenFilter("stop_test", stopConfig) + if err != nil { + t.Fatal(err) + } + + ouputTokenStream := stopFilter.Filter(inputTokenStream) + if !reflect.DeepEqual(ouputTokenStream, expectedTokenStream) { + t.Errorf("expected %#v got %#v", expectedTokenStream, ouputTokenStream) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter.go new file mode 100644 index 00000000..4ccd75ad --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter.go @@ -0,0 +1,62 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package truncate_token_filter + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "truncate_token" + +type TruncateTokenFilter struct { + length int +} + +func NewTruncateTokenFilter(length int) *TruncateTokenFilter { + return &TruncateTokenFilter{ + length: length, + } +} + +func (s *TruncateTokenFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + wordLen := utf8.RuneCount(token.Term) + if wordLen > s.length { + runes := bytes.Runes(token.Term)[0:s.length] + newterm := make([]byte, 0, s.length*4) + for _, r := range runes { + runeBytes := make([]byte, utf8.RuneLen(r)) + utf8.EncodeRune(runeBytes, r) + newterm = append(newterm, runeBytes...) + } + token.Term = newterm + } + } + return input +} + +func TruncateTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + lenVal, ok := config["length"].(float64) + if !ok { + return nil, fmt.Errorf("must specify length") + } + length := int(lenVal) + + return NewTruncateTokenFilter(length), nil +} + +func init() { + registry.RegisterTokenFilter(Name, TruncateTokenFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter_test.go new file mode 100644 index 00000000..5585ee00 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter/truncate_token_filter_test.go @@ -0,0 +1,74 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package truncate_token_filter + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestTruncateTokenFilter(t *testing.T) { + + tests := []struct { + length int + input analysis.TokenStream + output analysis.TokenStream + }{ + { + length: 5, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcdefgh"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("abcde"), + }, + }, + }, + { + length: 3, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こんにちは世界"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("こんに"), + }, + }, + }, + { + length: 10, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("แยกคำภาษาไทยก็ทำได้นะจ้ะ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("แยกคำภาษาไ"), + }, + }, + }, + } + + for _, test := range tests { + truncateTokenFilter := NewTruncateTokenFilter(test.length) + actual := truncateTokenFilter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize.go new file mode 100644 index 00000000..e60c449c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize.go @@ -0,0 +1,74 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package unicode_normalize + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/unicode/norm" +) + +const Name = "normalize_unicode" + +const NFC = "nfc" +const NFD = "nfd" +const NFKC = "nfkc" +const NFKD = "nfkd" + +var forms = map[string]norm.Form{ + NFC: norm.NFC, + NFD: norm.NFD, + NFKC: norm.NFKC, + NFKD: norm.NFKD, +} + +type UnicodeNormalizeFilter struct { + form norm.Form +} + +func NewUnicodeNormalizeFilter(formName string) (*UnicodeNormalizeFilter, error) { + form, ok := forms[formName] + if !ok { + return nil, fmt.Errorf("no form named %s", formName) + } + return &UnicodeNormalizeFilter{ + form: form, + }, nil +} + +func MustNewUnicodeNormalizeFilter(formName string) *UnicodeNormalizeFilter { + filter, err := NewUnicodeNormalizeFilter(formName) + if err != nil { + panic(err) + } + return filter +} + +func (s *UnicodeNormalizeFilter) Filter(input analysis.TokenStream) analysis.TokenStream { + for _, token := range input { + token.Term = s.form.Bytes(token.Term) + } + return input +} + +func UnicodeNormalizeFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) { + formVal, ok := config["form"].(string) + if !ok { + return nil, fmt.Errorf("must specify form") + } + form := formVal + return NewUnicodeNormalizeFilter(form) +} + +func init() { + registry.RegisterTokenFilter(Name, UnicodeNormalizeFilterConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize_test.go new file mode 100644 index 00000000..b1a33260 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize/unicode_normalize_test.go @@ -0,0 +1,157 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package unicode_normalize + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +// the following tests come from the lucene +// test cases for CJK width filter +// which is our basis for using this +// as a substitute for that +func TestUnicodeNormalization(t *testing.T) { + + tests := []struct { + formName string + input analysis.TokenStream + output analysis.TokenStream + }{ + { + formName: NFKD, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Test"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("Test"), + }, + }, + }, + { + formName: NFKD, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1234"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("1234"), + }, + }, + }, + { + formName: NFKD, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("カタカナ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("カタカナ"), + }, + }, + }, + { + formName: NFKC, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ヴィッツ"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("ヴィッツ"), + }, + }, + }, + { + formName: NFKC, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("パナソニック"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("パナソニック"), + }, + }, + }, + { + formName: NFD, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u212B"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0041\u030A"), + }, + }, + }, + { + formName: NFC, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u212B"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u00C5"), + }, + }, + }, + { + formName: NFKD, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\uFB01"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0066\u0069"), + }, + }, + }, + { + formName: NFKC, + input: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\uFB01"), + }, + }, + output: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("\u0066\u0069"), + }, + }, + }, + } + + for _, test := range tests { + filter := MustNewUnicodeNormalizeFilter(test.formName) + actual := filter.Filter(test.input) + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %s, got %s", test.output[0].Term, actual[0].Term) + t.Errorf("expected %#v, got %#v", test.output[0].Term, actual[0].Term) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map.go new file mode 100644 index 00000000..17a26f48 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map.go @@ -0,0 +1,65 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +import ( + "bufio" + "bytes" + "io" + "io/ioutil" + "strings" +) + +type TokenMap map[string]bool + +func NewTokenMap() TokenMap { + return make(TokenMap, 0) +} + +func (t TokenMap) LoadFile(filename string) error { + data, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + return t.LoadBytes(data) +} + +func (t TokenMap) LoadBytes(data []byte) error { + bytesReader := bytes.NewReader(data) + bufioReader := bufio.NewReader(bytesReader) + line, err := bufioReader.ReadString('\n') + for err == nil { + t.LoadLine(line) + line, err = bufioReader.ReadString('\n') + } + // if the err was EOF we still need to process the last value + if err == io.EOF { + t.LoadLine(line) + return nil + } + return err +} + +func (t TokenMap) LoadLine(line string) { + // find the start of a comment, if any + startComment := strings.IndexAny(line, "#|") + if startComment >= 0 { + line = line[:startComment] + } + + tokens := strings.Fields(line) + for _, token := range tokens { + t.AddToken(token) + } +} + +func (t TokenMap) AddToken(token string) { + t[token] = true +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map/custom.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map/custom.go new file mode 100644 index 00000000..ee614856 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map/custom.go @@ -0,0 +1,46 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package token_map + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "custom" + +func GenericTokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) { + rv := analysis.NewTokenMap() + + // first: try to load by filename + filename, ok := config["filename"].(string) + if ok { + err := rv.LoadFile(filename) + return rv, err + } + // next: look for an inline word list + tokens, ok := config["tokens"].([]interface{}) + if ok { + for _, token := range tokens { + tokenStr, ok := token.(string) + if ok { + rv.AddToken(tokenStr) + } + } + return rv, nil + } + return nil, fmt.Errorf("must specify filename or list of tokens for token map") +} + +func init() { + registry.RegisterTokenMap(Name, GenericTokenMapConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map_test.go new file mode 100644 index 00000000..c853b3c4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map_test.go @@ -0,0 +1,38 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +import ( + "reflect" + "testing" +) + +func TestTokenMapLoadFile(t *testing.T) { + tokenMap := NewTokenMap() + err := tokenMap.LoadFile("test_words.txt") + if err != nil { + t.Fatal(err) + } + + expectedTokens := NewTokenMap() + expectedTokens.AddToken("marty") + expectedTokens.AddToken("steve") + expectedTokens.AddToken("dustin") + expectedTokens.AddToken("siri") + expectedTokens.AddToken("multiple") + expectedTokens.AddToken("words") + expectedTokens.AddToken("with") + expectedTokens.AddToken("different") + expectedTokens.AddToken("whitespace") + + if !reflect.DeepEqual(tokenMap, expectedTokens) { + t.Errorf("expected %#v, got %#v", expectedTokens, tokenMap) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception.go new file mode 100644 index 00000000..a74308d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception.go @@ -0,0 +1,121 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package exception + +import ( + "fmt" + "regexp" + "strings" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "exception" + +type ExceptionsTokenizer struct { + exception *regexp.Regexp + remaining analysis.Tokenizer +} + +func NewExceptionsTokenizer(exception *regexp.Regexp, remaining analysis.Tokenizer) *ExceptionsTokenizer { + return &ExceptionsTokenizer{ + exception: exception, + remaining: remaining, + } +} + +func (t *ExceptionsTokenizer) Tokenize(input []byte) analysis.TokenStream { + rv := make(analysis.TokenStream, 0) + matches := t.exception.FindAllIndex(input, -1) + currInput := 0 + lastPos := 0 + for _, match := range matches { + start := match[0] + end := match[1] + if start > currInput { + // need to defer to remaining for unprocessed section + intermediate := t.remaining.Tokenize(input[currInput:start]) + // add intermediate tokens to our result stream + for _, token := range intermediate { + // adjust token offsets + token.Position += lastPos + token.Start += currInput + token.End += currInput + rv = append(rv, token) + } + lastPos += len(intermediate) + currInput = start + } + + // create single token with this regexp match + token := &analysis.Token{ + Term: input[start:end], + Start: start, + End: end, + Position: lastPos + 1, + } + rv = append(rv, token) + lastPos++ + currInput = end + + } + + if currInput < len(input) { + // need to defer to remaining for unprocessed section + intermediate := t.remaining.Tokenize(input[currInput:]) + // add intermediate tokens to our result stream + for _, token := range intermediate { + // adjust token offsets + token.Position += lastPos + token.Start += currInput + token.End += currInput + rv = append(rv, token) + } + } + + return rv +} + +func ExceptionsTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + exceptions := []string{} + iexceptions, ok := config["exceptions"].([]interface{}) + if ok { + for _, exception := range iexceptions { + exception, ok := exception.(string) + if ok { + exceptions = append(exceptions, exception) + } + } + } + aexceptions, ok := config["exceptions"].([]string) + if ok { + exceptions = append(exceptions, aexceptions...) + } + exceptionPattern := strings.Join(exceptions, "|") + r, err := regexp.Compile(exceptionPattern) + if err != nil { + return nil, fmt.Errorf("unable to build regexp tokenizer: %v", err) + } + + remainingName, ok := config["tokenizer"].(string) + if !ok { + return nil, fmt.Errorf("must specify tokenizer for remaining input") + } + remaining, err := cache.TokenizerNamed(remainingName) + if err != nil { + return nil, err + } + return NewExceptionsTokenizer(r, remaining), nil +} + +func init() { + registry.RegisterTokenizer(Name, ExceptionsTokenizerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception_test.go new file mode 100644 index 00000000..b2a56a5b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception/exception_test.go @@ -0,0 +1,157 @@ +package exception + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func TestExceptionsTokenizer(t *testing.T) { + tests := []struct { + config map[string]interface{} + input []byte + patterns []string + result analysis.TokenStream + }{ + { + input: []byte("test http://blevesearch.com/ words"), + config: map[string]interface{}{ + "type": "exception", + "tokenizer": "unicode", + "exceptions": []interface{}{ + `[hH][tT][tT][pP][sS]?://(\S)*`, + `[fF][iI][lL][eE]://(\S)*`, + `[fF][tT][pP]://(\S)*`, + }, + }, + result: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("test"), + Position: 1, + Start: 0, + End: 4, + }, + &analysis.Token{ + Term: []byte("http://blevesearch.com/"), + Position: 2, + Start: 5, + End: 28, + }, + &analysis.Token{ + Term: []byte("words"), + Position: 3, + Start: 29, + End: 34, + }, + }, + }, + { + input: []byte("what ftp://blevesearch.com/ songs"), + config: map[string]interface{}{ + "type": "exception", + "tokenizer": "unicode", + "exceptions": []interface{}{ + `[hH][tT][tT][pP][sS]?://(\S)*`, + `[fF][iI][lL][eE]://(\S)*`, + `[fF][tT][pP]://(\S)*`, + }, + }, + result: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("what"), + Position: 1, + Start: 0, + End: 4, + }, + &analysis.Token{ + Term: []byte("ftp://blevesearch.com/"), + Position: 2, + Start: 5, + End: 27, + }, + &analysis.Token{ + Term: []byte("songs"), + Position: 3, + Start: 28, + End: 33, + }, + }, + }, + { + input: []byte("please email marty@couchbase.com the URL https://blevesearch.com/"), + config: map[string]interface{}{ + "type": "exception", + "tokenizer": "unicode", + "exceptions": []interface{}{ + `[hH][tT][tT][pP][sS]?://(\S)*`, + `[fF][iI][lL][eE]://(\S)*`, + `[fF][tT][pP]://(\S)*`, + `\S+@\S+`, + }, + }, + result: analysis.TokenStream{ + &analysis.Token{ + Term: []byte("please"), + Position: 1, + Start: 0, + End: 6, + }, + &analysis.Token{ + Term: []byte("email"), + Position: 2, + Start: 7, + End: 12, + }, + &analysis.Token{ + Term: []byte("marty@couchbase.com"), + Position: 3, + Start: 13, + End: 32, + }, + &analysis.Token{ + Term: []byte("the"), + Position: 4, + Start: 33, + End: 36, + }, + &analysis.Token{ + Term: []byte("URL"), + Position: 5, + Start: 37, + End: 40, + }, + &analysis.Token{ + Term: []byte("https://blevesearch.com/"), + Position: 6, + Start: 41, + End: 65, + }, + }, + }, + } + + // remaining := unicode.NewUnicodeTokenizer() + for _, test := range tests { + + // build the requested exception tokenizer + cache := registry.NewCache() + tokenizer, err := cache.DefineTokenizer("custom", test.config) + if err != nil { + t.Fatal(err) + } + + // pattern := strings.Join(test.patterns, "|") + // r, err := regexp.Compile(pattern) + // if err != nil { + // t.Fatal(err) + // } + // tokenizer := NewExceptionsTokenizer(r, remaining) + actual := tokenizer.Tokenize(test.input) + if !reflect.DeepEqual(actual, test.result) { + t.Errorf("expected %v, got %v", test.result, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary.go new file mode 100644 index 00000000..ac5f9958 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary.go @@ -0,0 +1,138 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package icu + +// #cgo LDFLAGS: -licuuc -licudata +// #include +// #include +// #include "unicode/utypes.h" +// #include "unicode/uchar.h" +// #include "unicode/ubrk.h" +// #include "unicode/ustring.h" +import "C" + +import ( + "unsafe" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "icu" + +type UnicodeWordBoundaryTokenizer struct { + locale *C.char +} + +func NewUnicodeWordBoundaryTokenizer() *UnicodeWordBoundaryTokenizer { + return &UnicodeWordBoundaryTokenizer{} +} + +func NewUnicodeWordBoundaryCustomLocaleTokenizer(locale string) *UnicodeWordBoundaryTokenizer { + return &UnicodeWordBoundaryTokenizer{ + locale: C.CString(locale), + } +} + +func (t *UnicodeWordBoundaryTokenizer) Tokenize(input []byte) analysis.TokenStream { + rv := make(analysis.TokenStream, 0) + + if len(input) < 1 { + return rv + } + + // works + var myUnsafePointer = unsafe.Pointer(&(input[0])) + var myCCharPointer *C.char = (*C.char)(myUnsafePointer) + + var inlen C.int32_t = C.int32_t(len(input)) + var buflen C.int32_t = C.int32_t(2*len(input) + 1) // worse case each byte becomes 2 + var stringToExamine []C.UChar = make([]C.UChar, buflen) + var myUnsafePointerToExamine = unsafe.Pointer(&(stringToExamine[0])) + var myUCharPointer *C.UChar = (*C.UChar)(myUnsafePointerToExamine) + C.u_uastrncpy(myUCharPointer, myCCharPointer, inlen) + + var err C.UErrorCode = C.U_ZERO_ERROR + bi := C.ubrk_open(C.UBRK_WORD, t.locale, myUCharPointer, -1, &err) + + if err > C.U_ZERO_ERROR { + return rv + } + + defer C.ubrk_close(bi) + + position := 0 + var prev C.int32_t + p := C.ubrk_first(bi) + for p != C.UBRK_DONE { + + q := C.ubrk_getRuleStatus(bi) + + // convert boundaries back to utf8 positions + var nilCString *C.char + var indexA C.int32_t + + C.u_strToUTF8(nilCString, 0, &indexA, myUCharPointer, prev, &err) + if err > C.U_ZERO_ERROR && err != C.U_BUFFER_OVERFLOW_ERROR { + return rv + } else { + err = C.U_ZERO_ERROR + } + + var indexB C.int32_t + C.u_strToUTF8(nilCString, 0, &indexB, myUCharPointer, p, &err) + if err > C.U_ZERO_ERROR && err != C.U_BUFFER_OVERFLOW_ERROR { + return rv + } else { + err = C.U_ZERO_ERROR + } + + if q != 0 { + position += 1 + token := analysis.Token{ + Start: int(indexA), + End: int(indexB), + Term: input[indexA:indexB], + Position: position, + Type: analysis.AlphaNumeric, + } + if q == 100 { + token.Type = analysis.Numeric + } + if q == 400 { + token.Type = analysis.Ideographic + } + rv = append(rv, &token) + } + prev = p + p = C.ubrk_next(bi) + } + + return rv +} + +func UnicodeWordBoundaryTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + locale := "" + localeVal, ok := config["locale"].(string) + if ok { + locale = localeVal + } + if locale == "" { + return NewUnicodeWordBoundaryTokenizer(), nil + } else { + return NewUnicodeWordBoundaryCustomLocaleTokenizer(locale), nil + } +} + +func init() { + registry.RegisterTokenizer(Name, UnicodeWordBoundaryTokenizerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary_test.go new file mode 100644 index 00000000..1086314a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu/boundary_test.go @@ -0,0 +1,191 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package icu + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestBoundary(t *testing.T) { + + tests := []struct { + input []byte + locale string + output analysis.TokenStream + }{ + { + []byte("Hello World"), + "en_US", + analysis.TokenStream{ + { + Start: 0, + End: 5, + Term: []byte("Hello"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 6, + End: 11, + Term: []byte("World"), + Position: 2, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("steven's"), + "en_US", + analysis.TokenStream{ + { + Start: 0, + End: 8, + Term: []byte("steven's"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("こんにちは世界"), + "en_US", + analysis.TokenStream{ + { + Start: 0, + End: 15, + Term: []byte("こんにちは"), + Position: 1, + Type: analysis.Ideographic, + }, + { + Start: 15, + End: 21, + Term: []byte("世界"), + Position: 2, + Type: analysis.Ideographic, + }, + }, + }, + { + []byte("แยกคำภาษาไทยก็ทำได้นะจ้ะ"), + "th_TH", + analysis.TokenStream{ + { + Start: 0, + End: 9, + Term: []byte("แยก"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 9, + End: 15, + Term: []byte("คำ"), + Position: 2, + Type: analysis.AlphaNumeric, + }, + { + Start: 15, + End: 27, + Term: []byte("ภาษา"), + Position: 3, + Type: analysis.AlphaNumeric, + }, + { + Start: 27, + End: 36, + Term: []byte("ไทย"), + Position: 4, + Type: analysis.AlphaNumeric, + }, + { + Start: 36, + End: 42, + Term: []byte("ก็"), + Position: 5, + Type: analysis.AlphaNumeric, + }, + { + Start: 42, + End: 57, + Term: []byte("ทำได้"), + Position: 6, + Type: analysis.AlphaNumeric, + }, + { + Start: 57, + End: 63, + Term: []byte("นะ"), + Position: 7, + Type: analysis.AlphaNumeric, + }, + { + Start: 63, + End: 72, + Term: []byte("จ้ะ"), + Position: 8, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("age 25"), + "en_US", + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("age"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 4, + End: 6, + Term: []byte("25"), + Position: 2, + Type: analysis.Numeric, + }, + }, + }, + } + + for _, test := range tests { + tokenizer := NewUnicodeWordBoundaryCustomLocaleTokenizer(test.locale) + actual := tokenizer.Tokenize(test.input) + + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("Expected %v, got %v for %s", test.output, actual, string(test.input)) + } + } +} + +var sampleLargeInput = []byte(`There are three characteristics of liquids which are relevant to the discussion of a BLEVE: +If a liquid in a sealed container is boiled, the pressure inside the container increases. As the liquid changes to a gas it expands - this expansion in a vented container would cause the gas and liquid to take up more space. In a sealed container the gas and liquid are not able to take up more space and so the pressure rises. Pressurized vessels containing liquids can reach an equilibrium where the liquid stops boiling and the pressure stops rising. This occurs when no more heat is being added to the system (either because it has reached ambient temperature or has had a heat source removed). +The boiling temperature of a liquid is dependent on pressure - high pressures will yield high boiling temperatures, and low pressures will yield low boiling temperatures. A common simple experiment is to place a cup of water in a vacuum chamber, and then reduce the pressure in the chamber until the water boils. By reducing the pressure the water will boil even at room temperature. This works both ways - if the pressure is increased beyond normal atmospheric pressures, the boiling of hot water could be suppressed far beyond normal temperatures. The cooling system of a modern internal combustion engine is a real-world example. +When a liquid boils it turns into a gas. The resulting gas takes up far more space than the liquid did. +Typically, a BLEVE starts with a container of liquid which is held above its normal, atmospheric-pressure boiling temperature. Many substances normally stored as liquids, such as CO2, oxygen, and other similar industrial gases have boiling temperatures, at atmospheric pressure, far below room temperature. In the case of water, a BLEVE could occur if a pressurized chamber of water is heated far beyond the standard 100 °C (212 °F). That container, because the boiling water pressurizes it, is capable of holding liquid water at very high temperatures. +If the pressurized vessel, containing liquid at high temperature (which may be room temperature, depending on the substance) ruptures, the pressure which prevents the liquid from boiling is lost. If the rupture is catastrophic, where the vessel is immediately incapable of holding any pressure at all, then there suddenly exists a large mass of liquid which is at very high temperature and very low pressure. This causes the entire volume of liquid to instantaneously boil, which in turn causes an extremely rapid expansion. Depending on temperatures, pressures and the substance involved, that expansion may be so rapid that it can be classified as an explosion, fully capable of inflicting severe damage on its surroundings.`) + +func BenchmarkTokenizeEnglishText(b *testing.B) { + + tokenizer := NewUnicodeWordBoundaryCustomLocaleTokenizer("en_US") + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tokenizer.Tokenize(sampleLargeInput) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer.go new file mode 100644 index 00000000..7ea18805 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer.go @@ -0,0 +1,77 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package regexp_tokenizer + +import ( + "fmt" + "regexp" + "strconv" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "regexp" + +var IdeographRegexp = regexp.MustCompile(`\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}`) + +type RegexpTokenizer struct { + r *regexp.Regexp +} + +func NewRegexpTokenizer(r *regexp.Regexp) *RegexpTokenizer { + return &RegexpTokenizer{ + r: r, + } +} + +func (rt *RegexpTokenizer) Tokenize(input []byte) analysis.TokenStream { + matches := rt.r.FindAllIndex(input, -1) + rv := make(analysis.TokenStream, len(matches)) + for i, match := range matches { + matchBytes := input[match[0]:match[1]] + token := analysis.Token{ + Term: matchBytes, + Start: match[0], + End: match[1], + Position: i + 1, + Type: detectTokenType(matchBytes), + } + rv[i] = &token + } + return rv +} + +func RegexpTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + rval, ok := config["regexp"].(string) + if !ok { + return nil, fmt.Errorf("must specify regexp") + } + r, err := regexp.Compile(rval) + if err != nil { + return nil, fmt.Errorf("unable to build regexp tokenizer: %v", err) + } + return NewRegexpTokenizer(r), nil +} + +func init() { + registry.RegisterTokenizer(Name, RegexpTokenizerConstructor) +} + +func detectTokenType(termBytes []byte) analysis.TokenType { + if IdeographRegexp.Match(termBytes) { + return analysis.Ideographic + } + _, err := strconv.ParseFloat(string(termBytes), 64) + if err == nil { + return analysis.Numeric + } + return analysis.AlphaNumeric +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer_test.go new file mode 100644 index 00000000..c68e429e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer/regexp_tokenizer_test.go @@ -0,0 +1,115 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package regexp_tokenizer + +import ( + "reflect" + "regexp" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestBoundary(t *testing.T) { + + wordRegex := regexp.MustCompile(`\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}|\w+`) + + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + []byte("Hello World."), + analysis.TokenStream{ + { + Start: 0, + End: 5, + Term: []byte("Hello"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 6, + End: 11, + Term: []byte("World"), + Position: 2, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("こんにちは世界"), + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("こ"), + Position: 1, + Type: analysis.Ideographic, + }, + { + Start: 3, + End: 6, + Term: []byte("ん"), + Position: 2, + Type: analysis.Ideographic, + }, + { + Start: 6, + End: 9, + Term: []byte("に"), + Position: 3, + Type: analysis.Ideographic, + }, + { + Start: 9, + End: 12, + Term: []byte("ち"), + Position: 4, + Type: analysis.Ideographic, + }, + { + Start: 12, + End: 15, + Term: []byte("は"), + Position: 5, + Type: analysis.Ideographic, + }, + { + Start: 15, + End: 18, + Term: []byte("世"), + Position: 6, + Type: analysis.Ideographic, + }, + { + Start: 18, + End: 21, + Term: []byte("界"), + Position: 7, + Type: analysis.Ideographic, + }, + }, + }, + { + []byte(""), + analysis.TokenStream{}, + }, + } + + for _, test := range tests { + tokenizer := NewRegexpTokenizer(wordRegex) + actual := tokenizer.Tokenize(test.input) + + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("Expected %v, got %v for %s", test.output, actual, string(test.input)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token.go new file mode 100644 index 00000000..8c9f9002 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token.go @@ -0,0 +1,44 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package single_token + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "single" + +type SingleTokenTokenizer struct { +} + +func NewSingleTokenTokenizer() *SingleTokenTokenizer { + return &SingleTokenTokenizer{} +} + +func (t *SingleTokenTokenizer) Tokenize(input []byte) analysis.TokenStream { + return analysis.TokenStream{ + &analysis.Token{ + Term: input, + Position: 1, + Start: 0, + End: len(input), + Type: analysis.AlphaNumeric, + }, + } +} + +func SingleTokenTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + return NewSingleTokenTokenizer(), nil +} + +func init() { + registry.RegisterTokenizer(Name, SingleTokenTokenizerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token_test.go new file mode 100644 index 00000000..e64daef7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token/single_token_test.go @@ -0,0 +1,71 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package single_token + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func TestSingleTokenTokenizer(t *testing.T) { + + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + []byte("Hello World"), + analysis.TokenStream{ + { + Start: 0, + End: 11, + Term: []byte("Hello World"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("こんにちは世界"), + analysis.TokenStream{ + { + Start: 0, + End: 21, + Term: []byte("こんにちは世界"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("แยกคำภาษาไทยก็ทำได้นะจ้ะ"), + analysis.TokenStream{ + { + Start: 0, + End: 72, + Term: []byte("แยกคำภาษาไทยก็ทำได้นะจ้ะ"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + } + + for _, test := range tests { + tokenizer := NewSingleTokenTokenizer() + actual := tokenizer.Tokenize(test.input) + + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("Expected %v, got %v for %s", test.output, actual, string(test.input)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode.go new file mode 100644 index 00000000..9e7a4a0f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode.go @@ -0,0 +1,72 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package unicode + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/segment" +) + +const Name = "unicode" + +type UnicodeTokenizer struct { +} + +func NewUnicodeTokenizer() *UnicodeTokenizer { + return &UnicodeTokenizer{} +} + +func (rt *UnicodeTokenizer) Tokenize(input []byte) analysis.TokenStream { + + rv := make(analysis.TokenStream, 0) + + segmenter := segment.NewWordSegmenterDirect(input) + start := 0 + pos := 1 + for segmenter.Segment() { + segmentBytes := segmenter.Bytes() + end := start + len(segmentBytes) + if segmenter.Type() != segment.None { + token := analysis.Token{ + Term: segmentBytes, + Start: start, + End: end, + Position: pos, + Type: convertType(segmenter.Type()), + } + rv = append(rv, &token) + pos++ + } + start = end + + } + return rv +} + +func UnicodeTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + return NewUnicodeTokenizer(), nil +} + +func init() { + registry.RegisterTokenizer(Name, UnicodeTokenizerConstructor) +} + +func convertType(segmentWordType int) analysis.TokenType { + switch segmentWordType { + case segment.Ideo: + return analysis.Ideographic + case segment.Kana: + return analysis.Ideographic + case segment.Number: + return analysis.Numeric + } + return analysis.AlphaNumeric +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode_test.go new file mode 100644 index 00000000..1db6d0e7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode/unicode_test.go @@ -0,0 +1,197 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package unicode + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/segment" +) + +func TestUnicode(t *testing.T) { + + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + []byte("Hello World"), + analysis.TokenStream{ + { + Start: 0, + End: 5, + Term: []byte("Hello"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 6, + End: 11, + Term: []byte("World"), + Position: 2, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("steven's"), + analysis.TokenStream{ + { + Start: 0, + End: 8, + Term: []byte("steven's"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("こんにちは世界"), + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("こ"), + Position: 1, + Type: analysis.Ideographic, + }, + { + Start: 3, + End: 6, + Term: []byte("ん"), + Position: 2, + Type: analysis.Ideographic, + }, + { + Start: 6, + End: 9, + Term: []byte("に"), + Position: 3, + Type: analysis.Ideographic, + }, + { + Start: 9, + End: 12, + Term: []byte("ち"), + Position: 4, + Type: analysis.Ideographic, + }, + { + Start: 12, + End: 15, + Term: []byte("は"), + Position: 5, + Type: analysis.Ideographic, + }, + { + Start: 15, + End: 18, + Term: []byte("世"), + Position: 6, + Type: analysis.Ideographic, + }, + { + Start: 18, + End: 21, + Term: []byte("界"), + Position: 7, + Type: analysis.Ideographic, + }, + }, + }, + { + []byte("age 25"), + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("age"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 4, + End: 6, + Term: []byte("25"), + Position: 2, + Type: analysis.Numeric, + }, + }, + }, + { + []byte("カ"), + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("カ"), + Position: 1, + Type: analysis.Ideographic, + }, + }, + }, + } + + for _, test := range tests { + tokenizer := NewUnicodeTokenizer() + actual := tokenizer.Tokenize(test.input) + + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("Expected %v, got %v for %s", test.output, actual, string(test.input)) + } + } +} + +var sampleLargeInput = []byte(`There are three characteristics of liquids which are relevant to the discussion of a BLEVE: +If a liquid in a sealed container is boiled, the pressure inside the container increases. As the liquid changes to a gas it expands - this expansion in a vented container would cause the gas and liquid to take up more space. In a sealed container the gas and liquid are not able to take up more space and so the pressure rises. Pressurized vessels containing liquids can reach an equilibrium where the liquid stops boiling and the pressure stops rising. This occurs when no more heat is being added to the system (either because it has reached ambient temperature or has had a heat source removed). +The boiling temperature of a liquid is dependent on pressure - high pressures will yield high boiling temperatures, and low pressures will yield low boiling temperatures. A common simple experiment is to place a cup of water in a vacuum chamber, and then reduce the pressure in the chamber until the water boils. By reducing the pressure the water will boil even at room temperature. This works both ways - if the pressure is increased beyond normal atmospheric pressures, the boiling of hot water could be suppressed far beyond normal temperatures. The cooling system of a modern internal combustion engine is a real-world example. +When a liquid boils it turns into a gas. The resulting gas takes up far more space than the liquid did. +Typically, a BLEVE starts with a container of liquid which is held above its normal, atmospheric-pressure boiling temperature. Many substances normally stored as liquids, such as CO2, oxygen, and other similar industrial gases have boiling temperatures, at atmospheric pressure, far below room temperature. In the case of water, a BLEVE could occur if a pressurized chamber of water is heated far beyond the standard 100 °C (212 °F). That container, because the boiling water pressurizes it, is capable of holding liquid water at very high temperatures. +If the pressurized vessel, containing liquid at high temperature (which may be room temperature, depending on the substance) ruptures, the pressure which prevents the liquid from boiling is lost. If the rupture is catastrophic, where the vessel is immediately incapable of holding any pressure at all, then there suddenly exists a large mass of liquid which is at very high temperature and very low pressure. This causes the entire volume of liquid to instantaneously boil, which in turn causes an extremely rapid expansion. Depending on temperatures, pressures and the substance involved, that expansion may be so rapid that it can be classified as an explosion, fully capable of inflicting severe damage on its surroundings.`) + +func BenchmarkTokenizeEnglishText(b *testing.B) { + + tokenizer := NewUnicodeTokenizer() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tokenizer.Tokenize(sampleLargeInput) + } + +} + +func TestConvertType(t *testing.T) { + tests := []struct { + in int + out analysis.TokenType + }{ + { + segment.Ideo, analysis.Ideographic, + }, + { + segment.Kana, analysis.Ideographic, + }, + { + segment.Number, analysis.Numeric, + }, + { + segment.Letter, analysis.AlphaNumeric, + }, + } + + for _, test := range tests { + actual := convertType(test.in) + if actual != test.out { + t.Errorf("expected %d, got %d for %d", test.out, actual, test.in) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer.go new file mode 100644 index 00000000..753ea9cf --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer.go @@ -0,0 +1,30 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package whitespace_tokenizer + +import ( + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "whitespace" + +var whitespaceTokenizerRegexp = regexp.MustCompile(`\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}|[^\p{Z}\p{P}\p{C}\p{Han}\p{Hangul}\p{Hiragana}\p{Katakana}]+`) + +func TokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) { + return regexp_tokenizer.NewRegexpTokenizer(whitespaceTokenizerRegexp), nil +} + +func init() { + registry.RegisterTokenizer(Name, TokenizerConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer_test.go new file mode 100644 index 00000000..3aa12d19 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer/whitespace_tokenizer_test.go @@ -0,0 +1,150 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package whitespace_tokenizer + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer" +) + +func TestBoundary(t *testing.T) { + + tests := []struct { + input []byte + output analysis.TokenStream + }{ + { + []byte("Hello World."), + analysis.TokenStream{ + { + Start: 0, + End: 5, + Term: []byte("Hello"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 6, + End: 11, + Term: []byte("World"), + Position: 2, + Type: analysis.AlphaNumeric, + }, + }, + }, + { + []byte("こんにちは世界"), + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("こ"), + Position: 1, + Type: analysis.Ideographic, + }, + { + Start: 3, + End: 6, + Term: []byte("ん"), + Position: 2, + Type: analysis.Ideographic, + }, + { + Start: 6, + End: 9, + Term: []byte("に"), + Position: 3, + Type: analysis.Ideographic, + }, + { + Start: 9, + End: 12, + Term: []byte("ち"), + Position: 4, + Type: analysis.Ideographic, + }, + { + Start: 12, + End: 15, + Term: []byte("は"), + Position: 5, + Type: analysis.Ideographic, + }, + { + Start: 15, + End: 18, + Term: []byte("世"), + Position: 6, + Type: analysis.Ideographic, + }, + { + Start: 18, + End: 21, + Term: []byte("界"), + Position: 7, + Type: analysis.Ideographic, + }, + }, + }, + { + []byte(""), + analysis.TokenStream{}, + }, + { + []byte("abc界"), + analysis.TokenStream{ + { + Start: 0, + End: 3, + Term: []byte("abc"), + Position: 1, + Type: analysis.AlphaNumeric, + }, + { + Start: 3, + End: 6, + Term: []byte("界"), + Position: 2, + Type: analysis.Ideographic, + }, + }, + }, + } + + for _, test := range tests { + tokenizer := regexp_tokenizer.NewRegexpTokenizer(whitespaceTokenizerRegexp) + actual := tokenizer.Tokenize(test.input) + + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("Expected %v, got %v for %s", test.output, actual, string(test.input)) + } + } +} + +var sampleLargeInput = []byte(`There are three characteristics of liquids which are relevant to the discussion of a BLEVE: +If a liquid in a sealed container is boiled, the pressure inside the container increases. As the liquid changes to a gas it expands - this expansion in a vented container would cause the gas and liquid to take up more space. In a sealed container the gas and liquid are not able to take up more space and so the pressure rises. Pressurized vessels containing liquids can reach an equilibrium where the liquid stops boiling and the pressure stops rising. This occurs when no more heat is being added to the system (either because it has reached ambient temperature or has had a heat source removed). +The boiling temperature of a liquid is dependent on pressure - high pressures will yield high boiling temperatures, and low pressures will yield low boiling temperatures. A common simple experiment is to place a cup of water in a vacuum chamber, and then reduce the pressure in the chamber until the water boils. By reducing the pressure the water will boil even at room temperature. This works both ways - if the pressure is increased beyond normal atmospheric pressures, the boiling of hot water could be suppressed far beyond normal temperatures. The cooling system of a modern internal combustion engine is a real-world example. +When a liquid boils it turns into a gas. The resulting gas takes up far more space than the liquid did. +Typically, a BLEVE starts with a container of liquid which is held above its normal, atmospheric-pressure boiling temperature. Many substances normally stored as liquids, such as CO2, oxygen, and other similar industrial gases have boiling temperatures, at atmospheric pressure, far below room temperature. In the case of water, a BLEVE could occur if a pressurized chamber of water is heated far beyond the standard 100 °C (212 °F). That container, because the boiling water pressurizes it, is capable of holding liquid water at very high temperatures. +If the pressurized vessel, containing liquid at high temperature (which may be room temperature, depending on the substance) ruptures, the pressure which prevents the liquid from boiling is lost. If the rupture is catastrophic, where the vessel is immediately incapable of holding any pressure at all, then there suddenly exists a large mass of liquid which is at very high temperature and very low pressure. This causes the entire volume of liquid to instantaneously boil, which in turn causes an extremely rapid expansion. Depending on temperatures, pressures and the substance involved, that expansion may be so rapid that it can be classified as an explosion, fully capable of inflicting severe damage on its surroundings.`) + +func BenchmarkTokenizeEnglishText(b *testing.B) { + + tokenizer := regexp_tokenizer.NewRegexpTokenizer(whitespaceTokenizerRegexp) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tokenizer.Tokenize(sampleLargeInput) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/type.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/type.go new file mode 100644 index 00000000..0f32ece1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/type.go @@ -0,0 +1,85 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +import ( + "fmt" + "time" +) + +type CharFilter interface { + Filter([]byte) []byte +} + +type TokenType int + +const ( + AlphaNumeric TokenType = iota + Ideographic + Numeric + DateTime + Shingle + Single + Double +) + +type Token struct { + Start int `json:"start"` + End int `json:"end"` + Term []byte `json:"term"` + Position int `json:"position"` + Type TokenType `json:"type"` + KeyWord bool `json:"keyword"` +} + +func (t *Token) String() string { + return fmt.Sprintf("Start: %d End: %d Position: %d Token: %s Type: %d", t.Start, t.End, t.Position, string(t.Term), t.Type) +} + +type TokenStream []*Token + +type Tokenizer interface { + Tokenize([]byte) TokenStream +} + +type TokenFilter interface { + Filter(TokenStream) TokenStream +} + +type Analyzer struct { + CharFilters []CharFilter + Tokenizer Tokenizer + TokenFilters []TokenFilter +} + +func (a *Analyzer) Analyze(input []byte) TokenStream { + if a.CharFilters != nil { + for _, cf := range a.CharFilters { + input = cf.Filter(input) + } + } + tokens := a.Tokenizer.Tokenize(input) + if a.TokenFilters != nil { + for _, tf := range a.TokenFilters { + tokens = tf.Filter(tokens) + } + } + return tokens +} + +var ErrInvalidDateTime = fmt.Errorf("unable to parse datetime with any of the layouts") + +type DateTimeParser interface { + ParseDateTime(string) (time.Time, error) +} + +type ByteArrayConverter interface { + Convert([]byte) (interface{}, error) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util.go new file mode 100644 index 00000000..f15f08e4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util.go @@ -0,0 +1,69 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +import ( + "bytes" + "unicode/utf8" +) + +func DeleteRune(in []rune, pos int) []rune { + if pos >= len(in) { + return in + } + copy(in[pos:], in[pos+1:]) + return in[:len(in)-1] +} + +func InsertRune(in []rune, pos int, r rune) []rune { + // create a new slice 1 rune larger + rv := make([]rune, len(in)+1) + // copy the characters before the insert pos + copy(rv[0:pos], in[0:pos]) + // set the inserted rune + rv[pos] = r + // copy the characters after the insert pos + copy(rv[pos+1:], in[pos:]) + return rv +} + +func BuildTermFromRunes(runes []rune) []byte { + rv := make([]byte, 0, len(runes)*4) + for _, r := range runes { + runeBytes := make([]byte, utf8.RuneLen(r)) + utf8.EncodeRune(runeBytes, r) + rv = append(rv, runeBytes...) + } + return rv +} + +func TruncateRunes(input []byte, num int) []byte { + runes := bytes.Runes(input) + runes = runes[:len(runes)-num] + out := BuildTermFromRunes(runes) + return out +} + +func RunesEndsWith(input []rune, suffix string) bool { + inputLen := len(input) + suffixRunes := []rune(suffix) + suffixLen := len(suffixRunes) + if suffixLen > inputLen { + return false + } + + for i := suffixLen - 1; i >= 0; i-- { + if input[inputLen-(suffixLen-i)] != suffixRunes[i] { + return false + } + } + + return true +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util_test.go new file mode 100644 index 00000000..b426abfa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/util_test.go @@ -0,0 +1,71 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package analysis + +import ( + "reflect" + "testing" +) + +func TestDeleteRune(t *testing.T) { + tests := []struct { + in []rune + delPos int + out []rune + }{ + { + in: []rune{'a', 'b', 'c'}, + delPos: 1, + out: []rune{'a', 'c'}, + }, + } + + for _, test := range tests { + actual := DeleteRune(test.in, test.delPos) + if !reflect.DeepEqual(actual, test.out) { + t.Errorf("expected %#v, got %#v", test.out, actual) + } + } +} + +func TestInsertRune(t *testing.T) { + tests := []struct { + in []rune + insPos int + insRune rune + out []rune + }{ + { + in: []rune{'a', 'b', 'c'}, + insPos: 1, + insRune: 'x', + out: []rune{'a', 'x', 'b', 'c'}, + }, + { + in: []rune{'a', 'b', 'c'}, + insPos: 0, + insRune: 'x', + out: []rune{'x', 'a', 'b', 'c'}, + }, + { + in: []rune{'a', 'b', 'c'}, + insPos: 3, + insRune: 'x', + out: []rune{'a', 'b', 'c', 'x'}, + }, + } + + for _, test := range tests { + actual := InsertRune(test.in, test.insPos, test.insRune) + if !reflect.DeepEqual(actual, test.out) { + t.Errorf("expected %#v, got %#v", test.out, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config.go new file mode 100644 index 00000000..2a296265 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config.go @@ -0,0 +1,167 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "expvar" + "io/ioutil" + "log" + "time" + + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/custom_analyzer" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/keyword_analyzer" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/simple_analyzer" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/standard_analyzer" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/ignore" // token filters + + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/json" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/byte_array_converters/string" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/html_char_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/regexp_char_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/char_filters/zero_width_non_joiner" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/datetime_optional" // analyzers + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/datetime_parsers/flexible_go" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ar" // languages + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/bg" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ca" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cjk" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ckb" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/cs" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/da" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/de" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/el" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/en" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/es" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/eu" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fa" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fi" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/fr" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ga" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/gl" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hi" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hu" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/hy" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/id" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/in" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/it" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/nl" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/no" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/pt" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ro" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ru" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/sv" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/th" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/tr" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/apostrophe_filter" // kv stores + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/compound" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/edge_ngram_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/elision_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/keyword_marker_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/length_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/lower_case_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/ngram_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/shingle" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stop_tokens_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/truncate_token_filter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/unicode_normalize" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_map" // tokenizers + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/exception" // fragment formatters + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/single_token" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/unicode" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/whitespace_tokenizer" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb" // date time parsers + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down" // byte array converters + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi" + + // token maps + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple" // fragmenters + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple" // highlighters +) + +var bleveExpVar = expvar.NewMap("bleve") + +type configuration struct // char filters +{ + Cache *registry.Cache + DefaultHighlighter string + DefaultKVStore string + SlowSearchLogThreshold time.Duration + analysisQueue *upside_down.AnalysisQueue +} + +func newConfiguration() *configuration { + return &configuration{ + Cache: registry.NewCache(), + analysisQueue: upside_down.NewAnalysisQueue(4), + } +} + +// Config contains library level configuration +var Config *configuration + +func init() { + bootStart := time.Now() + + // build the default configuration + Config = newConfiguration() + + _, err := Config.Cache.DefineFragmentFormatter("highlightSpanHTML", + map[string]interface{}{ + "type": "html", + "before": ``, + "after": ``, + }) + if err != nil { + panic(err) + } + + _, err = Config.Cache.DefineHighlighter("html", + map[string]interface{}{ + "type": "simple", + "fragmenter": "simple", + "formatter": "highlightSpanHTML", + }) + if err != nil { + panic(err) + } + + _, err = Config.Cache.DefineHighlighter("ansi", + map[string]interface{}{ + "type": "simple", + "fragmenter": "simple", + "formatter": "ansi", + }) + if err != nil { + panic(err) + } + + // set the default highlighter + Config.DefaultHighlighter = "html" + + // default kv store + Config.DefaultKVStore = "boltdb" + + bootDuration := time.Since(bootStart) + bleveExpVar.Add("bootDuration", int64(bootDuration)) +} + +var logger = log.New(ioutil.Discard, "bleve", log.LstdFlags) + +// SetLog sets the logger used for logging +// by default log messages are sent to ioutil.Discard +func SetLog(l *log.Logger) { + logger = l +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_cld2.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_cld2.go new file mode 100644 index 00000000..413f1c77 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_cld2.go @@ -0,0 +1,20 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build cld2 full + +package bleve + +import ( + // cld2 token filter + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/detect_lang_analyzer" + + // detect language analyzer + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/cld2" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_cznicb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_cznicb.go new file mode 100644 index 00000000..9c267c09 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_cznicb.go @@ -0,0 +1,16 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build go1.4 + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_forestdb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_forestdb.go new file mode 100644 index 00000000..90ab4819 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_forestdb.go @@ -0,0 +1,16 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_icu.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_icu.go new file mode 100644 index 00000000..19ff4d6e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_icu.go @@ -0,0 +1,16 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build icu full + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/icu" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_kagome.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_kagome.go new file mode 100644 index 00000000..a188fcd8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_kagome.go @@ -0,0 +1,16 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build kagome full + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/ja" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_leveldb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_leveldb.go new file mode 100644 index 00000000..f33eb075 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_leveldb.go @@ -0,0 +1,21 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb" +) + +func init() { + // install leveldb as the default kv store + Config.DefaultKVStore = "leveldb" +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_metrics.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_metrics.go new file mode 100644 index 00000000..7e989adc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_metrics.go @@ -0,0 +1,16 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build debug + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_rocksdb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_rocksdb.go new file mode 100644 index 00000000..fc32c29c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_rocksdb.go @@ -0,0 +1,16 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/config_stemmer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_stemmer.go new file mode 100644 index 00000000..d55d39a0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/config_stemmer.go @@ -0,0 +1,17 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build libstemmer full + +package bleve + +import ( + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/language/porter" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/token_filters/stemmer_filter" +) diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/doc.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/doc.go new file mode 100644 index 00000000..017410ad --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/doc.go @@ -0,0 +1,33 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +/* +Package bleve is a library for indexing and searching text. + +Example Opening New Index, Indexing Data + + message := struct{ + Id: "example" + From: "marty.schoch@gmail.com", + Body: "bleve indexing is easy", + } + + mapping := bleve.NewIndexMapping() + index, _ := bleve.New("example.bleve", mapping) + index.Index(message.Id, message) + +Example Opening Existing Index, Searching Data + + index, _ := bleve.Open("example.bleve") + query := bleve.NewQueryStringQuery("bleve") + searchRequest := bleve.NewSearchRequest(query) + searchResult, _ := index.Search(searchRequest) + +*/ +package bleve diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/docs/bleve.png b/Godeps/_workspace/src/github.com/blevesearch/bleve/docs/bleve.png new file mode 100644 index 0000000000000000000000000000000000000000..c2227aea27728a63536b64cfb2f57e0e7bd81040 GIT binary patch literal 6727 zcmZ{n2UHVV_qUT6rHV8`niL^`KoW`|y%R#Onjk&2(53e#AiWm>0qLM3C@2U50i=o2 zi;DE#dv70j@Be-M?z-=+H8W@S-p|?lx96N$Nw|g@;yNKMApiilj#QM>y0}YSp7_@; zt}n5V#{d9AX{@ZQ22xg*NyEv(0&8my04QG1OmWxI{z3J$yH2RChn$6pZHLy2fT>SZ z@g`U^92uYi3Jr$1$z4^TB;$Nwrh@|_p0Z%%DT$s0nGO?dk!rLyYRbvajz-xKte4)~ z9!o!MLy!NMuNwYgx$Zk$1JF1L0ynv!fB^zID9W|vMtyRM&d>XxTckh|6c9IQVF5-Q z$bkk<>crF1iWOTc_ST>QX0;>S4H^*Vp>zLu79m;IYXCy|K|wJ;2=y!|NxPzjhVLBw zWha@FFO-*$Du*EVHOutpGTXhPIj-7{XQ_~x99nc2%_o7Zs9KG&bhgR7C~%JcGqwrK zJRdysIvr#>V0NFQzyIL53II--X7qI)l4BdrCr?SU7QO`n;3s_+{^Udwc_?g^1@I`e zoQVL3BTWm*hM!?)7uqe3HY>CbO?kPJnpG#mJXE@ODv4v@)B$AMD9@&g!t?$M|hO?Njk~uVdX!$VzvXbW|34+;-(Ptd0t>$EugXP*I<(3#hcaCN(?x zT78`fuyqwsIre<}cBrjk!sjVscB06Y6QHk4MbMgZRsVU21eUb}-hK=#fRR(nY=kni#%QeMLL`cGD+ z@nz1jd|qesM~p=J5%!ZR(k$9@d&IG3PHef{G6Mf#P(=_{3j9u5;`_xClRE5b&d1lpY_^)HxyNaq~GIHEv{5 zshUcHq^gN}l5PXQ9b(j!h%eQSf2CIeg-^FBCliNa1(Gq_#IxjsO61eyNb>1EMk~fY zp1E@EX^zRWTU4zy(@)V+lco<$hD?>L}9;i^y30jcy2Ob6$m=3-zM6th?bR!TX z%ZTRr{J=QY_)&T4+biEqRz&GZ+Hf>e^p1YjxAgh!@4W$6-58Fl4OnizJ_*_M_;h!S zay{rqqw|KT4|6@CKfV9$@mR*z2KG1tJ+MvC4dxUkR$EpbQd<0Z{L^5vCIQXBVs#gm zP*Ts&`lg(3W4=p&LefLj5-E|PtkhbpoN1MTI!J341Bf`JjybVI#0=qd3oT`+{)RQ1 z$%ySnf}}&5m1sF%-bGWFE!sz#q!!Ej*b10wW%>&|`>HEdD@A^q|AaFjgz}I36Bk={ z7#Hex2+Y~cAI);i($CV)R(#RA)&w^`;Mbxlh)RsAjf&kCnETj0-8~{$hBZ9@#F>0} z*Z!_gGE1^WGB7#zrHZb@Amw1@OS_lq18{4IwTbl)>*GP_tLW~cZuhM2Oe2BwnUkkW zOM8hNhFSs72pT?2W8I8p`5jhPeStfatm^&}yU-jP2)5{ZWy^s0uIAT*` z`Vpi&JQJCKjP6j?{ys3KV_ef+*-dOSX9W>>b+5K9xBM3x{aRt@g>bW2yHB2H#vvDx zcqA$^lWLU8hMNRVP(Dgkt5(~+N3zFq3_0e-6MyRQw2ox|yNeq~ZLsek+4906k$CK6cPVrDPXq1tMW6pr?NbPM7Tt>1Vz1D{VQMC zfypW8)a__=dw661X!uwid>{OpV1Y0ntN?z1CqcwVKz`K~+}sFktPNs>^%=414^V+* zPGsFe#0c&Y8{9l{z6IqLcnw+ctk(7L^Kb|An99q^ey&xFZSQMGL`G97Q@Ja2AX?-H z5vuau@~QI5sVHuA#f(CfUKCTII29w^O>b5=r;`1?QRS!8D^rBiYfygul!}#~PVZ++ zI=kP*88xCG-@Q%8$S_WN9!}9zGOO}t$LOQ`EOgZfBtM7-sq2fRC70IteM=cUyik7vQzxA(W%fG zZB93CA2Bwd`9ib2-q@;QeXdpJqm1Tc9Z%OI65AHro3^W?78Rw|BdIKgy}PEJQxQ|@ zY`+qg$I-qI4@bZ51+Uf>>=hilPq^W`{~BGa*+!+Aq78rayqPd4o&CC%yH!>DaHal% z$)m@{H?Xm0v6Xzq@9LDwtPz7nOZiKIw6W=PbxYn=tC>IBMur>4?fmG~3 zeLMZQ&Ea%nSJs>2)uIM}-p2#*eP-d!skQ^g^(PFwuqiu!?ia(1+&yAQ$1mIuVnVs3mtc>9=71nqb6 zo07m$5$y~BK<`|hK#u}RHvj<4iq%26pj1^vFb;N56Eg=>bEt=%<3%(8Am$-*F|;#x zF=6tsv$b~?@epVE9U*ctzBI#Fn0|-2*od>BR5h4n9h}UW?m-2ha25$dCMG5^Co>BX zEjfk1@rx&M7AqGQM-dpz-Q6AP&JT5PvV`#p3k$>Gd@w#fo{I<`XHR<<6AvDH=R1E* z@_+NlnLA^gu#PTR2YaT=c}+|mTwTOjSS}O&=lH8m7p%p9Gub=;E$c!c?9v0{g~DO~ zhM9X{{|9#I`Jb2>=0B<&U7c)yYcj*Y%x%r>%w4J&U3;vH1h3d{LH{)Wwx+x|0(KE+dt#c|C-@X>mS5r^F=hU9_F?vIqXGCf9ntw z5QF`z|!m5s5+QoEj;B+T+Ai-;JgANa3K+XUM9Hk<>3B>+<(OUQNg80 z*2&z&#lcC(!NFGIw+g$ zzLGLUo)}0+25u^)X{!60@&Q|60--0VHjqqthMC?$%PLF^93$GKy%zIC)NOswf-&(t zdo(L^G;K8V<4E26S9=zPMMcNw^=HTDHQsad9HvJ%ee#NM26b1ol*ztvsP)4dg{&oC zs;xh12<(o;$j9rQ-UC7=*wu1n<`}b`4SByl-f_(%c3}})K8;&??yeSe8cH`IK0LGE z%TjmrVY3 zrW-v%)U${vW&gUCI2q>-@***e>#bs)Nd_=@q=;yX!*G##p~0Y6vSSz3bZZqUcmumu zc%@|m+4x`=l~_jYSu{pE(USKKFdOyH8B!PjU*B+-)w?R`KN-Vvw;2#FIR3jXq$>T$R z$(BpcF|yQmz&V@q=GV4E)!|9<^yq)Dms&lKygSCjID0&{xv$sH2;UIUOnXS|JOL zp=VFv&`4JbpN#vEB*+zyei|^gie7rH;(!4&ul4a=t;c=vy4iPbB-{mBV(y%c?>aGQtjfSgZcIG(HQ~WCF72`hnx9PBBjaU7nKG@I zB&LGDD_*m+7YbrrQ8-xfbUKFXCqL2Tdkpg7U(;+4OKf9JM+Sjy$gzq6B%f$Xlq=%B zf1$ObrOUXVj1I>FT1bh&*u7L2J9GkR-4IDee|UScATer-n|}6ml15xc6YP!UR9dT! z&YGRDf?ySyGQNQo7=WP@s`AG=S3b7MX48jQ>M&TJ??F}!VNz0dF=mN-er&}Cwb#z( zv+@nIBY-Y5GaTETFOEk&>0V|%lNCnxC4tcARs)S-0;El`7K2B>mZdFO>>|#4M00O& z@m8g&u>N~lD@E4y{2bDwgIh}LX;BHVQ9{f2Ms?I!yF5bkgL(0*!>U4ko?WO+i-6Ez zdh!x-oK{i&+m4#Rw4szWElB^gxWyd=Np|gvq++k5#{=9(&$(4Anr#}4B8PO#*tf|o zGk1?Qb{F*7sN~AFK6lvC_dH+=ed3peL&+mU0BeV}#BL6GDMI`l8@dmg#9cVzae8V% zSnsr0R~-hywfbcTDixzJ>1`|mh3P99zEk}!%ilsOhC!HYEORA)TEnmxQ*lwSzP~HN z3kiJ7X92|;T_5Ke*rq!T8xn@7hOTpoH9s1h&U}ulCVFDzO?FQ?RqDgYlzrLz@UDVT zNaZ<}0Xa0f5k(*VLFlYFrQG{hv5$}7eTi~YFp_1J1ZGPw`%I$~N&HloP_VTfMZ=G& zO04+Vj=f%Fuyg<)Exz81)9u^MEcWyxvmQR7D$p(}R_|o?qL2$8d~rz4Mf%Z&W^B_) z>cD?~kgo}I|BlN6K1kFpcdE8xf>tapTP3BlKg|~iLXb##Z4lD4=Xtwvt)c2XfVKq# zS5k5vez6#ixHBA;^?4^to=AMTot~3UE8;^L_-zEcIUVA%MyzM(aWh^$W0GD9*u(U` zY(xs^Bz8iSrBJy_n_ND|78Upw4!La|75{b(u`k=r?5I<+i3Z1Lw|?bv%#K=liI_OG zD>f7uj|00k*~YYkgXy}N`n=@vkTI=}yYBv>(GUFH)M?(7`VuvcdRxu8iN%Jn zHt(3pa1#o(M@6FGVODq)#tX$AcrKO%8^IyGyn?ML^@~nXKjeHb6Z9rCiCDCWCp&j} z0-*#|_qo6DIDx=;zN=1PIdNj+AzAUOB&_T(f^oW!Vms;3Kd!Lz?H);i&*DIbW5TjK z!vQI8+LM>bX2e;dM@0l1`WZ?9qgx5(_XjDeZ#eBf;YReFrTRN1$2FVidpQC1485+C zNAD`y5XEmZi@7#0LZh)>G(X>()X9X&bz)NFGuraRxX!>IR$d5dtK6*OqYoJ=+7o+1 zEe^Xq@C|-IbbZWe4kmbzclFF8(8yq$%hoS4qcyFVeYW`PFaSX}*`2){`_QtN93!l`#plCGW1 z<&V$>&i9Fc?)S$93s>|amDQYCd#F(N!`eSu>}21g7=w)kb(P{VXF9OrL**W&lSw!m zuIfU#Rr)wG9bOo}*Wm1SbF?s8Tq}Mah#1^%^m>B3qV>A7=yQ)bl=ynv z7k62o(akc|YWO}P%++o2%hu@tD{lLl(D3%u;cKuXGbC^vw?Ps~PC=;-R|f6safdFi z*Tq^nbA4evqgn;2Gi$jef>_-HJzp*}@Y2c-y)LW^bhbk8@j+o1pNNX889q%S3E?^P zQW%N+5*U?-fi`Gm^XhY^|74h&XsHE`I^Lj-*g}tMvg#+29Asoke zC%roP713MbJDBay>i6WGO^GE&o(+q=ex42qP+nG?h)&@4zWNF9?%|I52P6e^)|Cyl zxNozp(xlpt`0l)wn#yG9p_R!;A()yWSddtU3r?<*dbfZvk*8q1!_h7UOkj3a-P<`9dPy}i&PNru(S>&c1zC0(W!fW#yxXE@$&AH$v6Zwd z5^m(0>0)g2j7_WGlnp+#ddmSGTBQUJoQmGG>A8(o#w=e!r?RU zxv+EFN=A;Z=olZP!^fVrdV(eApiizP{NT9u6<*+p&pIn#26}P7a-vk(z{~FEvLPAn z<|ZPF(*{p@8(hkn))n1YF_6}KsPaDI#E=4alZFH@l8D1ZV~H1-RiIXpRh7G4vb$Ke zB?EZ)>P`;ct9G4jfeG)N?Go3evMmL`Lp#NwkgGa<<${7 z!`qRBH?mg0i2~D*@QMI(@ob|KOa@;;5GgMDEj#LwymjOJ!zI4J`I8_rTyjRLB4*<- zLF5CQ_FWF(uVNDw#dyW^wY$fAA&E6A6T%G>V8=Tm~NB)mlK^cKhLYj%xW+<|#FS@p)zOw^4~d9UQO acc.out +for Dir in . $(find ./* -maxdepth 10 -type d ); +do + if ls $Dir/*.go &> /dev/null; + then + returnval=`go test -coverprofile=profile.out -covermode=count $Dir` + echo ${returnval} + if [[ ${returnval} != *FAIL* ]] + then + if [ -f profile.out ] + then + cat profile.out | grep -v "mode: count" >> acc.out + fi + else + exit 1 + fi + fi +done + +# collect integration test coverage +echo "mode: count" > integration-acc.out +INTPACKS=`go list ./... | grep -v utils | xargs | sed 's/ /,/g'` +returnval=`go test -coverpkg=$INTPACKS -coverprofile=profile.out -covermode=count ./test` +if [[ ${returnval} != *FAIL* ]] +then + if [ -f profile.out ] + then + cat profile.out | grep -v "mode: count" >> integration-acc.out + fi +else + exit 1 +fi + +cat acc.out integration-acc.out | go run docs/merge-coverprofile.go > merged.out + +if [ -n "$COVERALLS" ] +then + goveralls -service drone.io -coverprofile=merged.out -repotoken $COVERALLS +fi + +if [ -n "$COVERHTML" ] +then + go tool cover -html=merged.out +fi + +rm -rf ./profile.out +rm -rf ./acc.out +rm -rf ./integration-acc.out +rm -rf ./merged.out \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/document.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/document.go new file mode 100644 index 00000000..525ceb31 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/document.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "fmt" +) + +type Document struct { + ID string `json:"id"` + Fields []Field `json:"fields"` + CompositeFields []*CompositeField +} + +func NewDocument(id string) *Document { + return &Document{ + ID: id, + Fields: make([]Field, 0), + CompositeFields: make([]*CompositeField, 0), + } +} + +func (d *Document) AddField(f Field) *Document { + switch f := f.(type) { + case *CompositeField: + d.CompositeFields = append(d.CompositeFields, f) + default: + d.Fields = append(d.Fields, f) + } + return d +} + +func (d *Document) GoString() string { + fields := "" + for i, field := range d.Fields { + if i != 0 { + fields += ", " + } + fields += fmt.Sprintf("%#v", field) + } + compositeFields := "" + for i, field := range d.CompositeFields { + if i != 0 { + compositeFields += ", " + } + compositeFields += fmt.Sprintf("%#v", field) + } + return fmt.Sprintf("&document.Document{ID:%s, Fields: %s, CompositeFields: %s}", d.ID, fields, compositeFields) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field.go new file mode 100644 index 00000000..77323467 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field.go @@ -0,0 +1,22 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +type Field interface { + Name() string + ArrayPositions() []uint64 + Options() IndexingOptions + Analyze() (int, analysis.TokenFrequencies) + Value() []byte +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_composite.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_composite.go new file mode 100644 index 00000000..4ca6a4c1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_composite.go @@ -0,0 +1,86 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +const DefaultCompositeIndexingOptions = IndexField + +type CompositeField struct { + name string + includedFields map[string]bool + excludedFields map[string]bool + defaultInclude bool + options IndexingOptions + totalLength int + compositeFrequencies analysis.TokenFrequencies +} + +func NewCompositeField(name string, defaultInclude bool, include []string, exclude []string) *CompositeField { + return NewCompositeFieldWithIndexingOptions(name, defaultInclude, include, exclude, DefaultCompositeIndexingOptions) +} + +func NewCompositeFieldWithIndexingOptions(name string, defaultInclude bool, include []string, exclude []string, options IndexingOptions) *CompositeField { + rv := &CompositeField{ + name: name, + options: options, + defaultInclude: defaultInclude, + includedFields: make(map[string]bool, len(include)), + excludedFields: make(map[string]bool, len(exclude)), + } + + for _, i := range include { + rv.includedFields[i] = true + } + for _, e := range exclude { + rv.excludedFields[e] = true + } + + return rv +} + +func (c *CompositeField) Name() string { + return c.name +} + +func (c *CompositeField) ArrayPositions() []uint64 { + return []uint64{} +} + +func (c *CompositeField) Options() IndexingOptions { + return c.options +} + +func (c *CompositeField) Analyze() (int, analysis.TokenFrequencies) { + return c.totalLength, c.compositeFrequencies +} + +func (c *CompositeField) Value() []byte { + return []byte{} +} + +func (c *CompositeField) Compose(field string, length int, freq analysis.TokenFrequencies) { + shouldInclude := c.defaultInclude + _, fieldShouldBeIncluded := c.includedFields[field] + if fieldShouldBeIncluded { + shouldInclude = true + } + _, fieldShouldBeExcluded := c.excludedFields[field] + if fieldShouldBeExcluded { + shouldInclude = false + } + + if shouldInclude { + c.totalLength += length + c.compositeFrequencies = c.compositeFrequencies.MergeAll(field, freq) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_datetime.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_datetime.go new file mode 100644 index 00000000..b5520d65 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_datetime.go @@ -0,0 +1,130 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "fmt" + "math" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" +) + +const DefaultDateTimeIndexingOptions = StoreField | IndexField +const DefaultDateTimePrecisionStep uint = 4 + +var MinTimeRepresentable = time.Unix(0, math.MinInt64) +var MaxTimeRepresentable = time.Unix(0, math.MaxInt64) + +type DateTimeField struct { + name string + arrayPositions []uint64 + options IndexingOptions + value numeric_util.PrefixCoded +} + +func (n *DateTimeField) Name() string { + return n.name +} + +func (n *DateTimeField) ArrayPositions() []uint64 { + return n.arrayPositions +} + +func (n *DateTimeField) Options() IndexingOptions { + return n.options +} + +func (n *DateTimeField) Analyze() (int, analysis.TokenFrequencies) { + tokens := make(analysis.TokenStream, 0) + tokens = append(tokens, &analysis.Token{ + Start: 0, + End: len(n.value), + Term: n.value, + Position: 1, + Type: analysis.DateTime, + }) + + original, err := n.value.Int64() + if err == nil { + + shift := DefaultDateTimePrecisionStep + for shift < 64 { + shiftEncoded, err := numeric_util.NewPrefixCodedInt64(original, shift) + if err != nil { + break + } + token := analysis.Token{ + Start: 0, + End: len(shiftEncoded), + Term: shiftEncoded, + Position: 1, + Type: analysis.DateTime, + } + tokens = append(tokens, &token) + shift += DefaultDateTimePrecisionStep + } + } + + fieldLength := len(tokens) + tokenFreqs := analysis.TokenFrequency(tokens) + return fieldLength, tokenFreqs +} + +func (n *DateTimeField) Value() []byte { + return n.value +} + +func (n *DateTimeField) DateTime() (time.Time, error) { + i64, err := n.value.Int64() + if err != nil { + return time.Time{}, err + } + return time.Unix(0, i64).UTC(), nil +} + +func (n *DateTimeField) GoString() string { + return fmt.Sprintf("&document.DateField{Name:%s, Options: %s, Value: %s}", n.name, n.options, n.value) +} + +func NewDateTimeFieldFromBytes(name string, arrayPositions []uint64, value []byte) *DateTimeField { + return &DateTimeField{ + name: name, + arrayPositions: arrayPositions, + value: value, + options: DefaultDateTimeIndexingOptions, + } +} + +func NewDateTimeField(name string, arrayPositions []uint64, dt time.Time) (*DateTimeField, error) { + return NewDateTimeFieldWithIndexingOptions(name, arrayPositions, dt, DefaultDateTimeIndexingOptions) +} + +func NewDateTimeFieldWithIndexingOptions(name string, arrayPositions []uint64, dt time.Time, options IndexingOptions) (*DateTimeField, error) { + if canRepresent(dt) { + dtInt64 := dt.UnixNano() + prefixCoded := numeric_util.MustNewPrefixCodedInt64(dtInt64, 0) + return &DateTimeField{ + name: name, + arrayPositions: arrayPositions, + value: prefixCoded, + options: options, + }, nil + } + return nil, fmt.Errorf("cannot represent %s in this type", dt) +} + +func canRepresent(dt time.Time) bool { + if dt.Before(MinTimeRepresentable) || dt.After(MaxTimeRepresentable) { + return false + } + return true +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric.go new file mode 100644 index 00000000..49d97faa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric.go @@ -0,0 +1,116 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" +) + +const DefaultNumericIndexingOptions = StoreField | IndexField + +const DefaultPrecisionStep uint = 4 + +type NumericField struct { + name string + arrayPositions []uint64 + options IndexingOptions + value numeric_util.PrefixCoded +} + +func (n *NumericField) Name() string { + return n.name +} + +func (n *NumericField) ArrayPositions() []uint64 { + return n.arrayPositions +} + +func (n *NumericField) Options() IndexingOptions { + return n.options +} + +func (n *NumericField) Analyze() (int, analysis.TokenFrequencies) { + tokens := make(analysis.TokenStream, 0) + tokens = append(tokens, &analysis.Token{ + Start: 0, + End: len(n.value), + Term: n.value, + Position: 1, + Type: analysis.Numeric, + }) + + original, err := n.value.Int64() + if err == nil { + + shift := DefaultPrecisionStep + for shift < 64 { + shiftEncoded, err := numeric_util.NewPrefixCodedInt64(original, shift) + if err != nil { + break + } + token := analysis.Token{ + Start: 0, + End: len(shiftEncoded), + Term: shiftEncoded, + Position: 1, + Type: analysis.Numeric, + } + tokens = append(tokens, &token) + shift += DefaultPrecisionStep + } + } + + fieldLength := len(tokens) + tokenFreqs := analysis.TokenFrequency(tokens) + return fieldLength, tokenFreqs +} + +func (n *NumericField) Value() []byte { + return n.value +} + +func (n *NumericField) Number() (float64, error) { + i64, err := n.value.Int64() + if err != nil { + return 0.0, err + } + return numeric_util.Int64ToFloat64(i64), nil +} + +func (n *NumericField) GoString() string { + return fmt.Sprintf("&document.NumericField{Name:%s, Options: %s, Value: %s}", n.name, n.options, n.value) +} + +func NewNumericFieldFromBytes(name string, arrayPositions []uint64, value []byte) *NumericField { + return &NumericField{ + name: name, + arrayPositions: arrayPositions, + value: value, + options: DefaultNumericIndexingOptions, + } +} + +func NewNumericField(name string, arrayPositions []uint64, number float64) *NumericField { + return NewNumericFieldWithIndexingOptions(name, arrayPositions, number, DefaultNumericIndexingOptions) +} + +func NewNumericFieldWithIndexingOptions(name string, arrayPositions []uint64, number float64, options IndexingOptions) *NumericField { + numberInt64 := numeric_util.Float64ToInt64(number) + prefixCoded := numeric_util.MustNewPrefixCodedInt64(numberInt64, 0) + return &NumericField{ + name: name, + arrayPositions: arrayPositions, + value: prefixCoded, + options: options, + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric_test.go new file mode 100644 index 00000000..df40c588 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_numeric_test.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "testing" +) + +func TestNumericField(t *testing.T) { + nf := NewNumericField("age", []uint64{}, 3.4) + numTokens, tokenFreqs := nf.Analyze() + if numTokens != 16 { + t.Errorf("expected 16 tokens") + } + if len(tokenFreqs) != 16 { + t.Errorf("expected 16 token freqs") + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_text.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_text.go new file mode 100644 index 00000000..deb2761a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/field_text.go @@ -0,0 +1,106 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +const DefaultTextIndexingOptions = IndexField + +type TextField struct { + name string + arrayPositions []uint64 + options IndexingOptions + analyzer *analysis.Analyzer + value []byte +} + +func (t *TextField) Name() string { + return t.name +} + +func (t *TextField) ArrayPositions() []uint64 { + return t.arrayPositions +} + +func (t *TextField) Options() IndexingOptions { + return t.options +} + +func (t *TextField) Analyze() (int, analysis.TokenFrequencies) { + var tokens analysis.TokenStream + if t.analyzer != nil { + bytesToAnalyze := t.Value() + if t.options.IsStored() { + // need to copy + bytesCopied := make([]byte, len(bytesToAnalyze)) + copy(bytesCopied, bytesToAnalyze) + bytesToAnalyze = bytesCopied + } + tokens = t.analyzer.Analyze(bytesToAnalyze) + } else { + tokens = analysis.TokenStream{ + &analysis.Token{ + Start: 0, + End: len(t.value), + Term: t.value, + Position: 1, + Type: analysis.AlphaNumeric, + }, + } + } + fieldLength := len(tokens) // number of tokens in this doc field + tokenFreqs := analysis.TokenFrequency(tokens) + return fieldLength, tokenFreqs +} + +func (t *TextField) Value() []byte { + return t.value +} + +func (t *TextField) GoString() string { + return fmt.Sprintf("&document.TextField{Name:%s, Options: %s, Analyzer: %s, Value: %s}", t.name, t.options, t.analyzer, t.value) +} + +func NewTextField(name string, arrayPositions []uint64, value []byte) *TextField { + return NewTextFieldWithIndexingOptions(name, arrayPositions, value, DefaultTextIndexingOptions) +} + +func NewTextFieldWithIndexingOptions(name string, arrayPositions []uint64, value []byte, options IndexingOptions) *TextField { + return &TextField{ + name: name, + arrayPositions: arrayPositions, + options: options, + value: value, + } +} + +func NewTextFieldWithAnalyzer(name string, arrayPositions []uint64, value []byte, analyzer *analysis.Analyzer) *TextField { + return &TextField{ + name: name, + arrayPositions: arrayPositions, + options: DefaultTextIndexingOptions, + analyzer: analyzer, + value: value, + } +} + +func NewTextFieldCustom(name string, arrayPositions []uint64, value []byte, options IndexingOptions, analyzer *analysis.Analyzer) *TextField { + return &TextField{ + name: name, + arrayPositions: arrayPositions, + options: options, + analyzer: analyzer, + value: value, + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options.go new file mode 100644 index 00000000..63c4c7c9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options.go @@ -0,0 +1,50 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +type IndexingOptions int + +const ( + IndexField IndexingOptions = 1 << iota + StoreField + IncludeTermVectors +) + +func (o IndexingOptions) IsIndexed() bool { + return o&IndexField != 0 +} + +func (o IndexingOptions) IsStored() bool { + return o&StoreField != 0 +} + +func (o IndexingOptions) IncludeTermVectors() bool { + return o&IncludeTermVectors != 0 +} + +func (o IndexingOptions) String() string { + rv := "" + if o.IsIndexed() { + rv += "INDEXED" + } + if o.IsStored() { + if rv != "" { + rv += ", " + } + rv += "STORE" + } + if o.IncludeTermVectors() { + if rv != "" { + rv += ", " + } + rv += "TV" + } + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options_test.go new file mode 100644 index 00000000..3357de32 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/document/indexing_options_test.go @@ -0,0 +1,69 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package document + +import ( + "testing" +) + +func TestIndexingOptions(t *testing.T) { + tests := []struct { + options IndexingOptions + isIndexed bool + isStored bool + includeTermVectors bool + }{ + { + options: IndexField | StoreField | IncludeTermVectors, + isIndexed: true, + isStored: true, + includeTermVectors: true, + }, + { + options: IndexField | IncludeTermVectors, + isIndexed: true, + isStored: false, + includeTermVectors: true, + }, + { + options: StoreField | IncludeTermVectors, + isIndexed: false, + isStored: true, + includeTermVectors: true, + }, + { + options: IndexField, + isIndexed: true, + isStored: false, + includeTermVectors: false, + }, + { + options: StoreField, + isIndexed: false, + isStored: true, + includeTermVectors: false, + }, + } + + for _, test := range tests { + actuallyIndexed := test.options.IsIndexed() + if actuallyIndexed != test.isIndexed { + t.Errorf("expected indexed to be %v, got %v for %d", test.isIndexed, actuallyIndexed, test.options) + } + actuallyStored := test.options.IsStored() + if actuallyStored != test.isStored { + t.Errorf("expected stored to be %v, got %v for %d", test.isStored, actuallyStored, test.options) + } + actuallyIncludeTermVectors := test.options.IncludeTermVectors() + if actuallyIncludeTermVectors != test.includeTermVectors { + t.Errorf("expected includeTermVectors to be %v, got %v for %d", test.includeTermVectors, actuallyIncludeTermVectors, test.options) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/error.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/error.go new file mode 100644 index 00000000..52d845e3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/error.go @@ -0,0 +1,51 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +// Constant Error values which can be compared to determine the type of error +const ( + ErrorIndexPathExists Error = iota + ErrorIndexPathDoesNotExist + ErrorIndexMetaMissing + ErrorIndexMetaCorrupt + ErrorDisjunctionFewerThanMinClauses + ErrorBooleanQueryNeedsMustOrShould + ErrorNumericQueryNoBounds + ErrorPhraseQueryNoTerms + ErrorUnknownQueryType + ErrorUnknownStorageType + ErrorIndexClosed + ErrorAliasMulti + ErrorAliasEmpty +) + +// Error represents a more strongly typed bleve error for detecting +// and handling specific types of errors. +type Error int + +func (e Error) Error() string { + return errorMessages[int(e)] +} + +var errorMessages = map[int]string{ + int(ErrorIndexPathExists): "cannot create new index, path already exists", + int(ErrorIndexPathDoesNotExist): "cannot open index, path does not exist", + int(ErrorIndexMetaMissing): "cannot open index, metadata missing", + int(ErrorIndexMetaCorrupt): "cannot open index, metadata corrupt", + int(ErrorDisjunctionFewerThanMinClauses): "disjunction query has fewer than the minimum number of clauses to satisfy", + int(ErrorBooleanQueryNeedsMustOrShould): "boolean query must contain at least one must or should clause", + int(ErrorNumericQueryNoBounds): "numeric range query must specify min or max", + int(ErrorPhraseQueryNoTerms): "phrase query must contain at least one term", + int(ErrorUnknownQueryType): "unknown query type", + int(ErrorUnknownStorageType): "unknown storage type", + int(ErrorIndexClosed): "index is closed", + int(ErrorAliasMulti): "cannot perform single index operation on multiple index alias", + int(ErrorAliasEmpty): "cannot perform operation on empty alias", +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/examples_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/examples_test.go new file mode 100644 index 00000000..6abef9aa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/examples_test.go @@ -0,0 +1,485 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "fmt" + "os" + "testing" + "time" +) + +var mapping *IndexMapping +var example_index Index +var err error + +func TestMain(m *testing.M) { + err = os.RemoveAll("path_to_index") + if err != nil { + panic(err) + } + toRun := m.Run() + err = os.RemoveAll("path_to_index") + if err != nil { + panic(err) + } + os.Exit(toRun) +} + +func ExampleNew() { + mapping = NewIndexMapping() + example_index, err = New("path_to_index", mapping) + if err != nil { + panic(err) + } + count, err := example_index.DocCount() + if err != nil { + panic(err) + } + + fmt.Println(count) + // Output: + // 0 +} + +func ExampleIndex_indexing() { + data := struct { + Name string + Created time.Time + }{Name: "named one", Created: time.Now()} + data2 := struct { + Name string + Created time.Time + }{Name: "great nameless one", Created: time.Now()} + + // index some data + err = example_index.Index("document id 1", data) + if err != nil { + panic(err) + } + err = example_index.Index("document id 2", data2) + if err != nil { + panic(err) + } + + // 2 documents have been indexed + count, err := example_index.DocCount() + if err != nil { + panic(err) + } + + fmt.Println(count) + // Output: + // 2 +} + +// Examples for query related functions + +func ExampleNewMatchQuery() { + // finds documents with fields fully matching the given query text + query := NewMatchQuery("named one") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 1 +} + +func ExampleNewMatchAllQuery() { + // finds all documents in the index + query := NewMatchAllQuery() + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(len(searchResults.Hits)) + // Output: + // 2 +} + +func ExampleNewMatchNoneQuery() { + // matches no documents in the index + query := NewMatchNoneQuery() + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(len(searchResults.Hits)) + // Output: + // 0 +} + +func ExampleNewMatchPhraseQuery() { + // finds all documents with the given phrase in the index + query := NewMatchPhraseQuery("nameless one") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 2 +} + +func ExampleNewNumericRangeQuery() { + value1 := float64(11) + value2 := float64(100) + data := struct{ Priority float64 }{Priority: float64(15)} + data2 := struct{ Priority float64 }{Priority: float64(10)} + + err = example_index.Index("document id 3", data) + if err != nil { + panic(err) + } + err = example_index.Index("document id 4", data2) + if err != nil { + panic(err) + } + + query := NewNumericRangeQuery(&value1, &value2) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 3 +} + +func ExampleNewNumericRangeInclusiveQuery() { + value1 := float64(10) + value2 := float64(100) + v1incl := false + v2incl := false + + query := NewNumericRangeInclusiveQuery(&value1, &value2, &v1incl, &v2incl) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 3 +} + +func ExampleNewPhraseQuery() { + // finds all documents with the given phrases in the given field in the index + query := NewPhraseQuery([]string{"nameless", "one"}, "Name") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 2 +} + +func ExampleNewPrefixQuery() { + // finds all documents with terms having the given prefix in the index + query := NewPrefixQuery("name") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(len(searchResults.Hits)) + // Output: + // 2 +} + +func ExampleNewQueryStringQuery() { + query := NewQueryStringQuery("+one -great") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 1 +} + +func ExampleNewTermQuery() { + query := NewTermQuery("great") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 2 +} + +func ExampleNewFacetRequest() { + facet := NewFacetRequest("Name", 1) + query := NewMatchAllQuery() + searchRequest := NewSearchRequest(query) + searchRequest.AddFacet("facet name", facet) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + // total number of terms + fmt.Println(searchResults.Facets["facet name"].Total) + // numer of docs with no value for this field + fmt.Println(searchResults.Facets["facet name"].Missing) + // term with highest occurences in field name + fmt.Println(searchResults.Facets["facet name"].Terms[0].Term) + // Output: + // 5 + // 2 + // one +} + +func ExampleFacetRequest_AddDateTimeRange() { + facet := NewFacetRequest("Created", 1) + facet.AddDateTimeRange("range name", time.Unix(0, 0), time.Now()) + query := NewMatchAllQuery() + searchRequest := NewSearchRequest(query) + searchRequest.AddFacet("facet name", facet) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + // dates in field Created since starting of unix time till now + fmt.Println(searchResults.Facets["facet name"].DateRanges[0].Count) + // Output: + // 2 +} + +func ExampleFacetRequest_AddNumericRange() { + value1 := float64(11) + + facet := NewFacetRequest("Priority", 1) + facet.AddNumericRange("range name", &value1, nil) + query := NewMatchAllQuery() + searchRequest := NewSearchRequest(query) + searchRequest.AddFacet("facet name", facet) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + // number documents with field Priority in the given range + fmt.Println(searchResults.Facets["facet name"].NumericRanges[0].Count) + // Output: + // 1 +} + +func ExampleNewHighlight() { + query := NewMatchQuery("nameless") + searchRequest := NewSearchRequest(query) + searchRequest.Highlight = NewHighlight() + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].Fragments["Name"][0]) + // Output: + // great nameless one +} + +func ExampleNewHighlightWithStyle() { + query := NewMatchQuery("nameless") + searchRequest := NewSearchRequest(query) + searchRequest.Highlight = NewHighlightWithStyle("ansi") + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].Fragments["Name"][0]) + // Output: + // great nameless one +} + +func ExampleSearchRequest_AddFacet() { + facet := NewFacetRequest("Name", 1) + query := NewMatchAllQuery() + searchRequest := NewSearchRequest(query) + searchRequest.AddFacet("facet name", facet) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + // total number of terms + fmt.Println(searchResults.Facets["facet name"].Total) + // numer of docs with no value for this field + fmt.Println(searchResults.Facets["facet name"].Missing) + // term with highest occurences in field name + fmt.Println(searchResults.Facets["facet name"].Terms[0].Term) + // Output: + // 5 + // 2 + // one +} + +func ExampleNewSearchRequest() { + // finds documents with fields fully matching the given query text + query := NewMatchQuery("named one") + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 1 +} + +func ExampleNewBooleanQuery() { + must := make([]Query, 1) + mustNot := make([]Query, 1) + must[0] = NewMatchQuery("one") + mustNot[0] = NewMatchQuery("great") + query := NewBooleanQuery(must, nil, mustNot) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 1 +} + +func ExampleNewBooleanQueryMinShould() { + should := make([]Query, 2) + should[0] = NewMatchQuery("great") + should[1] = NewMatchQuery("one") + query := NewBooleanQueryMinShould(nil, should, nil, float64(2)) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 2 +} + +func ExampleNewConjunctionQuery() { + conjuncts := make([]Query, 2) + conjuncts[0] = NewMatchQuery("great") + conjuncts[1] = NewMatchQuery("one") + query := NewConjunctionQuery(conjuncts) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(searchResults.Hits[0].ID) + // Output: + // document id 2 +} + +func ExampleNewDisjunctionQuery() { + disjuncts := make([]Query, 2) + disjuncts[0] = NewMatchQuery("great") + disjuncts[1] = NewMatchQuery("named") + query := NewDisjunctionQuery(disjuncts) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(len(searchResults.Hits)) + // Output: + // 2 +} + +func ExampleNewDisjunctionQueryMin() { + disjuncts := make([]Query, 2) + disjuncts[0] = NewMatchQuery("great") + disjuncts[1] = NewMatchQuery("named") + query := NewDisjunctionQueryMin(disjuncts, float64(2)) + searchRequest := NewSearchRequest(query) + searchResults, err := example_index.Search(searchRequest) + if err != nil { + panic(err) + } + + fmt.Println(len(searchResults.Hits)) + // Output: + // 0 +} + +// Examples for Mapping related functions + +func ExampleDocumentMapping_AddSubDocumentMapping() { + // adds a document mapping for a property in a document + // useful for mapping nested documents + documentMapping := NewDocumentMapping() + subDocumentMapping := NewDocumentMapping() + documentMapping.AddSubDocumentMapping("Property", subDocumentMapping) + + fmt.Println(len(documentMapping.Properties)) + // Output: + // 1 +} + +func ExampleDocumentMapping_AddFieldMapping() { + // you can only add field mapping to those properties which already have a document mapping + documentMapping := NewDocumentMapping() + subDocumentMapping := NewDocumentMapping() + documentMapping.AddSubDocumentMapping("Property", subDocumentMapping) + + fieldMapping := NewTextFieldMapping() + fieldMapping.Analyzer = "en" + subDocumentMapping.AddFieldMapping(fieldMapping) + + fmt.Println(len(documentMapping.Properties["Property"].Fields)) + // Output: + // 1 +} + +func ExampleDocumentMapping_AddFieldMappingsAt() { + // you can only add field mapping to those properties which already have a document mapping + documentMapping := NewDocumentMapping() + subDocumentMapping := NewDocumentMapping() + documentMapping.AddSubDocumentMapping("NestedProperty", subDocumentMapping) + + fieldMapping := NewTextFieldMapping() + fieldMapping.Analyzer = "en" + documentMapping.AddFieldMappingsAt("NestedProperty", fieldMapping) + + fmt.Println(len(documentMapping.Properties["NestedProperty"].Fields)) + // Output: + // 1 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/alias.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/alias.go new file mode 100644 index 00000000..4bd5d826 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/alias.go @@ -0,0 +1,65 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +type AliasAction struct { + Alias string `json:"alias"` + AddIndexes []string `json:"add"` + RemoveIndexes []string `json:"remove"` +} + +type AliasHandler struct{} + +func NewAliasHandler() *AliasHandler { + return &AliasHandler{} +} + +func (h *AliasHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + + // read the request body + requestBody, err := ioutil.ReadAll(req.Body) + if err != nil { + showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400) + return + } + + var aliasAction AliasAction + // interpret request body as alias actions + if len(requestBody) > 0 { + err := json.Unmarshal(requestBody, &aliasAction) + if err != nil { + showError(w, req, fmt.Sprintf("error parsing alias actions: %v", err), 400) + return + } + } else { + showError(w, req, "request body must contain alias actions", 400) + return + } + + err = UpdateAlias(aliasAction.Alias, aliasAction.AddIndexes, aliasAction.RemoveIndexes) + if err != nil { + showError(w, req, fmt.Sprintf("error updating alias: %v", err), 400) + return + } + + rv := struct { + Status string `json:"status"` + }{ + Status: "ok", + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/debug.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/debug.go new file mode 100644 index 00000000..7109515f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/debug.go @@ -0,0 +1,74 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down" +) + +// DebugDocumentHandler allows you to debug the index content +// for a given document id. +type DebugDocumentHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc + DocIDLookup varLookupFunc +} + +func NewDebugDocumentHandler(defaultIndexName string) *DebugDocumentHandler { + return &DebugDocumentHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *DebugDocumentHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + // find the docID + var docID string + if h.DocIDLookup != nil { + docID = h.DocIDLookup(req) + } + + rv := make([]interface{}, 0) + rowChan := index.DumpDoc(docID) + for row := range rowChan { + switch row := row.(type) { + case error: + showError(w, req, fmt.Sprintf("error debugging document: %v", row), 500) + return + case upside_down.UpsideDownCouchRow: + tmp := struct { + Key []byte `json:"key"` + Val []byte `json:"val"` + }{ + Key: row.Key(), + Val: row.Value(), + } + rv = append(rv, tmp) + } + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_count.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_count.go new file mode 100644 index 00000000..2318190c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_count.go @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" +) + +type DocCountHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc +} + +func NewDocCountHandler(defaultIndexName string) *DocCountHandler { + return &DocCountHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *DocCountHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + docCount, err := index.DocCount() + if err != nil { + showError(w, req, fmt.Sprintf("error counting docs: %v", err), 500) + return + } + rv := struct { + Status string `json:"status"` + Count uint64 `json:"count"` + }{ + Status: "ok", + Count: docCount, + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_delete.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_delete.go new file mode 100644 index 00000000..0c136c21 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_delete.go @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" +) + +type DocDeleteHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc + DocIDLookup varLookupFunc +} + +func NewDocDeleteHandler(defaultIndexName string) *DocDeleteHandler { + return &DocDeleteHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *DocDeleteHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + // find the doc id + var docID string + if h.DocIDLookup != nil { + docID = h.DocIDLookup(req) + } + if docID == "" { + showError(w, req, "document id cannot be empty", 400) + return + } + + err := index.Delete(docID) + if err != nil { + showError(w, req, fmt.Sprintf("error deleting document '%s': %v", docID, err), 500) + return + } + + rv := struct { + Status string `json:"status"` + }{ + Status: "ok", + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_get.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_get.go new file mode 100644 index 00000000..890e4250 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_get.go @@ -0,0 +1,107 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" +) + +type DocGetHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc + DocIDLookup varLookupFunc +} + +func NewDocGetHandler(defaultIndexName string) *DocGetHandler { + return &DocGetHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *DocGetHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + // find the doc id + var docID string + if h.DocIDLookup != nil { + docID = h.DocIDLookup(req) + } + if docID == "" { + showError(w, req, "document id cannot be empty", 400) + return + } + + doc, err := index.Document(docID) + if err != nil { + showError(w, req, fmt.Sprintf("error deleting document '%s': %v", docID, err), 500) + return + } + if doc == nil { + showError(w, req, fmt.Sprintf("no such document '%s'", docID), 404) + return + } + + rv := struct { + ID string `json:"id"` + Fields map[string]interface{} `json:"fields"` + }{ + ID: docID, + Fields: map[string]interface{}{}, + } + for _, field := range doc.Fields { + var newval interface{} + switch field := field.(type) { + case *document.TextField: + newval = string(field.Value()) + case *document.NumericField: + n, err := field.Number() + if err == nil { + newval = n + } + case *document.DateTimeField: + d, err := field.DateTime() + if err == nil { + newval = d.Format(time.RFC3339Nano) + } + } + existing, existed := rv.Fields[field.Name()] + if existed { + switch existing := existing.(type) { + case []interface{}: + rv.Fields[field.Name()] = append(existing, newval) + case interface{}: + arr := make([]interface{}, 2) + arr[0] = existing + arr[1] = newval + rv.Fields[field.Name()] = arr + } + } else { + rv.Fields[field.Name()] = newval + } + } + + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_index.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_index.go new file mode 100644 index 00000000..d076417f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/doc_index.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "io/ioutil" + "net/http" +) + +type DocIndexHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc + DocIDLookup varLookupFunc +} + +func NewDocIndexHandler(defaultIndexName string) *DocIndexHandler { + return &DocIndexHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *DocIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + // find the doc id + var docID string + if h.DocIDLookup != nil { + docID = h.DocIDLookup(req) + } + if docID == "" { + showError(w, req, "document id cannot be empty", 400) + return + } + + // read the request body + requestBody, err := ioutil.ReadAll(req.Body) + if err != nil { + showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400) + return + } + + err = index.Index(docID, requestBody) + if err != nil { + showError(w, req, fmt.Sprintf("error indexing document '%s': %v", docID, err), 500) + return + } + + rv := struct { + Status string `json:"status"` + }{ + Status: "ok", + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/fields.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/fields.go new file mode 100644 index 00000000..dd3afba2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/fields.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" +) + +type ListFieldsHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc +} + +func NewListFieldsHandler(defaultIndexName string) *ListFieldsHandler { + return &ListFieldsHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *ListFieldsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + fields, err := index.Fields() + if err != nil { + showError(w, req, fmt.Sprintf("error: %v", err), 500) + return + } + + fieldsResponse := struct { + Fields []string `json:"fields"` + }{ + Fields: fields, + } + + // encode the response + mustEncode(w, fieldsResponse) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/handlers_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/handlers_test.go new file mode 100644 index 00000000..492f9bb5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/handlers_test.go @@ -0,0 +1,704 @@ +package http + +import ( + "bytes" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "os" + "reflect" + "testing" +) + +func docIDLookup(req *http.Request) string { + return req.FormValue("docID") +} + +func indexNameLookup(req *http.Request) string { + return req.FormValue("indexName") +} + +func TestHandlers(t *testing.T) { + + basePath := "testbase" + err := os.MkdirAll(basePath, 0700) + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.RemoveAll(basePath) + if err != nil { + t.Fatal(err) + } + }() + + createIndexHandler := NewCreateIndexHandler(basePath) + createIndexHandler.IndexNameLookup = indexNameLookup + + getIndexHandler := NewGetIndexHandler() + getIndexHandler.IndexNameLookup = indexNameLookup + + deleteIndexHandler := NewDeleteIndexHandler(basePath) + deleteIndexHandler.IndexNameLookup = indexNameLookup + + listIndexesHandler := NewListIndexesHandler() + + docIndexHandler := NewDocIndexHandler("") + docIndexHandler.IndexNameLookup = indexNameLookup + docIndexHandler.DocIDLookup = docIDLookup + + docCountHandler := NewDocCountHandler("") + docCountHandler.IndexNameLookup = indexNameLookup + + docGetHandler := NewDocGetHandler("") + docGetHandler.IndexNameLookup = indexNameLookup + docGetHandler.DocIDLookup = docIDLookup + + docDeleteHandler := NewDocDeleteHandler("") + docDeleteHandler.IndexNameLookup = indexNameLookup + docDeleteHandler.DocIDLookup = docIDLookup + + searchHandler := NewSearchHandler("") + searchHandler.IndexNameLookup = indexNameLookup + + listFieldsHandler := NewListFieldsHandler("") + listFieldsHandler.IndexNameLookup = indexNameLookup + + debugHandler := NewDebugDocumentHandler("") + debugHandler.IndexNameLookup = indexNameLookup + debugHandler.DocIDLookup = docIDLookup + + aliasHandler := NewAliasHandler() + + tests := []struct { + Desc string + Handler http.Handler + Path string + Method string + Params url.Values + Body []byte + Status int + ResponseBody []byte + ResponseMatch map[string]bool + }{ + { + Desc: "create index", + Handler: createIndexHandler, + Path: "/create", + Method: "PUT", + Params: url.Values{"indexName": []string{"ti1"}}, + Body: []byte("{}"), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "create existing index", + Handler: createIndexHandler, + Path: "/create", + Method: "PUT", + Params: url.Values{"indexName": []string{"ti1"}}, + Body: []byte("{}"), + Status: http.StatusInternalServerError, + ResponseMatch: map[string]bool{ + `path already exists`: true, + }, + }, + { + Desc: "create index missing index", + Handler: createIndexHandler, + Path: "/create", + Method: "PUT", + Body: []byte("{}"), + Status: http.StatusBadRequest, + ResponseBody: []byte(`index name is required`), + }, + { + Desc: "create index invalid json", + Handler: createIndexHandler, + Path: "/create", + Method: "PUT", + Params: url.Values{"indexName": []string{"ti9"}}, + Body: []byte("{"), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `error parsing index mapping`: true, + }, + }, + { + Desc: "get index", + Handler: getIndexHandler, + Path: "/get", + Method: "GET", + Params: url.Values{"indexName": []string{"ti1"}}, + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"status":"ok"`: true, + `"name":"ti1"`: true, + }, + }, + { + Desc: "get index does not exist", + Handler: getIndexHandler, + Path: "/get", + Method: "GET", + Params: url.Values{"indexName": []string{"dne"}}, + Status: http.StatusNotFound, + ResponseMatch: map[string]bool{ + `no such index`: true, + }, + }, + { + Desc: "get index missing name", + Handler: getIndexHandler, + Path: "/get", + Method: "GET", + Status: http.StatusBadRequest, + ResponseBody: []byte(`index name is required`), + }, + { + Desc: "create another index", + Handler: createIndexHandler, + Path: "/create", + Method: "PUT", + Params: url.Values{"indexName": []string{"ti2"}}, + Body: []byte("{}"), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "list indexes", + Handler: listIndexesHandler, + Path: "/list", + Method: "GET", + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"status":"ok"`: true, + `"ti1"`: true, + `"ti2"`: true, + }, + }, + { + Desc: "delete index", + Handler: deleteIndexHandler, + Path: "/delete", + Method: "DELETE", + Params: url.Values{"indexName": []string{"ti2"}}, + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "delete index missing name", + Handler: deleteIndexHandler, + Path: "/delete", + Method: "DELETE", + Status: http.StatusBadRequest, + ResponseBody: []byte(`index name is required`), + }, + { + Desc: "list indexes after delete", + Handler: listIndexesHandler, + Path: "/list", + Method: "GET", + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"status":"ok"`: true, + `"ti1"`: true, + `"ti2"`: false, + }, + }, + { + Desc: "index doc", + Handler: docIndexHandler, + Path: "/ti1/a", + Method: "PUT", + Params: url.Values{ + "indexName": []string{"ti1"}, + "docID": []string{"a"}, + }, + Body: []byte(`{"name":"a","body":"test","rating":7,"created":"2014-11-26","former_ratings":[3,4,2]}`), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "index doc invalid index", + Handler: docIndexHandler, + Path: "/tix/a", + Method: "PUT", + Params: url.Values{ + "indexName": []string{"tix"}, + "docID": []string{"a"}, + }, + Body: []byte(`{"name":"a","body":"test","rating":7,"created":"2014-11-26","former_ratings":[3,4,2]}`), + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "index doc missing ID", + Handler: docIndexHandler, + Path: "/ti1/a", + Method: "PUT", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Body: []byte(`{"name":"a","body":"test","rating":7,"created":"2014-11-26","former_ratings":[3,4,2]}`), + Status: http.StatusBadRequest, + ResponseBody: []byte(`document id cannot be empty`), + }, + { + Desc: "doc count", + Handler: docCountHandler, + Path: "/ti1/count", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok","count":1}`), + }, + { + Desc: "doc count invalid index", + Handler: docCountHandler, + Path: "/tix/count", + Method: "GET", + Params: url.Values{ + "indexName": []string{"tix"}, + }, + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "doc get", + Handler: docGetHandler, + Path: "/ti1/a", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + "docID": []string{"a"}, + }, + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"id":"a"`: true, + `"body":"test"`: true, + `"name":"a"`: true, + }, + }, + { + Desc: "doc get invalid index", + Handler: docGetHandler, + Path: "/tix/a", + Method: "GET", + Params: url.Values{ + "indexName": []string{"tix"}, + "docID": []string{"a"}, + }, + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "doc get missing ID", + Handler: docGetHandler, + Path: "/ti1/a", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Status: http.StatusBadRequest, + ResponseBody: []byte(`document id cannot be empty`), + }, + { + Desc: "index another doc", + Handler: docIndexHandler, + Path: "/ti1/b", + Method: "PUT", + Params: url.Values{ + "indexName": []string{"ti1"}, + "docID": []string{"b"}, + }, + Body: []byte(`{"name":"b","body":"del"}`), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "doc count again", + Handler: docCountHandler, + Path: "/ti1/count", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok","count":2}`), + }, + { + Desc: "delete doc", + Handler: docDeleteHandler, + Path: "/ti1/b", + Method: "DELETE", + Params: url.Values{ + "indexName": []string{"ti1"}, + "docID": []string{"b"}, + }, + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "delete doc invalid index", + Handler: docDeleteHandler, + Path: "/tix/b", + Method: "DELETE", + Params: url.Values{ + "indexName": []string{"tix"}, + "docID": []string{"b"}, + }, + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "delete doc missing docID", + Handler: docDeleteHandler, + Path: "/ti1/b", + Method: "DELETE", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Status: http.StatusBadRequest, + ResponseBody: []byte(`document id cannot be empty`), + }, + { + Desc: "doc get", + Handler: docGetHandler, + Path: "/ti1/b", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + "docID": []string{"b"}, + }, + Status: http.StatusNotFound, + ResponseMatch: map[string]bool{ + `no such document`: true, + }, + }, + { + Desc: "search", + Handler: searchHandler, + Path: "/ti1/search", + Method: "POST", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Body: []byte(`{ + "from": 0, + "size": 10, + "query": { + "fuzziness": 0, + "prefix_length": 0, + "field": "body", + "match": "test" + } + }`), + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"total_hits":1`: true, + `"id":"a"`: true, + }, + }, + { + Desc: "search index doesnt exist", + Handler: searchHandler, + Path: "/tix/search", + Method: "POST", + Params: url.Values{ + "indexName": []string{"tix"}, + }, + Body: []byte(`{ + "from": 0, + "size": 10, + "query": { + "fuzziness": 0, + "prefix_length": 0, + "field": "body", + "match": "test" + } + }`), + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "search invalid json", + Handler: searchHandler, + Path: "/ti1/search", + Method: "POST", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Body: []byte(`{`), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `error parsing query`: true, + }, + }, + { + Desc: "search query does not validate", + Handler: searchHandler, + Path: "/ti1/search", + Method: "POST", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Body: []byte(`{ + "from": 0, + "size": 10, + "query": { + "field": "body", + "terms": [] + } + }`), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `error validating query`: true, + }, + }, + { + Desc: "list fields", + Handler: listFieldsHandler, + Path: "/ti1/fields", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + }, + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"fields":`: true, + `"name"`: true, + `"body"`: true, + `"_all"`: true, + }, + }, + { + Desc: "list fields invalid index", + Handler: listFieldsHandler, + Path: "/tix/fields", + Method: "GET", + Params: url.Values{ + "indexName": []string{"tix"}, + }, + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "debug doc", + Handler: debugHandler, + Path: "/ti1/a/debug", + Method: "GET", + Params: url.Values{ + "indexName": []string{"ti1"}, + "docID": []string{"a"}, + }, + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"key"`: true, + `"val"`: true, + }, + }, + { + Desc: "debug doc invalid index", + Handler: debugHandler, + Path: "/ti1/a/debug", + Method: "GET", + Params: url.Values{ + "indexName": []string{"tix"}, + "docID": []string{"a"}, + }, + Status: http.StatusNotFound, + ResponseBody: []byte(`no such index 'tix'`), + }, + { + Desc: "create alias", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a1", + "add": ["ti1"] + }`), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "create alias invalid json", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{`), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `error parsing alias actions`: true, + }, + }, + { + Desc: "create alias empty", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(``), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `request body must contain alias actions`: true, + }, + }, + { + Desc: "create alias referring to non-existant index", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a2", + "add": ["tix"] + }`), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `index named 'tix' does not exist`: true, + }, + }, + { + Desc: "create alias removing from new", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a2", + "remove": ["ti1"] + }`), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `cannot remove indexes from a new alias`: true, + }, + }, + { + Desc: "create alias same name as index", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "ti1", + "remove": ["ti1"] + }`), + Status: http.StatusBadRequest, + ResponseMatch: map[string]bool{ + `is not an alias`: true, + }, + }, + { + Desc: "search alias", + Handler: searchHandler, + Path: "/a1/search", + Method: "POST", + Params: url.Values{ + "indexName": []string{"a1"}, + }, + Body: []byte(`{ + "from": 0, + "size": 10, + "query": { + "fuzziness": 0, + "prefix_length": 0, + "field": "body", + "match": "test" + } + }`), + Status: http.StatusOK, + ResponseMatch: map[string]bool{ + `"total_hits":1`: true, + `"id":"a"`: true, + }, + }, + { + Desc: "create index to add to alias", + Handler: createIndexHandler, + Path: "/create", + Method: "PUT", + Params: url.Values{"indexName": []string{"ti6"}}, + Body: []byte("{}"), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "update alias add ti6", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a1", + "add": ["ti6"] + }`), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "update alias add doesnt exist", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a1", + "add": ["ti99"] + }`), + Status: http.StatusBadRequest, + ResponseBody: []byte(`error updating alias: index named 'ti99' does not exist`), + }, + { + Desc: "update alias remove ti6", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a1", + "remove": ["ti6"] + }`), + Status: http.StatusOK, + ResponseBody: []byte(`{"status":"ok"}`), + }, + { + Desc: "update alias remove doesnt exist", + Handler: aliasHandler, + Path: "/alias", + Method: "POST", + Body: []byte(`{ + "alias": "a1", + "remove": ["ti98"] + }`), + Status: http.StatusBadRequest, + ResponseBody: []byte(`error updating alias: index named 'ti98' does not exist`), + }, + } + + for _, test := range tests { + record := httptest.NewRecorder() + req := &http.Request{ + Method: test.Method, + URL: &url.URL{Path: test.Path}, + Form: test.Params, + Body: ioutil.NopCloser(bytes.NewBuffer(test.Body)), + } + test.Handler.ServeHTTP(record, req) + if got, want := record.Code, test.Status; got != want { + t.Errorf("%s: response code = %d, want %d", test.Desc, got, want) + t.Errorf("%s: response body = %s", test.Desc, record.Body) + } + + got := bytes.TrimRight(record.Body.Bytes(), "\n") + if test.ResponseBody != nil { + if !reflect.DeepEqual(got, test.ResponseBody) { + t.Errorf("%s: expected: '%s', got: '%s'", test.Desc, test.ResponseBody, got) + } + } + for pattern, shouldMatch := range test.ResponseMatch { + didMatch := bytes.Contains(got, []byte(pattern)) + if didMatch != shouldMatch { + t.Errorf("%s: expected match %t for pattern %s, got %t", test.Desc, shouldMatch, pattern, didMatch) + t.Errorf("%s: response body was: %s", test.Desc, got) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_create.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_create.go new file mode 100644 index 00000000..afada612 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_create.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +type CreateIndexHandler struct { + basePath string + IndexNameLookup varLookupFunc +} + +func NewCreateIndexHandler(basePath string) *CreateIndexHandler { + return &CreateIndexHandler{ + basePath: basePath, + } +} + +func (h *CreateIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // find the name of the index to create + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + showError(w, req, "index name is required", 400) + return + } + + indexMapping := bleve.NewIndexMapping() + + // read the request body + requestBody, err := ioutil.ReadAll(req.Body) + if err != nil { + showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400) + return + } + + // interpret request body as index mapping + if len(requestBody) > 0 { + err := json.Unmarshal(requestBody, &indexMapping) + if err != nil { + showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400) + return + } + } + + newIndex, err := bleve.New(h.indexPath(indexName), indexMapping) + if err != nil { + showError(w, req, fmt.Sprintf("error creating index: %v", err), 500) + return + } + RegisterIndexName(indexName, newIndex) + rv := struct { + Status string `json:"status"` + }{ + Status: "ok", + } + mustEncode(w, rv) +} + +func (h *CreateIndexHandler) indexPath(name string) string { + return h.basePath + string(os.PathSeparator) + name +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_delete.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_delete.go new file mode 100644 index 00000000..43171de4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_delete.go @@ -0,0 +1,70 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" + "os" +) + +type DeleteIndexHandler struct { + basePath string + IndexNameLookup varLookupFunc +} + +func NewDeleteIndexHandler(basePath string) *DeleteIndexHandler { + return &DeleteIndexHandler{ + basePath: basePath, + } +} + +func (h *DeleteIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // find the name of the index to delete + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + showError(w, req, "index name is required", 400) + return + } + + indexToDelete := UnregisterIndexByName(indexName) + if indexToDelete == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + // close the index + err := indexToDelete.Close() + if err != nil { + showError(w, req, fmt.Sprintf("error closing index: %v", err), 500) + return + } + + // now delete it + err = os.RemoveAll(h.indexPath(indexName)) + if err != nil { + showError(w, req, fmt.Sprintf("error deleting index: %v", err), 500) + return + } + + rv := struct { + Status string `json:"status"` + }{ + Status: "ok", + } + mustEncode(w, rv) +} + +func (h *DeleteIndexHandler) indexPath(name string) string { + return h.basePath + string(os.PathSeparator) + name +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_get.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_get.go new file mode 100644 index 00000000..a8411a81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_get.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "net/http" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +type GetIndexHandler struct { + IndexNameLookup varLookupFunc +} + +func NewGetIndexHandler() *GetIndexHandler { + return &GetIndexHandler{} +} + +func (h *GetIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // find the name of the index to create + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + showError(w, req, "index name is required", 400) + return + } + + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + rv := struct { + Status string `json:"status"` + Name string `json:"name"` + Mapping *bleve.IndexMapping `json:"mapping"` + }{ + Status: "ok", + Name: indexName, + Mapping: index.Mapping(), + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_list.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_list.go new file mode 100644 index 00000000..ffd09f76 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/index_list.go @@ -0,0 +1,33 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "net/http" +) + +type ListIndexesHandler struct { +} + +func NewListIndexesHandler() *ListIndexesHandler { + return &ListIndexesHandler{} +} + +func (h *ListIndexesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + indexNames := IndexNames() + rv := struct { + Status string `json:"status"` + Indexes []string `json:"indexes"` + }{ + Status: "ok", + Indexes: indexNames, + } + mustEncode(w, rv) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/registry.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/registry.go new file mode 100644 index 00000000..bdd75f43 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/registry.go @@ -0,0 +1,120 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "fmt" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +var indexNameMapping map[string]bleve.Index +var indexNameMappingLock sync.RWMutex +var indexStats = bleve.IndexStats{} + +func RegisterIndexName(name string, idx bleve.Index) { + indexNameMappingLock.Lock() + defer indexNameMappingLock.Unlock() + + if indexNameMapping == nil { + indexNameMapping = make(map[string]bleve.Index) + } + indexNameMapping[name] = idx + indexStats[name] = idx.Stats() +} + +func UnregisterIndexByName(name string) bleve.Index { + indexNameMappingLock.Lock() + defer indexNameMappingLock.Unlock() + + if indexNameMapping == nil { + return nil + } + rv := indexNameMapping[name] + if rv != nil { + delete(indexNameMapping, name) + } + delete(indexStats, name) + return rv +} + +func IndexByName(name string) bleve.Index { + indexNameMappingLock.RLock() + defer indexNameMappingLock.RUnlock() + + return indexNameMapping[name] +} + +func IndexNames() []string { + indexNameMappingLock.RLock() + defer indexNameMappingLock.RUnlock() + + rv := make([]string, len(indexNameMapping)) + count := 0 + for k := range indexNameMapping { + rv[count] = k + count++ + } + return rv +} + +func IndexStats() bleve.IndexStats { + return indexStats +} + +func UpdateAlias(alias string, add, remove []string) error { + indexNameMappingLock.Lock() + defer indexNameMappingLock.Unlock() + + index, exists := indexNameMapping[alias] + if !exists { + // new alias + if len(remove) > 0 { + return fmt.Errorf("cannot remove indexes from a new alias") + } + indexes := make([]bleve.Index, len(add)) + for i, addIndexName := range add { + addIndex, indexExists := indexNameMapping[addIndexName] + if !indexExists { + return fmt.Errorf("index named '%s' does not exist", addIndexName) + } + indexes[i] = addIndex + } + indexAlias := bleve.NewIndexAlias(indexes...) + indexNameMapping[alias] = indexAlias + } else { + // something with this name already exists + indexAlias, isAlias := index.(bleve.IndexAlias) + if !isAlias { + return fmt.Errorf("'%s' is not an alias", alias) + } + // build list of add indexes + addIndexes := make([]bleve.Index, len(add)) + for i, addIndexName := range add { + addIndex, indexExists := indexNameMapping[addIndexName] + if !indexExists { + return fmt.Errorf("index named '%s' does not exist", addIndexName) + } + addIndexes[i] = addIndex + } + // build list of remove indexes + removeIndexes := make([]bleve.Index, len(remove)) + for i, removeIndexName := range remove { + removeIndex, indexExists := indexNameMapping[removeIndexName] + if !indexExists { + return fmt.Errorf("index named '%s' does not exist", removeIndexName) + } + removeIndexes[i] = removeIndex + } + indexAlias.Swap(addIndexes, removeIndexes) + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/search.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/search.go new file mode 100644 index 00000000..6c43a4a9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/search.go @@ -0,0 +1,84 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +// SearchHandler can handle search requests sent over HTTP +type SearchHandler struct { + defaultIndexName string + IndexNameLookup varLookupFunc +} + +func NewSearchHandler(defaultIndexName string) *SearchHandler { + return &SearchHandler{ + defaultIndexName: defaultIndexName, + } +} + +func (h *SearchHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + + // find the index to operate on + var indexName string + if h.IndexNameLookup != nil { + indexName = h.IndexNameLookup(req) + } + if indexName == "" { + indexName = h.defaultIndexName + } + index := IndexByName(indexName) + if index == nil { + showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404) + return + } + + // read the request body + requestBody, err := ioutil.ReadAll(req.Body) + if err != nil { + showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400) + return + } + + logger.Printf("request body: %s", requestBody) + + // parse the request + var searchRequest bleve.SearchRequest + err = json.Unmarshal(requestBody, &searchRequest) + if err != nil { + showError(w, req, fmt.Sprintf("error parsing query: %v", err), 400) + return + } + + logger.Printf("parsed request %#v", searchRequest) + + // validate the query + err = searchRequest.Query.Validate() + if err != nil { + showError(w, req, fmt.Sprintf("error validating query: %v", err), 400) + return + } + + // execute the query + searchResponse, err := index.Search(&searchRequest) + if err != nil { + showError(w, req, fmt.Sprintf("error executing query: %v", err), 500) + return + } + + // encode the response + mustEncode(w, searchResponse) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/http/util.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/util.go new file mode 100644 index 00000000..845df7cc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/http/util.go @@ -0,0 +1,46 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package http + +import ( + "encoding/json" + "io" + "io/ioutil" + "log" + "net/http" +) + +func showError(w http.ResponseWriter, r *http.Request, + msg string, code int) { + logger.Printf("Reporting error %v/%v", code, msg) + http.Error(w, msg, code) +} + +func mustEncode(w io.Writer, i interface{}) { + if headered, ok := w.(http.ResponseWriter); ok { + headered.Header().Set("Cache-Control", "no-cache") + headered.Header().Set("Content-type", "application/json") + } + + e := json.NewEncoder(w) + if err := e.Encode(i); err != nil { + panic(err) + } +} + +type varLookupFunc func(req *http.Request) string + +var logger = log.New(ioutil.Discard, "bleve.http", log.LstdFlags) + +// SetLog sets the logger used for logging +// by default log messages are sent to ioutil.Discard +func SetLog(l *log.Logger) { + logger = l +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index.go new file mode 100644 index 00000000..50805c2f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index.go @@ -0,0 +1,146 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +// A Batch groups together multiple Index and Delete +// operations you would like performed at the same +// time. +type Batch struct { + index Index + internal *index.Batch +} + +// Index adds the specified index operation to the +// batch. NOTE: the bleve Index is not updated +// until the batch is executed. +func (b *Batch) Index(id string, data interface{}) error { + doc := document.NewDocument(id) + err := b.index.Mapping().mapDocument(doc, data) + if err != nil { + return err + } + b.internal.Update(doc) + return nil +} + +// Delete adds the specified delete operation to the +// batch. NOTE: the bleve Index is not updated until +// the batch is executed. +func (b *Batch) Delete(id string) { + b.internal.Delete(id) +} + +// SetInternal adds the specified set internal +// operation to the batch. NOTE: the bleve Index is +// not updated until the batch is executed. +func (b *Batch) SetInternal(key, val []byte) { + b.internal.SetInternal(key, val) +} + +// SetInternal adds the specified delete internal +// operation to the batch. NOTE: the bleve Index is +// not updated until the batch is executed. +func (b *Batch) DeleteInternal(key []byte) { + b.internal.DeleteInternal(key) +} + +// Size returns the total number of operations inside the batch +// including normal index operations and internal operations. +func (b *Batch) Size() int { + return len(b.internal.IndexOps) + len(b.internal.InternalOps) +} + +// String prints a user friendly string represenation of what +// is inside this batch. +func (b *Batch) String() string { + return b.internal.String() +} + +// An Index implements all the indexing and searching +// capabilities of bleve. An Index can be created +// using the New() and Open() methods. +type Index interface { + Index(id string, data interface{}) error + Delete(id string) error + + NewBatch() *Batch + Batch(b *Batch) error + + Document(id string) (*document.Document, error) + DocCount() (uint64, error) + + Search(req *SearchRequest) (*SearchResult, error) + + Fields() ([]string, error) + + FieldDict(field string) (index.FieldDict, error) + FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) + FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) + + DumpAll() chan interface{} + DumpDoc(id string) chan interface{} + DumpFields() chan interface{} + + Close() error + + Mapping() *IndexMapping + + Stats() *IndexStat + + GetInternal(key []byte) ([]byte, error) + SetInternal(key, val []byte) error + DeleteInternal(key []byte) error + + Advanced() (index.Index, store.KVStore, error) +} + +// A Classifier is an interface describing any object +// which knows how to identify its own type. +type Classifier interface { + Type() string +} + +// New index at the specified path, must not exist. +// The provided mapping will be used for all +// Index/Search operations. +func New(path string, mapping *IndexMapping) (Index, error) { + return newIndexUsing(path, mapping, Config.DefaultKVStore, nil) +} + +// NewUsing creates index at the specified path, +// which must not already exist. +// The provided mapping will be used for all +// Index/Search operations. +// The specified kvstore implemenation will be used +// and the provided kvconfig will be passed to its +// constructor. +func NewUsing(path string, mapping *IndexMapping, kvstore string, kvconfig map[string]interface{}) (Index, error) { + return newIndexUsing(path, mapping, kvstore, kvconfig) +} + +// Open index at the specified path, must exist. +// The mapping used when it was created will be used for all Index/Search operations. +func Open(path string) (Index, error) { + return openIndexUsing(path, nil) +} + +// OpenUsing opens index at the specified path, must exist. +// The mapping used when it was created will be used for all Index/Search operations. +// The provided runtimeConfig can override settings +// persisted when the kvstore was created. +func OpenUsing(path string, runtimeConfig map[string]interface{}) (Index, error) { + return openIndexUsing(path, runtimeConfig) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/index.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/index.go new file mode 100644 index 00000000..5c984e99 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/index.go @@ -0,0 +1,146 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package index + +import ( + "encoding/json" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" +) + +type Index interface { + Open() error + Close() error + + DocCount() (uint64, error) + + Update(doc *document.Document) error + Delete(id string) error + Batch(batch *Batch) error + + SetInternal(key, val []byte) error + DeleteInternal(key []byte) error + + DumpAll() chan interface{} + DumpDoc(id string) chan interface{} + DumpFields() chan interface{} + + Reader() (IndexReader, error) + + Stats() json.Marshaler +} + +type IndexReader interface { + TermFieldReader(term []byte, field string) (TermFieldReader, error) + DocIDReader(start, end string) (DocIDReader, error) + + FieldDict(field string) (FieldDict, error) + FieldDictRange(field string, startTerm []byte, endTerm []byte) (FieldDict, error) + FieldDictPrefix(field string, termPrefix []byte) (FieldDict, error) + + Document(id string) (*document.Document, error) + DocumentFieldTerms(id string) (FieldTerms, error) + + Fields() ([]string, error) + + GetInternal(key []byte) ([]byte, error) + + DocCount() uint64 + + Close() error +} + +type FieldTerms map[string][]string + +type TermFieldVector struct { + Field string + Pos uint64 + Start uint64 + End uint64 +} + +type TermFieldDoc struct { + Term string + ID string + Freq uint64 + Norm float64 + Vectors []*TermFieldVector +} + +type TermFieldReader interface { + Next() (*TermFieldDoc, error) + Advance(ID string) (*TermFieldDoc, error) + Count() uint64 + Close() error +} + +type DictEntry struct { + Term string + Count uint64 +} + +type FieldDict interface { + Next() (*DictEntry, error) + Close() error +} + +type DocIDReader interface { + Next() (string, error) + Advance(ID string) (string, error) + Close() error +} + +type Batch struct { + IndexOps map[string]*document.Document + InternalOps map[string][]byte +} + +func NewBatch() *Batch { + return &Batch{ + IndexOps: make(map[string]*document.Document), + InternalOps: make(map[string][]byte), + } +} + +func (b *Batch) Update(doc *document.Document) { + b.IndexOps[doc.ID] = doc +} + +func (b *Batch) Delete(id string) { + b.IndexOps[id] = nil +} + +func (b *Batch) SetInternal(key, val []byte) { + b.InternalOps[string(key)] = val +} + +func (b *Batch) DeleteInternal(key []byte) { + b.InternalOps[string(key)] = nil +} + +func (b *Batch) String() string { + rv := fmt.Sprintf("Batch (%d ops, %d internal ops)\n", len(b.IndexOps), len(b.InternalOps)) + for k, v := range b.IndexOps { + if v != nil { + rv += fmt.Sprintf("\tINDEX - '%s'\n", k) + } else { + rv += fmt.Sprintf("\tDELETE - '%s'\n", k) + } + } + for k, v := range b.InternalOps { + if v != nil { + rv += fmt.Sprintf("\tSET INTERNAL - '%s'\n", k) + } else { + rv += fmt.Sprintf("\tDELETE INTERNAL - '%s'\n", k) + } + } + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/batch.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/batch.go new file mode 100644 index 00000000..4a3c76bc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/batch.go @@ -0,0 +1,69 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package store + +type op struct { + K []byte + V []byte +} + +type EmulatedBatch struct { + w KVWriter + ops []*op + merge *EmulatedMerge +} + +func NewEmulatedBatch(w KVWriter, mo MergeOperator) *EmulatedBatch { + return &EmulatedBatch{ + w: w, + ops: make([]*op, 0, 1000), + merge: NewEmulatedMerge(mo), + } +} + +func (b *EmulatedBatch) Set(key, val []byte) { + b.ops = append(b.ops, &op{key, val}) +} + +func (b *EmulatedBatch) Delete(key []byte) { + b.ops = append(b.ops, &op{key, nil}) +} + +func (b *EmulatedBatch) Merge(key, val []byte) { + b.merge.Merge(key, val) +} + +func (b *EmulatedBatch) Execute() error { + // first process merges + err := b.merge.Execute(b.w) + if err != nil { + return err + } + + // now apply all the ops + for _, op := range b.ops { + if op.V != nil { + err := b.w.Set(op.K, op.V) + if err != nil { + return err + } + } else { + err := b.w.Delete(op.K) + if err != nil { + return err + } + } + } + return nil +} + +func (b *EmulatedBatch) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/iterator.go new file mode 100644 index 00000000..2aed7219 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/iterator.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package boltdb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" +) + +type Iterator struct { + store *Store + tx *bolt.Tx + cursor *bolt.Cursor + valid bool + key []byte + val []byte +} + +func (i *Iterator) SeekFirst() { + i.key, i.val = i.cursor.First() + i.valid = (i.key != nil) +} + +func (i *Iterator) Seek(k []byte) { + i.key, i.val = i.cursor.Seek(k) + i.valid = (i.key != nil) +} + +func (i *Iterator) Next() { + i.key, i.val = i.cursor.Next() + i.valid = (i.key != nil) +} + +func (i *Iterator) Current() ([]byte, []byte, bool) { + return i.key, i.val, i.valid +} + +func (i *Iterator) Key() []byte { + return i.key +} + +func (i *Iterator) Value() []byte { + return i.val +} + +func (i *Iterator) Valid() bool { + return i.valid +} + +func (i *Iterator) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/reader.go new file mode 100644 index 00000000..d85671e5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/reader.go @@ -0,0 +1,47 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package boltdb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" +) + +type Reader struct { + store *Store + tx *bolt.Tx +} + +func (r *Reader) BytesSafeAfterClose() bool { + return false +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + rv := r.tx.Bucket([]byte(r.store.bucket)).Get(key) + return rv, nil +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + b := r.tx.Bucket([]byte(r.store.bucket)) + cursor := b.Cursor() + + rv := &Iterator{ + store: r.store, + tx: r.tx, + cursor: cursor, + } + + rv.Seek(key) + return rv +} + +func (r *Reader) Close() error { + return r.tx.Rollback() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store.go new file mode 100644 index 00000000..42357fd8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store.go @@ -0,0 +1,112 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package boltdb + +import ( + "fmt" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" +) + +const Name = "boltdb" + +type Store struct { + path string + bucket string + db *bolt.DB + writer sync.Mutex + mo store.MergeOperator +} + +func New(path string, bucket string) *Store { + rv := Store{ + path: path, + bucket: bucket, + } + return &rv +} + +func (bs *Store) Open() error { + + var err error + bs.db, err = bolt.Open(bs.path, 0600, nil) + if err != nil { + return err + } + + err = bs.db.Update(func(tx *bolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte(bs.bucket)) + + return err + }) + if err != nil { + return err + } + + return nil +} + +func (bs *Store) SetMergeOperator(mo store.MergeOperator) { + bs.mo = mo +} + +func (bs *Store) Close() error { + return bs.db.Close() +} + +func (bs *Store) Reader() (store.KVReader, error) { + tx, err := bs.db.Begin(false) + if err != nil { + return nil, err + } + return &Reader{ + store: bs, + tx: tx, + }, nil +} + +func (bs *Store) Writer() (store.KVWriter, error) { + bs.writer.Lock() + tx, err := bs.db.Begin(true) + if err != nil { + bs.writer.Unlock() + return nil, err + } + reader := &Reader{ + store: bs, + tx: tx, + } + return &Writer{ + store: bs, + tx: tx, + reader: reader, + }, nil +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + path, ok := config["path"].(string) + if !ok { + return nil, fmt.Errorf("must specify path") + } + + bucket, ok := config["bucket"].(string) + if !ok { + bucket = "bleve" + } + + return New(path, bucket), nil +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store_test.go new file mode 100644 index 00000000..a5e194f7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/store_test.go @@ -0,0 +1,272 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package boltdb + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func TestStore(t *testing.T) { + s := New("test", "bleve") + err := s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + CommonTestKVStore(t, s) +} + +func TestReaderIsolation(t *testing.T) { + s := New("test", "bleve") + err := s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + CommonTestReaderIsolation(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it2 := newReader.Iterator([]byte{0}) + defer func() { + err := it2.Close() + if err != nil { + t.Fatal(err) + } + }() + for it2.Valid() { + it2.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it3 := reader.Iterator([]byte{0}) + defer func() { + err := it3.Close() + if err != nil { + t.Fatal(err) + } + }() + for it3.Valid() { + it3.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/writer.go new file mode 100644 index 00000000..00f3317c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb/writer.go @@ -0,0 +1,50 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package boltdb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" +) + +type Writer struct { + store *Store + tx *bolt.Tx + reader *Reader +} + +func (w *Writer) Set(key, val []byte) error { + return w.tx.Bucket([]byte(w.store.bucket)).Put(key, val) +} + +func (w *Writer) Delete(key []byte) error { + return w.tx.Bucket([]byte(w.store.bucket)).Delete(key) +} + +func (w *Writer) NewBatch() store.KVBatch { + return store.NewEmulatedBatch(w, w.store.mo) +} + +func (w *Writer) Close() error { + w.store.writer.Unlock() + return w.tx.Commit() +} + +func (w *Writer) BytesSafeAfterClose() bool { + return w.reader.BytesSafeAfterClose() +} + +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.reader.Get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.reader.Iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/batch.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/batch.go new file mode 100644 index 00000000..02757eca --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/batch.go @@ -0,0 +1,88 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// +build go1.4 + +package cznicb + +import () + +type op struct { + k []byte + v []byte +} + +type Batch struct { + s *Store + ops []op + merges map[string][][]byte +} + +func (b *Batch) Set(k, v []byte) { + b.ops = append(b.ops, op{k, v}) +} + +func (b *Batch) Delete(k []byte) { + b.ops = append(b.ops, op{k, nil}) +} + +func (b *Batch) Merge(key, val []byte) { + ops, ok := b.merges[string(key)] + if ok && len(ops) > 0 { + last := ops[len(ops)-1] + mergedVal, partialMergeOk := b.s.mo.PartialMerge(key, last, val) + if partialMergeOk { + // replace last entry with the result of the merge + ops[len(ops)-1] = mergedVal + } else { + // could not partial merge, append this to the end + ops = append(ops, val) + } + } else { + ops = [][]byte{val} + } + b.merges[string(key)] = ops +} + +func (b *Batch) Execute() (err error) { + b.s.m.Lock() + defer b.s.m.Unlock() + + t := b.s.t + for key, mergeOps := range b.merges { + k := []byte(key) + t.Put(k, func(oldV interface{}, exists bool) (newV interface{}, write bool) { + ob := []byte(nil) + if exists && oldV != nil { + ob = oldV.([]byte) + } + mergedVal, fullMergeOk := b.s.mo.FullMerge(k, ob, mergeOps) + if !fullMergeOk { + return nil, false + } + return mergedVal, true + }) + } + + for _, op := range b.ops { + if op.v != nil { + t.Set(op.k, op.v) + } else { + t.Delete(op.k) + } + } + + return nil +} + +func (b *Batch) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb.go new file mode 100644 index 00000000..fbc9c91a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb.go @@ -0,0 +1,111 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// +build go1.4 + +// Package cznicb provides an in-memory implementation of the KVStore +// interfaces using the cznic/b in-memory btree. Of note: this +// implementation does not have reader isolation. +package cznicb + +import ( + "bytes" + "fmt" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/cznic/b" +) + +const Name = "cznicb" + +const MAX_CONCURRENT_WRITERS = 1 + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + s := &Store{ + t: b.TreeNew(itemCompare), + availableWriters: make(chan bool, MAX_CONCURRENT_WRITERS), + } + for i := 0; i < MAX_CONCURRENT_WRITERS; i++ { + s.availableWriters <- true + } + return s, nil +} + +func itemCompare(a, b interface{}) int { + return bytes.Compare(a.([]byte), b.([]byte)) +} + +type Store struct { + availableWriters chan bool + m sync.RWMutex + t *b.Tree + mo store.MergeOperator +} + +func (s *Store) Open() error { + return nil +} + +func (s *Store) SetMergeOperator(mo store.MergeOperator) { + s.mo = mo +} + +func (s *Store) Reader() (store.KVReader, error) { + return &Reader{s: s}, nil +} + +func (s *Store) Writer() (store.KVWriter, error) { + available, ok := <-s.availableWriters + if !ok || !available { + return nil, fmt.Errorf("no available writers") + } + return &Writer{s: s, r: &Reader{s: s}}, nil +} + +func (s *Store) Close() error { + return nil +} + +func (s *Store) get(k []byte) ([]byte, error) { + s.m.RLock() + defer s.m.RUnlock() + v, ok := s.t.Get(k) + if !ok || v == nil { + return nil, nil + } + return v.([]byte), nil +} + +func (s *Store) iterator(k []byte) store.KVIterator { + iter := &Iterator{s: s} + iter.Seek(k) + return iter +} + +func (s *Store) set(k, v []byte) (err error) { + s.m.Lock() + defer s.m.Unlock() + s.t.Set(k, v) + return nil +} + +func (s *Store) delete(k []byte) (err error) { + s.m.Lock() + defer s.m.Unlock() + s.t.Delete(k) + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb_test.go new file mode 100644 index 00000000..f7b78bc0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/cznicb_test.go @@ -0,0 +1,133 @@ +// Copyright (c) 2014 Couchbase, Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +package cznicb + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func TestCznicBStore(t *testing.T) { + s, err := StoreConstructor(nil) + if err != nil { + t.Fatal(err) + } + + CommonTestKVStore(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + v, err := writer.Get([]byte("a")) + if err != nil { + t.Fatal(err) + } + if string(v) != "val-a" { + t.Errorf("expected val-a") + } + v, err = writer.Get([]byte("not-there")) + if err != nil { + t.Fatal(err) + } + if v != nil { + t.Errorf("expected nil v") + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/iterator.go new file mode 100644 index 00000000..135b97cf --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/iterator.go @@ -0,0 +1,113 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// +build go1.4 + +package cznicb + +import ( + "errors" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/cznic/b" +) + +var iteratorDoneErr = errors.New("iteratorDoneErr") // A sentinel value. + +type Iterator struct { // Assuming that iterators are used single-threaded. + s *Store + e *b.Enumerator + + currK interface{} + currV interface{} + currErr error +} + +func (i *Iterator) SeekFirst() { + i.currK = nil + i.currV = nil + i.currErr = nil + + var err error + i.s.m.RLock() + i.e, err = i.s.t.SeekFirst() + i.s.m.RUnlock() // cannot defer, must unlock before Next + if err != nil { + i.currK = nil + i.currV = nil + i.currErr = iteratorDoneErr + } + + i.Next() +} + +func (i *Iterator) Seek(k []byte) { + i.currK = nil + i.currV = nil + i.currErr = nil + + i.s.m.RLock() + i.e, _ = i.s.t.Seek(k) + i.s.m.RUnlock() // cannot defer, must unlock before Next + + i.Next() +} + +func (i *Iterator) Next() { + if i.currErr != nil { + i.currK = nil + i.currV = nil + i.currErr = iteratorDoneErr + return + } + + i.s.m.RLock() + defer i.s.m.RUnlock() + i.currK, i.currV, i.currErr = i.e.Next() +} + +func (i *Iterator) Current() ([]byte, []byte, bool) { + if i.currErr == iteratorDoneErr || + i.currK == nil || + i.currV == nil { + return nil, nil, false + } + + return i.currK.([]byte), i.currV.([]byte), true +} + +func (i *Iterator) Key() []byte { + k, _, ok := i.Current() + if !ok { + return nil + } + return k +} + +func (i *Iterator) Value() []byte { + _, v, ok := i.Current() + if !ok { + return nil + } + return v +} + +func (i *Iterator) Valid() bool { + _, _, ok := i.Current() + return ok +} + +func (i *Iterator) Close() error { + if i.e != nil { + i.e.Close() + } + i.e = nil + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/reader.go new file mode 100644 index 00000000..2c5ea86a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/reader.go @@ -0,0 +1,44 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// +build go1.4 + +package cznicb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Reader struct { + s *Store +} + +func newReader(s *Store) (*Reader, error) { + return &Reader{ + s: s, + }, nil +} + +func (r *Reader) BytesSafeAfterClose() bool { + return false +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + return r.s.get(key) +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + return r.s.iterator(key) +} + +func (r *Reader) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/writer.go new file mode 100644 index 00000000..f69aa85a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb/writer.go @@ -0,0 +1,55 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build go1.4 + +package cznicb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Writer struct { + s *Store + r *Reader +} + +func (w *Writer) BytesSafeAfterClose() bool { + return false +} + +func (w *Writer) Set(key, val []byte) error { + return w.s.set(key, val) +} + +func (w *Writer) Delete(key []byte) error { + return w.s.delete(key) +} + +func (w *Writer) NewBatch() store.KVBatch { + return &Batch{ + s: w.s, + ops: make([]op, 0, 1000), + merges: make(map[string][][]byte), + } +} + +func (w *Writer) Close() error { + w.s.availableWriters <- true + w.s = nil + return nil +} + +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.r.s.get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.r.s.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/batch.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/batch.go new file mode 100644 index 00000000..a8fad295 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/batch.go @@ -0,0 +1,86 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package forestdb + +import ( + "fmt" +) + +type op struct { + k []byte + v []byte +} + +type Batch struct { + s *Store + ops []op + merges map[string][][]byte +} + +func (b *Batch) Set(k, v []byte) { + b.ops = append(b.ops, op{k, v}) +} + +func (b *Batch) Delete(k []byte) { + b.ops = append(b.ops, op{k, nil}) +} + +func (b *Batch) Merge(key, val []byte) { + ops, ok := b.merges[string(key)] + if ok && len(ops) > 0 { + last := ops[len(ops)-1] + mergedVal, partialMergeOk := b.s.mo.PartialMerge(key, last, val) + if partialMergeOk { + // replace last entry with the result of the merge + ops[len(ops)-1] = mergedVal + } else { + // could not partial merge, append this to the end + ops = append(ops, val) + } + } else { + ops = [][]byte{val} + } + b.merges[string(key)] = ops +} + +func (b *Batch) Execute() (err error) { + + for k, mergeOps := range b.merges { + kb := []byte(k) + existingVal, err := b.s.get(kb) + if err != nil { + return err + } + mergedVal, fullMergeOk := b.s.mo.FullMerge(kb, existingVal, mergeOps) + if !fullMergeOk { + return fmt.Errorf("merge operator returned failure") + } + err = b.s.setlocked(kb, mergedVal) + if err != nil { + return err + } + } + + for _, op := range b.ops { + if op.v != nil { + b.s.setlocked(op.k, op.v) + } else { + b.s.deletelocked(op.k) + } + } + + return b.s.commit() +} + +func (b *Batch) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/iterator.go new file mode 100644 index 00000000..5210352d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/iterator.go @@ -0,0 +1,117 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package forestdb + +import ( + "github.com/couchbase/goforestdb" +) + +type Iterator struct { + store *Store + snapshot *forestdb.KVStore + iterator *forestdb.Iterator + curr *forestdb.Doc + valid bool +} + +func newIterator(store *Store) *Iterator { + itr, err := store.dbkv.IteratorInit([]byte{}, nil, forestdb.ITR_NONE) + rv := Iterator{ + store: store, + iterator: itr, + valid: err == nil, + } + return &rv +} + +func newIteratorWithSnapshot(store *Store, snapshot *forestdb.KVStore) *Iterator { + itr, err := snapshot.IteratorInit([]byte{}, nil, forestdb.ITR_NONE) + rv := Iterator{ + store: store, + iterator: itr, + valid: err == nil, + } + return &rv +} + +func (i *Iterator) SeekFirst() { + err := i.iterator.SeekMin() + if err != nil { + i.valid = false + return + } + if i.curr != nil { + i.curr.Close() + } + i.curr, err = i.iterator.Get() + if err != nil { + i.valid = false + } +} + +func (i *Iterator) Seek(key []byte) { + err := i.iterator.Seek(key, forestdb.FDB_ITR_SEEK_HIGHER) + if err != nil { + i.valid = false + return + } + if i.curr != nil { + i.curr.Close() + } + i.curr, err = i.iterator.Get() + if err != nil { + i.valid = false + return + } +} + +func (i *Iterator) Next() { + err := i.iterator.Next() + if err != nil { + i.valid = false + return + } + if i.curr != nil { + i.curr.Close() + } + i.curr, err = i.iterator.Get() + if err != nil { + i.valid = false + } +} + +func (i *Iterator) Current() ([]byte, []byte, bool) { + if i.Valid() { + return i.Key(), i.Value(), true + } + return nil, nil, false +} + +func (i *Iterator) Key() []byte { + return i.curr.Key() +} + +func (i *Iterator) Value() []byte { + return i.curr.Body() +} + +func (i *Iterator) Valid() bool { + return i.valid +} + +func (i *Iterator) Close() error { + i.valid = false + if i.curr != nil { + i.curr.Close() + } + return i.iterator.Close() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/reader.go new file mode 100644 index 00000000..c4b26f16 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/reader.go @@ -0,0 +1,57 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package forestdb + +import ( + "fmt" + + "github.com/couchbase/goforestdb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Reader struct { + store *Store + snapshot *forestdb.KVStore +} + +func (r *Reader) BytesSafeAfterClose() bool { + return true +} + +func newReader(store *Store) (*Reader, error) { + snapshot, err := store.newSnapshot() + if err != nil { + return nil, fmt.Errorf("error opening snapshot: %v", err) + } + return &Reader{ + store: store, + snapshot: snapshot, + }, nil +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + res, err := r.snapshot.GetKV(key) + if err != nil && err != forestdb.RESULT_KEY_NOT_FOUND { + return nil, err + } + return res, nil +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + rv := newIteratorWithSnapshot(r.store, r.snapshot) + rv.Seek(key) + return rv +} + +func (r *Reader) Close() error { + return r.snapshot.Close() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store.go new file mode 100644 index 00000000..054b9033 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store.go @@ -0,0 +1,297 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package forestdb + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "sync" + + "github.com/couchbase/goforestdb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +type ForestDBConfig struct { + BlockSize uint32 + BufferCacheSize uint64 + ChunkSize uint16 + CleanupCacheOnClose bool + CompactionBufferSizeMax uint32 + CompactionMinimumFilesize uint64 + CompactionMode forestdb.CompactOpt + CompactionThreshold uint8 + CompactorSleepDuration uint64 + CompressDocumentBody bool + DurabilityOpt forestdb.DurabilityOpt + OpenFlags forestdb.OpenFlags + PurgingInterval uint32 + SeqTreeOpt forestdb.SeqTreeOpt + WalFlushBeforeCommit bool + WalThreshold uint64 +} + +const Name = "forestdb" + +type Store struct { + path string + config *forestdb.Config + kvconfig *forestdb.KVStoreConfig + dbfile *forestdb.File + dbkv *forestdb.KVStore + writer sync.Mutex + mo store.MergeOperator +} + +func New(path string, createIfMissing bool, + config map[string]interface{}) (*Store, error) { + if config == nil { + config = map[string]interface{}{} + } + + forestDBDefaultConfig := forestdb.DefaultConfig() + forestDBDefaultConfig.SetCompactionMode(forestdb.COMPACT_AUTO) + forestDBConfig, err := applyConfig(forestDBDefaultConfig, config) + if err != nil { + return nil, err + } + + rv := Store{ + path: path, + config: forestDBConfig, + kvconfig: forestdb.DefaultKVStoreConfig(), + } + + if createIfMissing { + rv.kvconfig.SetCreateIfMissing(true) + } + + return &rv, nil +} + +func (s *Store) Open() error { + var err error + s.dbfile, err = forestdb.Open(s.path, s.config) + if err != nil { + return err + } + + s.dbkv, err = s.dbfile.OpenKVStoreDefault(s.kvconfig) + if err != nil { + return err + } + + return nil +} + +func (s *Store) SetMergeOperator(mo store.MergeOperator) { + s.mo = mo +} + +func (s *Store) get(key []byte) ([]byte, error) { + res, err := s.dbkv.GetKV(key) + if err != nil && err != forestdb.RESULT_KEY_NOT_FOUND { + return nil, err + } + return res, nil +} + +func (s *Store) set(key, val []byte) error { + s.writer.Lock() + defer s.writer.Unlock() + return s.setlocked(key, val) +} + +func (s *Store) setlocked(key, val []byte) error { + return s.dbkv.SetKV(key, val) +} + +func (s *Store) delete(key []byte) error { + s.writer.Lock() + defer s.writer.Unlock() + return s.deletelocked(key) +} + +func (s *Store) deletelocked(key []byte) error { + return s.dbkv.DeleteKV(key) +} + +func (s *Store) commit() error { + return s.dbfile.Commit(forestdb.COMMIT_NORMAL) +} + +func (s *Store) Close() error { + err := s.dbkv.Close() + if err != nil { + return err + } + return s.dbfile.Close() + +} + +func (ldbs *Store) iterator(key []byte) store.KVIterator { + rv := newIterator(ldbs) + rv.Seek(key) + return rv +} + +func (s *Store) Reader() (store.KVReader, error) { + return newReader(s) +} + +func (ldbs *Store) Writer() (store.KVWriter, error) { + return newWriter(ldbs) +} + +func (s *Store) getSeqNum() (forestdb.SeqNum, error) { + dbinfo, err := s.dbkv.Info() + if err != nil { + return 0, err + } + return dbinfo.LastSeqNum(), nil +} + +func (s *Store) newSnapshot() (*forestdb.KVStore, error) { + seqNum, err := s.getSeqNum() + if err != nil { + return nil, fmt.Errorf("error getting snapshot seqnum: %v", err) + } + snapshot, err := s.dbkv.SnapshotOpen(seqNum) + if err == forestdb.RESULT_NO_DB_INSTANCE { + checkAgainSeqNum, err := s.getSeqNum() + if err != nil { + return nil, fmt.Errorf("error getting snapshot seqnum again: %v", err) + } + return nil, fmt.Errorf("cannot open snapshot %v, checked again its %v, error: %v", seqNum, checkAgainSeqNum, err) + } + return snapshot, err +} + +func (s *Store) GetRollbackID() ([]byte, error) { + seqNum, err := s.getSeqNum() + if err != nil { + return nil, err + } + buf := new(bytes.Buffer) + err = binary.Write(buf, binary.LittleEndian, seqNum) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func (s *Store) RollbackTo(rollbackId []byte) error { + s.writer.Lock() + defer s.writer.Unlock() + buf := bytes.NewReader(rollbackId) + var seqNum forestdb.SeqNum + err := binary.Read(buf, binary.LittleEndian, &seqNum) + if err != nil { + return err + } + err = s.dbkv.Rollback(seqNum) + if err != nil { + return err + } + return nil +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + path, ok := config["path"].(string) + if !ok { + return nil, fmt.Errorf("must specify path") + } + createIfMissing := false + cim, ok := config["create_if_missing"].(bool) + if ok { + createIfMissing = cim + } + return New(path, createIfMissing, config) +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +func applyConfig(c *forestdb.Config, config map[string]interface{}) ( + *forestdb.Config, error) { + v, exists := config["forestDBConfig"] + if !exists || v == nil { + return c, nil + } + m, ok := v.(map[string]interface{}) + if !ok { + return c, nil + } + // These extra steps of json.Marshal()/Unmarshal() help to convert + // to the types that we need for the setter calls. + b, err := json.Marshal(m) + if err != nil { + return nil, err + } + var f ForestDBConfig + err = json.Unmarshal(b, &f) + if err != nil { + return nil, err + } + if _, exists := m["blockSize"]; exists { + c.SetBlockSize(f.BlockSize) + } + if _, exists := m["bufferCacheSize"]; exists { + c.SetBufferCacheSize(f.BufferCacheSize) + } + if _, exists := m["chunkSize"]; exists { + c.SetChunkSize(f.ChunkSize) + } + if _, exists := m["cleanupCacheOnClose"]; exists { + c.SetCleanupCacheOnClose(f.CleanupCacheOnClose) + } + if _, exists := m["compactionBufferSizeMax"]; exists { + c.SetCompactionBufferSizeMax(f.CompactionBufferSizeMax) + } + if _, exists := m["compactionMinimumFilesize"]; exists { + c.SetCompactionMinimumFilesize(f.CompactionMinimumFilesize) + } + if _, exists := m["compactionMode"]; exists { + c.SetCompactionMode(f.CompactionMode) + } + if _, exists := m["compactionThreshold"]; exists { + c.SetCompactionThreshold(f.CompactionThreshold) + } + if _, exists := m["compactorSleepDuration"]; exists { + c.SetCompactorSleepDuration(f.CompactorSleepDuration) + } + if _, exists := m["compressDocumentBody"]; exists { + c.SetCompressDocumentBody(f.CompressDocumentBody) + } + if _, exists := m["durabilityOpt"]; exists { + c.SetDurabilityOpt(f.DurabilityOpt) + } + if _, exists := m["openFlags"]; exists { + c.SetOpenFlags(f.OpenFlags) + } + if _, exists := m["purgingInterval"]; exists { + c.SetPurgingInterval(f.PurgingInterval) + } + if _, exists := m["seqTreeOpt"]; exists { + c.SetSeqTreeOpt(f.SeqTreeOpt) + } + if _, exists := m["walFlushBeforeCommit"]; exists { + c.SetWalFlushBeforeCommit(f.WalFlushBeforeCommit) + } + if _, exists := m["walThreshold"]; exists { + c.SetWalThreshold(f.WalThreshold) + } + return c, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store_test.go new file mode 100644 index 00000000..19a71691 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/store_test.go @@ -0,0 +1,636 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package forestdb + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func TestForestDBStore(t *testing.T) { + defer func() { + err := os.RemoveAll("testdir") + if err != nil { + t.Fatal(err) + } + }() + + err := os.MkdirAll("testdir", 0700) + if err != nil { + t.Fatal(err) + } + s, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestKVStore(t, s) +} + +func TestReaderIsolation(t *testing.T) { + defer func() { + err := os.RemoveAll("testdir") + if err != nil { + t.Fatal(err) + } + }() + + err := os.MkdirAll("testdir", 0700) + if err != nil { + t.Fatal(err) + } + s, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestReaderIsolation(t, s) +} + +// TestRollbackSameHandle tries to rollback a handle +// and ensure that subsequent reads from it also +// reflect the rollback +func TestRollbackSameHandle(t *testing.T) { + defer func() { + err := os.RemoveAll("testdir") + if err != nil { + t.Fatal(err) + } + }() + + err := os.MkdirAll("testdir", 0700) + if err != nil { + t.Fatal(err) + } + s, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + writer, err := s.Writer() + if err != nil { + t.Fatal(err) + } + + // create 2 docs, a and b + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Error(err) + } + + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Error(err) + } + + // get the rollback id + rollbackId, err := s.GetRollbackID() + if err != nil { + t.Error(err) + } + + // create a 3rd doc c + err = writer.Set([]byte("c"), []byte("val-c")) + if err != nil { + t.Error(err) + } + + err = writer.Close() + if err != nil { + t.Error(err) + } + + // make sure c is there + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + val, err := reader.Get([]byte("c")) + if err != nil { + t.Error(err) + } + if string(val) != "val-c" { + t.Errorf("expected value 'val-c' got '%s'", val) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } + + // now rollback + err = s.RollbackTo(rollbackId) + if err != nil { + t.Fatal(err) + } + + // now make sure c is not there + reader, err = s.Reader() + if err != nil { + t.Error(err) + } + val, err = reader.Get([]byte("c")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected missing, got '%s'", val) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } +} + +// TestRollbackNewHandle tries to rollback the +// database, then opens a new handle, and ensures +// that the rollback is reflected there as well +func TestRollbackNewHandle(t *testing.T) { + defer func() { + err := os.RemoveAll("testdir") + if err != nil { + t.Fatal(err) + } + }() + + err := os.MkdirAll("testdir", 0700) + if err != nil { + t.Fatal(err) + } + s, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + writer, err := s.Writer() + if err != nil { + t.Fatal(err) + } + + // create 2 docs, a and b + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Error(err) + } + + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Error(err) + } + + // get the rollback id + rollbackId, err := s.GetRollbackID() + if err != nil { + t.Error(err) + } + + // create a 3rd doc c + err = writer.Set([]byte("c"), []byte("val-c")) + if err != nil { + t.Error(err) + } + + err = writer.Close() + if err != nil { + t.Error(err) + } + + // make sure c is there + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + val, err := reader.Get([]byte("c")) + if err != nil { + t.Error(err) + } + if string(val) != "val-c" { + t.Errorf("expected value 'val-c' got '%s'", val) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } + + // now rollback + err = s.RollbackTo(rollbackId) + if err != nil { + t.Fatal(err) + } + + // now lets open another handle + s2, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s2.Open() + if err != nil { + t.Fatal(err) + } + defer s2.Close() + + // now make sure c is not there + reader2, err := s2.Reader() + if err != nil { + t.Error(err) + } + val, err = reader2.Get([]byte("c")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected missing, got '%s'", val) + } + err = reader2.Close() + if err != nil { + t.Fatal(err) + } +} + +// TestRollbackOtherHandle tries to create 2 handles +// at the beginning, then rollback one of them +// and ensure it affects the other +func TestRollbackOtherHandle(t *testing.T) { + defer func() { + err := os.RemoveAll("testdir") + if err != nil { + t.Fatal(err) + } + }() + + err := os.MkdirAll("testdir", 0700) + if err != nil { + t.Fatal(err) + } + s, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + // open another handle at the same time + s2, err := New("testdir/test", true, nil) + if err != nil { + t.Fatal(err) + } + err = s2.Open() + if err != nil { + t.Fatal(err) + } + defer s2.Close() + + writer, err := s.Writer() + if err != nil { + t.Fatal(err) + } + + // create 2 docs, a and b + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Error(err) + } + + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Error(err) + } + + // get the rollback id + rollbackId, err := s.GetRollbackID() + if err != nil { + t.Error(err) + } + + // create a 3rd doc c + err = writer.Set([]byte("c"), []byte("val-c")) + if err != nil { + t.Error(err) + } + + err = writer.Close() + if err != nil { + t.Error(err) + } + + // make sure c is there + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + val, err := reader.Get([]byte("c")) + if err != nil { + t.Error(err) + } + if string(val) != "val-c" { + t.Errorf("expected value 'val-c' got '%s'", val) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } + + // now rollback + err = s.RollbackTo(rollbackId) + if err != nil { + t.Fatal(err) + } + + // now make sure c is not on the other handle + reader2, err := s2.Reader() + if err != nil { + t.Error(err) + } + val, err = reader2.Get([]byte("c")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected missing, got '%s'", val) + } + err = reader2.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it2 := newReader.Iterator([]byte{0}) + defer func() { + err := it2.Close() + if err != nil { + t.Fatal(err) + } + }() + for it2.Valid() { + it2.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it3 := reader.Iterator([]byte{0}) + defer func() { + err := it3.Close() + if err != nil { + t.Fatal(err) + } + }() + for it3.Valid() { + it3.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/writer.go new file mode 100644 index 00000000..6a5b2bc6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb/writer.go @@ -0,0 +1,71 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package forestdb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Writer struct { + store *Store +} + +func (w *Writer) BytesSafeAfterClose() bool { + return true +} + +func newWriter(store *Store) (*Writer, error) { + store.writer.Lock() + return &Writer{ + store: store, + }, nil +} + +func (w *Writer) Set(key, val []byte) error { + err := w.store.setlocked(key, val) + if err != nil { + return err + } + return w.store.commit() +} + +func (w *Writer) Delete(key []byte) error { + err := w.store.deletelocked(key) + if err != nil { + return err + } + return w.store.commit() +} + +func (w *Writer) NewBatch() store.KVBatch { + return &Batch{ + s: w.store, + ops: make([]op, 0, 1000), + merges: make(map[string][][]byte), + } +} + +func (w *Writer) Close() error { + w.store.writer.Unlock() + return nil +} + +// these two methods can safely read using the regular +// methods without a read transaction, because we know +// that no one else is writing but us +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.store.get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.store.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/batch.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/batch.go new file mode 100644 index 00000000..9b0e67bc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/batch.go @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb" +) + +type Batch struct { + w *Writer + merge *store.EmulatedMerge + batch *leveldb.Batch +} + +func (b *Batch) Set(key, val []byte) { + b.batch.Put(key, val) +} + +func (b *Batch) Delete(key []byte) { + b.batch.Delete(key) +} + +func (b *Batch) Merge(key, val []byte) { + b.merge.Merge(key, val) +} + +func (b *Batch) Execute() error { + + // first process merges + ops, err := b.merge.ExecuteDeferred(b.w) + if err != nil { + return err + } + for _, op := range ops { + b.batch.Put(op.K, op.V) + } + + wopts := defaultWriteOptions() + err = b.w.store.db.Write(b.batch, wopts) + return err +} + +func (b *Batch) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/iterator.go new file mode 100644 index 00000000..455a3306 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/iterator.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" +) + +type Iterator struct { + store *Store + iterator iterator.Iterator +} + +func newIterator(store *Store) *Iterator { + ropts := defaultReadOptions() + iter := store.db.NewIterator(nil, ropts) + rv := Iterator{ + store: store, + iterator: iter, + } + return &rv +} + +func newIteratorWithSnapshot(store *Store, snapshot *leveldb.Snapshot) *Iterator { + options := defaultReadOptions() + iter := snapshot.NewIterator(nil, options) + rv := Iterator{ + store: store, + iterator: iter, + } + return &rv +} + +func (ldi *Iterator) SeekFirst() { + ldi.iterator.First() +} + +func (ldi *Iterator) Seek(key []byte) { + ldi.iterator.Seek(key) +} + +func (ldi *Iterator) Next() { + ldi.iterator.Next() +} + +func (ldi *Iterator) Current() ([]byte, []byte, bool) { + if ldi.Valid() { + return ldi.Key(), ldi.Value(), true + } + return nil, nil, false +} + +func (ldi *Iterator) Key() []byte { + return ldi.iterator.Key() +} + +func (ldi *Iterator) Value() []byte { + return ldi.iterator.Value() +} + +func (ldi *Iterator) Valid() bool { + return ldi.iterator.Valid() +} + +func (ldi *Iterator) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/reader.go new file mode 100644 index 00000000..8a5985ae --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/reader.go @@ -0,0 +1,47 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb" +) + +type Reader struct { + store *Store + snapshot *leveldb.Snapshot +} + +func newReader(store *Store) (*Reader, error) { + snapshot, _ := store.db.GetSnapshot() + return &Reader{ + store: store, + snapshot: snapshot, + }, nil +} + +func (r *Reader) BytesSafeAfterClose() bool { + return false +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + return r.store.getWithSnapshot(key, r.snapshot) +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + rv := newIteratorWithSnapshot(r.store, r.snapshot) + rv.Seek(key) + return rv +} + +func (r *Reader) Close() error { + r.snapshot.Release() + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store.go new file mode 100644 index 00000000..6ffd209b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store.go @@ -0,0 +1,172 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "fmt" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" +) + +const Name = "goleveldb" + +type Store struct { + path string + opts *opt.Options + db *leveldb.DB + writer sync.Mutex + mo store.MergeOperator +} + +func New(path string, config map[string]interface{}) (*Store, error) { + rv := Store{ + path: path, + opts: &opt.Options{}, + } + + _, err := applyConfig(rv.opts, config) + if err != nil { + return nil, err + } + + return &rv, nil +} + +func (ldbs *Store) Open() error { + var err error + ldbs.db, err = leveldb.OpenFile(ldbs.path, ldbs.opts) + if err != nil { + return err + } + return nil +} + +func (ldbs *Store) SetMergeOperator(mo store.MergeOperator) { + ldbs.mo = mo +} + +func (ldbs *Store) get(key []byte) ([]byte, error) { + options := defaultReadOptions() + b, err := ldbs.db.Get(key, options) + if err == leveldb.ErrNotFound { + return nil, nil + } + return b, err +} + +func (ldbs *Store) getWithSnapshot(key []byte, snapshot *leveldb.Snapshot) ([]byte, error) { + options := defaultReadOptions() + b, err := snapshot.Get(key, options) + if err == leveldb.ErrNotFound { + return nil, nil + } + return b, err +} + +func (ldbs *Store) set(key, val []byte) error { + ldbs.writer.Lock() + defer ldbs.writer.Unlock() + return ldbs.setlocked(key, val) +} + +func (ldbs *Store) setlocked(key, val []byte) error { + options := defaultWriteOptions() + err := ldbs.db.Put(key, val, options) + return err +} + +func (ldbs *Store) delete(key []byte) error { + ldbs.writer.Lock() + defer ldbs.writer.Unlock() + return ldbs.deletelocked(key) +} + +func (ldbs *Store) deletelocked(key []byte) error { + options := defaultWriteOptions() + err := ldbs.db.Delete(key, options) + return err +} + +func (ldbs *Store) Close() error { + return ldbs.db.Close() +} + +func (ldbs *Store) iterator(key []byte) store.KVIterator { + rv := newIterator(ldbs) + rv.Seek(key) + return rv +} + +func (ldbs *Store) Reader() (store.KVReader, error) { + return newReader(ldbs) +} + +func (ldbs *Store) Writer() (store.KVWriter, error) { + return newWriter(ldbs) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + path, ok := config["path"].(string) + if !ok { + return nil, fmt.Errorf("must specify path") + } + return New(path, config) +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +func applyConfig(o *opt.Options, config map[string]interface{}) ( + *opt.Options, error) { + + cim, ok := config["create_if_missing"].(bool) + if ok { + o.ErrorIfMissing = !cim + } + + eie, ok := config["error_if_exists"].(bool) + if ok { + o.ErrorIfExist = eie + } + + wbs, ok := config["write_buffer_size"].(float64) + if ok { + o.WriteBuffer = int(wbs) + } + + bs, ok := config["block_size"].(float64) + if ok { + o.BlockSize = int(bs) + } + + bri, ok := config["block_restart_interval"].(float64) + if ok { + o.BlockRestartInterval = int(bri) + } + + lcc, ok := config["lru_cache_capacity"].(float64) + if ok { + o.BlockCacheCapacity = int(lcc) + } + + bfbpk, ok := config["bloom_filter_bits_per_key"].(float64) + if ok { + bf := filter.NewBloomFilter(int(bfbpk)) + o.Filter = bf + } + + return o, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store_test.go new file mode 100644 index 00000000..ef807b4c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/store_test.go @@ -0,0 +1,296 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +var leveldbTestOptions = map[string]interface{}{ + "create_if_missing": true, +} + +func TestLevelDBStore(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s, err := New("test", leveldbTestOptions) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestKVStore(t, s) +} + +func TestReaderIsolation(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s, err := New("test", leveldbTestOptions) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestReaderIsolation(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it = newReader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it = reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/util.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/util.go new file mode 100644 index 00000000..353e4a9e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/util.go @@ -0,0 +1,26 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" +) + +func defaultWriteOptions() *opt.WriteOptions { + wo := &opt.WriteOptions{} + // request fsync on write for safety + wo.Sync = true + return wo +} + +func defaultReadOptions() *opt.ReadOptions { + ro := &opt.ReadOptions{} + return ro +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/writer.go new file mode 100644 index 00000000..f62f4c82 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb/writer.go @@ -0,0 +1,63 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package goleveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb" +) + +type Writer struct { + store *Store +} + +func newWriter(store *Store) (*Writer, error) { + store.writer.Lock() + return &Writer{ + store: store, + }, nil +} + +func (w *Writer) BytesSafeAfterClose() bool { + return false +} + +func (w *Writer) Set(key, val []byte) error { + return w.store.setlocked(key, val) +} + +func (w *Writer) Delete(key []byte) error { + return w.store.deletelocked(key) +} + +func (w *Writer) NewBatch() store.KVBatch { + rv := Batch{ + w: w, + merge: store.NewEmulatedMerge(w.store.mo), + batch: new(leveldb.Batch), + } + return &rv +} + +func (w *Writer) Close() error { + w.store.writer.Unlock() + return nil +} + +// these two methods can safely read using the regular +// methods without a read transaction, because we know +// that no one else is writing but us +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.store.get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.store.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/batch.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/batch.go new file mode 100644 index 00000000..3d80ece8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/batch.go @@ -0,0 +1,43 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "github.com/tecbot/gorocksdb" +) + +type Batch struct { + w *Writer + batch *gorocksdb.WriteBatch +} + +func (b *Batch) Set(key, val []byte) { + b.batch.Put(key, val) +} + +func (b *Batch) Delete(key []byte) { + b.batch.Delete(key) +} + +func (b *Batch) Merge(key, val []byte) { + b.batch.Merge(key, val) +} + +func (b *Batch) Execute() error { + wopts := defaultWriteOptions() + err := b.w.store.db.Write(wopts, b.batch) + return err +} + +func (b *Batch) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/iterator.go new file mode 100644 index 00000000..9acdb76d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/iterator.go @@ -0,0 +1,76 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "github.com/tecbot/gorocksdb" +) + +type Iterator struct { + store *Store + iterator *gorocksdb.Iterator +} + +func newIterator(store *Store) *Iterator { + ropts := defaultReadOptions() + rv := Iterator{ + store: store, + iterator: store.db.NewIterator(ropts), + } + return &rv +} + +func newIteratorWithSnapshot(store *Store, snapshot *gorocksdb.Snapshot) *Iterator { + options := defaultReadOptions() + options.SetSnapshot(snapshot) + rv := Iterator{ + store: store, + iterator: store.db.NewIterator(options), + } + return &rv +} + +func (ldi *Iterator) SeekFirst() { + ldi.iterator.SeekToFirst() +} + +func (ldi *Iterator) Seek(key []byte) { + ldi.iterator.Seek(key) +} + +func (ldi *Iterator) Next() { + ldi.iterator.Next() +} + +func (ldi *Iterator) Current() ([]byte, []byte, bool) { + if ldi.Valid() { + return ldi.Key(), ldi.Value(), true + } + return nil, nil, false +} + +func (ldi *Iterator) Key() []byte { + return ldi.iterator.Key().Data() +} + +func (ldi *Iterator) Value() []byte { + return ldi.iterator.Value().Data() +} + +func (ldi *Iterator) Valid() bool { + return ldi.iterator.Valid() +} + +func (ldi *Iterator) Close() error { + ldi.iterator.Close() + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/reader.go new file mode 100644 index 00000000..e220a3ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/reader.go @@ -0,0 +1,48 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/tecbot/gorocksdb" +) + +type Reader struct { + store *Store + snapshot *gorocksdb.Snapshot +} + +func newReader(store *Store) (*Reader, error) { + return &Reader{ + store: store, + snapshot: store.db.NewSnapshot(), + }, nil +} + +func (r *Reader) BytesSafeAfterClose() bool { + return false +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + return r.store.getWithSnapshot(key, r.snapshot) +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + rv := newIteratorWithSnapshot(r.store, r.snapshot) + rv.Seek(key) + return rv +} + +func (r *Reader) Close() error { + r.snapshot.Release() + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store.go new file mode 100644 index 00000000..33591ed6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store.go @@ -0,0 +1,146 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "fmt" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/tecbot/gorocksdb" +) + +const Name = "rocksdb" + +type Store struct { + path string + opts *gorocksdb.Options + db *gorocksdb.DB + writer sync.Mutex +} + +func New(path string, config map[string]interface{}) (*Store, error) { + rv := Store{ + path: path, + opts: gorocksdb.NewDefaultOptions(), + } + + _, err := applyConfig(rv.opts, config) + if err != nil { + return nil, err + } + + return &rv, nil +} + +func (ldbs *Store) Open() error { + var err error + ldbs.db, err = gorocksdb.OpenDb(ldbs.opts, ldbs.path) + if err != nil { + return err + } + return nil +} + +func (ldbs *Store) SetMergeOperator(mo store.MergeOperator) { + ldbs.opts.SetMergeOperator(mo) +} + +func (ldbs *Store) get(key []byte) ([]byte, error) { + options := defaultReadOptions() + b, err := ldbs.db.Get(options, key) + return b.Data(), err +} + +func (ldbs *Store) getWithSnapshot(key []byte, snapshot *gorocksdb.Snapshot) ([]byte, error) { + options := defaultReadOptions() + options.SetSnapshot(snapshot) + b, err := ldbs.db.Get(options, key) + return b.Data(), err +} + +func (ldbs *Store) set(key, val []byte) error { + ldbs.writer.Lock() + defer ldbs.writer.Unlock() + return ldbs.setlocked(key, val) +} + +func (ldbs *Store) setlocked(key, val []byte) error { + options := defaultWriteOptions() + err := ldbs.db.Put(options, key, val) + return err +} + +func (ldbs *Store) delete(key []byte) error { + ldbs.writer.Lock() + defer ldbs.writer.Unlock() + return ldbs.deletelocked(key) +} + +func (ldbs *Store) deletelocked(key []byte) error { + options := defaultWriteOptions() + err := ldbs.db.Delete(options, key) + return err +} + +func (ldbs *Store) Close() error { + ldbs.db.Close() + return nil +} + +func (ldbs *Store) iterator(key []byte) store.KVIterator { + rv := newIterator(ldbs) + rv.Seek(key) + return rv +} + +func (ldbs *Store) Reader() (store.KVReader, error) { + return newReader(ldbs) +} + +func (ldbs *Store) Writer() (store.KVWriter, error) { + return newWriter(ldbs) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + path, ok := config["path"].(string) + if !ok { + return nil, fmt.Errorf("must specify path") + } + return New(path, config) +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +func applyConfig(o *gorocksdb.Options, config map[string]interface{}) ( + *gorocksdb.Options, error) { + + cim, ok := config["create_if_missing"].(bool) + if ok { + o.SetCreateIfMissing(cim) + } + + eie, ok := config["error_if_exists"].(bool) + if ok { + o.SetErrorIfExists(eie) + } + + wbs, ok := config["write_buffer_size"].(float64) + if ok { + o.SetWriteBufferSize(int(wbs)) + } + + return o, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store_test.go new file mode 100644 index 00000000..1ff20aea --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/store_test.go @@ -0,0 +1,298 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +var rocksdbTestOptions = map[string]interface{}{ + "create_if_missing": true, +} + +func TestGoRocksDBStore(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s, err := New("test", rocksdbTestOptions) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestKVStore(t, s) +} + +func TestReaderIsolation(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s, err := New("test", rocksdbTestOptions) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestReaderIsolation(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it2 := newReader.Iterator([]byte{0}) + defer func() { + err := it2.Close() + if err != nil { + t.Fatal(err) + } + }() + for it2.Valid() { + it2.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it3 := reader.Iterator([]byte{0}) + defer func() { + err := it3.Close() + if err != nil { + t.Fatal(err) + } + }() + for it3.Valid() { + it3.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/util.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/util.go new file mode 100644 index 00000000..830fe490 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/util.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "github.com/tecbot/gorocksdb" +) + +func defaultWriteOptions() *gorocksdb.WriteOptions { + wo := gorocksdb.NewDefaultWriteOptions() + // request fsync on write for safety + wo.SetSync(true) + return wo +} + +func defaultReadOptions() *gorocksdb.ReadOptions { + ro := gorocksdb.NewDefaultReadOptions() + return ro +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/writer.go new file mode 100644 index 00000000..fde00896 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb/writer.go @@ -0,0 +1,64 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package rocksdb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/tecbot/gorocksdb" +) + +type Writer struct { + store *Store +} + +func newWriter(store *Store) (*Writer, error) { + store.writer.Lock() + return &Writer{ + store: store, + }, nil +} + +func (w *Writer) BytesSafeAfterClose() bool { + return false +} + +func (w *Writer) Set(key, val []byte) error { + return w.store.setlocked(key, val) +} + +func (w *Writer) Delete(key []byte) error { + return w.store.deletelocked(key) +} + +func (w *Writer) NewBatch() store.KVBatch { + rv := Batch{ + w: w, + batch: gorocksdb.NewWriteBatch(), + } + return &rv +} + +func (w *Writer) Close() error { + w.store.writer.Unlock() + return nil +} + +// these two methods can safely read using the regular +// methods without a read transaction, because we know +// that no one else is writing but us +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.store.get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.store.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap.go new file mode 100644 index 00000000..311e15ba --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap.go @@ -0,0 +1,95 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// Package gtreap provides an in-memory implementation of the +// KVStore interfaces using the gtreap balanced-binary treap, +// copy-on-write data structure. +package gtreap + +import ( + "bytes" + "fmt" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/steveyen/gtreap" +) + +const Name = "gtreap" + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +const MAX_CONCURRENT_WRITERS = 1 + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + s := &Store{ + availableWriters: make(chan bool, MAX_CONCURRENT_WRITERS), + t: gtreap.NewTreap(itemCompare), + } + for i := 0; i < MAX_CONCURRENT_WRITERS; i++ { + s.availableWriters <- true + } + return s, nil +} + +type Item struct { + k []byte + v []byte +} + +func itemCompare(a, b interface{}) int { + return bytes.Compare(a.(*Item).k, b.(*Item).k) +} + +type Store struct { + availableWriters chan bool + + m sync.Mutex + t *gtreap.Treap + + mo store.MergeOperator +} + +type Writer struct { + s *Store +} + +func (s *Store) Open() error { + return nil +} + +func (s *Store) SetMergeOperator(mo store.MergeOperator) { + s.mo = mo +} + +func (s *Store) Close() error { + close(s.availableWriters) + return nil +} + +func (s *Store) Reader() (store.KVReader, error) { + s.m.Lock() + t := s.t + s.m.Unlock() + return &Reader{t: t}, nil +} + +func (s *Store) Writer() (store.KVWriter, error) { + available, ok := <-s.availableWriters + if !ok || !available { + return nil, fmt.Errorf("no available writers") + } + + return &Writer{s: s}, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap_test.go new file mode 100644 index 00000000..93f4598c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/gtreap_test.go @@ -0,0 +1,259 @@ +// Copyright (c) 2014 Couchbase, Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +package gtreap + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func TestGTreapStore(t *testing.T) { + s, err := StoreConstructor(nil) + if err != nil { + t.Fatal(err) + } + + CommonTestKVStore(t, s) +} + +func TestReaderIsolation(t *testing.T) { + s, err := StoreConstructor(nil) + if err != nil { + t.Fatal(err) + } + + CommonTestReaderIsolation(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + valB := []byte("val-b") + err = writer.Set([]byte("b"), valB) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got %s", val) + } + + // ensure that the director iterator sees it + count = 0 + it2 := newReader.Iterator([]byte{0}) + defer func() { + err := it2.Close() + if err != nil { + t.Fatal(err) + } + }() + for it2.Valid() { + it2.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it3 := reader.Iterator([]byte{0}) + defer func() { + err := it3.Close() + if err != nil { + t.Fatal(err) + } + }() + for it3.Valid() { + it3.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/iterator.go new file mode 100644 index 00000000..3c242639 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/iterator.go @@ -0,0 +1,132 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// Package gtreap provides an in-memory implementation of the +// KVStore interfaces using the gtreap balanced-binary treap, +// copy-on-write data structure. +package gtreap + +import ( + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/steveyen/gtreap" +) + +type Iterator struct { + t *gtreap.Treap + + m sync.Mutex + cancelCh chan struct{} + nextCh chan *Item + curr *Item + currOk bool +} + +func newIterator(t *gtreap.Treap) *Iterator { + return &Iterator{t: t} +} + +func (w *Iterator) SeekFirst() { + min := w.t.Min() + if min != nil { + w.restart(min.(*Item)) + } else { + w.restart(nil) + } +} + +func (w *Iterator) Seek(k []byte) { + w.restart(&Item{k: k}) +} + +func (w *Iterator) restart(start *Item) *Iterator { + cancelCh := make(chan struct{}) + nextCh := make(chan *Item, 1) + + w.m.Lock() + if w.cancelCh != nil { + close(w.cancelCh) + } + w.cancelCh = cancelCh + w.nextCh = nextCh + w.curr = nil + w.currOk = false + w.m.Unlock() + + go func() { + if start != nil { + w.t.VisitAscend(start, func(itm gtreap.Item) bool { + select { + case <-cancelCh: + return false + case nextCh <- itm.(*Item): + return true + } + }) + } + close(nextCh) + }() + + w.Next() + + return w +} + +func (w *Iterator) Next() { + w.m.Lock() + nextCh := w.nextCh + w.m.Unlock() + w.curr, w.currOk = <-nextCh +} + +func (w *Iterator) Current() ([]byte, []byte, bool) { + w.m.Lock() + defer w.m.Unlock() + if !w.currOk || w.curr == nil { + return nil, nil, false + } + return w.curr.k, w.curr.v, w.currOk +} + +func (w *Iterator) Key() []byte { + k, _, ok := w.Current() + if !ok { + return nil + } + return k +} + +func (w *Iterator) Value() []byte { + _, v, ok := w.Current() + if !ok { + return nil + } + return v +} + +func (w *Iterator) Valid() bool { + _, _, ok := w.Current() + return ok +} + +func (w *Iterator) Close() error { + w.m.Lock() + if w.cancelCh != nil { + close(w.cancelCh) + } + w.cancelCh = nil + w.nextCh = nil + w.curr = nil + w.currOk = false + w.m.Unlock() + + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/reader.go new file mode 100644 index 00000000..59685291 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/reader.go @@ -0,0 +1,44 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// Package gtreap provides an in-memory implementation of the +// KVStore interfaces using the gtreap balanced-binary treap, +// copy-on-write data structure. +package gtreap + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/steveyen/gtreap" +) + +type Reader struct { + t *gtreap.Treap +} + +func (w *Reader) BytesSafeAfterClose() bool { + return false +} + +func (w *Reader) Get(k []byte) (v []byte, err error) { + itm := w.t.Get(&Item{k: k}) + if itm != nil { + return itm.(*Item).v, nil + } + return nil, nil +} + +func (w *Reader) Iterator(k []byte) store.KVIterator { + return newIterator(w.t).restart(&Item{k: k}) +} + +func (w *Reader) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/writer.go new file mode 100644 index 00000000..0c5d1736 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap/writer.go @@ -0,0 +1,72 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// Package gtreap provides an in-memory implementation of the +// KVStore interfaces using the gtreap balanced-binary treap, +// copy-on-write data structure. +package gtreap + +import ( + "math/rand" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func (w *Writer) BytesSafeAfterClose() bool { + return false +} + +func (w *Writer) Get(k []byte) (v []byte, err error) { + w.s.m.Lock() + t := w.s.t + w.s.m.Unlock() + + itm := t.Get(&Item{k: k}) + if itm != nil { + return itm.(*Item).v, nil + } + return nil, nil +} + +func (w *Writer) Iterator(k []byte) store.KVIterator { + w.s.m.Lock() + t := w.s.t + w.s.m.Unlock() + + return newIterator(t).restart(&Item{k: k}) +} + +func (w *Writer) Close() error { + w.s.availableWriters <- true + w.s = nil + + return nil +} + +func (w *Writer) Set(k, v []byte) (err error) { + w.s.m.Lock() + w.s.t = w.s.t.Upsert(&Item{k: k, v: v}, rand.Int()) + w.s.m.Unlock() + + return nil +} + +func (w *Writer) Delete(k []byte) (err error) { + w.s.m.Lock() + w.s.t = w.s.t.Delete(&Item{k: k}) + w.s.m.Unlock() + + return nil +} + +func (w *Writer) NewBatch() store.KVBatch { + return store.NewEmulatedBatch(w, w.s.mo) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/iterator.go new file mode 100644 index 00000000..dfb3dc93 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/iterator.go @@ -0,0 +1,70 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package inmem + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist" +) + +type Iterator struct { + store *Store + iterator skiplist.Iterator + valid bool +} + +func newIterator(store *Store) *Iterator { + rv := Iterator{ + store: store, + iterator: store.list.Iterator(), + } + return &rv +} + +func (i *Iterator) SeekFirst() { + i.Seek([]byte{0}) +} + +func (i *Iterator) Seek(k []byte) { + i.valid = i.iterator.Seek(string(k)) +} + +func (i *Iterator) Next() { + i.valid = i.iterator.Next() +} + +func (i *Iterator) Current() ([]byte, []byte, bool) { + if i.valid { + return []byte(i.Key()), []byte(i.Value()), true + } + return nil, nil, false +} + +func (i *Iterator) Key() []byte { + if i.valid { + return []byte(i.iterator.Key().(string)) + } + return nil +} + +func (i *Iterator) Value() []byte { + if i.valid { + return []byte(i.iterator.Value().(string)) + } + return nil +} + +func (i *Iterator) Valid() bool { + return i.valid +} + +func (i *Iterator) Close() error { + i.iterator.Close() + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/reader.go new file mode 100644 index 00000000..a7757919 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/reader.go @@ -0,0 +1,40 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package inmem + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Reader struct { + store *Store +} + +func newReader(store *Store) (*Reader, error) { + return &Reader{ + store: store, + }, nil +} + +func (r *Reader) BytesSafeAfterClose() bool { + return false +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + return r.store.get(key) +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + return r.store.iterator(key) +} + +func (r *Reader) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store.go new file mode 100644 index 00000000..8048ef6a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store.go @@ -0,0 +1,106 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package inmem + +import ( + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist" +) + +const Name = "mem" + +type Store struct { + list *skiplist.SkipList + writer sync.Mutex + mo store.MergeOperator +} + +func New() (*Store, error) { + rv := Store{ + list: skiplist.NewStringMap(), + } + + return &rv, nil +} + +func MustOpen() *Store { + rv := Store{ + list: skiplist.NewStringMap(), + } + + return &rv +} + +func (i *Store) Open() error { + return nil +} + +func (i *Store) SetMergeOperator(mo store.MergeOperator) { + i.mo = mo +} + +func (i *Store) get(key []byte) ([]byte, error) { + val, ok := i.list.Get(string(key)) + if ok { + return []byte(val.(string)), nil + } + return nil, nil +} + +func (i *Store) set(key, val []byte) error { + i.writer.Lock() + defer i.writer.Unlock() + return i.setlocked(key, val) +} + +func (i *Store) setlocked(key, val []byte) error { + i.list.Set(string(key), string(val)) + return nil +} + +func (i *Store) delete(key []byte) error { + i.writer.Lock() + defer i.writer.Unlock() + return i.deletelocked(key) +} + +func (i *Store) deletelocked(key []byte) error { + i.list.Delete(string(key)) + return nil +} + +func (i *Store) Close() error { + return nil +} + +func (i *Store) iterator(key []byte) store.KVIterator { + rv := newIterator(i) + rv.Seek(key) + return rv +} + +func (i *Store) Reader() (store.KVReader, error) { + return newReader(i) +} + +func (i *Store) Writer() (store.KVWriter, error) { + return newWriter(i) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + return New() +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store_test.go new file mode 100644 index 00000000..ff0a695c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/store_test.go @@ -0,0 +1,254 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package inmem + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func TestStore(t *testing.T) { + s, err := New() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestKVStore(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it = newReader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it = reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/writer.go new file mode 100644 index 00000000..6dbd8f14 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem/writer.go @@ -0,0 +1,57 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package inmem + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Writer struct { + store *Store +} + +func newWriter(store *Store) (*Writer, error) { + store.writer.Lock() + return &Writer{ + store: store, + }, nil +} + +func (w *Writer) BytesSafeAfterClose() bool { + return false +} + +func (w *Writer) Set(key, val []byte) error { + return w.store.setlocked(key, val) +} + +func (w *Writer) Delete(key []byte) error { + return w.store.deletelocked(key) +} + +func (w *Writer) NewBatch() store.KVBatch { + return store.NewEmulatedBatch(w, w.store.mo) +} + +func (w *Writer) Close() error { + w.store.writer.Unlock() + return nil +} + +// these two methods can safely read using the regular +// methods without a read transaction, because we know +// that no one else is writing but us +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.store.get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.store.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/kvstore.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/kvstore.go new file mode 100644 index 00000000..4be8e0a5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/kvstore.go @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package store + +type KVBatch interface { + Set(key, val []byte) + Delete(key []byte) + Merge(key, val []byte) + Execute() error + Close() error +} + +type KVIterator interface { + SeekFirst() + Seek([]byte) + Next() + + Current() ([]byte, []byte, bool) + Key() []byte + Value() []byte + Valid() bool + + Close() error +} + +type KVStore interface { + Open() error + SetMergeOperator(MergeOperator) + Writer() (KVWriter, error) + Reader() (KVReader, error) + Close() error +} + +type KVWriter interface { + KVReader + Set(key, val []byte) error + Delete(key []byte) error + NewBatch() KVBatch +} + +type KVReader interface { + BytesSafeAfterClose() bool + Get(key []byte) ([]byte, error) + Iterator(key []byte) KVIterator + Close() error +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/batch.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/batch.go new file mode 100644 index 00000000..dee96d6e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/batch.go @@ -0,0 +1,55 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "github.com/jmhodges/levigo" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Batch struct { + w *Writer + merge *store.EmulatedMerge + batch *levigo.WriteBatch +} + +func (b *Batch) Set(key, val []byte) { + b.batch.Put(key, val) +} + +func (b *Batch) Delete(key []byte) { + b.batch.Delete(key) +} + +func (b *Batch) Merge(key, val []byte) { + b.merge.Merge(key, val) +} + +func (b *Batch) Execute() error { + // first process merges + ops, err := b.merge.ExecuteDeferred(b.w) + if err != nil { + return err + } + for _, op := range ops { + b.batch.Put(op.K, op.V) + } + + wopts := defaultWriteOptions() + defer wopts.Close() + err = b.w.store.db.Write(wopts, b.batch) + return err +} + +func (b *Batch) Close() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/iterator.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/iterator.go new file mode 100644 index 00000000..10ef8d7d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/iterator.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "github.com/jmhodges/levigo" +) + +type Iterator struct { + store *Store + iterator *levigo.Iterator +} + +func newIterator(store *Store) *Iterator { + ropts := defaultReadOptions() + rv := Iterator{ + store: store, + iterator: store.db.NewIterator(ropts), + } + ropts.Close() + return &rv +} + +func newIteratorWithSnapshot(store *Store, snapshot *levigo.Snapshot) *Iterator { + options := defaultReadOptions() + options.SetSnapshot(snapshot) + rv := Iterator{ + store: store, + iterator: store.db.NewIterator(options), + } + options.Close() + return &rv +} + +func (ldi *Iterator) SeekFirst() { + ldi.iterator.SeekToFirst() +} + +func (ldi *Iterator) Seek(key []byte) { + ldi.iterator.Seek(key) +} + +func (ldi *Iterator) Next() { + ldi.iterator.Next() +} + +func (ldi *Iterator) Current() ([]byte, []byte, bool) { + if ldi.Valid() { + return ldi.Key(), ldi.Value(), true + } + return nil, nil, false +} + +func (ldi *Iterator) Key() []byte { + return ldi.iterator.Key() +} + +func (ldi *Iterator) Value() []byte { + return ldi.iterator.Value() +} + +func (ldi *Iterator) Valid() bool { + return ldi.iterator.Valid() +} + +func (ldi *Iterator) Close() error { + ldi.iterator.Close() + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/reader.go new file mode 100644 index 00000000..230f3479 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/reader.go @@ -0,0 +1,48 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "github.com/jmhodges/levigo" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Reader struct { + store *Store + snapshot *levigo.Snapshot +} + +func newReader(store *Store) (*Reader, error) { + return &Reader{ + store: store, + snapshot: store.db.NewSnapshot(), + }, nil +} + +func (r *Reader) BytesSafeAfterClose() bool { + return true +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + return r.store.getWithSnapshot(key, r.snapshot) +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + rv := newIteratorWithSnapshot(r.store, r.snapshot) + rv.Seek(key) + return rv +} + +func (r *Reader) Close() error { + r.store.db.ReleaseSnapshot(r.snapshot) + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store.go new file mode 100644 index 00000000..e46cee22 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store.go @@ -0,0 +1,174 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "fmt" + "sync" + + "github.com/jmhodges/levigo" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const Name = "leveldb" + +type Store struct { + path string + opts *levigo.Options + db *levigo.DB + writer sync.Mutex + mo store.MergeOperator +} + +func New(path string, config map[string]interface{}) (*Store, error) { + rv := Store{ + path: path, + opts: levigo.NewOptions(), + } + + _, err := applyConfig(rv.opts, config) + if err != nil { + return nil, err + } + + return &rv, nil +} + +func (ldbs *Store) Open() error { + var err error + ldbs.db, err = levigo.Open(ldbs.path, ldbs.opts) + if err != nil { + return err + } + return nil +} + +func (ldbs *Store) SetMergeOperator(mo store.MergeOperator) { + ldbs.mo = mo +} + +func (ldbs *Store) get(key []byte) ([]byte, error) { + options := defaultReadOptions() + b, err := ldbs.db.Get(options, key) + options.Close() + return b, err +} + +func (ldbs *Store) getWithSnapshot(key []byte, snapshot *levigo.Snapshot) ([]byte, error) { + options := defaultReadOptions() + options.SetSnapshot(snapshot) + b, err := ldbs.db.Get(options, key) + options.Close() + return b, err +} + +func (ldbs *Store) set(key, val []byte) error { + ldbs.writer.Lock() + defer ldbs.writer.Unlock() + return ldbs.setlocked(key, val) +} + +func (ldbs *Store) setlocked(key, val []byte) error { + options := defaultWriteOptions() + err := ldbs.db.Put(options, key, val) + options.Close() + return err +} + +func (ldbs *Store) delete(key []byte) error { + ldbs.writer.Lock() + defer ldbs.writer.Unlock() + return ldbs.deletelocked(key) +} + +func (ldbs *Store) deletelocked(key []byte) error { + options := defaultWriteOptions() + err := ldbs.db.Delete(options, key) + options.Close() + return err +} + +func (ldbs *Store) Close() error { + ldbs.db.Close() + ldbs.opts.Close() + return nil +} + +func (ldbs *Store) iterator(key []byte) store.KVIterator { + rv := newIterator(ldbs) + rv.Seek(key) + return rv +} + +func (ldbs *Store) Reader() (store.KVReader, error) { + return newReader(ldbs) +} + +func (ldbs *Store) Writer() (store.KVWriter, error) { + return newWriter(ldbs) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + path, ok := config["path"].(string) + if !ok { + return nil, fmt.Errorf("must specify path") + } + return New(path, config) +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +func applyConfig(o *levigo.Options, config map[string]interface{}) ( + *levigo.Options, error) { + + cim, ok := config["create_if_missing"].(bool) + if ok { + o.SetCreateIfMissing(cim) + } + + eie, ok := config["error_if_exists"].(bool) + if ok { + o.SetErrorIfExists(eie) + } + + wbs, ok := config["write_buffer_size"].(float64) + if ok { + o.SetWriteBufferSize(int(wbs)) + } + + bs, ok := config["block_size"].(float64) + if ok { + o.SetBlockSize(int(bs)) + } + + bri, ok := config["block_restart_interval"].(float64) + if ok { + o.SetBlockRestartInterval(int(bri)) + } + + lcc, ok := config["lru_cache_capacity"].(float64) + if ok { + lruCache := levigo.NewLRUCache(int(lcc)) + o.SetCache(lruCache) + } + + bfbpk, ok := config["bloom_filter_bits_per_key"].(float64) + if ok { + bf := levigo.NewBloomFilter(int(bfbpk)) + o.SetFilterPolicy(bf) + } + + return o, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store_test.go new file mode 100644 index 00000000..ad7848d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/store_test.go @@ -0,0 +1,298 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +var leveldbTestOptions = map[string]interface{}{ + "create_if_missing": true, +} + +func TestLevelDBStore(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s, err := New("test", leveldbTestOptions) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestKVStore(t, s) +} + +func TestReaderIsolation(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s, err := New("test", leveldbTestOptions) + if err != nil { + t.Fatal(err) + } + err = s.Open() + if err != nil { + t.Fatal(err) + } + defer func() { + err := s.Close() + if err != nil { + t.Fatal(err) + } + }() + + CommonTestReaderIsolation(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it2 := newReader.Iterator([]byte{0}) + defer func() { + err := it2.Close() + if err != nil { + t.Fatal(err) + } + }() + for it2.Valid() { + it2.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it3 := reader.Iterator([]byte{0}) + defer func() { + err := it3.Close() + if err != nil { + t.Fatal(err) + } + }() + for it3.Valid() { + it3.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/util.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/util.go new file mode 100644 index 00000000..a34f6f84 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/util.go @@ -0,0 +1,28 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "github.com/jmhodges/levigo" +) + +func defaultWriteOptions() *levigo.WriteOptions { + wo := levigo.NewWriteOptions() + // request fsync on write for safety + wo.SetSync(true) + return wo +} + +func defaultReadOptions() *levigo.ReadOptions { + ro := levigo.NewReadOptions() + return ro +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/writer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/writer.go new file mode 100644 index 00000000..b40cb716 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb/writer.go @@ -0,0 +1,65 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package leveldb + +import ( + "github.com/jmhodges/levigo" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Writer struct { + store *Store +} + +func newWriter(store *Store) (*Writer, error) { + store.writer.Lock() + return &Writer{ + store: store, + }, nil +} + +func (w *Writer) BytesSafeAfterClose() bool { + return true +} + +func (w *Writer) Set(key, val []byte) error { + return w.store.setlocked(key, val) +} + +func (w *Writer) Delete(key []byte) error { + return w.store.deletelocked(key) +} + +func (w *Writer) NewBatch() store.KVBatch { + rv := Batch{ + w: w, + merge: store.NewEmulatedMerge(w.store.mo), + batch: levigo.NewWriteBatch(), + } + return &rv +} + +func (w *Writer) Close() error { + w.store.writer.Unlock() + return nil +} + +// these two methods can safely read using the regular +// methods without a read transaction, because we know +// that no one else is writing but us +func (w *Writer) Get(key []byte) ([]byte, error) { + return w.store.get(key) +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.store.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/merge.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/merge.go new file mode 100644 index 00000000..390727bf --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/merge.go @@ -0,0 +1,120 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package store + +import ( + "fmt" +) + +// At the moment this happens to be the same interface as described by +// RocksDB, but this may not always be the case. + +type MergeOperator interface { + + // FullMerge the full sequence of operands on top of the existingValue + // if no value currently exists, existingValue is nil + // return the merged value, and success/failure + FullMerge(key, existingValue []byte, operands [][]byte) ([]byte, bool) + + // Partially merge these two operands. + // If partial merge cannot be done, return nil,false, which will defer + // all processing until the FullMerge is done. + PartialMerge(key, leftOperand, rightOperand []byte) ([]byte, bool) + + // Name returns an identifier for the operator + Name() string +} + +// EmulatedMergeSingle removes some duplicated code across +// KV stores which do not support merge operations +// on their own. It is up to the caller to ensure +// that an appropriate lock has been acquired in +// order for this behavior to be valid +func EmulatedMergeSingle(writer KVWriter, mo MergeOperator, key []byte, operand []byte) error { + existingValue, err := writer.Get(key) + if err != nil { + return err + } + newValue, ok := mo.FullMerge(key, existingValue, [][]byte{operand}) + if !ok { + return fmt.Errorf("merge operator returned failure") + } + err = writer.Set(key, newValue) + if err != nil { + return err + } + return nil +} + +type EmulatedMerge struct { + merges map[string][][]byte + mo MergeOperator +} + +func NewEmulatedMerge(mo MergeOperator) *EmulatedMerge { + return &EmulatedMerge{ + merges: make(map[string][][]byte), + mo: mo, + } +} + +func (m *EmulatedMerge) Merge(key, val []byte) { + ops, ok := m.merges[string(key)] + if ok && len(ops) > 0 { + last := ops[len(ops)-1] + mergedVal, partialMergeOk := m.mo.PartialMerge(key, last, val) + if partialMergeOk { + // replace last entry with the result of the merge + ops[len(ops)-1] = mergedVal + } else { + // could not partial merge, append this to the end + ops = append(ops, val) + } + } else { + ops = [][]byte{val} + } + m.merges[string(key)] = ops +} + +func (m *EmulatedMerge) Execute(w KVWriter) error { + for k, mergeOps := range m.merges { + kb := []byte(k) + existingVal, err := w.Get(kb) + if err != nil { + return err + } + mergedVal, fullMergeOk := m.mo.FullMerge(kb, existingVal, mergeOps) + if !fullMergeOk { + return fmt.Errorf("merge operator returned failure") + } + err = w.Set(kb, mergedVal) + if err != nil { + return err + } + } + return nil +} + +func (m *EmulatedMerge) ExecuteDeferred(w KVWriter) ([]*op, error) { + rv := make([]*op, 0, 1000) + for k, mergeOps := range m.merges { + kb := []byte(k) + existingVal, err := w.Get(kb) + if err != nil { + return nil, err + } + mergedVal, fullMergeOk := m.mo.FullMerge(kb, existingVal, mergeOps) + if !fullMergeOk { + return nil, fmt.Errorf("merge operator returned failure") + } + rv = append(rv, &op{kb, mergedVal}) + } + return rv, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics.go new file mode 100644 index 00000000..ba94b089 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics.go @@ -0,0 +1,475 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// +build debug + +// Package metrics provides a bleve.store.KVStore implementation that +// wraps another, real KVStore implementation, and uses go-metrics to +// track runtime performance metrics. +package metrics + +import ( + "container/list" + "encoding/json" + "fmt" + "io" + "sync" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/rcrowley/go-metrics" +) + +const Name = "metrics" +const MaxErrors = 100 + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + name, ok := config["kvStoreName_actual"].(string) + if !ok || name == "" { + return nil, fmt.Errorf("metrics: missing kvStoreName_actual,"+ + " config: %#v", config) + } + + if name == Name { + return nil, fmt.Errorf("metrics: circular kvStoreName_actual") + } + + ctr := registry.KVStoreConstructorByName(name) + if ctr == nil { + return nil, fmt.Errorf("metrics: no kv store constructor,"+ + " kvStoreName_actual: %s", name) + } + + kvs, err := ctr(config) + if err != nil { + return nil, err + } + + return NewBleveMetricsStore(kvs), nil +} + +func NewBleveMetricsStore(o store.KVStore) *Store { + return &Store{ + o: o, + + TimerReaderGet: metrics.NewTimer(), + TimerReaderIterator: metrics.NewTimer(), + TimerWriterGet: metrics.NewTimer(), + TimerWriterIterator: metrics.NewTimer(), + TimerWriterSet: metrics.NewTimer(), + TimerWriterDelete: metrics.NewTimer(), + TimerIteratorSeekFirst: metrics.NewTimer(), + TimerIteratorSeek: metrics.NewTimer(), + TimerIteratorNext: metrics.NewTimer(), + TimerBatchMerge: metrics.NewTimer(), + TimerBatchExecute: metrics.NewTimer(), + + errors: list.New(), + } +} + +// The following structs are wrappers around "real" bleve kvstore +// implementations. + +type Store struct { + o store.KVStore + + TimerReaderGet metrics.Timer + TimerReaderIterator metrics.Timer + TimerWriterGet metrics.Timer + TimerWriterIterator metrics.Timer + TimerWriterSet metrics.Timer + TimerWriterDelete metrics.Timer + TimerIteratorSeekFirst metrics.Timer + TimerIteratorSeek metrics.Timer + TimerIteratorNext metrics.Timer + TimerBatchMerge metrics.Timer + TimerBatchExecute metrics.Timer + + m sync.Mutex // Protects the fields that follow. + errors *list.List // Capped list of StoreError's. +} + +type StoreError struct { + Time string + Op string + Err string + Key string +} + +type Reader struct { + s *Store + o store.KVReader +} + +type Writer struct { + s *Store + o store.KVWriter +} + +type Iterator struct { + s *Store + o store.KVIterator +} + +type Batch struct { + s *Store + o store.KVBatch +} + +func (s *Store) Close() error { + return s.o.Close() +} + +func (s *Store) Reader() (store.KVReader, error) { + o, err := s.o.Reader() + if err != nil { + s.AddError("Reader", err, nil) + return nil, err + } + return &Reader{s: s, o: o}, nil +} + +func (s *Store) Writer() (store.KVWriter, error) { + o, err := s.o.Writer() + if err != nil { + s.AddError("Writer", err, nil) + return nil, err + } + return &Writer{s: s, o: o}, nil +} + +func (s *Store) Actual() store.KVStore { + return s.o +} + +func (w *Reader) BytesSafeAfterClose() bool { + return w.o.BytesSafeAfterClose() +} + +func (w *Reader) Get(key []byte) (v []byte, err error) { + w.s.TimerReaderGet.Time(func() { + v, err = w.o.Get(key) + if err != nil { + w.s.AddError("Reader.Get", err, key) + } + }) + return +} + +func (w *Reader) Iterator(key []byte) (i store.KVIterator) { + w.s.TimerReaderIterator.Time(func() { + i = &Iterator{s: w.s, o: w.o.Iterator(key)} + }) + return +} + +func (w *Reader) Close() error { + err := w.o.Close() + if err != nil { + w.s.AddError("Reader.Close", err, nil) + } + return err +} + +func (w *Writer) BytesSafeAfterClose() bool { + return w.o.BytesSafeAfterClose() +} + +func (w *Writer) Get(key []byte) (v []byte, err error) { + w.s.TimerWriterGet.Time(func() { + v, err = w.o.Get(key) + if err != nil { + w.s.AddError("Writer.Get", err, key) + } + }) + return +} + +func (w *Writer) Iterator(key []byte) (i store.KVIterator) { + w.s.TimerWriterIterator.Time(func() { + i = &Iterator{s: w.s, o: w.o.Iterator(key)} + }) + return +} + +func (w *Writer) Close() error { + err := w.o.Close() + if err != nil { + w.s.AddError("Writer.Close", err, nil) + } + return err +} + +func (w *Writer) Set(key, val []byte) (err error) { + w.s.TimerWriterSet.Time(func() { + err = w.o.Set(key, val) + if err != nil { + w.s.AddError("Writer.Set", err, key) + } + }) + return +} + +func (w *Writer) Delete(key []byte) (err error) { + w.s.TimerWriterDelete.Time(func() { + err = w.o.Delete(key) + if err != nil { + w.s.AddError("Writer.Delete", err, key) + } + }) + return +} + +func (w *Writer) NewBatch() store.KVBatch { + return &Batch{s: w.s, o: w.o.NewBatch()} +} + +func (w *Iterator) SeekFirst() { + w.s.TimerIteratorSeekFirst.Time(func() { + w.o.SeekFirst() + }) +} + +func (w *Iterator) Seek(x []byte) { + w.s.TimerIteratorSeek.Time(func() { + w.o.Seek(x) + }) +} + +func (w *Iterator) Next() { + w.s.TimerIteratorNext.Time(func() { + w.o.Next() + }) +} + +func (w *Iterator) Current() ([]byte, []byte, bool) { + return w.o.Current() +} + +func (w *Iterator) Key() []byte { + return w.o.Key() +} + +func (w *Iterator) Value() []byte { + return w.o.Value() +} + +func (w *Iterator) Valid() bool { + return w.o.Valid() +} + +func (w *Iterator) Close() error { + err := w.o.Close() + if err != nil { + w.s.AddError("Iterator.Close", err, nil) + } + return err +} + +func (w *Batch) Set(key, val []byte) { + w.o.Set(key, val) +} + +func (w *Batch) Delete(key []byte) { + w.o.Delete(key) +} + +func (w *Batch) Merge(key []byte, oper store.AssociativeMerge) { + w.s.TimerBatchMerge.Time(func() { + w.o.Merge(key, oper) + }) +} + +func (w *Batch) Execute() (err error) { + w.s.TimerBatchExecute.Time(func() { + err = w.o.Execute() + if err != nil { + w.s.AddError("Batch.Execute", err, nil) + } + }) + return +} + +func (w *Batch) Close() error { + err := w.o.Close() + if err != nil { + w.s.AddError("Batch.Close", err, nil) + } + return err +} + +// -------------------------------------------------------- + +func (s *Store) AddError(op string, err error, key []byte) { + e := &StoreError{ + Time: time.Now().Format(time.RFC3339Nano), + Op: op, + Err: fmt.Sprintf("%v", err), + Key: string(key), + } + + s.m.Lock() + for s.errors.Len() >= MaxErrors { + s.errors.Remove(s.errors.Front()) + } + s.errors.PushBack(e) + s.m.Unlock() +} + +// -------------------------------------------------------- + +func (s *Store) WriteJSON(w io.Writer) { + w.Write([]byte(`{"TimerReaderGet":`)) + WriteTimerJSON(w, s.TimerReaderGet) + w.Write([]byte(`,"TimerReaderIterator":`)) + WriteTimerJSON(w, s.TimerReaderIterator) + w.Write([]byte(`,"TimerWriterGet":`)) + WriteTimerJSON(w, s.TimerWriterGet) + w.Write([]byte(`,"TimerWriterIterator":`)) + WriteTimerJSON(w, s.TimerWriterIterator) + w.Write([]byte(`,"TimerWriterSet":`)) + WriteTimerJSON(w, s.TimerWriterSet) + w.Write([]byte(`,"TimerWriterDelete":`)) + WriteTimerJSON(w, s.TimerWriterDelete) + w.Write([]byte(`,"TimerIteratorSeekFirst":`)) + WriteTimerJSON(w, s.TimerIteratorSeekFirst) + w.Write([]byte(`,"TimerIteratorSeek":`)) + WriteTimerJSON(w, s.TimerIteratorSeek) + w.Write([]byte(`,"TimerIteratorNext":`)) + WriteTimerJSON(w, s.TimerIteratorNext) + w.Write([]byte(`,"TimerBatchMerge":`)) + WriteTimerJSON(w, s.TimerBatchMerge) + w.Write([]byte(`,"TimerBatchExecute":`)) + WriteTimerJSON(w, s.TimerBatchExecute) + + w.Write([]byte(`,"Errors":[`)) + s.m.Lock() + e := s.errors.Front() + i := 0 + for e != nil { + se, ok := e.Value.(*StoreError) + if ok && se != nil { + if i > 0 { + w.Write([]byte(",")) + } + buf, err := json.Marshal(se) + if err == nil { + w.Write(buf) + } + } + e = e.Next() + i = i + 1 + } + s.m.Unlock() + w.Write([]byte(`]`)) + + w.Write([]byte(`}`)) +} + +func (s *Store) WriteCSVHeader(w io.Writer) { + WriteTimerCSVHeader(w, "TimerReaderGet") + WriteTimerCSVHeader(w, "TimerReaderIterator") + WriteTimerCSVHeader(w, "TimerWriterGet") + WriteTimerCSVHeader(w, "TimerWriterIterator") + WriteTimerCSVHeader(w, "TimerWriterSet") + WriteTimerCSVHeader(w, "TimerWriterDelete") + WriteTimerCSVHeader(w, "TimerIteratorSeekFirst") + WriteTimerCSVHeader(w, "TimerIteratorSeek") + WriteTimerCSVHeader(w, "TimerIteratorNext") + WriteTimerCSVHeader(w, "TimerBatchMerge") + WriteTimerCSVHeader(w, "TimerBatchExecute") +} + +func (s *Store) WriteCSV(w io.Writer) { + WriteTimerCSV(w, s.TimerReaderGet) + WriteTimerCSV(w, s.TimerReaderIterator) + WriteTimerCSV(w, s.TimerWriterGet) + WriteTimerCSV(w, s.TimerWriterIterator) + WriteTimerCSV(w, s.TimerWriterSet) + WriteTimerCSV(w, s.TimerWriterDelete) + WriteTimerCSV(w, s.TimerIteratorSeekFirst) + WriteTimerCSV(w, s.TimerIteratorSeek) + WriteTimerCSV(w, s.TimerIteratorNext) + WriteTimerCSV(w, s.TimerBatchMerge) + WriteTimerCSV(w, s.TimerBatchExecute) +} + +// -------------------------------------------------------- + +// NOTE: This is copy & pasted from cbft as otherwise there +// would be an import cycle. + +var timerPercentiles = []float64{0.5, 0.75, 0.95, 0.99, 0.999} + +func WriteTimerJSON(w io.Writer, timer metrics.Timer) { + t := timer.Snapshot() + p := t.Percentiles(timerPercentiles) + + fmt.Fprintf(w, `{"count":%9d,`, t.Count()) + fmt.Fprintf(w, `"min":%9d,`, t.Min()) + fmt.Fprintf(w, `"max":%9d,`, t.Max()) + fmt.Fprintf(w, `"mean":%12.2f,`, t.Mean()) + fmt.Fprintf(w, `"stddev":%12.2f,`, t.StdDev()) + fmt.Fprintf(w, `"percentiles":{`) + fmt.Fprintf(w, `"median":%12.2f,`, p[0]) + fmt.Fprintf(w, `"75%%":%12.2f,`, p[1]) + fmt.Fprintf(w, `"95%%":%12.2f,`, p[2]) + fmt.Fprintf(w, `"99%%":%12.2f,`, p[3]) + fmt.Fprintf(w, `"99.9%%":%12.2f},`, p[4]) + fmt.Fprintf(w, `"rates":{`) + fmt.Fprintf(w, `"1-min":%12.2f,`, t.Rate1()) + fmt.Fprintf(w, `"5-min":%12.2f,`, t.Rate5()) + fmt.Fprintf(w, `"15-min":%12.2f,`, t.Rate15()) + fmt.Fprintf(w, `"mean":%12.2f}}`, t.RateMean()) +} + +func WriteTimerCSVHeader(w io.Writer, prefix string) { + fmt.Fprintf(w, "%s-count,", prefix) + fmt.Fprintf(w, "%s-min,", prefix) + fmt.Fprintf(w, "%s-max,", prefix) + fmt.Fprintf(w, "%s-mean,", prefix) + fmt.Fprintf(w, "%s-stddev,", prefix) + fmt.Fprintf(w, "%s-percentile-50%%,", prefix) + fmt.Fprintf(w, "%s-percentile-75%%,", prefix) + fmt.Fprintf(w, "%s-percentile-95%%,", prefix) + fmt.Fprintf(w, "%s-percentile-99%%,", prefix) + fmt.Fprintf(w, "%s-percentile-99.9%%,", prefix) + fmt.Fprintf(w, "%s-rate-1-min,", prefix) + fmt.Fprintf(w, "%s-rate-5-min,", prefix) + fmt.Fprintf(w, "%s-rate-15-min,", prefix) + fmt.Fprintf(w, "%s-rate-mean", prefix) +} + +func WriteTimerCSV(w io.Writer, timer metrics.Timer) { + t := timer.Snapshot() + p := t.Percentiles(timerPercentiles) + + fmt.Fprintf(w, `%d,`, t.Count()) + fmt.Fprintf(w, `%d,`, t.Min()) + fmt.Fprintf(w, `%d,`, t.Max()) + fmt.Fprintf(w, `%f,`, t.Mean()) + fmt.Fprintf(w, `%f,`, t.StdDev()) + fmt.Fprintf(w, `%f,`, p[0]) + fmt.Fprintf(w, `%f,`, p[1]) + fmt.Fprintf(w, `%f,`, p[2]) + fmt.Fprintf(w, `%f,`, p[3]) + fmt.Fprintf(w, `%f,`, p[4]) + fmt.Fprintf(w, `%f,`, t.Rate1()) + fmt.Fprintf(w, `%f,`, t.Rate5()) + fmt.Fprintf(w, `%f,`, t.Rate15()) + fmt.Fprintf(w, `%f`, t.RateMean()) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics_test.go new file mode 100644 index 00000000..074a6e49 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/metrics/metrics_test.go @@ -0,0 +1,368 @@ +// Copyright (c) 2015 Couchbase, Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS +// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language +// governing permissions and limitations under the License. + +// +build debug + +package metrics + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap" +) + +func TestMetricsStore(t *testing.T) { + s, err := StoreConstructor(map[string]interface{}{}) + if err == nil { + t.Errorf("expected err when bad config") + } + + s, err = StoreConstructor(map[string]interface{}{ + "kvStoreName_actual": "some-invalid-kvstore-name", + }) + if err == nil { + t.Errorf("expected err when unknown kvStoreName_actual") + } + + s, err = StoreConstructor(map[string]interface{}{ + "kvStoreName_actual": "gtreap", + }) + if err != nil { + t.Fatal(err) + } + + CommonTestKVStore(t, s) + + b := bytes.NewBuffer(nil) + s.(*Store).WriteJSON(b) + if b.Len() <= 0 { + t.Errorf("expected some output from WriteJSON") + } + var m map[string]interface{} + err = json.Unmarshal(b.Bytes(), &m) + if err != nil { + t.Errorf("expected WriteJSON to be unmarshallable") + } + if len(m) <= 0 { + t.Errorf("expected some entries") + } + + b = bytes.NewBuffer(nil) + s.(*Store).WriteCSVHeader(b) + if b.Len() <= 0 { + t.Errorf("expected some output from WriteCSVHeader") + } + + b = bytes.NewBuffer(nil) + s.(*Store).WriteCSV(b) + if b.Len() <= 0 { + t.Errorf("expected some output from WriteCSV") + } +} + +func TestReaderIsolation(t *testing.T) { + s, err := StoreConstructor(map[string]interface{}{ + "kvStoreName_actual": "gtreap", + }) + if err != nil { + t.Fatal(err) + } + + CommonTestReaderIsolation(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "b" { + t.Fatalf("expected key b, got %s", key) + } + if string(val) != "val-b" { + t.Fatalf("expected value val-b, got %s", val) + } + + it.Next() + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "c" { + t.Fatalf("expected key c, got %s", key) + } + if string(val) != "val-c" { + t.Fatalf("expected value val-c, got %s", val) + } + + it.Seek([]byte("i")) + key, val, valid = it.Current() + if !valid { + t.Fatalf("valid false, expected true") + } + if string(key) != "i" { + t.Fatalf("expected key i, got %s", key) + } + if string(val) != "val-i" { + t.Fatalf("expected value val-i, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } +} + +func CommonTestReaderIsolation(t *testing.T, s store.KVStore) { + // insert a kv pair + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // create an isolated reader + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // verify that we see the value already inserted + val, err := reader.Get([]byte("a")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-a")) { + t.Errorf("expected val-a, got nil") + } + + // verify that an iterator sees it + count := 0 + it := reader.Iterator([]byte{0}) + defer func() { + err := it.Close() + if err != nil { + t.Fatal(err) + } + }() + for it.Valid() { + it.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } + + // add something after the reader was created + writer, err = s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("b"), []byte("val-b")) + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + // ensure that a newer reader sees it + newReader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := newReader.Close() + if err != nil { + t.Fatal(err) + } + }() + val, err = newReader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(val, []byte("val-b")) { + t.Errorf("expected val-b, got nil") + } + + // ensure that the director iterator sees it + count = 0 + it2 := newReader.Iterator([]byte{0}) + defer func() { + err := it2.Close() + if err != nil { + t.Fatal(err) + } + }() + for it2.Valid() { + it2.Next() + count++ + } + if count != 2 { + t.Errorf("expected iterator to see 2, saw %d", count) + } + + // but that the isolated reader does not + val, err = reader.Get([]byte("b")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %v", val) + } + + // and ensure that the iterator on the isolated reader also does not + count = 0 + it3 := reader.Iterator([]byte{0}) + defer func() { + err := it3.Close() + if err != nil { + t.Fatal(err) + } + }() + for it3.Valid() { + it3.Next() + count++ + } + if count != 1 { + t.Errorf("expected iterator to see 1, saw %d", count) + } +} + +func TestErrors(t *testing.T) { + s, err := StoreConstructor(map[string]interface{}{ + "kvStoreName_actual": "gtreap", + }) + if err != nil { + t.Fatal(err) + } + + x, ok := s.(*Store) + if !ok { + t.Errorf("expecting a Store") + } + + x.AddError("foo", fmt.Errorf("Foo"), []byte("fooKey")) + x.AddError("bar", fmt.Errorf("Bar"), nil) + x.AddError("baz", fmt.Errorf("Baz"), []byte("bazKey")) + + b := bytes.NewBuffer(nil) + x.WriteJSON(b) + + var m map[string]interface{} + err = json.Unmarshal(b.Bytes(), &m) + if err != nil { + t.Errorf("expected unmarshallable writeJSON, err: %v, b: %s", + err, b.Bytes()) + } + + errorsi, ok := m["Errors"] + if !ok || errorsi == nil { + t.Errorf("expected errorsi") + } + errors, ok := errorsi.([]interface{}) + if !ok || errors == nil { + t.Errorf("expected errorsi is array") + } + if len(errors) != 3 { + t.Errorf("expected errors len 3") + } + + e := errors[0].(map[string]interface{}) + if e["Op"].(string) != "foo" || + e["Err"].(string) != "Foo" || + len(e["Time"].(string)) < 10 || + e["Key"].(string) != "fooKey" { + t.Errorf("expected foo, %#v", e) + } + e = errors[1].(map[string]interface{}) + if e["Op"].(string) != "bar" || + e["Err"].(string) != "Bar" || + len(e["Time"].(string)) < 10 || + e["Key"].(string) != "" { + t.Errorf("expected bar, %#v", e) + } + e = errors[2].(map[string]interface{}) + if e["Op"].(string) != "baz" || + e["Err"].(string) != "Baz" || + len(e["Time"].(string)) < 10 || + e["Key"].(string) != "bazKey" { + t.Errorf("expected baz, %#v", e) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null.go new file mode 100644 index 00000000..f316e815 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null.go @@ -0,0 +1,173 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package null + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type Store struct{} + +func New() (*Store, error) { + rv := Store{} + return &rv, nil +} + +func (i *Store) Open() error { + return nil +} + +func (i *Store) SetMergeOperator(mo store.MergeOperator) { + +} + +func (i *Store) Close() error { + return nil +} + +func (i *Store) iterator(key []byte) store.KVIterator { + rv := newIterator(i) + return rv +} + +func (i *Store) Reader() (store.KVReader, error) { + return newReader(i) +} + +func (i *Store) Writer() (store.KVWriter, error) { + return newWriter(i) +} + +func (i *Store) newBatch() store.KVBatch { + return newBatch(i) +} + +type Reader struct { + store *Store +} + +func newReader(store *Store) (*Reader, error) { + return &Reader{ + store: store, + }, nil +} + +func (r *Reader) BytesSafeAfterClose() bool { + return true +} + +func (r *Reader) Get(key []byte) ([]byte, error) { + return nil, nil +} + +func (r *Reader) Iterator(key []byte) store.KVIterator { + return r.store.iterator(key) +} + +func (r *Reader) Close() error { + return nil +} + +type Iterator struct{} + +func newIterator(store *Store) *Iterator { + return &Iterator{} +} + +func (i *Iterator) SeekFirst() {} + +func (i *Iterator) Seek(k []byte) {} + +func (i *Iterator) Next() {} + +func (i *Iterator) Current() ([]byte, []byte, bool) { + return nil, nil, false +} + +func (i *Iterator) Key() []byte { + return nil +} + +func (i *Iterator) Value() []byte { + return nil +} + +func (i *Iterator) Valid() bool { + return false +} + +func (i *Iterator) Close() error { + return nil +} + +type Batch struct{} + +func newBatch(s *Store) *Batch { + rv := Batch{} + return &rv +} + +func (i *Batch) Set(key, val []byte) { +} + +func (i *Batch) Delete(key []byte) { +} + +func (i *Batch) Merge(key, val []byte) { +} + +func (i *Batch) Execute() error { + return nil +} + +func (i *Batch) Close() error { + return nil +} + +type Writer struct { + store *Store +} + +func newWriter(store *Store) (*Writer, error) { + return &Writer{ + store: store, + }, nil +} + +func (w *Writer) BytesSafeAfterClose() bool { + return true +} + +func (w *Writer) Set(key, val []byte) error { + return nil +} + +func (w *Writer) Delete(key []byte) error { + return nil +} + +func (w *Writer) NewBatch() store.KVBatch { + return newBatch(w.store) +} + +func (w *Writer) Close() error { + return nil +} + +// these two methods can safely read using the regular +// methods without a read transaction, because we know +// that no one else is writing but us +func (w *Writer) Get(key []byte) ([]byte, error) { + return nil, nil +} + +func (w *Writer) Iterator(key []byte) store.KVIterator { + return w.store.iterator(key) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null_test.go new file mode 100644 index 00000000..cf8246c8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null/null_test.go @@ -0,0 +1,88 @@ +package null + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func TestStore(t *testing.T) { + s, err := New() + if err != nil { + t.Fatal(err) + } + + CommonTestKVStore(t, s) +} + +func CommonTestKVStore(t *testing.T, s store.KVStore) { + + writer, err := s.Writer() + if err != nil { + t.Error(err) + } + err = writer.Set([]byte("a"), []byte("val-a")) + if err != nil { + t.Fatal(err) + } + err = writer.Set([]byte("z"), []byte("val-z")) + if err != nil { + t.Fatal(err) + } + err = writer.Delete([]byte("z")) + if err != nil { + t.Fatal(err) + } + + batch := writer.NewBatch() + batch.Set([]byte("b"), []byte("val-b")) + batch.Set([]byte("c"), []byte("val-c")) + batch.Set([]byte("d"), []byte("val-d")) + batch.Set([]byte("e"), []byte("val-e")) + batch.Set([]byte("f"), []byte("val-f")) + batch.Set([]byte("g"), []byte("val-g")) + batch.Set([]byte("h"), []byte("val-h")) + batch.Set([]byte("i"), []byte("val-i")) + batch.Set([]byte("j"), []byte("val-j")) + + err = batch.Execute() + if err != nil { + t.Fatal(err) + } + err = writer.Close() + if err != nil { + t.Fatal(err) + } + + reader, err := s.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + it := reader.Iterator([]byte("b")) + key, val, valid := it.Current() + if valid { + t.Fatalf("valid true, expected false") + } + if key != nil { + t.Fatalf("expected key nil, got %s", key) + } + if val != nil { + t.Fatalf("expected value nil, got %s", val) + } + + err = it.Close() + if err != nil { + t.Fatal(err) + } + + err = s.Close() + if err != nil { + t.Fatal(err) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/analysis_pool.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/analysis_pool.go new file mode 100644 index 00000000..aee4bd18 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/analysis_pool.go @@ -0,0 +1,121 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" +) + +type AnalysisResult struct { + docID string + rows []UpsideDownCouchRow +} + +type AnalysisWork struct { + udc *UpsideDownCouch + d *document.Document + rc chan *AnalysisResult +} + +type AnalysisQueue struct { + queue chan *AnalysisWork + done chan struct{} +} + +func (q *AnalysisQueue) Queue(work *AnalysisWork) { + q.queue <- work +} + +func (q *AnalysisQueue) Close() { + close(q.done) +} + +func NewAnalysisQueue(numWorkers int) *AnalysisQueue { + rv := AnalysisQueue{ + queue: make(chan *AnalysisWork), + done: make(chan struct{}), + } + for i := 0; i < numWorkers; i++ { + go AnalysisWorker(rv) + } + return &rv +} + +func AnalysisWorker(q AnalysisQueue) { + // read work off the queue + for { + select { + case <-q.done: + return + case w := <-q.queue: + + rv := &AnalysisResult{ + docID: w.d.ID, + rows: make([]UpsideDownCouchRow, 0, 100), + } + + // track our back index entries + backIndexTermEntries := make([]*BackIndexTermEntry, 0) + backIndexStoredEntries := make([]*BackIndexStoreEntry, 0) + + for _, field := range w.d.Fields { + fieldIndex, newFieldRow := w.udc.fieldIndexCache.FieldIndex(field.Name()) + if newFieldRow != nil { + rv.rows = append(rv.rows, newFieldRow) + } + + if field.Options().IsIndexed() { + + fieldLength, tokenFreqs := field.Analyze() + + // see if any of the composite fields need this + for _, compositeField := range w.d.CompositeFields { + compositeField.Compose(field.Name(), fieldLength, tokenFreqs) + } + + // encode this field + indexRows, indexBackIndexTermEntries := w.udc.indexField(w.d.ID, field, fieldIndex, fieldLength, tokenFreqs) + rv.rows = append(rv.rows, indexRows...) + backIndexTermEntries = append(backIndexTermEntries, indexBackIndexTermEntries...) + } + + if field.Options().IsStored() { + storeRows, indexBackIndexStoreEntries := w.udc.storeField(w.d.ID, field, fieldIndex) + rv.rows = append(rv.rows, storeRows...) + backIndexStoredEntries = append(backIndexStoredEntries, indexBackIndexStoreEntries...) + } + + } + + // now index the composite fields + for _, compositeField := range w.d.CompositeFields { + fieldIndex, newFieldRow := w.udc.fieldIndexCache.FieldIndex(compositeField.Name()) + if newFieldRow != nil { + rv.rows = append(rv.rows, newFieldRow) + } + if compositeField.Options().IsIndexed() { + fieldLength, tokenFreqs := compositeField.Analyze() + // encode this field + indexRows, indexBackIndexTermEntries := w.udc.indexField(w.d.ID, compositeField, fieldIndex, fieldLength, tokenFreqs) + rv.rows = append(rv.rows, indexRows...) + backIndexTermEntries = append(backIndexTermEntries, indexBackIndexTermEntries...) + } + } + + // build the back index row + backIndexRow := NewBackIndexRow(w.d.ID, backIndexTermEntries, backIndexStoredEntries) + rv.rows = append(rv.rows, backIndexRow) + + w.rc <- rv + + } + + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_all.sh b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_all.sh new file mode 100644 index 00000000..079fef18 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_all.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +BENCHMARKS=`grep "func Benchmark" *_test.go | sed 's/.*func //' | sed s/\(.*{//` + +for BENCHMARK in $BENCHMARKS +do + go test -v -run=xxx -bench=^$BENCHMARK$ -benchtime=10s -tags 'forestdb leveldb' | grep -v ok | grep -v PASS +done diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_boltdb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_boltdb_test.go new file mode 100644 index 00000000..d2933191 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_boltdb_test.go @@ -0,0 +1,77 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "os" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb" +) + +func CreateBoltDB() (store.KVStore, error) { + s := boltdb.New("test", "bleve") + return s, nil +} + +func DestroyBoltDB() error { + return os.RemoveAll("test") +} + +func BenchmarkBoltDBIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateBoltDB, DestroyBoltDB, 1) +} + +func BenchmarkBoltDBIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateBoltDB, DestroyBoltDB, 2) +} + +func BenchmarkBoltDBIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateBoltDB, DestroyBoltDB, 4) +} + +// batches + +func BenchmarkBoltDBIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 1, 10) +} + +func BenchmarkBoltDBIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 2, 10) +} + +func BenchmarkBoltDBIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 4, 10) +} + +func BenchmarkBoltDBIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 1, 100) +} + +func BenchmarkBoltDBIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 2, 100) +} + +func BenchmarkBoltDBIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 4, 100) +} + +func BenchmarkBoltBIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 1, 1000) +} + +func BenchmarkBoltBIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 2, 1000) +} + +func BenchmarkBoltBIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateBoltDB, DestroyBoltDB, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_common_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_common_test.go new file mode 100644 index 00000000..ccbecbdb --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_common_test.go @@ -0,0 +1,143 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "strconv" + "testing" + + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/analyzers/standard_analyzer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +var benchmarkDocBodies = []string{ + "A boiling liquid expanding vapor explosion (BLEVE, /ˈblɛviː/ blev-ee) is an explosion caused by the rupture of a vessel containing a pressurized liquid above its boiling point.", + "A boiler explosion is a catastrophic failure of a boiler. As seen today, boiler explosions are of two kinds. One kind is a failure of the pressure parts of the steam and water sides. There can be many different causes, such as failure of the safety valve, corrosion of critical parts of the boiler, or low water level. Corrosion along the edges of lap joints was a common cause of early boiler explosions.", + "A boiler is a closed vessel in which water or other fluid is heated. The fluid does not necessarily boil. (In North America the term \"furnace\" is normally used if the purpose is not actually to boil the fluid.) The heated or vaporized fluid exits the boiler for use in various processes or heating applications,[1][2] including central heating, boiler-based power generation, cooking, and sanitation.", + "A pressure vessel is a closed container designed to hold gases or liquids at a pressure substantially different from the ambient pressure.", + "Pressure (symbol: p or P) is the ratio of force to the area over which that force is distributed.", + "Liquid is one of the four fundamental states of matter (the others being solid, gas, and plasma), and is the only state with a definite volume but no fixed shape.", + "The boiling point of a substance is the temperature at which the vapor pressure of the liquid equals the pressure surrounding the liquid[1][2] and the liquid changes into a vapor.", + "Vapor pressure or equilibrium vapor pressure is defined as the pressure exerted by a vapor in thermodynamic equilibrium with its condensed phases (solid or liquid) at a given temperature in a closed system.", + "Industrial gases are a group of gases that are specifically manufactured for use in a wide range of industries, which include oil and gas, petrochemicals, chemicals, power, mining, steelmaking, metals, environmental protection, medicine, pharmaceuticals, biotechnology, food, water, fertilizers, nuclear power, electronics and aerospace.", + "The expansion ratio of a liquefied and cryogenic substance is the volume of a given amount of that substance in liquid form compared to the volume of the same amount of substance in gaseous form, at room temperature and normal atmospheric pressure.", +} + +type KVStoreCreate func() (store.KVStore, error) +type KVStoreDestroy func() error + +func CommonBenchmarkIndex(b *testing.B, create KVStoreCreate, destroy KVStoreDestroy, analysisWorkers int) { + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed("standard") + if err != nil { + b.Fatal(err) + } + + indexDocument := document.NewDocument(""). + AddField(document.NewTextFieldWithAnalyzer("body", []uint64{}, []byte(benchmarkDocBodies[0]), analyzer)) + + b.ResetTimer() + b.StopTimer() + for i := 0; i < b.N; i++ { + s, err := create() + if err != nil { + b.Fatal(err) + } + analysisQueue := NewAnalysisQueue(analysisWorkers) + idx := NewUpsideDownCouch(s, analysisQueue) + + err = idx.Open() + if err != nil { + b.Fatal(err) + } + indexDocument.ID = strconv.Itoa(i) + // just time the indexing portion + b.StartTimer() + err = idx.Update(indexDocument) + if err != nil { + b.Fatal(err) + } + b.StopTimer() + err = idx.Close() + if err != nil { + b.Fatal(err) + } + err = destroy() + if err != nil { + b.Fatal(err) + } + analysisQueue.Close() + } +} + +func CommonBenchmarkIndexBatch(b *testing.B, create KVStoreCreate, destroy KVStoreDestroy, analysisWorkers, batchSize int) { + + cache := registry.NewCache() + analyzer, err := cache.AnalyzerNamed("standard") + if err != nil { + b.Fatal(err) + } + + b.ResetTimer() + b.StopTimer() + for i := 0; i < b.N; i++ { + + s, err := create() + if err != nil { + b.Fatal(err) + } + analysisQueue := NewAnalysisQueue(analysisWorkers) + idx := NewUpsideDownCouch(s, analysisQueue) + + err = idx.Open() + if err != nil { + b.Fatal(err) + } + + b.StartTimer() + batch := index.NewBatch() + for j := 0; j < 1000; j++ { + if j%batchSize == 0 { + if len(batch.IndexOps) > 0 { + err := idx.Batch(batch) + if err != nil { + b.Fatal(err) + } + } + batch = index.NewBatch() + } + indexDocument := document.NewDocument(""). + AddField(document.NewTextFieldWithAnalyzer("body", []uint64{}, []byte(benchmarkDocBodies[j%10]), analyzer)) + indexDocument.ID = strconv.Itoa(i) + "-" + strconv.Itoa(j) + batch.Update(indexDocument) + } + // close last batch + if len(batch.IndexOps) > 0 { + err := idx.Batch(batch) + if err != nil { + b.Fatal(err) + } + } + b.StopTimer() + err = idx.Close() + if err != nil { + b.Fatal(err) + } + err = destroy() + if err != nil { + b.Fatal(err) + } + analysisQueue.Close() + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_cznicb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_cznicb_test.go new file mode 100644 index 00000000..d265d045 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_cznicb_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/cznicb" +) + +func CreateCznicB() (store.KVStore, error) { + return cznicb.StoreConstructor(nil) +} + +func DestroyCznicB() error { + return nil +} + +func BenchmarkCznicBIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateCznicB, DestroyCznicB, 1) +} + +func BenchmarkCznicBIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateCznicB, DestroyCznicB, 2) +} + +func BenchmarkCznicBIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateCznicB, DestroyCznicB, 4) +} + +// batches + +func BenchmarkCznicBIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 1, 10) +} + +func BenchmarkCznicBIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 2, 10) +} + +func BenchmarkCznicBIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 4, 10) +} + +func BenchmarkCznicBIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 1, 100) +} + +func BenchmarkCznicBIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 2, 100) +} + +func BenchmarkCznicBIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 4, 100) +} + +func BenchmarkCznicBIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 1, 1000) +} + +func BenchmarkCznicBIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 2, 1000) +} + +func BenchmarkCznicBIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateCznicB, DestroyCznicB, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_forestdb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_forestdb_test.go new file mode 100644 index 00000000..33d769f6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_forestdb_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build forestdb + +package upside_down + +import ( + "os" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/forestdb" +) + +func CreateForestDB() (store.KVStore, error) { + err := os.MkdirAll("testdir", 0700) + if err != nil { + return nil, err + } + s, err := forestdb.New("testdir/test", true, nil) + if err != nil { + return nil, err + } + return s, nil +} + +func DestroyForestDB() error { + return os.RemoveAll("testdir") +} + +func BenchmarkForestDBIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateForestDB, DestroyForestDB, 1) +} + +func BenchmarkForestDBIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateForestDB, DestroyForestDB, 2) +} + +func BenchmarkForestDBIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateForestDB, DestroyForestDB, 4) +} + +// batches + +func BenchmarkForestDBIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 1, 10) +} + +func BenchmarkForestDBIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 2, 10) +} + +func BenchmarkForestDBIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 4, 10) +} + +func BenchmarkForestDBIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 1, 100) +} + +func BenchmarkForestDBIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 2, 100) +} + +func BenchmarkForestDBIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 4, 100) +} + +func BenchmarkForestDBIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 1, 1000) +} + +func BenchmarkForestDBIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 2, 1000) +} + +func BenchmarkForestDBIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateForestDB, DestroyForestDB, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_goleveldb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_goleveldb_test.go new file mode 100644 index 00000000..df8e7cb0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_goleveldb_test.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "os" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/goleveldb" +) + +var goLevelDBTestOptions = map[string]interface{}{ + "create_if_missing": true, +} + +func CreateGoLevelDB() (store.KVStore, error) { + return goleveldb.New("test", goLevelDBTestOptions) +} + +func DestroyGoLevelDB() error { + return os.RemoveAll("test") +} + +func BenchmarkGoLevelDBIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGoLevelDB, DestroyGoLevelDB, 1) +} + +func BenchmarkGoLevelDBIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGoLevelDB, DestroyGoLevelDB, 2) +} + +func BenchmarkGoLevelDBIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGoLevelDB, DestroyGoLevelDB, 4) +} + +// batches + +func BenchmarkGoLevelDBIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 1, 10) +} + +func BenchmarkGoLevelDBIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 2, 10) +} + +func BenchmarkGoLevelDBIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 4, 10) +} + +func BenchmarkGoLevelDBIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 1, 100) +} + +func BenchmarkGoLevelDBIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 2, 100) +} + +func BenchmarkGoLevelDBIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 4, 100) +} + +func BenchmarkGoLevelDBIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 1, 1000) +} + +func BenchmarkGoLevelDBIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 2, 1000) +} + +func BenchmarkGoLevelDBIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoLevelDB, DestroyGoLevelDB, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gorocksdb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gorocksdb_test.go new file mode 100644 index 00000000..559817af --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gorocksdb_test.go @@ -0,0 +1,82 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build rocksdb + +package upside_down + +import ( + "os" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gorocksdb" +) + +var rocksdbTestOptions = map[string]interface{}{ + "create_if_missing": true, +} + +func CreateGoRocksDB() (store.KVStore, error) { + return rocksdb.New("test", rocksdbTestOptions) +} + +func DestroyGoRocksDB() error { + return os.RemoveAll("test") +} + +func BenchmarkRocksDBIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGoRocksDB, DestroyGoRocksDB, 1) +} + +func BenchmarkRocksDBIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGoRocksDB, DestroyGoRocksDB, 2) +} + +func BenchmarkRocksDBIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGoRocksDB, DestroyGoRocksDB, 4) +} + +// batches + +func BenchmarkRocksDBIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 1, 10) +} + +func BenchmarkRocksDBIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 2, 10) +} + +func BenchmarkRocksDBIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 4, 10) +} + +func BenchmarkRocksDBIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 1, 100) +} + +func BenchmarkRocksDBIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 2, 100) +} + +func BenchmarkRocksDBIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 4, 100) +} + +func BenchmarkRocksDBIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 1, 1000) +} + +func BenchmarkRocksDBIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 2, 1000) +} + +func BenchmarkRocksDBIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGoRocksDB, DestroyGoRocksDB, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gtreap_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gtreap_test.go new file mode 100644 index 00000000..53e20e9a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_gtreap_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/gtreap" +) + +func CreateGTreap() (store.KVStore, error) { + return gtreap.StoreConstructor(nil) +} + +func DestroyGTreap() error { + return nil +} + +func BenchmarkGTreapIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGTreap, DestroyGTreap, 1) +} + +func BenchmarkGTreapIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGTreap, DestroyGTreap, 2) +} + +func BenchmarkGTreapIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateGTreap, DestroyGTreap, 4) +} + +// batches + +func BenchmarkGTreapIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 1, 10) +} + +func BenchmarkGTreapIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 2, 10) +} + +func BenchmarkGTreapIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 4, 10) +} + +func BenchmarkGTreapIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 1, 100) +} + +func BenchmarkGTreapIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 2, 100) +} + +func BenchmarkGTreapIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 4, 100) +} + +func BenchmarkGTreapIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 1, 1000) +} + +func BenchmarkGTreapIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 2, 1000) +} + +func BenchmarkGTreapIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateGTreap, DestroyGTreap, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_inmem_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_inmem_test.go new file mode 100644 index 00000000..1de51d85 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_inmem_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem" +) + +func CreateInMem() (store.KVStore, error) { + return inmem.New() +} + +func DestroyInMem() error { + return nil +} + +func BenchmarkInMemIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateInMem, DestroyInMem, 1) +} + +func BenchmarkInMemIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateInMem, DestroyInMem, 2) +} + +func BenchmarkInMemIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateInMem, DestroyInMem, 4) +} + +// batches + +func BenchmarkInMemIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 1, 10) +} + +func BenchmarkInMemIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 2, 10) +} + +func BenchmarkInMemIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 4, 10) +} + +func BenchmarkInMemIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 1, 100) +} + +func BenchmarkInMemIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 2, 100) +} + +func BenchmarkInMemIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 4, 100) +} + +func BenchmarkInMemIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 1, 1000) +} + +func BenchmarkInMemIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 2, 1000) +} + +func BenchmarkInMemIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateInMem, DestroyInMem, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_leveldb_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_leveldb_test.go new file mode 100644 index 00000000..a516d2de --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_leveldb_test.go @@ -0,0 +1,82 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build leveldb full + +package upside_down + +import ( + "os" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/leveldb" +) + +var leveldbTestOptions = map[string]interface{}{ + "create_if_missing": true, +} + +func CreateLevelDB() (store.KVStore, error) { + return leveldb.New("test", leveldbTestOptions) +} + +func DestroyLevelDB() error { + return os.RemoveAll("test") +} + +func BenchmarkLevelDBIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateLevelDB, DestroyLevelDB, 1) +} + +func BenchmarkLevelDBIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateLevelDB, DestroyLevelDB, 2) +} + +func BenchmarkLevelDBIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateLevelDB, DestroyLevelDB, 4) +} + +// batches + +func BenchmarkLevelDBIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 1, 10) +} + +func BenchmarkLevelDBIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 2, 10) +} + +func BenchmarkLevelDBIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 4, 10) +} + +func BenchmarkLevelDBIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 1, 100) +} + +func BenchmarkLevelDBIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 2, 100) +} + +func BenchmarkLevelDBIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 4, 100) +} + +func BenchmarkLevelDBIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 1, 1000) +} + +func BenchmarkLevelDBIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 2, 1000) +} + +func BenchmarkLevelDBIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateLevelDB, DestroyLevelDB, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_null_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_null_test.go new file mode 100644 index 00000000..c32ac512 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/benchmark_null_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/null" +) + +func CreateNull() (store.KVStore, error) { + return null.New() +} + +func DestroyNull() error { + return nil +} + +func BenchmarkNullIndexing1Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateNull, DestroyNull, 1) +} + +func BenchmarkNullIndexing2Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateNull, DestroyNull, 2) +} + +func BenchmarkNullIndexing4Workers(b *testing.B) { + CommonBenchmarkIndex(b, CreateNull, DestroyNull, 4) +} + +// batches + +func BenchmarkNullIndexing1Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 1, 10) +} + +func BenchmarkNullIndexing2Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 2, 10) +} + +func BenchmarkNullIndexing4Workers10Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 4, 10) +} + +func BenchmarkNullIndexing1Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 1, 100) +} + +func BenchmarkNullIndexing2Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 2, 100) +} + +func BenchmarkNullIndexing4Workers100Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 4, 100) +} + +func BenchmarkNullIndexing1Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 1, 1000) +} + +func BenchmarkNullIndexing2Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 2, 1000) +} + +func BenchmarkNullIndexing4Workers1000Batch(b *testing.B) { + CommonBenchmarkIndexBatch(b, CreateNull, DestroyNull, 4, 1000) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump.go new file mode 100644 index 00000000..094280d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump.go @@ -0,0 +1,177 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "bytes" + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +// the functions in this file are only intended to be used by +// the bleve_dump utility and the debug http handlers +// if your application relies on them, you're doing something wrong +// they may change or be removed at any time + +func (udc *UpsideDownCouch) dumpPrefix(kvreader store.KVReader, rv chan interface{}, prefix []byte) { + start := prefix + if start == nil { + start = []byte{0} + } + it := kvreader.Iterator(start) + defer func() { + cerr := it.Close() + if cerr != nil { + rv <- cerr + } + }() + key, val, valid := it.Current() + for valid { + + if prefix != nil && !bytes.HasPrefix(key, prefix) { + break + } + + row, err := ParseFromKeyValue(key, val) + if err != nil { + rv <- err + return + } + rv <- row + + it.Next() + key, val, valid = it.Current() + } +} + +func (udc *UpsideDownCouch) DumpAll() chan interface{} { + rv := make(chan interface{}) + go func() { + defer close(rv) + + // start an isolated reader for use during the dump + kvreader, err := udc.store.Reader() + if err != nil { + rv <- err + return + } + defer func() { + cerr := kvreader.Close() + if cerr != nil { + rv <- cerr + } + }() + + udc.dumpPrefix(kvreader, rv, nil) + }() + return rv +} + +func (udc *UpsideDownCouch) DumpFields() chan interface{} { + rv := make(chan interface{}) + go func() { + defer close(rv) + + // start an isolated reader for use during the dump + kvreader, err := udc.store.Reader() + if err != nil { + rv <- err + return + } + defer func() { + cerr := kvreader.Close() + if cerr != nil { + rv <- cerr + } + }() + + udc.dumpPrefix(kvreader, rv, []byte{'f'}) + }() + return rv +} + +type keyset [][]byte + +func (k keyset) Len() int { return len(k) } +func (k keyset) Swap(i, j int) { k[i], k[j] = k[j], k[i] } +func (k keyset) Less(i, j int) bool { return bytes.Compare(k[i], k[j]) < 0 } + +// DumpDoc returns all rows in the index related to this doc id +func (udc *UpsideDownCouch) DumpDoc(id string) chan interface{} { + rv := make(chan interface{}) + + go func() { + defer close(rv) + + // start an isolated reader for use during the dump + kvreader, err := udc.store.Reader() + if err != nil { + rv <- err + return + } + defer func() { + cerr := kvreader.Close() + if cerr != nil { + rv <- cerr + } + }() + + back, err := udc.backIndexRowForDoc(kvreader, id) + if err != nil { + rv <- err + return + } + + // no such doc + if back == nil { + return + } + // build sorted list of term keys + keys := make(keyset, 0) + for _, entry := range back.termEntries { + tfr := NewTermFrequencyRow([]byte(*entry.Term), uint16(*entry.Field), id, 0, 0) + key := tfr.Key() + keys = append(keys, key) + } + sort.Sort(keys) + + // first add all the stored rows + storedRowPrefix := NewStoredRow(id, 0, []uint64{}, 'x', []byte{}).ScanPrefixForDoc() + udc.dumpPrefix(kvreader, rv, storedRowPrefix) + + // now walk term keys in order and add them as well + if len(keys) > 0 { + it := kvreader.Iterator(keys[0]) + defer func() { + cerr := it.Close() + if cerr != nil { + rv <- cerr + } + }() + + for _, key := range keys { + it.Seek(key) + rkey, rval, valid := it.Current() + if !valid { + break + } + row, err := ParseFromKeyValue(rkey, rval) + if err != nil { + rv <- err + return + } + rv <- row + } + } + }() + + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump_test.go new file mode 100644 index 00000000..9fafa6a3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/dump_test.go @@ -0,0 +1,127 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb" + "os" + "testing" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" +) + +func TestDump(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s := boltdb.New("test", "bleve") + s.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(s, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField)) + doc.AddField(document.NewNumericFieldWithIndexingOptions("age", []uint64{}, 35.99, document.IndexField|document.StoreField)) + dateField, err := document.NewDateTimeFieldWithIndexingOptions("unixEpoch", []uint64{}, time.Unix(0, 0), document.IndexField|document.StoreField) + if err != nil { + t.Error(err) + } + doc.AddField(dateField) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + doc = document.NewDocument("2") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test2"), document.IndexField|document.StoreField)) + doc.AddField(document.NewNumericFieldWithIndexingOptions("age", []uint64{}, 35.99, document.IndexField|document.StoreField)) + dateField, err = document.NewDateTimeFieldWithIndexingOptions("unixEpoch", []uint64{}, time.Unix(0, 0), document.IndexField|document.StoreField) + if err != nil { + t.Error(err) + } + doc.AddField(dateField) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + fieldsCount := 0 + fieldsRows := idx.DumpFields() + for _ = range fieldsRows { + fieldsCount++ + } + if fieldsCount != 3 { + t.Errorf("expected 3 fields, got %d", fieldsCount) + } + + // 1 text term + // 16 numeric terms + // 16 date terms + // 3 stored fields + expectedDocRowCount := int(1 + (2 * (64 / document.DefaultPrecisionStep)) + 3) + docRowCount := 0 + docRows := idx.DumpDoc("1") + for _ = range docRows { + docRowCount++ + } + if docRowCount != expectedDocRowCount { + t.Errorf("expected %d rows for document, got %d", expectedDocRowCount, docRowCount) + } + + docRowCount = 0 + docRows = idx.DumpDoc("2") + for _ = range docRows { + docRowCount++ + } + if docRowCount != expectedDocRowCount { + t.Errorf("expected %d rows for document, got %d", expectedDocRowCount, docRowCount) + } + + // 1 version + // fieldsCount field rows + // 2 docs * expectedDocRowCount + // 2 back index rows + // 2 text term row count (2 different text terms) + // 16 numeric term row counts (shared for both docs, same numeric value) + // 16 date term row counts (shared for both docs, same date value) + expectedAllRowCount := int(1 + fieldsCount + (2 * expectedDocRowCount) + 2 + 2 + int((2 * (64 / document.DefaultPrecisionStep)))) + allRowCount := 0 + allRows := idx.DumpAll() + for _ = range allRows { + allRowCount++ + } + if allRowCount != expectedAllRowCount { + t.Errorf("expected %d rows for all, got %d", expectedAllRowCount, allRowCount) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict.go new file mode 100644 index 00000000..6b893bfe --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict.go @@ -0,0 +1,86 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "bytes" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type UpsideDownCouchFieldDict struct { + indexReader *IndexReader + iterator store.KVIterator + endKey []byte + field uint16 +} + +func newUpsideDownCouchFieldDict(indexReader *IndexReader, field uint16, startTerm, endTerm []byte) (*UpsideDownCouchFieldDict, error) { + + startKey := NewDictionaryRow(startTerm, field, 0).Key() + if endTerm == nil { + endTerm = []byte{ByteSeparator} + } + endKey := NewDictionaryRow(endTerm, field, 0).Key() + + it := indexReader.kvreader.Iterator(startKey) + + return &UpsideDownCouchFieldDict{ + indexReader: indexReader, + iterator: it, + field: field, + endKey: endKey, + }, nil + +} + +func (r *UpsideDownCouchFieldDict) Next() (*index.DictEntry, error) { + key, val, valid := r.iterator.Current() + if !valid { + return nil, nil + } + + // past end term + if bytes.Compare(key, r.endKey) > 0 { + return nil, nil + } + + currRow, err := NewDictionaryRowKV(key, val) + if err != nil { + return nil, fmt.Errorf("unexpected error parsing dictionary row kv: %v", err) + } + rv := index.DictEntry{ + Term: string(currRow.term), + Count: currRow.count, + } + // advance the iterator to the next term + r.iterator.Next() + return &rv, nil + +} + +func (r *UpsideDownCouchFieldDict) Close() error { + return r.iterator.Close() +} + +func incrementBytes(in []byte) []byte { + rv := make([]byte, len(in)) + copy(rv, in) + for i := len(rv) - 1; i >= 0; i-- { + rv[i] = rv[i] + 1 + if rv[i] != 0 { + // didn't overflow, so stop + break + } + } + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict_test.go new file mode 100644 index 00000000..c53b016a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_dict_test.go @@ -0,0 +1,180 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb" +) + +func TestIndexFieldDict(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s := boltdb.New("test", "bleve") + s.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(s, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + doc = document.NewDocument("2") + doc.AddField(document.NewTextFieldWithAnalyzer("name", []uint64{}, []byte("test test test"), testAnalyzer)) + doc.AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("eat more rice"), document.IndexField|document.IncludeTermVectors, testAnalyzer)) + doc.AddField(document.NewTextFieldCustom("prefix", []uint64{}, []byte("bob cat cats catting dog doggy zoo"), document.IndexField|document.IncludeTermVectors, testAnalyzer)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + dict, err := indexReader.FieldDict("name") + if err != nil { + t.Errorf("error creating reader: %v", err) + } + defer func() { + err := dict.Close() + if err != nil { + t.Fatal(err) + } + }() + + termCount := 0 + curr, err := dict.Next() + for err == nil && curr != nil { + termCount++ + if curr.Term != "test" { + t.Errorf("expected term to be 'test', got '%s'", curr.Term) + } + curr, err = dict.Next() + } + if termCount != 1 { + t.Errorf("expected 1 term for this field, got %d", termCount) + } + + dict2, err := indexReader.FieldDict("desc") + if err != nil { + t.Errorf("error creating reader: %v", err) + } + defer func() { + err := dict2.Close() + if err != nil { + t.Fatal(err) + } + }() + + termCount = 0 + terms := make([]string, 0) + curr, err = dict2.Next() + for err == nil && curr != nil { + termCount++ + terms = append(terms, curr.Term) + curr, err = dict2.Next() + } + if termCount != 3 { + t.Errorf("expected 3 term for this field, got %d", termCount) + } + expectedTerms := []string{"eat", "more", "rice"} + if !reflect.DeepEqual(expectedTerms, terms) { + t.Errorf("expected %#v, got %#v", expectedTerms, terms) + } + + // test start and end range + dict3, err := indexReader.FieldDictRange("desc", []byte("fun"), []byte("nice")) + if err != nil { + t.Errorf("error creating reader: %v", err) + } + defer func() { + err := dict3.Close() + if err != nil { + t.Fatal(err) + } + }() + + termCount = 0 + terms = make([]string, 0) + curr, err = dict3.Next() + for err == nil && curr != nil { + termCount++ + terms = append(terms, curr.Term) + curr, err = dict3.Next() + } + if termCount != 1 { + t.Errorf("expected 1 term for this field, got %d", termCount) + } + expectedTerms = []string{"more"} + if !reflect.DeepEqual(expectedTerms, terms) { + t.Errorf("expected %#v, got %#v", expectedTerms, terms) + } + + // test use case for prefix + dict4, err := indexReader.FieldDictPrefix("prefix", []byte("cat")) + if err != nil { + t.Errorf("error creating reader: %v", err) + } + defer func() { + err := dict4.Close() + if err != nil { + t.Fatal(err) + } + }() + + termCount = 0 + terms = make([]string, 0) + curr, err = dict4.Next() + for err == nil && curr != nil { + termCount++ + terms = append(terms, curr.Term) + curr, err = dict4.Next() + } + if termCount != 3 { + t.Errorf("expected 3 term for this field, got %d", termCount) + } + expectedTerms = []string{"cat", "cats", "catting"} + if !reflect.DeepEqual(expectedTerms, terms) { + t.Errorf("expected %#v, got %#v", expectedTerms, terms) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_index_cache.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_index_cache.go new file mode 100644 index 00000000..8d0b23a7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/field_index_cache.go @@ -0,0 +1,69 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "sync" +) + +type FieldIndexCache struct { + fieldIndexes map[string]uint16 + lastFieldIndex int + mutex sync.RWMutex +} + +func NewFieldIndexCache() *FieldIndexCache { + return &FieldIndexCache{ + fieldIndexes: make(map[string]uint16), + } +} + +func (f *FieldIndexCache) AddExisting(field string, index uint16) { + f.mutex.Lock() + defer f.mutex.Unlock() + f.fieldIndexes[field] = index + if int(index) > f.lastFieldIndex { + f.lastFieldIndex = int(index) + } +} + +func (f *FieldIndexCache) FieldExists(field string) (uint16, bool) { + f.mutex.RLock() + defer f.mutex.RUnlock() + if index, ok := f.fieldIndexes[field]; ok { + return index, true + } + return 0, false +} + +func (f *FieldIndexCache) FieldIndex(field string) (uint16, *FieldRow) { + f.mutex.Lock() + defer f.mutex.Unlock() + index, exists := f.fieldIndexes[field] + if exists { + return index, nil + } + // assign next field id + index = uint16(f.lastFieldIndex + 1) + f.fieldIndexes[field] = index + f.lastFieldIndex = int(index) + return index, NewFieldRow(uint16(index), field) +} + +func (f *FieldIndexCache) FieldName(index uint16) string { + f.mutex.RLock() + defer f.mutex.RUnlock() + for fieldName, fieldIndex := range f.fieldIndexes { + if index == fieldIndex { + return fieldName + } + } + return "" +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/index_reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/index_reader.go new file mode 100644 index 00000000..3277074c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/index_reader.go @@ -0,0 +1,164 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type IndexReader struct { + index *UpsideDownCouch + kvreader store.KVReader + docCount uint64 +} + +func (i *IndexReader) TermFieldReader(term []byte, fieldName string) (index.TermFieldReader, error) { + fieldIndex, fieldExists := i.index.fieldIndexCache.FieldExists(fieldName) + if fieldExists { + return newUpsideDownCouchTermFieldReader(i, term, uint16(fieldIndex)) + } + return newUpsideDownCouchTermFieldReader(i, []byte{ByteSeparator}, ^uint16(0)) +} + +func (i *IndexReader) FieldDict(fieldName string) (index.FieldDict, error) { + return i.FieldDictRange(fieldName, nil, nil) +} + +func (i *IndexReader) FieldDictRange(fieldName string, startTerm []byte, endTerm []byte) (index.FieldDict, error) { + fieldIndex, fieldExists := i.index.fieldIndexCache.FieldExists(fieldName) + if fieldExists { + return newUpsideDownCouchFieldDict(i, uint16(fieldIndex), startTerm, endTerm) + } + return newUpsideDownCouchFieldDict(i, ^uint16(0), []byte{ByteSeparator}, []byte{}) +} + +func (i *IndexReader) FieldDictPrefix(fieldName string, termPrefix []byte) (index.FieldDict, error) { + return i.FieldDictRange(fieldName, termPrefix, incrementBytes(termPrefix)) +} + +func (i *IndexReader) DocIDReader(start, end string) (index.DocIDReader, error) { + return newUpsideDownCouchDocIDReader(i, start, end) +} + +func (i *IndexReader) Document(id string) (doc *document.Document, err error) { + // first hit the back index to confirm doc exists + var backIndexRow *BackIndexRow + backIndexRow, err = i.index.backIndexRowForDoc(i.kvreader, id) + if err != nil { + return + } + if backIndexRow == nil { + return + } + doc = document.NewDocument(id) + storedRow := NewStoredRow(id, 0, []uint64{}, 'x', nil) + storedRowScanPrefix := storedRow.ScanPrefixForDoc() + it := i.kvreader.Iterator(storedRowScanPrefix) + defer func() { + if cerr := it.Close(); err == nil && cerr != nil { + err = cerr + } + }() + key, val, valid := it.Current() + for valid { + if !bytes.HasPrefix(key, storedRowScanPrefix) { + break + } + safeVal := val + if !i.kvreader.BytesSafeAfterClose() { + safeVal = make([]byte, len(val)) + copy(safeVal, val) + } + var row *StoredRow + row, err = NewStoredRowKV(key, safeVal) + if err != nil { + doc = nil + return + } + if row != nil { + fieldName := i.index.fieldIndexCache.FieldName(row.field) + field := decodeFieldType(row.typ, fieldName, row.value) + if field != nil { + doc.AddField(field) + } + } + + it.Next() + key, val, valid = it.Current() + } + return +} + +func (i *IndexReader) DocumentFieldTerms(id string) (index.FieldTerms, error) { + back, err := i.index.backIndexRowForDoc(i.kvreader, id) + if err != nil { + return nil, err + } + rv := make(index.FieldTerms, len(back.termEntries)) + for _, entry := range back.termEntries { + fieldName := i.index.fieldIndexCache.FieldName(uint16(*entry.Field)) + terms, ok := rv[fieldName] + if !ok { + terms = make([]string, 0) + } + terms = append(terms, *entry.Term) + rv[fieldName] = terms + } + return rv, nil +} + +func (i *IndexReader) Fields() (fields []string, err error) { + fields = make([]string, 0) + it := i.kvreader.Iterator([]byte{'f'}) + defer func() { + if cerr := it.Close(); err == nil && cerr != nil { + err = cerr + } + }() + key, val, valid := it.Current() + for valid { + if !bytes.HasPrefix(key, []byte{'f'}) { + break + } + var row UpsideDownCouchRow + row, err = ParseFromKeyValue(key, val) + if err != nil { + fields = nil + return + } + if row != nil { + fieldRow, ok := row.(*FieldRow) + if ok { + fields = append(fields, fieldRow.name) + } + } + + it.Next() + key, val, valid = it.Current() + } + return +} + +func (i *IndexReader) GetInternal(key []byte) ([]byte, error) { + internalRow := NewInternalRow(key, nil) + return i.kvreader.Get(internalRow.Key()) +} + +func (i *IndexReader) DocCount() uint64 { + return i.docCount +} + +func (i *IndexReader) Close() error { + return i.kvreader.Close() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader.go new file mode 100644 index 00000000..b035effc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader.go @@ -0,0 +1,187 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "bytes" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +type UpsideDownCouchTermFieldReader struct { + indexReader *IndexReader + iterator store.KVIterator + count uint64 + term []byte + field uint16 + readerPrefix []byte +} + +func newUpsideDownCouchTermFieldReader(indexReader *IndexReader, term []byte, field uint16) (*UpsideDownCouchTermFieldReader, error) { + dictionaryRow := NewDictionaryRow(term, field, 0) + val, err := indexReader.kvreader.Get(dictionaryRow.Key()) + if err != nil { + return nil, err + } + if val == nil { + return &UpsideDownCouchTermFieldReader{ + count: 0, + term: term, + field: field, + }, nil + } + + err = dictionaryRow.parseDictionaryV(val) + if err != nil { + return nil, err + } + + tfr := NewTermFrequencyRow(term, field, "", 0, 0) + readerPrefix := tfr.Key() + it := indexReader.kvreader.Iterator(readerPrefix) + + return &UpsideDownCouchTermFieldReader{ + indexReader: indexReader, + iterator: it, + count: dictionaryRow.count, + term: term, + field: field, + readerPrefix: readerPrefix, + }, nil +} + +func (r *UpsideDownCouchTermFieldReader) Count() uint64 { + return r.count +} + +func (r *UpsideDownCouchTermFieldReader) Next() (*index.TermFieldDoc, error) { + if r.iterator != nil { + key, val, valid := r.iterator.Current() + if valid { + if !bytes.HasPrefix(key, r.readerPrefix) { + // end of the line + return nil, nil + } + tfr, err := NewTermFrequencyRowKV(key, val) + if err != nil { + return nil, err + } + r.iterator.Next() + return &index.TermFieldDoc{ + ID: string(tfr.doc), + Freq: tfr.freq, + Norm: float64(tfr.norm), + Vectors: r.indexReader.index.termFieldVectorsFromTermVectors(tfr.vectors), + }, nil + } + } + return nil, nil +} + +func (r *UpsideDownCouchTermFieldReader) Advance(docID string) (*index.TermFieldDoc, error) { + if r.iterator != nil { + tfr := NewTermFrequencyRow(r.term, r.field, docID, 0, 0) + r.iterator.Seek(tfr.Key()) + key, val, valid := r.iterator.Current() + if valid { + if !bytes.HasPrefix(key, r.readerPrefix) { + // end of the line + return nil, nil + } + tfr, err := NewTermFrequencyRowKV(key, val) + if err != nil { + return nil, err + } + r.iterator.Next() + return &index.TermFieldDoc{ + ID: string(tfr.doc), + Freq: tfr.freq, + Norm: float64(tfr.norm), + Vectors: r.indexReader.index.termFieldVectorsFromTermVectors(tfr.vectors), + }, nil + } + } + return nil, nil +} + +func (r *UpsideDownCouchTermFieldReader) Close() error { + if r.iterator != nil { + return r.iterator.Close() + } + return nil +} + +type UpsideDownCouchDocIDReader struct { + indexReader *IndexReader + iterator store.KVIterator + start string + end string +} + +func newUpsideDownCouchDocIDReader(indexReader *IndexReader, start, end string) (*UpsideDownCouchDocIDReader, error) { + if start == "" { + start = string([]byte{0x0}) + } + if end == "" { + end = string([]byte{0xff}) + } + bisr := NewBackIndexRow(start, nil, nil) + it := indexReader.kvreader.Iterator(bisr.Key()) + + return &UpsideDownCouchDocIDReader{ + indexReader: indexReader, + iterator: it, + start: start, + end: end, + }, nil +} + +func (r *UpsideDownCouchDocIDReader) Next() (string, error) { + key, val, valid := r.iterator.Current() + if valid { + bier := NewBackIndexRow(r.end, nil, nil) + if bytes.Compare(key, bier.Key()) > 0 { + // end of the line + return "", nil + } + br, err := NewBackIndexRowKV(key, val) + if err != nil { + return "", err + } + r.iterator.Next() + return string(br.doc), nil + } + return "", nil +} + +func (r *UpsideDownCouchDocIDReader) Advance(docID string) (string, error) { + bir := NewBackIndexRow(docID, nil, nil) + r.iterator.Seek(bir.Key()) + key, val, valid := r.iterator.Current() + if valid { + bier := NewBackIndexRow(r.end, nil, nil) + if bytes.Compare(key, bier.Key()) > 0 { + // end of the line + return "", nil + } + br, err := NewBackIndexRowKV(key, val) + if err != nil { + return "", err + } + r.iterator.Next() + return string(br.doc), nil + } + return "", nil +} + +func (r *UpsideDownCouchDocIDReader) Close() error { + return r.iterator.Close() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader_test.go new file mode 100644 index 00000000..e658e4ea --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/reader_test.go @@ -0,0 +1,297 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "os" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb" +) + +func TestIndexReader(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s := boltdb.New("test", "bleve") + s.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(s, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + doc = document.NewDocument("2") + doc.AddField(document.NewTextFieldWithAnalyzer("name", []uint64{}, []byte("test test test"), testAnalyzer)) + doc.AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("eat more rice"), document.IndexField|document.IncludeTermVectors, testAnalyzer)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // first look for a term that doesn't exist + reader, err := indexReader.TermFieldReader([]byte("nope"), "name") + if err != nil { + t.Errorf("Error accessing term field reader: %v", err) + } + count := reader.Count() + if count != 0 { + t.Errorf("Expected doc count to be: %d got: %d", 0, count) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } + + reader, err = indexReader.TermFieldReader([]byte("test"), "name") + if err != nil { + t.Errorf("Error accessing term field reader: %v", err) + } + + expectedCount = 2 + count = reader.Count() + if count != expectedCount { + t.Errorf("Exptected doc count to be: %d got: %d", expectedCount, count) + } + + var match *index.TermFieldDoc + var actualCount uint64 + match, err = reader.Next() + for err == nil && match != nil { + match, err = reader.Next() + if err != nil { + t.Errorf("unexpected error reading next") + } + actualCount++ + } + if actualCount != count { + t.Errorf("count was 2, but only saw %d", actualCount) + } + + expectedMatch := &index.TermFieldDoc{ + ID: "2", + Freq: 1, + Norm: 0.5773502588272095, + Vectors: []*index.TermFieldVector{ + &index.TermFieldVector{ + Field: "desc", + Pos: 3, + Start: 9, + End: 13, + }, + }, + } + tfr, err := indexReader.TermFieldReader([]byte("rice"), "desc") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + match, err = tfr.Next() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if !reflect.DeepEqual(expectedMatch, match) { + t.Errorf("got %#v, expected %#v", match, expectedMatch) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } + + // now test usage of advance + reader, err = indexReader.TermFieldReader([]byte("test"), "name") + if err != nil { + t.Errorf("Error accessing term field reader: %v", err) + } + + match, err = reader.Advance("2") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if match == nil { + t.Fatalf("Expected match, got nil") + } + if match.ID != "2" { + t.Errorf("Expected ID '2', got '%s'", match.ID) + } + match, err = reader.Advance("3") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if match != nil { + t.Errorf("expected nil, got %v", match) + } + err = reader.Close() + if err != nil { + t.Fatal(err) + } + + // now test creating a reader for a field that doesn't exist + reader, err = indexReader.TermFieldReader([]byte("water"), "doesnotexist") + if err != nil { + t.Errorf("Error accessing term field reader: %v", err) + } + count = reader.Count() + if count != 0 { + t.Errorf("expected count 0 for reader of non-existant field") + } + match, err = reader.Next() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if match != nil { + t.Errorf("expected nil, got %v", match) + } + match, err = reader.Advance("anywhere") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if match != nil { + t.Errorf("expected nil, got %v", match) + } + +} + +func TestIndexDocIdReader(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + s := boltdb.New("test", "bleve") + s.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(s, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + doc = document.NewDocument("2") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test test test"))) + doc.AddField(document.NewTextFieldWithIndexingOptions("desc", []uint64{}, []byte("eat more rice"), document.IndexField|document.IncludeTermVectors)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Error(err) + } + }() + + // first get all doc ids + reader, err := indexReader.DocIDReader("", "") + if err != nil { + t.Errorf("Error accessing doc id reader: %v", err) + } + defer func() { + err := reader.Close() + if err != nil { + t.Fatal(err) + } + }() + + id, err := reader.Next() + count := uint64(0) + for id != "" { + count++ + id, err = reader.Next() + } + if count != expectedCount { + t.Errorf("expected %d, got %d", expectedCount, count) + } + + // try it again, but jump to the second doc this time + reader2, err := indexReader.DocIDReader("", "") + if err != nil { + t.Errorf("Error accessing doc id reader: %v", err) + } + defer func() { + err := reader2.Close() + if err != nil { + t.Error(err) + } + }() + + id, err = reader2.Advance("2") + if err != nil { + t.Error(err) + } + if id != "2" { + t.Errorf("expected to find id '2', got '%s'", id) + } + + id, err = reader2.Advance("3") + if err != nil { + t.Error(err) + } + if id != "" { + t.Errorf("expected to find id '', got '%s'", id) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row.go new file mode 100644 index 00000000..36451cda --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row.go @@ -0,0 +1,641 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "math" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" +) + +const ByteSeparator byte = 0xff + +type UpsideDownCouchRowStream chan UpsideDownCouchRow + +type UpsideDownCouchRow interface { + Key() []byte + Value() []byte +} + +func ParseFromKeyValue(key, value []byte) (UpsideDownCouchRow, error) { + if len(key) > 0 { + switch key[0] { + case 'v': + return NewVersionRowKV(key, value) + case 'f': + return NewFieldRowKV(key, value) + case 'd': + return NewDictionaryRowKV(key, value) + case 't': + return NewTermFrequencyRowKV(key, value) + case 'b': + return NewBackIndexRowKV(key, value) + case 's': + return NewStoredRowKV(key, value) + case 'i': + return NewInternalRowKV(key, value) + } + return nil, fmt.Errorf("Unknown field type '%s'", string(key[0])) + } + return nil, fmt.Errorf("Invalid empty key") +} + +// VERSION + +type VersionRow struct { + version uint8 +} + +func (v *VersionRow) Key() []byte { + return []byte{'v'} +} + +func (v *VersionRow) Value() []byte { + return []byte{byte(v.version)} +} + +func (v *VersionRow) String() string { + return fmt.Sprintf("Version: %d", v.version) +} + +func NewVersionRow(version uint8) *VersionRow { + return &VersionRow{ + version: version, + } +} + +func NewVersionRowKV(key, value []byte) (*VersionRow, error) { + rv := VersionRow{} + buf := bytes.NewBuffer(value) + err := binary.Read(buf, binary.LittleEndian, &rv.version) + if err != nil { + return nil, err + } + return &rv, nil +} + +// INTERNAL STORAGE + +type InternalRow struct { + key []byte + val []byte +} + +func (i *InternalRow) Key() []byte { + buf := make([]byte, len(i.key)+1) + buf[0] = 'i' + copy(buf[1:], i.key) + return buf +} + +func (i *InternalRow) Value() []byte { + return i.val +} + +func (i *InternalRow) String() string { + return fmt.Sprintf("InternalStore - Key: %s (% x) Val: %s (% x)", i.key, i.key, i.val, i.val) +} + +func NewInternalRow(key, val []byte) *InternalRow { + return &InternalRow{ + key: key, + val: val, + } +} + +func NewInternalRowKV(key, value []byte) (*InternalRow, error) { + rv := InternalRow{} + rv.key = key[1:] + rv.val = value + return &rv, nil +} + +// FIELD definition + +type FieldRow struct { + index uint16 + name string +} + +func (f *FieldRow) Key() []byte { + buf := make([]byte, 3) + buf[0] = 'f' + binary.LittleEndian.PutUint16(buf[1:3], f.index) + return buf +} + +func (f *FieldRow) Value() []byte { + return append([]byte(f.name), ByteSeparator) +} + +func (f *FieldRow) String() string { + return fmt.Sprintf("Field: %d Name: %s", f.index, f.name) +} + +func NewFieldRow(index uint16, name string) *FieldRow { + return &FieldRow{ + index: index, + name: name, + } +} + +func NewFieldRowKV(key, value []byte) (*FieldRow, error) { + rv := FieldRow{} + + buf := bytes.NewBuffer(key) + _, err := buf.ReadByte() // type + if err != nil { + return nil, err + } + err = binary.Read(buf, binary.LittleEndian, &rv.index) + if err != nil { + return nil, err + } + + buf = bytes.NewBuffer(value) + rv.name, err = buf.ReadString(ByteSeparator) + if err != nil { + return nil, err + } + rv.name = rv.name[:len(rv.name)-1] // trim off separator byte + + return &rv, nil +} + +// DICTIONARY + +type DictionaryRow struct { + field uint16 + term []byte + count uint64 +} + +func (dr *DictionaryRow) Key() []byte { + buf := make([]byte, 3+len(dr.term)) + buf[0] = 'd' + binary.LittleEndian.PutUint16(buf[1:3], dr.field) + copy(buf[3:], dr.term) + return buf +} + +func (dr *DictionaryRow) Value() []byte { + used := 0 + buf := make([]byte, 8) + + used += binary.PutUvarint(buf[used:used+8], dr.count) + + return buf[0:used] +} + +func (dr *DictionaryRow) String() string { + return fmt.Sprintf("Dictionary Term: `%s` Field: %d Count: %d ", string(dr.term), dr.field, dr.count) +} + +func NewDictionaryRow(term []byte, field uint16, count uint64) *DictionaryRow { + return &DictionaryRow{ + term: term, + field: field, + count: count, + } +} + +func NewDictionaryRowKV(key, value []byte) (*DictionaryRow, error) { + rv, err := NewDictionaryRowK(key) + if err != nil { + return nil, err + } + + err = rv.parseDictionaryV(value) + if err != nil { + return nil, err + } + return rv, nil + +} + +func NewDictionaryRowK(key []byte) (*DictionaryRow, error) { + rv := DictionaryRow{} + buf := bytes.NewBuffer(key) + _, err := buf.ReadByte() // type + if err != nil { + return nil, err + } + + err = binary.Read(buf, binary.LittleEndian, &rv.field) + if err != nil { + return nil, err + } + + rv.term, err = buf.ReadBytes(ByteSeparator) + // there is no separator expected here, should get EOF + if err != io.EOF { + return nil, err + } + + return &rv, nil +} + +func (dr *DictionaryRow) parseDictionaryV(value []byte) error { + buf := bytes.NewBuffer((value)) + + count, err := binary.ReadUvarint(buf) + if err != nil { + return err + } + dr.count = count + + return nil +} + +// TERM FIELD FREQUENCY + +type TermVector struct { + field uint16 + pos uint64 + start uint64 + end uint64 +} + +func (tv *TermVector) String() string { + return fmt.Sprintf("Field: %d Pos: %d Start: %d End %d", tv.field, tv.pos, tv.start, tv.end) +} + +type TermFrequencyRow struct { + term []byte + field uint16 + doc []byte + freq uint64 + norm float32 + vectors []*TermVector +} + +func (tfr *TermFrequencyRow) ScanPrefixForField() []byte { + buf := make([]byte, 3) + buf[0] = 't' + binary.LittleEndian.PutUint16(buf[1:3], tfr.field) + return buf +} + +func (tfr *TermFrequencyRow) ScanPrefixForFieldTermPrefix() []byte { + buf := make([]byte, 3+len(tfr.term)) + buf[0] = 't' + binary.LittleEndian.PutUint16(buf[1:3], tfr.field) + copy(buf[3:], tfr.term) + return buf +} + +func (tfr *TermFrequencyRow) ScanPrefixForFieldTerm() []byte { + buf := make([]byte, 3+len(tfr.term)+1) + buf[0] = 't' + binary.LittleEndian.PutUint16(buf[1:3], tfr.field) + termLen := copy(buf[3:], tfr.term) + buf[3+termLen] = ByteSeparator + return buf +} + +func (tfr *TermFrequencyRow) Key() []byte { + buf := make([]byte, 3+len(tfr.term)+1+len(tfr.doc)) + buf[0] = 't' + binary.LittleEndian.PutUint16(buf[1:3], tfr.field) + termLen := copy(buf[3:], tfr.term) + buf[3+termLen] = ByteSeparator + copy(buf[3+termLen+1:], tfr.doc) + return buf +} + +func (tfr *TermFrequencyRow) DictionaryRowKey() []byte { + dr := NewDictionaryRow(tfr.term, tfr.field, 0) + return dr.Key() +} + +func (tfr *TermFrequencyRow) Value() []byte { + used := 0 + buf := make([]byte, 8+8+(len(tfr.vectors)*(8+8+8+8))) + + used += binary.PutUvarint(buf[used:used+8], tfr.freq) + + normuint32 := math.Float32bits(tfr.norm) + newbuf := buf[used : used+8] + used += binary.PutUvarint(newbuf, uint64(normuint32)) + + for _, vector := range tfr.vectors { + used += binary.PutUvarint(buf[used:used+8], uint64(vector.field)) + used += binary.PutUvarint(buf[used:used+8], vector.pos) + used += binary.PutUvarint(buf[used:used+8], vector.start) + used += binary.PutUvarint(buf[used:used+8], vector.end) + } + return buf[0:used] +} + +func (tfr *TermFrequencyRow) String() string { + return fmt.Sprintf("Term: `%s` Field: %d DocId: `%s` Frequency: %d Norm: %f Vectors: %v", string(tfr.term), tfr.field, string(tfr.doc), tfr.freq, tfr.norm, tfr.vectors) +} + +func NewTermFrequencyRow(term []byte, field uint16, doc string, freq uint64, norm float32) *TermFrequencyRow { + return &TermFrequencyRow{ + term: term, + field: field, + doc: []byte(doc), + freq: freq, + norm: norm, + } +} + +func NewTermFrequencyRowWithTermVectors(term []byte, field uint16, doc string, freq uint64, norm float32, vectors []*TermVector) *TermFrequencyRow { + return &TermFrequencyRow{ + term: term, + field: field, + doc: []byte(doc), + freq: freq, + norm: norm, + vectors: vectors, + } +} + +func NewTermFrequencyRowK(key []byte) (*TermFrequencyRow, error) { + rv := TermFrequencyRow{} + keyLen := len(key) + if keyLen < 3 { + return nil, fmt.Errorf("invalid term frequency key, no valid field") + } + rv.field = binary.LittleEndian.Uint16(key[1:3]) + + termEndPos := bytes.IndexByte(key[3:], ByteSeparator) + if termEndPos < 0 { + return nil, fmt.Errorf("invalid term frequency key, no byte separator terminating term") + } + rv.term = key[3 : 3+termEndPos] + + docLen := len(key) - (3 + termEndPos + 1) + if docLen < 1 { + return nil, fmt.Errorf("invalid term frequency key, empty docid") + } + rv.doc = key[3+termEndPos+1:] + + return &rv, nil +} + +func (tfr *TermFrequencyRow) parseV(value []byte) error { + currOffset := 0 + bytesRead := 0 + tfr.freq, bytesRead = binary.Uvarint(value[currOffset:]) + if bytesRead <= 0 { + return fmt.Errorf("invalid term frequency value, invalid frequency") + } + currOffset += bytesRead + + var norm uint64 + norm, bytesRead = binary.Uvarint(value[currOffset:]) + if bytesRead <= 0 { + return fmt.Errorf("invalid term frequency value, no norm") + } + currOffset += bytesRead + + tfr.norm = math.Float32frombits(uint32(norm)) + + var field uint64 + field, bytesRead = binary.Uvarint(value[currOffset:]) + for bytesRead > 0 { + currOffset += bytesRead + tv := TermVector{} + tv.field = uint16(field) + // at this point we expect at least one term vector + if tfr.vectors == nil { + tfr.vectors = make([]*TermVector, 0) + } + + tv.pos, bytesRead = binary.Uvarint(value[currOffset:]) + if bytesRead <= 0 { + return fmt.Errorf("invalid term frequency value, vector contains no position") + } + currOffset += bytesRead + + tv.start, bytesRead = binary.Uvarint(value[currOffset:]) + if bytesRead <= 0 { + return fmt.Errorf("invalid term frequency value, vector contains no start") + } + currOffset += bytesRead + + tv.end, bytesRead = binary.Uvarint(value[currOffset:]) + if bytesRead <= 0 { + return fmt.Errorf("invalid term frequency value, vector contains no end") + } + currOffset += bytesRead + + tfr.vectors = append(tfr.vectors, &tv) + // try to read next record (may not exist) + field, bytesRead = binary.Uvarint(value[currOffset:]) + } + if len(value[currOffset:]) > 0 && bytesRead <= 0 { + return fmt.Errorf("invalid term frequency value, vector field invalid") + } + + return nil +} + +func NewTermFrequencyRowKV(key, value []byte) (*TermFrequencyRow, error) { + rv, err := NewTermFrequencyRowK(key) + if err != nil { + return nil, err + } + + err = rv.parseV(value) + if err != nil { + return nil, err + } + return rv, nil + +} + +type BackIndexRow struct { + doc []byte + termEntries []*BackIndexTermEntry + storedEntries []*BackIndexStoreEntry +} + +func (br *BackIndexRow) AllTermKeys() [][]byte { + if br == nil { + return nil + } + rv := make([][]byte, len(br.termEntries)) + for i, termEntry := range br.termEntries { + termRow := NewTermFrequencyRow([]byte(termEntry.GetTerm()), uint16(termEntry.GetField()), string(br.doc), 0, 0) + rv[i] = termRow.Key() + } + return rv +} + +func (br *BackIndexRow) AllStoredKeys() [][]byte { + if br == nil { + return nil + } + rv := make([][]byte, len(br.storedEntries)) + for i, storedEntry := range br.storedEntries { + storedRow := NewStoredRow(string(br.doc), uint16(storedEntry.GetField()), storedEntry.GetArrayPositions(), 'x', []byte{}) + rv[i] = storedRow.Key() + } + return rv +} + +func (br *BackIndexRow) Key() []byte { + buf := make([]byte, len(br.doc)+1) + buf[0] = 'b' + copy(buf[1:], br.doc) + return buf +} + +func (br *BackIndexRow) Value() []byte { + birv := &BackIndexRowValue{ + TermEntries: br.termEntries, + StoredEntries: br.storedEntries, + } + bytes, _ := proto.Marshal(birv) + return bytes +} + +func (br *BackIndexRow) String() string { + return fmt.Sprintf("Backindex DocId: `%s` Term Entries: %v, Stored Entries: %v", string(br.doc), br.termEntries, br.storedEntries) +} + +func NewBackIndexRow(doc string, entries []*BackIndexTermEntry, storedFields []*BackIndexStoreEntry) *BackIndexRow { + return &BackIndexRow{ + doc: []byte(doc), + termEntries: entries, + storedEntries: storedFields, + } +} + +func NewBackIndexRowKV(key, value []byte) (*BackIndexRow, error) { + rv := BackIndexRow{} + + buf := bytes.NewBuffer(key) + _, err := buf.ReadByte() // type + if err != nil { + return nil, err + } + + rv.doc, err = buf.ReadBytes(ByteSeparator) + if err == io.EOF && len(rv.doc) < 1 { + err = fmt.Errorf("invalid doc length 0") + } + if err != io.EOF { + return nil, err + } + + var birv BackIndexRowValue + err = proto.Unmarshal(value, &birv) + if err != nil { + return nil, err + } + rv.termEntries = birv.TermEntries + rv.storedEntries = birv.StoredEntries + + return &rv, nil +} + +// STORED + +type StoredRow struct { + doc []byte + field uint16 + arrayPositions []uint64 + typ byte + value []byte +} + +func (s *StoredRow) Key() []byte { + docLen := len(s.doc) + buf := make([]byte, 1+docLen+1+2+(binary.MaxVarintLen64*len(s.arrayPositions))) + buf[0] = 's' + copy(buf[1:], s.doc) + buf[1+docLen] = ByteSeparator + binary.LittleEndian.PutUint16(buf[1+docLen+1:], s.field) + bytesUsed := 1 + docLen + 1 + 2 + for _, arrayPosition := range s.arrayPositions { + varbytes := binary.PutUvarint(buf[bytesUsed:], arrayPosition) + bytesUsed += varbytes + } + return buf[0:bytesUsed] +} + +func (s *StoredRow) Value() []byte { + rv := make([]byte, len(s.value)+1) + rv[0] = s.typ + copy(rv[1:], s.value) + return rv +} + +func (s *StoredRow) String() string { + return fmt.Sprintf("Document: %s Field %d, Array Positions: %v, Type: %s Value: %s", s.doc, s.field, s.arrayPositions, string(s.typ), s.value) +} + +func (s *StoredRow) ScanPrefixForDoc() []byte { + docLen := len(s.doc) + buf := make([]byte, 1+docLen+1) + buf[0] = 's' + copy(buf[1:], s.doc) + buf[1+docLen] = ByteSeparator + return buf +} + +func NewStoredRow(doc string, field uint16, arrayPositions []uint64, typ byte, value []byte) *StoredRow { + return &StoredRow{ + doc: []byte(doc), + field: field, + arrayPositions: arrayPositions, + typ: typ, + value: value, + } +} + +func NewStoredRowK(key []byte) (*StoredRow, error) { + rv := StoredRow{} + + buf := bytes.NewBuffer(key) + _, err := buf.ReadByte() // type + if err != nil { + return nil, err + } + + rv.doc, err = buf.ReadBytes(ByteSeparator) + if len(rv.doc) < 2 { // 1 for min doc id length, 1 for separator + err = fmt.Errorf("invalid doc length 0") + return nil, err + } + + rv.doc = rv.doc[:len(rv.doc)-1] // trim off separator byte + + err = binary.Read(buf, binary.LittleEndian, &rv.field) + if err != nil { + return nil, err + } + + rv.arrayPositions = make([]uint64, 0) + nextArrayPos, err := binary.ReadUvarint(buf) + for err == nil { + rv.arrayPositions = append(rv.arrayPositions, nextArrayPos) + nextArrayPos, err = binary.ReadUvarint(buf) + } + return &rv, nil +} + +func NewStoredRowKV(key, value []byte) (*StoredRow, error) { + rv, err := NewStoredRowK(key) + if err != nil { + return nil, err + } + rv.typ = value[0] + rv.value = value[1:] + return rv, nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_merge.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_merge.go new file mode 100644 index 00000000..fb9d987a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_merge.go @@ -0,0 +1,70 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "encoding/binary" +) + +var mergeOperator upsideDownMerge + +var dictionaryTermIncr []byte +var dictionaryTermDecr []byte + +func init() { + dictionaryTermIncr = make([]byte, 8) + binary.LittleEndian.PutUint64(dictionaryTermIncr, uint64(1)) + dictionaryTermDecr = make([]byte, 8) + var negOne = int64(-1) + binary.LittleEndian.PutUint64(dictionaryTermDecr, uint64(negOne)) +} + +type upsideDownMerge struct{} + +func (m *upsideDownMerge) FullMerge(key, existingValue []byte, operands [][]byte) ([]byte, bool) { + // set up record based on key + dr, err := NewDictionaryRowK(key) + if err != nil { + return nil, false + } + if len(existingValue) > 0 { + // if existing value, parse it + err = dr.parseDictionaryV(existingValue) + if err != nil { + return nil, false + } + } + + // now process operands + for _, operand := range operands { + next := int64(binary.LittleEndian.Uint64(operand)) + if next < 0 && uint64(-next) > dr.count { + // subtracting next from existing would overflow + dr.count = 0 + } else if next < 0 { + dr.count -= uint64(-next) + } else { + dr.count += uint64(next) + } + } + + return dr.Value(), true +} + +func (m *upsideDownMerge) PartialMerge(key, leftOperand, rightOperand []byte) ([]byte, bool) { + left := int64(binary.LittleEndian.Uint64(leftOperand)) + right := int64(binary.LittleEndian.Uint64(rightOperand)) + binary.LittleEndian.PutUint64(leftOperand, uint64(left+right)) + return leftOperand, true +} + +func (m *upsideDownMerge) Name() string { + return "upsideDownMerge" +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_test.go new file mode 100644 index 00000000..753b40ca --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/row_test.go @@ -0,0 +1,329 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" +) + +func TestRows(t *testing.T) { + tests := []struct { + input UpsideDownCouchRow + outKey []byte + outVal []byte + }{ + { + NewVersionRow(1), + []byte{'v'}, + []byte{0x1}, + }, + { + NewFieldRow(0, "name"), + []byte{'f', 0, 0}, + []byte{'n', 'a', 'm', 'e', ByteSeparator}, + }, + { + NewFieldRow(1, "desc"), + []byte{'f', 1, 0}, + []byte{'d', 'e', 's', 'c', ByteSeparator}, + }, + { + NewFieldRow(513, "style"), + []byte{'f', 1, 2}, + []byte{'s', 't', 'y', 'l', 'e', ByteSeparator}, + }, + { + NewDictionaryRow([]byte{'b', 'e', 'e', 'r'}, 0, 27), + []byte{'d', 0, 0, 'b', 'e', 'e', 'r'}, + []byte{27}, + }, + { + NewTermFrequencyRow([]byte{'b', 'e', 'e', 'r'}, 0, "catz", 3, 3.14), + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'c', 'a', 't', 'z'}, + []byte{3, 195, 235, 163, 130, 4}, + }, + { + NewTermFrequencyRow([]byte{'b', 'e', 'e', 'r'}, 0, "budweiser", 3, 3.14), + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3, 195, 235, 163, 130, 4}, + }, + { + NewTermFrequencyRowWithTermVectors([]byte{'b', 'e', 'e', 'r'}, 0, "budweiser", 3, 3.14, []*TermVector{&TermVector{field: 0, pos: 1, start: 3, end: 11}, &TermVector{field: 0, pos: 2, start: 23, end: 31}, &TermVector{field: 0, pos: 3, start: 43, end: 51}}), + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3, 195, 235, 163, 130, 4, 0, 1, 3, 11, 0, 2, 23, 31, 0, 3, 43, 51}, + }, + // test larger varints + { + NewTermFrequencyRowWithTermVectors([]byte{'b', 'e', 'e', 'r'}, 0, "budweiser", 25896, 3.14, []*TermVector{&TermVector{field: 255, pos: 1, start: 3, end: 11}, &TermVector{field: 0, pos: 2198, start: 23, end: 31}, &TermVector{field: 0, pos: 3, start: 43, end: 51}}), + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{168, 202, 1, 195, 235, 163, 130, 4, 255, 1, 1, 3, 11, 0, 150, 17, 23, 31, 0, 3, 43, 51}, + }, + { + NewBackIndexRow("budweiser", []*BackIndexTermEntry{&BackIndexTermEntry{Term: proto.String("beer"), Field: proto.Uint32(0)}}, nil), + []byte{'b', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{10, 8, 10, 4, 'b', 'e', 'e', 'r', 16, 0}, + }, + { + NewBackIndexRow("budweiser", []*BackIndexTermEntry{&BackIndexTermEntry{Term: proto.String("beer"), Field: proto.Uint32(0)}, &BackIndexTermEntry{Term: proto.String("beat"), Field: proto.Uint32(1)}}, nil), + []byte{'b', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{10, 8, 10, 4, 'b', 'e', 'e', 'r', 16, 0, 10, 8, 10, 4, 'b', 'e', 'a', 't', 16, 1}, + }, + { + NewBackIndexRow("budweiser", []*BackIndexTermEntry{&BackIndexTermEntry{Term: proto.String("beer"), Field: proto.Uint32(0)}, &BackIndexTermEntry{Term: proto.String("beat"), Field: proto.Uint32(1)}}, []*BackIndexStoreEntry{&BackIndexStoreEntry{Field: proto.Uint32(3)}, &BackIndexStoreEntry{Field: proto.Uint32(4)}, &BackIndexStoreEntry{Field: proto.Uint32(5)}}), + []byte{'b', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{10, 8, 10, 4, 'b', 'e', 'e', 'r', 16, 0, 10, 8, 10, 4, 'b', 'e', 'a', 't', 16, 1, 18, 2, 8, 3, 18, 2, 8, 4, 18, 2, 8, 5}, + }, + { + NewStoredRow("budweiser", 0, []uint64{}, byte('t'), []byte("an american beer")), + []byte{'s', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r', ByteSeparator, 0, 0}, + []byte{'t', 'a', 'n', ' ', 'a', 'm', 'e', 'r', 'i', 'c', 'a', 'n', ' ', 'b', 'e', 'e', 'r'}, + }, + { + NewStoredRow("budweiser", 0, []uint64{2, 294, 3078}, byte('t'), []byte("an american beer")), + []byte{'s', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r', ByteSeparator, 0, 0, 2, 166, 2, 134, 24}, + []byte{'t', 'a', 'n', ' ', 'a', 'm', 'e', 'r', 'i', 'c', 'a', 'n', ' ', 'b', 'e', 'e', 'r'}, + }, + { + NewInternalRow([]byte("mapping"), []byte(`{"mapping":"json content"}`)), + []byte{'i', 'm', 'a', 'p', 'p', 'i', 'n', 'g'}, + []byte{'{', '"', 'm', 'a', 'p', 'p', 'i', 'n', 'g', '"', ':', '"', 'j', 's', 'o', 'n', ' ', 'c', 'o', 'n', 't', 'e', 'n', 't', '"', '}'}, + }, + } + + // test going from struct to k/v bytes + for i, test := range tests { + rk := test.input.Key() + if !reflect.DeepEqual(rk, test.outKey) { + t.Errorf("Expected key to be %v got: %v", test.outKey, rk) + } + rv := test.input.Value() + if !reflect.DeepEqual(rv, test.outVal) { + t.Errorf("Expected value to be %v got: %v for %d", test.outVal, rv, i) + } + } + + // now test going back from k/v bytes to struct + for i, test := range tests { + row, err := ParseFromKeyValue(test.outKey, test.outVal) + if err != nil { + t.Errorf("error parsking key/value: %v", err) + } + if !reflect.DeepEqual(row, test.input) { + t.Errorf("Expected: %#v got: %#v for %d", test.input, row, i) + } + } + +} + +func TestInvalidRows(t *testing.T) { + tests := []struct { + key []byte + val []byte + }{ + // empty key + { + []byte{}, + []byte{}, + }, + // no such type q + { + []byte{'q'}, + []byte{}, + }, + // type v, invalid empty value + { + []byte{'v'}, + []byte{}, + }, + // type f, invalid key + { + []byte{'f'}, + []byte{}, + }, + // type f, valid key, invalid value + { + []byte{'f', 0, 0}, + []byte{}, + }, + // type t, invalid key (missing field) + { + []byte{'t'}, + []byte{}, + }, + // type t, invalid key (missing term) + { + []byte{'t', 0, 0}, + []byte{}, + }, + // type t, invalid key (missing id) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator}, + []byte{}, + }, + // type t, invalid val (missing freq) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{}, + }, + // type t, invalid val (missing norm) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3}, + }, + // type t, invalid val (half missing tv field, full missing is valid (no term vectors)) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3, 25, 255}, + }, + // type t, invalid val (missing tv pos) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3, 25, 0}, + }, + // type t, invalid val (missing tv start) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3, 25, 0, 0}, + }, + // type t, invalid val (missing tv end) + { + []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{3, 25, 0, 0, 0}, + }, + // type b, invalid key (missing id) + { + []byte{'b'}, + []byte{'b', 'e', 'e', 'r', ByteSeparator, 0, 0}, + }, + // type b, invalid val (missing field) + { + []byte{'b', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'}, + []byte{'g', 'a', 'r', 'b', 'a', 'g', 'e'}, + }, + // type s, invalid key (missing id) + { + []byte{'s'}, + []byte{'t', 'a', 'n', ' ', 'a', 'm', 'e', 'r', 'i', 'c', 'a', 'n', ' ', 'b', 'e', 'e', 'r'}, + }, + // type b, invalid val (missing field) + { + []byte{'s', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r', ByteSeparator}, + []byte{'t', 'a', 'n', ' ', 'a', 'm', 'e', 'r', 'i', 'c', 'a', 'n', ' ', 'b', 'e', 'e', 'r'}, + }, + } + + for _, test := range tests { + _, err := ParseFromKeyValue(test.key, test.val) + if err == nil { + t.Errorf("expected error, got nil") + } + } +} + +func BenchmarkTermFrequencyRowEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + row := NewTermFrequencyRowWithTermVectors( + []byte{'b', 'e', 'e', 'r'}, + 0, + "budweiser", + 3, + 3.14, + []*TermVector{ + &TermVector{ + field: 0, + pos: 1, + start: 3, + end: 11, + }, + &TermVector{ + field: 0, + pos: 2, + start: 23, + end: 31, + }, + &TermVector{ + field: 0, + pos: 3, + start: 43, + end: 51, + }, + }) + + row.Key() + row.Value() + } +} + +func BenchmarkTermFrequencyRowDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + k := []byte{'t', 0, 0, 'b', 'e', 'e', 'r', ByteSeparator, 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r'} + v := []byte{3, 195, 235, 163, 130, 4, 0, 1, 3, 11, 0, 2, 23, 31, 0, 3, 43, 51} + _, err := NewTermFrequencyRowKV(k, v) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkBackIndexRowEncode(b *testing.B) { + field := uint32(1) + t1 := "term1" + for i := 0; i < b.N; i++ { + row := NewBackIndexRow("beername", + []*BackIndexTermEntry{ + &BackIndexTermEntry{ + Term: &t1, + Field: &field, + }, + }, + []*BackIndexStoreEntry{ + &BackIndexStoreEntry{ + Field: &field, + }, + }) + + row.Key() + row.Value() + } +} + +func BenchmarkBackIndexRowDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + k := []byte{0x62, 0x62, 0x65, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65} + v := []byte{0x0a, 0x09, 0x0a, 0x05, 0x74, 0x65, 0x72, 0x6d, 0x31, 0x10, 0x01, 0x12, 0x02, 0x08, 0x01} + _, err := NewBackIndexRowKV(k, v) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkStoredRowEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + row := NewStoredRow("budweiser", 0, []uint64{}, byte('t'), []byte("an american beer")) + + row.Key() + row.Value() + } +} + +func BenchmarkStoredRowDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + k := []byte{'s', 'b', 'u', 'd', 'w', 'e', 'i', 's', 'e', 'r', ByteSeparator, 0, 0} + v := []byte{'t', 'a', 'n', ' ', 'a', 'm', 'e', 'r', 'i', 'c', 'a', 'n', ' ', 'b', 'e', 'e', 'r'} + _, err := NewStoredRowKV(k, v) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/stats.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/stats.go new file mode 100644 index 00000000..e447b28b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/stats.go @@ -0,0 +1,31 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "encoding/json" + "sync/atomic" +) + +type indexStat struct { + updates, deletes, batches, errors uint64 + analysisTime, indexTime uint64 +} + +func (i *indexStat) MarshalJSON() ([]byte, error) { + m := map[string]interface{}{} + m["updates"] = atomic.LoadUint64(&i.updates) + m["deletes"] = atomic.LoadUint64(&i.deletes) + m["batches"] = atomic.LoadUint64(&i.batches) + m["errors"] = atomic.LoadUint64(&i.errors) + m["analysis_time"] = atomic.LoadUint64(&i.analysisTime) + m["index_time"] = atomic.LoadUint64(&i.indexTime) + return json.Marshal(m) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.go new file mode 100644 index 00000000..58846979 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.go @@ -0,0 +1,720 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "bytes" + "encoding/json" + "fmt" + "math" + "sync/atomic" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" +) + +var VersionKey = []byte{'v'} + +const Version uint8 = 4 + +var IncompatibleVersion = fmt.Errorf("incompatible version, %d is supported", Version) + +type UpsideDownCouch struct { + version uint8 + path string + store store.KVStore + fieldIndexCache *FieldIndexCache + docCount uint64 + analysisQueue *AnalysisQueue + stats *indexStat +} + +func NewUpsideDownCouch(s store.KVStore, analysisQueue *AnalysisQueue) *UpsideDownCouch { + return &UpsideDownCouch{ + version: Version, + fieldIndexCache: NewFieldIndexCache(), + store: s, + analysisQueue: analysisQueue, + stats: &indexStat{}, + } +} + +func (udc *UpsideDownCouch) init(kvwriter store.KVWriter) (err error) { + // prepare a list of rows + rows := make([]UpsideDownCouchRow, 0) + + // version marker + rows = append(rows, NewVersionRow(udc.version)) + + return udc.batchRows(kvwriter, nil, rows, nil) +} + +func (udc *UpsideDownCouch) loadSchema(kvreader store.KVReader) (err error) { + + keyPrefix := []byte{'f'} + it := kvreader.Iterator(keyPrefix) + defer func() { + if cerr := it.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + it.Seek(keyPrefix) + key, val, valid := it.Current() + for valid { + + // stop when + if !bytes.HasPrefix(key, keyPrefix) { + break + } + var fieldRow *FieldRow + fieldRow, err = NewFieldRowKV(key, val) + if err != nil { + return + } + udc.fieldIndexCache.AddExisting(fieldRow.name, fieldRow.index) + + it.Next() + key, val, valid = it.Current() + } + + keyPrefix = []byte{'v'} + val, err = kvreader.Get(keyPrefix) + if err != nil { + return + } + var vr *VersionRow + vr, err = NewVersionRowKV(keyPrefix, val) + if err != nil { + return + } + if vr.version != Version { + err = IncompatibleVersion + return + } + + return +} + +func (udc *UpsideDownCouch) batchRows(writer store.KVWriter, addRows []UpsideDownCouchRow, updateRows []UpsideDownCouchRow, deleteRows []UpsideDownCouchRow) (err error) { + + // prepare batch + wb := writer.NewBatch() + + // add + for _, row := range addRows { + tfr, ok := row.(*TermFrequencyRow) + if ok { + // need to increment counter + dictionaryKey := tfr.DictionaryRowKey() + wb.Merge(dictionaryKey, dictionaryTermIncr) + } + wb.Set(row.Key(), row.Value()) + } + + // update + for _, row := range updateRows { + wb.Set(row.Key(), row.Value()) + } + + // delete + for _, row := range deleteRows { + tfr, ok := row.(*TermFrequencyRow) + if ok { + // need to decrement counter + dictionaryKey := tfr.DictionaryRowKey() + wb.Merge(dictionaryKey, dictionaryTermDecr) + } + wb.Delete(row.Key()) + } + + // write out the batch + err = wb.Execute() + if err != nil { + return + } + return +} + +func (udc *UpsideDownCouch) DocCount() (uint64, error) { + return udc.docCount, nil +} + +func (udc *UpsideDownCouch) Open() (err error) { + // install the merge operator + udc.store.SetMergeOperator(&mergeOperator) + + // now open the kv store + err = udc.store.Open() + if err != nil { + return + } + + // start a writer for the open process + var kvwriter store.KVWriter + kvwriter, err = udc.store.Writer() + if err != nil { + return + } + defer func() { + if cerr := kvwriter.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + var value []byte + value, err = kvwriter.Get(VersionKey) + if err != nil { + return + } + + // init new index OR load schema + if value == nil { + err = udc.init(kvwriter) + if err != nil { + return + } + } else { + err = udc.loadSchema(kvwriter) + if err != nil { + return + } + } + // set doc count + udc.docCount, err = udc.countDocs(kvwriter) + return +} + +func (udc *UpsideDownCouch) countDocs(kvreader store.KVReader) (count uint64, err error) { + it := kvreader.Iterator([]byte{'b'}) + defer func() { + if cerr := it.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + key, _, valid := it.Current() + for valid { + if !bytes.HasPrefix(key, []byte{'b'}) { + break + } + count++ + it.Next() + key, _, valid = it.Current() + } + + return +} + +func (udc *UpsideDownCouch) rowCount() (count uint64, err error) { + // start an isolated reader for use during the rowcount + kvreader, err := udc.store.Reader() + if err != nil { + return + } + defer func() { + if cerr := kvreader.Close(); err == nil && cerr != nil { + err = cerr + } + }() + it := kvreader.Iterator([]byte{0}) + defer func() { + if cerr := it.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + _, _, valid := it.Current() + for valid { + count++ + it.Next() + _, _, valid = it.Current() + } + + return +} + +func (udc *UpsideDownCouch) Close() error { + return udc.store.Close() +} + +func (udc *UpsideDownCouch) Update(doc *document.Document) (err error) { + // do analysis before acquiring write lock + analysisStart := time.Now() + resultChan := make(chan *AnalysisResult) + aw := AnalysisWork{ + udc: udc, + d: doc, + rc: resultChan, + } + // put the work on the queue + go func() { + udc.analysisQueue.Queue(&aw) + }() + + // wait for the result + result := <-resultChan + close(resultChan) + atomic.AddUint64(&udc.stats.analysisTime, uint64(time.Since(analysisStart))) + + // start a writer for this update + indexStart := time.Now() + var kvwriter store.KVWriter + kvwriter, err = udc.store.Writer() + if err != nil { + return + } + defer func() { + if cerr := kvwriter.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + // first we lookup the backindex row for the doc id if it exists + // lookup the back index row + var backIndexRow *BackIndexRow + backIndexRow, err = udc.backIndexRowForDoc(kvwriter, doc.ID) + if err != nil { + atomic.AddUint64(&udc.stats.errors, 1) + return + } + + // prepare a list of rows + addRows := make([]UpsideDownCouchRow, 0) + updateRows := make([]UpsideDownCouchRow, 0) + deleteRows := make([]UpsideDownCouchRow, 0) + + addRows, updateRows, deleteRows = udc.mergeOldAndNew(backIndexRow, result.rows, addRows, updateRows, deleteRows) + + err = udc.batchRows(kvwriter, addRows, updateRows, deleteRows) + if err == nil && backIndexRow == nil { + udc.docCount++ + } + atomic.AddUint64(&udc.stats.indexTime, uint64(time.Since(indexStart))) + if err == nil { + atomic.AddUint64(&udc.stats.updates, 1) + } else { + atomic.AddUint64(&udc.stats.errors, 1) + } + return +} + +func (udc *UpsideDownCouch) mergeOldAndNew(backIndexRow *BackIndexRow, rows, addRows, updateRows, deleteRows []UpsideDownCouchRow) ([]UpsideDownCouchRow, []UpsideDownCouchRow, []UpsideDownCouchRow) { + existingTermKeys := make(map[string]bool) + for _, key := range backIndexRow.AllTermKeys() { + existingTermKeys[string(key)] = true + } + + existingStoredKeys := make(map[string]bool) + for _, key := range backIndexRow.AllStoredKeys() { + existingStoredKeys[string(key)] = true + } + + for _, row := range rows { + switch row := row.(type) { + case *TermFrequencyRow: + rowKey := string(row.Key()) + if _, ok := existingTermKeys[rowKey]; ok { + updateRows = append(updateRows, row) + delete(existingTermKeys, rowKey) + } else { + addRows = append(addRows, row) + } + case *StoredRow: + rowKey := string(row.Key()) + if _, ok := existingStoredKeys[rowKey]; ok { + updateRows = append(updateRows, row) + delete(existingStoredKeys, rowKey) + } else { + addRows = append(addRows, row) + } + default: + updateRows = append(updateRows, row) + } + + } + + // any of the existing rows that weren't updated need to be deleted + for existingTermKey := range existingTermKeys { + termFreqRow, err := NewTermFrequencyRowK([]byte(existingTermKey)) + if err == nil { + deleteRows = append(deleteRows, termFreqRow) + } + } + + // any of the existing stored fields that weren't updated need to be deleted + for existingStoredKey := range existingStoredKeys { + storedRow, err := NewStoredRowK([]byte(existingStoredKey)) + if err == nil { + deleteRows = append(deleteRows, storedRow) + } + } + + return addRows, updateRows, deleteRows +} + +func (udc *UpsideDownCouch) storeField(docID string, field document.Field, fieldIndex uint16) ([]UpsideDownCouchRow, []*BackIndexStoreEntry) { + rows := make([]UpsideDownCouchRow, 0, 100) + backIndexStoredEntries := make([]*BackIndexStoreEntry, 0) + fieldType := encodeFieldType(field) + storedRow := NewStoredRow(docID, fieldIndex, field.ArrayPositions(), fieldType, field.Value()) + + // record the back index entry + backIndexStoredEntry := BackIndexStoreEntry{Field: proto.Uint32(uint32(fieldIndex)), ArrayPositions: field.ArrayPositions()} + backIndexStoredEntries = append(backIndexStoredEntries, &backIndexStoredEntry) + + rows = append(rows, storedRow) + return rows, backIndexStoredEntries +} + +func encodeFieldType(f document.Field) byte { + fieldType := byte('x') + switch f.(type) { + case *document.TextField: + fieldType = 't' + case *document.NumericField: + fieldType = 'n' + case *document.DateTimeField: + fieldType = 'd' + case *document.CompositeField: + fieldType = 'c' + } + return fieldType +} + +func (udc *UpsideDownCouch) indexField(docID string, field document.Field, fieldIndex uint16, fieldLength int, tokenFreqs analysis.TokenFrequencies) ([]UpsideDownCouchRow, []*BackIndexTermEntry) { + + rows := make([]UpsideDownCouchRow, 0, 100) + backIndexTermEntries := make([]*BackIndexTermEntry, 0) + fieldNorm := float32(1.0 / math.Sqrt(float64(fieldLength))) + + for _, tf := range tokenFreqs { + var termFreqRow *TermFrequencyRow + if field.Options().IncludeTermVectors() { + tv, newFieldRows := udc.termVectorsFromTokenFreq(fieldIndex, tf) + rows = append(rows, newFieldRows...) + termFreqRow = NewTermFrequencyRowWithTermVectors(tf.Term, fieldIndex, docID, uint64(frequencyFromTokenFreq(tf)), fieldNorm, tv) + } else { + termFreqRow = NewTermFrequencyRow(tf.Term, fieldIndex, docID, uint64(frequencyFromTokenFreq(tf)), fieldNorm) + } + + // record the back index entry + backIndexTermEntry := BackIndexTermEntry{Term: proto.String(string(tf.Term)), Field: proto.Uint32(uint32(fieldIndex))} + backIndexTermEntries = append(backIndexTermEntries, &backIndexTermEntry) + + rows = append(rows, termFreqRow) + } + + return rows, backIndexTermEntries +} + +func (udc *UpsideDownCouch) Delete(id string) (err error) { + indexStart := time.Now() + // start a writer for this delete + var kvwriter store.KVWriter + kvwriter, err = udc.store.Writer() + if err != nil { + return + } + defer func() { + if cerr := kvwriter.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + // lookup the back index row + var backIndexRow *BackIndexRow + backIndexRow, err = udc.backIndexRowForDoc(kvwriter, id) + if err != nil { + atomic.AddUint64(&udc.stats.errors, 1) + return + } + if backIndexRow == nil { + atomic.AddUint64(&udc.stats.deletes, 1) + return + } + + deleteRows := make([]UpsideDownCouchRow, 0) + deleteRows = udc.deleteSingle(id, backIndexRow, deleteRows) + + err = udc.batchRows(kvwriter, nil, nil, deleteRows) + if err == nil { + udc.docCount-- + } + atomic.AddUint64(&udc.stats.indexTime, uint64(time.Since(indexStart))) + if err == nil { + atomic.AddUint64(&udc.stats.deletes, 1) + } else { + atomic.AddUint64(&udc.stats.errors, 1) + } + return +} + +func (udc *UpsideDownCouch) deleteSingle(id string, backIndexRow *BackIndexRow, deleteRows []UpsideDownCouchRow) []UpsideDownCouchRow { + + for _, backIndexEntry := range backIndexRow.termEntries { + tfr := NewTermFrequencyRow([]byte(*backIndexEntry.Term), uint16(*backIndexEntry.Field), id, 0, 0) + deleteRows = append(deleteRows, tfr) + } + for _, se := range backIndexRow.storedEntries { + sf := NewStoredRow(id, uint16(*se.Field), se.ArrayPositions, 'x', nil) + deleteRows = append(deleteRows, sf) + } + + // also delete the back entry itself + deleteRows = append(deleteRows, backIndexRow) + return deleteRows +} + +func (udc *UpsideDownCouch) backIndexRowForDoc(kvreader store.KVReader, docID string) (*BackIndexRow, error) { + // use a temporary row structure to build key + tempRow := &BackIndexRow{ + doc: []byte(docID), + } + key := tempRow.Key() + value, err := kvreader.Get(key) + if err != nil { + return nil, err + } + if value == nil { + return nil, nil + } + backIndexRow, err := NewBackIndexRowKV(key, value) + if err != nil { + return nil, err + } + return backIndexRow, nil +} + +func (udc *UpsideDownCouch) backIndexRowsForBatch(kvreader store.KVReader, batch *index.Batch) (map[string]*BackIndexRow, error) { + // FIXME faster to order the ids and scan sequentially + // for now just get it working + rv := make(map[string]*BackIndexRow, 0) + for docID := range batch.IndexOps { + backIndexRow, err := udc.backIndexRowForDoc(kvreader, docID) + if err != nil { + return nil, err + } + rv[docID] = backIndexRow + } + return rv, nil +} + +func decodeFieldType(typ byte, name string, value []byte) document.Field { + switch typ { + case 't': + return document.NewTextField(name, []uint64{}, value) + case 'n': + return document.NewNumericFieldFromBytes(name, []uint64{}, value) + case 'd': + return document.NewDateTimeFieldFromBytes(name, []uint64{}, value) + } + return nil +} + +func frequencyFromTokenFreq(tf *analysis.TokenFreq) int { + return len(tf.Locations) +} + +func (udc *UpsideDownCouch) termVectorsFromTokenFreq(field uint16, tf *analysis.TokenFreq) ([]*TermVector, []UpsideDownCouchRow) { + rv := make([]*TermVector, len(tf.Locations)) + newFieldRows := make([]UpsideDownCouchRow, 0) + + for i, l := range tf.Locations { + var newFieldRow *FieldRow + fieldIndex := field + if l.Field != "" { + // lookup correct field + fieldIndex, newFieldRow = udc.fieldIndexCache.FieldIndex(l.Field) + if newFieldRow != nil { + newFieldRows = append(newFieldRows, newFieldRow) + } + } + tv := TermVector{ + field: fieldIndex, + pos: uint64(l.Position), + start: uint64(l.Start), + end: uint64(l.End), + } + rv[i] = &tv + } + + return rv, newFieldRows +} + +func (udc *UpsideDownCouch) termFieldVectorsFromTermVectors(in []*TermVector) []*index.TermFieldVector { + rv := make([]*index.TermFieldVector, len(in)) + + for i, tv := range in { + fieldName := udc.fieldIndexCache.FieldName(tv.field) + tfv := index.TermFieldVector{ + Field: fieldName, + Pos: tv.pos, + Start: tv.start, + End: tv.end, + } + rv[i] = &tfv + } + return rv +} + +func (udc *UpsideDownCouch) Batch(batch *index.Batch) (err error) { + analysisStart := time.Now() + resultChan := make(chan *AnalysisResult) + + var numUpdates uint64 + for _, doc := range batch.IndexOps { + if doc != nil { + numUpdates++ + } + } + + go func() { + for _, doc := range batch.IndexOps { + if doc != nil { + aw := AnalysisWork{ + udc: udc, + d: doc, + rc: resultChan, + } + // put the work on the queue + udc.analysisQueue.Queue(&aw) + } + } + }() + + newRowsMap := make(map[string][]UpsideDownCouchRow) + // wait for the result + var itemsDeQueued uint64 + for itemsDeQueued < numUpdates { + result := <-resultChan + newRowsMap[result.docID] = result.rows + itemsDeQueued++ + } + close(resultChan) + + atomic.AddUint64(&udc.stats.analysisTime, uint64(time.Since(analysisStart))) + + indexStart := time.Now() + // start a writer for this batch + var kvwriter store.KVWriter + kvwriter, err = udc.store.Writer() + if err != nil { + return + } + defer func() { + if cerr := kvwriter.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + // first lookup all the back index rows + var backIndexRows map[string]*BackIndexRow + backIndexRows, err = udc.backIndexRowsForBatch(kvwriter, batch) + if err != nil { + return + } + + // prepare a list of rows + addRows := make([]UpsideDownCouchRow, 0) + updateRows := make([]UpsideDownCouchRow, 0) + deleteRows := make([]UpsideDownCouchRow, 0) + + docsAdded := uint64(0) + docsDeleted := uint64(0) + for docID, doc := range batch.IndexOps { + backIndexRow := backIndexRows[docID] + if doc == nil && backIndexRow != nil { + // delete + deleteRows = udc.deleteSingle(docID, backIndexRow, deleteRows) + docsDeleted++ + } else if doc != nil { + addRows, updateRows, deleteRows = udc.mergeOldAndNew(backIndexRow, newRowsMap[docID], addRows, updateRows, deleteRows) + if backIndexRow == nil { + docsAdded++ + } + } + } + + // add the internal ops + for internalKey, internalValue := range batch.InternalOps { + if internalValue == nil { + // delete + deleteInternalRow := NewInternalRow([]byte(internalKey), nil) + deleteRows = append(deleteRows, deleteInternalRow) + } else { + updateInternalRow := NewInternalRow([]byte(internalKey), internalValue) + updateRows = append(updateRows, updateInternalRow) + } + } + + err = udc.batchRows(kvwriter, addRows, updateRows, deleteRows) + atomic.AddUint64(&udc.stats.indexTime, uint64(time.Since(indexStart))) + if err == nil { + udc.docCount += docsAdded + udc.docCount -= docsDeleted + atomic.AddUint64(&udc.stats.updates, numUpdates) + atomic.AddUint64(&udc.stats.deletes, docsDeleted) + atomic.AddUint64(&udc.stats.batches, 1) + } else { + atomic.AddUint64(&udc.stats.errors, 1) + } + return +} + +func (udc *UpsideDownCouch) SetInternal(key, val []byte) (err error) { + internalRow := NewInternalRow(key, val) + var writer store.KVWriter + writer, err = udc.store.Writer() + if err != nil { + return + } + defer func() { + if cerr := writer.Close(); err == nil && cerr != nil { + err = cerr + } + }() + return writer.Set(internalRow.Key(), internalRow.Value()) +} + +func (udc *UpsideDownCouch) DeleteInternal(key []byte) (err error) { + internalRow := NewInternalRow(key, nil) + var writer store.KVWriter + writer, err = udc.store.Writer() + if err != nil { + return + } + defer func() { + if cerr := writer.Close(); err == nil && cerr != nil { + err = cerr + } + }() + return writer.Delete(internalRow.Key()) +} + +func (udc *UpsideDownCouch) Reader() (index.IndexReader, error) { + kvr, err := udc.store.Reader() + if err != nil { + return nil, fmt.Errorf("error opening store reader: %v", err) + } + return &IndexReader{ + index: udc, + kvreader: kvr, + docCount: udc.docCount, + }, nil +} + +func (udc *UpsideDownCouch) Stats() json.Marshaler { + return udc.stats +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.pb.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.pb.go new file mode 100644 index 00000000..95556f39 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.pb.go @@ -0,0 +1,98 @@ +// Code generated by protoc-gen-go. +// source: upside_down.proto +// DO NOT EDIT! + +/* +Package upside_down is a generated protocol buffer package. + +It is generated from these files: + upside_down.proto + +It has these top-level messages: + BackIndexTermEntry + BackIndexStoreEntry + BackIndexRowValue +*/ +package upside_down + +import proto "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = math.Inf + +type BackIndexTermEntry struct { + Term *string `protobuf:"bytes,1,req,name=term" json:"term,omitempty"` + Field *uint32 `protobuf:"varint,2,req,name=field" json:"field,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *BackIndexTermEntry) Reset() { *m = BackIndexTermEntry{} } +func (m *BackIndexTermEntry) String() string { return proto.CompactTextString(m) } +func (*BackIndexTermEntry) ProtoMessage() {} + +func (m *BackIndexTermEntry) GetTerm() string { + if m != nil && m.Term != nil { + return *m.Term + } + return "" +} + +func (m *BackIndexTermEntry) GetField() uint32 { + if m != nil && m.Field != nil { + return *m.Field + } + return 0 +} + +type BackIndexStoreEntry struct { + Field *uint32 `protobuf:"varint,1,req,name=field" json:"field,omitempty"` + ArrayPositions []uint64 `protobuf:"varint,2,rep,name=arrayPositions" json:"arrayPositions,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *BackIndexStoreEntry) Reset() { *m = BackIndexStoreEntry{} } +func (m *BackIndexStoreEntry) String() string { return proto.CompactTextString(m) } +func (*BackIndexStoreEntry) ProtoMessage() {} + +func (m *BackIndexStoreEntry) GetField() uint32 { + if m != nil && m.Field != nil { + return *m.Field + } + return 0 +} + +func (m *BackIndexStoreEntry) GetArrayPositions() []uint64 { + if m != nil { + return m.ArrayPositions + } + return nil +} + +type BackIndexRowValue struct { + TermEntries []*BackIndexTermEntry `protobuf:"bytes,1,rep,name=termEntries" json:"termEntries,omitempty"` + StoredEntries []*BackIndexStoreEntry `protobuf:"bytes,2,rep,name=storedEntries" json:"storedEntries,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *BackIndexRowValue) Reset() { *m = BackIndexRowValue{} } +func (m *BackIndexRowValue) String() string { return proto.CompactTextString(m) } +func (*BackIndexRowValue) ProtoMessage() {} + +func (m *BackIndexRowValue) GetTermEntries() []*BackIndexTermEntry { + if m != nil { + return m.TermEntries + } + return nil +} + +func (m *BackIndexRowValue) GetStoredEntries() []*BackIndexStoreEntry { + if m != nil { + return m.StoredEntries + } + return nil +} + +func init() { +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.proto b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.proto new file mode 100644 index 00000000..27f24ccb --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down.proto @@ -0,0 +1,14 @@ +message BackIndexTermEntry { + required string term = 1; + required uint32 field = 2; +} + +message BackIndexStoreEntry { + required uint32 field = 1; + repeated uint64 arrayPositions = 2; +} + +message BackIndexRowValue { + repeated BackIndexTermEntry termEntries = 1; + repeated BackIndexStoreEntry storedEntries = 2; +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down_test.go new file mode 100644 index 00000000..58e28a48 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down/upside_down_test.go @@ -0,0 +1,1177 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package upside_down + +import ( + "os" + "reflect" + "regexp" + "testing" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/boltdb" +) + +var testAnalyzer = &analysis.Analyzer{ + Tokenizer: regexp_tokenizer.NewRegexpTokenizer(regexp.MustCompile(`\w+`)), +} + +func TestIndexOpenReopen(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + + var expectedCount uint64 + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + // opening the database should have inserted a version + expectedLength := uint64(1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } + + // now close it + err = idx.Close() + if err != nil { + t.Fatal(err) + } + + store = boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + idx = NewUpsideDownCouch(store, analysisQueue) + err = idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + + // now close it + err = idx.Close() + if err != nil { + t.Fatal(err) + } +} + +func TestIndexInsert(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + // should have 4 rows (1 for version, 1 for schema field, and 1 for single term, and 1 for the term count, and 1 for the back index entry) + expectedLength := uint64(1 + 1 + 1 + 1 + 1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } +} + +func TestIndexInsertThenDelete(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + doc2 := document.NewDocument("2") + doc2.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc2) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + err = idx.Delete("1") + if err != nil { + t.Errorf("Error deleting entry from index: %v", err) + } + expectedCount-- + + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + err = idx.Delete("2") + if err != nil { + t.Errorf("Error deleting entry from index: %v", err) + } + expectedCount-- + + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + // should have 2 rows (1 for version, 1 for schema field, 1 for dictionary row garbage) + expectedLength := uint64(1 + 1 + 1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } +} + +func TestIndexInsertThenUpdate(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + // this update should overwrite one term, and introduce one new one + doc = document.NewDocument("1") + doc.AddField(document.NewTextFieldWithAnalyzer("name", []uint64{}, []byte("test fail"), testAnalyzer)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error deleting entry from index: %v", err) + } + + // should have 2 rows (1 for version, 1 for schema field, and 2 for the two term, and 2 for the term counts, and 1 for the back index entry) + expectedLength := uint64(1 + 1 + 2 + 2 + 1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } + + // now do another update that should remove one of the terms + doc = document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("fail"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error deleting entry from index: %v", err) + } + + // should have 2 rows (1 for version, 1 for schema field, and 1 for the remaining term, and 2 for the term diciontary, and 1 for the back index entry) + expectedLength = uint64(1 + 1 + 1 + 2 + 1) + rowCount, err = idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } +} + +func TestIndexInsertMultiple(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + + var expectedCount uint64 + + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + doc = document.NewDocument("2") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + // should have 4 rows (1 for version, 1 for schema field, and 2 for single term, and 1 for the term count, and 2 for the back index entries) + expectedLength := uint64(1 + 1 + 2 + 1 + 2) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } + + // close, reopen and add one more to test that counting works correctly + err = idx.Close() + if err != nil { + t.Fatal(err) + } + + store = boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + idx = NewUpsideDownCouch(store, analysisQueue) + err = idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc = document.NewDocument("3") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("expected doc count: %d, got %d", expectedCount, docCount) + } +} + +func TestIndexInsertWithStore(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + // should have 6 rows (1 for version, 1 for schema field, and 1 for single term, and 1 for the stored field and 1 for the term count, and 1 for the back index entry) + expectedLength := uint64(1 + 1 + 1 + 1 + 1 + 1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + storedDoc, err := indexReader.Document("1") + if err != nil { + t.Error(err) + } + + if len(storedDoc.Fields) != 1 { + t.Errorf("expected 1 stored field, got %d", len(storedDoc.Fields)) + } + textField, ok := storedDoc.Fields[0].(*document.TextField) + if !ok { + t.Errorf("expected text field") + } + if string(textField.Value()) != "test" { + t.Errorf("expected field content 'test', got '%s'", string(textField.Value())) + } +} + +func TestIndexInternalCRUD(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // get something that doesn't exist yet + val, err := indexReader.GetInternal([]byte("key")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %s", val) + } + + // set + err = idx.SetInternal([]byte("key"), []byte("abc")) + if err != nil { + t.Error(err) + } + + indexReader2, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader2.Close() + if err != nil { + t.Fatal(err) + } + }() + + // get + val, err = indexReader2.GetInternal([]byte("key")) + if err != nil { + t.Error(err) + } + if string(val) != "abc" { + t.Errorf("expected %s, got '%s'", "abc", val) + } + + // delete + err = idx.DeleteInternal([]byte("key")) + if err != nil { + t.Error(err) + } + + indexReader3, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader3.Close() + if err != nil { + t.Fatal(err) + } + }() + + // get again + val, err = indexReader3.GetInternal([]byte("key")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got %s", val) + } +} + +func TestIndexBatch(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + + // first create 2 docs the old fashioned way + doc := document.NewDocument("1") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + doc = document.NewDocument("2") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test2"))) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + // now create a batch which does 3 things + // insert new doc + // update existing doc + // delete existing doc + // net document count change 0 + + batch := index.NewBatch() + doc = document.NewDocument("3") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test3"))) + batch.Update(doc) + doc = document.NewDocument("2") + doc.AddField(document.NewTextField("name", []uint64{}, []byte("test2updated"))) + batch.Update(doc) + batch.Delete("1") + + err = idx.Batch(batch) + if err != nil { + t.Error(err) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + docCount := indexReader.DocCount() + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + docIDReader, err := indexReader.DocIDReader("", "") + if err != nil { + t.Error(err) + } + docIds := make([]string, 0) + docID, err := docIDReader.Next() + for docID != "" && err == nil { + docIds = append(docIds, docID) + docID, err = docIDReader.Next() + } + if err != nil { + t.Error(err) + } + expectedDocIds := []string{"2", "3"} + if !reflect.DeepEqual(docIds, expectedDocIds) { + t.Errorf("expected ids: %v, got ids: %v", expectedDocIds, docIds) + } +} + +func TestIndexInsertUpdateDeleteWithMultipleTypesStored(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + var expectedCount uint64 + docCount, err := idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField)) + doc.AddField(document.NewNumericFieldWithIndexingOptions("age", []uint64{}, 35.99, document.IndexField|document.StoreField)) + df, err := document.NewDateTimeFieldWithIndexingOptions("unixEpoch", []uint64{}, time.Unix(0, 0), document.IndexField|document.StoreField) + if err != nil { + t.Error(err) + } + doc.AddField(df) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + expectedCount++ + + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + // should have 72 rows + // 1 for version + // 3 for schema fields + // 1 for text term + // 16 for numeric terms + // 16 for date terms + // 3 for the stored field + // 1 for the text term count + // 16 for numeric term counts + // 16 for date term counts + // 1 for the back index entry + expectedLength := uint64(1 + 3 + 1 + (64 / document.DefaultPrecisionStep) + (64 / document.DefaultPrecisionStep) + 3 + 1 + (64 / document.DefaultPrecisionStep) + (64 / document.DefaultPrecisionStep) + 1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Error(err) + } + }() + + storedDoc, err := indexReader.Document("1") + if err != nil { + t.Error(err) + } + + if len(storedDoc.Fields) != 3 { + t.Errorf("expected 3 stored field, got %d", len(storedDoc.Fields)) + } + textField, ok := storedDoc.Fields[0].(*document.TextField) + if !ok { + t.Errorf("expected text field") + } + if string(textField.Value()) != "test" { + t.Errorf("expected field content 'test', got '%s'", string(textField.Value())) + } + numField, ok := storedDoc.Fields[1].(*document.NumericField) + if !ok { + t.Errorf("expected numeric field") + } + numFieldNumer, err := numField.Number() + if err != nil { + t.Error(err) + } else { + if numFieldNumer != 35.99 { + t.Errorf("expeted numeric value 35.99, got %f", numFieldNumer) + } + } + dateField, ok := storedDoc.Fields[2].(*document.DateTimeField) + if !ok { + t.Errorf("expected date field") + } + dateFieldDate, err := dateField.DateTime() + if err != nil { + t.Error(err) + } else { + if dateFieldDate != time.Unix(0, 0).UTC() { + t.Errorf("expected date value unix epoch, got %v", dateFieldDate) + } + } + + // now update the document, but omit one of the fields + doc = document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("testup"), document.IndexField|document.StoreField)) + doc.AddField(document.NewNumericFieldWithIndexingOptions("age", []uint64{}, 36.99, document.IndexField|document.StoreField)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + indexReader2, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader2.Close() + if err != nil { + t.Error(err) + } + }() + + // expected doc count shouldn't have changed + docCount = indexReader2.DocCount() + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } + + // should only get 2 fields back now though + storedDoc, err = indexReader2.Document("1") + if err != nil { + t.Error(err) + } + + if len(storedDoc.Fields) != 2 { + t.Errorf("expected 3 stored field, got %d", len(storedDoc.Fields)) + } + textField, ok = storedDoc.Fields[0].(*document.TextField) + if !ok { + t.Errorf("expected text field") + } + if string(textField.Value()) != "testup" { + t.Errorf("expected field content 'testup', got '%s'", string(textField.Value())) + } + numField, ok = storedDoc.Fields[1].(*document.NumericField) + if !ok { + t.Errorf("expected numeric field") + } + numFieldNumer, err = numField.Number() + if err != nil { + t.Error(err) + } else { + if numFieldNumer != 36.99 { + t.Errorf("expeted numeric value 36.99, got %f", numFieldNumer) + } + } + + // now delete the document + err = idx.Delete("1") + expectedCount-- + + // expected doc count shouldn't have changed + docCount, err = idx.DocCount() + if err != nil { + t.Error(err) + } + if docCount != expectedCount { + t.Errorf("Expected document count to be %d got %d", expectedCount, docCount) + } +} + +func TestIndexInsertFields(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField)) + doc.AddField(document.NewNumericFieldWithIndexingOptions("age", []uint64{}, 35.99, document.IndexField|document.StoreField)) + dateField, err := document.NewDateTimeFieldWithIndexingOptions("unixEpoch", []uint64{}, time.Unix(0, 0), document.IndexField|document.StoreField) + if err != nil { + t.Error(err) + } + doc.AddField(dateField) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + fields, err := indexReader.Fields() + if err != nil { + t.Error(err) + } else { + expectedFields := []string{"name", "age", "unixEpoch"} + if !reflect.DeepEqual(fields, expectedFields) { + t.Errorf("expected fields: %v, got %v", expectedFields, fields) + } + } + +} + +func TestIndexUpdateComposites(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField)) + doc.AddField(document.NewTextFieldWithIndexingOptions("title", []uint64{}, []byte("mister"), document.IndexField|document.StoreField)) + doc.AddField(document.NewCompositeFieldWithIndexingOptions("_all", true, nil, nil, document.IndexField)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + // should have 72 rows + // 1 for version + // 3 for schema fields + // 4 for text term + // 2 for the stored field + // 4 for the text term count + // 1 for the back index entry + expectedLength := uint64(1 + 3 + 4 + 2 + 4 + 1) + rowCount, err := idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } + + // now lets update it + doc = document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("testupdated"), document.IndexField|document.StoreField)) + doc.AddField(document.NewTextFieldWithIndexingOptions("title", []uint64{}, []byte("misterupdated"), document.IndexField|document.StoreField)) + doc.AddField(document.NewCompositeFieldWithIndexingOptions("_all", true, nil, nil, document.IndexField)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // make sure new values are in index + storedDoc, err := indexReader.Document("1") + if err != nil { + t.Error(err) + } + if len(storedDoc.Fields) != 2 { + t.Errorf("expected 2 stored field, got %d", len(storedDoc.Fields)) + } + textField, ok := storedDoc.Fields[0].(*document.TextField) + if !ok { + t.Errorf("expected text field") + } + if string(textField.Value()) != "testupdated" { + t.Errorf("expected field content 'test', got '%s'", string(textField.Value())) + } + + // should have the same row count as before, plus 4 term dictionary garbage rows + expectedLength += 4 + rowCount, err = idx.rowCount() + if err != nil { + t.Error(err) + } + if rowCount != expectedLength { + t.Errorf("expected %d rows, got: %d", expectedLength, rowCount) + } +} + +func TestIndexFieldsMisc(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField)) + doc.AddField(document.NewTextFieldWithIndexingOptions("title", []uint64{}, []byte("mister"), document.IndexField|document.StoreField)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + fieldName1 := idx.fieldIndexCache.FieldName(1) + if fieldName1 != "name" { + t.Errorf("expected field named 'name', got '%s'", fieldName1) + } + fieldName2 := idx.fieldIndexCache.FieldName(2) + if fieldName2 != "title" { + t.Errorf("expected field named 'title', got '%s'", fieldName2) + } + fieldName3 := idx.fieldIndexCache.FieldName(3) + if fieldName3 != "" { + t.Errorf("expected field named '', got '%s'", fieldName3) + } + +} + +func TestIndexTermReaderCompositeFields(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField|document.IncludeTermVectors)) + doc.AddField(document.NewTextFieldWithIndexingOptions("title", []uint64{}, []byte("mister"), document.IndexField|document.StoreField|document.IncludeTermVectors)) + doc.AddField(document.NewCompositeFieldWithIndexingOptions("_all", true, nil, nil, document.IndexField|document.IncludeTermVectors)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + termFieldReader, err := indexReader.TermFieldReader([]byte("mister"), "_all") + if err != nil { + t.Error(err) + } + + tfd, err := termFieldReader.Next() + for tfd != nil && err == nil { + if tfd.ID != "1" { + t.Errorf("expected to find document id 1") + } + tfd, err = termFieldReader.Next() + } + if err != nil { + t.Error(err) + } +} + +func TestIndexDocumentFieldTerms(t *testing.T) { + defer func() { + err := os.RemoveAll("test") + if err != nil { + t.Fatal(err) + } + }() + + store := boltdb.New("test", "bleve") + store.SetMergeOperator(&mergeOperator) + analysisQueue := NewAnalysisQueue(1) + idx := NewUpsideDownCouch(store, analysisQueue) + err := idx.Open() + if err != nil { + t.Errorf("error opening index: %v", err) + } + defer func() { + err := idx.Close() + if err != nil { + t.Fatal(err) + } + }() + + doc := document.NewDocument("1") + doc.AddField(document.NewTextFieldWithIndexingOptions("name", []uint64{}, []byte("test"), document.IndexField|document.StoreField|document.IncludeTermVectors)) + doc.AddField(document.NewTextFieldWithIndexingOptions("title", []uint64{}, []byte("mister"), document.IndexField|document.StoreField|document.IncludeTermVectors)) + err = idx.Update(doc) + if err != nil { + t.Errorf("Error updating index: %v", err) + } + + indexReader, err := idx.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + fieldTerms, err := indexReader.DocumentFieldTerms("1") + if err != nil { + t.Error(err) + } + expectedFieldTerms := index.FieldTerms{ + "name": []string{"test"}, + "title": []string{"mister"}, + } + if !reflect.DeepEqual(fieldTerms, expectedFieldTerms) { + t.Errorf("expected field terms: %#v, got: %#v", expectedFieldTerms, fieldTerms) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias.go new file mode 100644 index 00000000..c46be279 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias.go @@ -0,0 +1,32 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +// An IndexAlias is a wrapper around one or more +// Index objects. It has two distinct modes of +// operation. +// 1. When it points to a single index, ALL index +// operations are valid and will be passed through +// to the underlying index. +// 2. When it points to more than one index, the only +// valid operation is Search. In this case the +// search will be performed across all the +// underlying indexes and the results merged. +// Calls to Add/Remove/Swap the underlying indexes +// are atomic, so you can safely change the +// underlying Index objects while other components +// are performing operations. +type IndexAlias interface { + Index + + Add(i ...Index) + Remove(i ...Index) + Swap(in, out []Index) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl.go new file mode 100644 index 00000000..d5c71576 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl.go @@ -0,0 +1,576 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "sort" + "sync" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type indexAliasImpl struct { + indexes []Index + mutex sync.RWMutex + open bool +} + +// NewIndexAlias creates a new IndexAlias over the provided +// Index objects. +func NewIndexAlias(indexes ...Index) *indexAliasImpl { + return &indexAliasImpl{ + indexes: indexes, + open: true, + } +} + +func (i *indexAliasImpl) isAliasToSingleIndex() error { + if len(i.indexes) < 1 { + return ErrorAliasEmpty + } else if len(i.indexes) > 1 { + return ErrorAliasMulti + } + return nil +} + +func (i *indexAliasImpl) Index(id string, data interface{}) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return err + } + + return i.indexes[0].Index(id, data) +} + +func (i *indexAliasImpl) Delete(id string) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return err + } + + return i.indexes[0].Delete(id) +} + +func (i *indexAliasImpl) Batch(b *Batch) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return err + } + + return i.indexes[0].Batch(b) +} + +func (i *indexAliasImpl) Document(id string) (*document.Document, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil, err + } + + return i.indexes[0].Document(id) +} + +func (i *indexAliasImpl) DocCount() (uint64, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + rv := uint64(0) + + if !i.open { + return 0, ErrorIndexClosed + } + + for _, index := range i.indexes { + otherCount, err := index.DocCount() + if err != nil { + return 0, err + } + rv += otherCount + } + + return rv, nil +} + +func (i *indexAliasImpl) Search(req *SearchRequest) (*SearchResult, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + + if len(i.indexes) < 1 { + return nil, ErrorAliasEmpty + } + + // short circuit the simple case + if len(i.indexes) == 1 { + return i.indexes[0].Search(req) + } + + return MultiSearch(req, i.indexes...) +} + +func (i *indexAliasImpl) Fields() ([]string, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil, err + } + + return i.indexes[0].Fields() +} + +func (i *indexAliasImpl) FieldDict(field string) (index.FieldDict, error) { + i.mutex.RLock() + + if !i.open { + i.mutex.RUnlock() + return nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + fieldDict, err := i.indexes[0].FieldDict(field) + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + return &indexAliasImplFieldDict{ + index: i, + fieldDict: fieldDict, + }, nil +} + +func (i *indexAliasImpl) FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) { + i.mutex.RLock() + + if !i.open { + i.mutex.RUnlock() + return nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + fieldDict, err := i.indexes[0].FieldDictRange(field, startTerm, endTerm) + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + return &indexAliasImplFieldDict{ + index: i, + fieldDict: fieldDict, + }, nil +} + +func (i *indexAliasImpl) FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) { + i.mutex.RLock() + + if !i.open { + i.mutex.RUnlock() + return nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + fieldDict, err := i.indexes[0].FieldDictPrefix(field, termPrefix) + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + return &indexAliasImplFieldDict{ + index: i, + fieldDict: fieldDict, + }, nil +} + +func (i *indexAliasImpl) DumpAll() chan interface{} { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil + } + + return i.indexes[0].DumpAll() +} + +func (i *indexAliasImpl) DumpDoc(id string) chan interface{} { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil + } + + return i.indexes[0].DumpDoc(id) +} + +func (i *indexAliasImpl) DumpFields() chan interface{} { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil + } + + return i.indexes[0].DumpFields() +} + +func (i *indexAliasImpl) Close() error { + i.mutex.Lock() + defer i.mutex.Unlock() + + i.open = false + return nil +} + +func (i *indexAliasImpl) Mapping() *IndexMapping { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil + } + + return i.indexes[0].Mapping() +} + +func (i *indexAliasImpl) Stats() *IndexStat { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil + } + + return i.indexes[0].Stats() +} + +func (i *indexAliasImpl) GetInternal(key []byte) ([]byte, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil, err + } + + return i.indexes[0].GetInternal(key) +} + +func (i *indexAliasImpl) SetInternal(key, val []byte) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return err + } + + return i.indexes[0].SetInternal(key, val) +} + +func (i *indexAliasImpl) DeleteInternal(key []byte) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return err + } + + return i.indexes[0].DeleteInternal(key) +} + +func (i *indexAliasImpl) Advanced() (index.Index, store.KVStore, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, nil, ErrorIndexClosed + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil, nil, err + } + + return i.indexes[0].Advanced() +} + +func (i *indexAliasImpl) Add(indexes ...Index) { + i.mutex.Lock() + defer i.mutex.Unlock() + + i.indexes = append(i.indexes, indexes...) +} + +func (i *indexAliasImpl) removeSingle(index Index) { + for pos, in := range i.indexes { + if in == index { + i.indexes = append(i.indexes[:pos], i.indexes[pos+1:]...) + break + } + } +} + +func (i *indexAliasImpl) Remove(indexes ...Index) { + i.mutex.Lock() + defer i.mutex.Unlock() + + for _, in := range indexes { + i.removeSingle(in) + } +} + +func (i *indexAliasImpl) Swap(in, out []Index) { + i.mutex.Lock() + defer i.mutex.Unlock() + + // add + i.indexes = append(i.indexes, in...) + + // delete + for _, ind := range out { + i.removeSingle(ind) + } +} + +// createChildSearchRequest creates a separate +// request from the original +// For now, avoid data race on req structure. +// TODO disable highligh/field load on child +// requests, and add code to do this only on +// the actual final results. +// Perhaps that part needs to be optional, +// could be slower in remote usages. +func createChildSearchRequest(req *SearchRequest) *SearchRequest { + rv := SearchRequest{ + Query: req.Query, + Size: req.Size + req.From, + From: 0, + Highlight: req.Highlight, + Fields: req.Fields, + Facets: req.Facets, + Explain: req.Explain, + } + return &rv +} + +// MultiSearch executes a SearchRequest across multiple +// Index objects, then merges the results. +func MultiSearch(req *SearchRequest, indexes ...Index) (*SearchResult, error) { + searchStart := time.Now() + results := make(chan *SearchResult) + errs := make(chan error) + + // run search on each index in separate go routine + var waitGroup sync.WaitGroup + + var searchChildIndex = func(waitGroup *sync.WaitGroup, in Index, results chan *SearchResult, errs chan error) { + go func() { + defer waitGroup.Done() + childReq := createChildSearchRequest(req) + searchResult, err := in.Search(childReq) + if err != nil { + errs <- err + } else { + results <- searchResult + } + }() + } + + for _, in := range indexes { + waitGroup.Add(1) + searchChildIndex(&waitGroup, in, results, errs) + } + + // on another go routine, close after finished + go func() { + waitGroup.Wait() + close(results) + close(errs) + }() + + var sr *SearchResult + var err error + var result *SearchResult + ok := true + for ok { + select { + case result, ok = <-results: + if ok { + if sr == nil { + // first result + sr = result + } else { + // merge with previous + sr.Merge(result) + } + } + case err, ok = <-errs: + // for now stop on any error + // FIXME offer other behaviors + if err != nil { + return nil, err + } + } + } + + // merge just concatenated all the hits + // now lets clean it up + + // first sort it by score + sort.Sort(sr.Hits) + + // now skip over the correct From + if req.From > 0 && len(sr.Hits) > req.From { + sr.Hits = sr.Hits[req.From:] + } else if req.From > 0 { + sr.Hits = search.DocumentMatchCollection{} + } + + // now trim to the correct size + if req.Size > 0 && len(sr.Hits) > req.Size { + sr.Hits = sr.Hits[0:req.Size] + } + + // fix up facets + for name, fr := range req.Facets { + sr.Facets.Fixup(name, fr.Size) + } + + // fix up original request + sr.Request = req + searchDuration := time.Since(searchStart) + sr.Took = searchDuration + + return sr, nil +} + +func (i *indexAliasImpl) NewBatch() *Batch { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + err := i.isAliasToSingleIndex() + if err != nil { + return nil + } + + return i.indexes[0].NewBatch() +} + +type indexAliasImplFieldDict struct { + index *indexAliasImpl + fieldDict index.FieldDict +} + +func (f *indexAliasImplFieldDict) Next() (*index.DictEntry, error) { + return f.fieldDict.Next() +} + +func (f *indexAliasImplFieldDict) Close() error { + defer f.index.mutex.RUnlock() + return f.fieldDict.Close() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl_test.go new file mode 100644 index 00000000..dbfa8e55 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_alias_impl_test.go @@ -0,0 +1,790 @@ +package bleve + +import ( + "fmt" + "reflect" + "testing" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestIndexAliasSingle(t *testing.T) { + expectedError := fmt.Errorf("expected") + ei1 := &stubIndex{ + err: expectedError, + } + + alias := NewIndexAlias(ei1) + + err := alias.Index("a", "a") + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + err = alias.Delete("a") + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + batch := alias.NewBatch() + err = alias.Batch(batch) + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + _, err = alias.Document("a") + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + _, err = alias.Fields() + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + _, err = alias.GetInternal([]byte("a")) + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + err = alias.SetInternal([]byte("a"), []byte("a")) + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + err = alias.DeleteInternal([]byte("a")) + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + res := alias.DumpAll() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpDoc("a") + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpFields() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + mapping := alias.Mapping() + if mapping != nil { + t.Errorf("expected nil, got %v", res) + } + + indexStat := alias.Stats() + if indexStat != nil { + t.Errorf("expected nil, got %v", res) + } + + // now a few things that should work + sr := NewSearchRequest(NewTermQuery("test")) + _, err = alias.Search(sr) + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + _, err = alias.DocCount() + if err != expectedError { + t.Errorf("expected %v, got %v", expectedError, err) + } + + // now change the def using add/remove + expectedError2 := fmt.Errorf("expected2") + ei2 := &stubIndex{ + err: expectedError2, + } + + alias.Add(ei2) + alias.Remove(ei1) + + err = alias.Index("a", "a") + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + err = alias.Delete("a") + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + err = alias.Batch(batch) + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + _, err = alias.Document("a") + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + _, err = alias.Fields() + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + _, err = alias.GetInternal([]byte("a")) + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + err = alias.SetInternal([]byte("a"), []byte("a")) + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + err = alias.DeleteInternal([]byte("a")) + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + res = alias.DumpAll() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpDoc("a") + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpFields() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + mapping = alias.Mapping() + if mapping != nil { + t.Errorf("expected nil, got %v", res) + } + + indexStat = alias.Stats() + if indexStat != nil { + t.Errorf("expected nil, got %v", res) + } + + // now a few things that should work + _, err = alias.Search(sr) + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + _, err = alias.DocCount() + if err != expectedError2 { + t.Errorf("expected %v, got %v", expectedError2, err) + } + + // now change the def using swap + expectedError3 := fmt.Errorf("expected3") + ei3 := &stubIndex{ + err: expectedError3, + } + + alias.Swap([]Index{ei3}, []Index{ei2}) + + err = alias.Index("a", "a") + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + err = alias.Delete("a") + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + err = alias.Batch(batch) + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + _, err = alias.Document("a") + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + _, err = alias.Fields() + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + _, err = alias.GetInternal([]byte("a")) + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + err = alias.SetInternal([]byte("a"), []byte("a")) + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + err = alias.DeleteInternal([]byte("a")) + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + res = alias.DumpAll() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpDoc("a") + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpFields() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + mapping = alias.Mapping() + if mapping != nil { + t.Errorf("expected nil, got %v", res) + } + + indexStat = alias.Stats() + if indexStat != nil { + t.Errorf("expected nil, got %v", res) + } + + // now a few things that should work + _, err = alias.Search(sr) + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } + + _, err = alias.DocCount() + if err != expectedError3 { + t.Errorf("expected %v, got %v", expectedError3, err) + } +} + +func TestIndexAliasClosed(t *testing.T) { + alias := NewIndexAlias() + err := alias.Close() + if err != nil { + t.Fatal(err) + } + + err = alias.Index("a", "a") + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + err = alias.Delete("a") + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + batch := alias.NewBatch() + err = alias.Batch(batch) + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + _, err = alias.Document("a") + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + _, err = alias.Fields() + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + _, err = alias.GetInternal([]byte("a")) + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + err = alias.SetInternal([]byte("a"), []byte("a")) + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + err = alias.DeleteInternal([]byte("a")) + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + res := alias.DumpAll() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpDoc("a") + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpFields() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + mapping := alias.Mapping() + if mapping != nil { + t.Errorf("expected nil, got %v", res) + } + + indexStat := alias.Stats() + if indexStat != nil { + t.Errorf("expected nil, got %v", res) + } + + // now a few things that should work + sr := NewSearchRequest(NewTermQuery("test")) + _, err = alias.Search(sr) + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } + + _, err = alias.DocCount() + if err != ErrorIndexClosed { + t.Errorf("expected %v, got %v", ErrorIndexClosed, err) + } +} + +func TestIndexAliasEmpty(t *testing.T) { + alias := NewIndexAlias() + + err := alias.Index("a", "a") + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + err = alias.Delete("a") + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + batch := alias.NewBatch() + err = alias.Batch(batch) + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + _, err = alias.Document("a") + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + _, err = alias.Fields() + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + _, err = alias.GetInternal([]byte("a")) + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + err = alias.SetInternal([]byte("a"), []byte("a")) + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + err = alias.DeleteInternal([]byte("a")) + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + res := alias.DumpAll() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpDoc("a") + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpFields() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + mapping := alias.Mapping() + if mapping != nil { + t.Errorf("expected nil, got %v", res) + } + + indexStat := alias.Stats() + if indexStat != nil { + t.Errorf("expected nil, got %v", res) + } + + // now a few things that should work + sr := NewSearchRequest(NewTermQuery("test")) + _, err = alias.Search(sr) + if err != ErrorAliasEmpty { + t.Errorf("expected %v, got %v", ErrorAliasEmpty, err) + } + + count, err := alias.DocCount() + if count != 0 { + t.Errorf("expected %d, got %d", 0, count) + } +} + +func TestIndexAliasMulti(t *testing.T) { + ei1Count := uint64(7) + ei1 := &stubIndex{ + err: nil, + docCountResult: &ei1Count, + searchResult: &SearchResult{ + Total: 1, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 1.0, + }, + }, + MaxScore: 1.0, + }} + ei2Count := uint64(8) + ei2 := &stubIndex{ + err: nil, + docCountResult: &ei2Count, + searchResult: &SearchResult{ + Total: 1, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "b", + Score: 2.0, + }, + }, + MaxScore: 2.0, + }} + + alias := NewIndexAlias(ei1, ei2) + + err := alias.Index("a", "a") + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + err = alias.Delete("a") + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + batch := alias.NewBatch() + err = alias.Batch(batch) + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + _, err = alias.Document("a") + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + _, err = alias.Fields() + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + _, err = alias.GetInternal([]byte("a")) + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + err = alias.SetInternal([]byte("a"), []byte("a")) + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + err = alias.DeleteInternal([]byte("a")) + if err != ErrorAliasMulti { + t.Errorf("expected %v, got %v", ErrorAliasMulti, err) + } + + res := alias.DumpAll() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpDoc("a") + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + res = alias.DumpFields() + if res != nil { + t.Errorf("expected nil, got %v", res) + } + + mapping := alias.Mapping() + if mapping != nil { + t.Errorf("expected nil, got %v", res) + } + + indexStat := alias.Stats() + if indexStat != nil { + t.Errorf("expected nil, got %v", res) + } + + // now a few things that should work + sr := NewSearchRequest(NewTermQuery("test")) + expected := &SearchResult{ + Request: sr, + Total: 2, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "b", + Score: 2.0, + }, + &search.DocumentMatch{ + ID: "a", + Score: 1.0, + }, + }, + MaxScore: 2.0, + } + results, err := alias.Search(sr) + if err != nil { + t.Error(err) + } + // cheat and ensure that Took field matches since it invovles time + expected.Took = results.Took + if !reflect.DeepEqual(results, expected) { + t.Errorf("expected %#v, got %#v", expected, results) + } + + count, err := alias.DocCount() + if count != (*ei1.docCountResult + *ei2.docCountResult) { + t.Errorf("expected %d, got %d", (*ei1.docCountResult + *ei2.docCountResult), count) + } +} + +// TestMultiSearchNoError +func TestMultiSearchNoError(t *testing.T) { + ei1 := &stubIndex{err: nil, searchResult: &SearchResult{ + Total: 1, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 1.0, + }, + }, + MaxScore: 1.0, + }} + ei2 := &stubIndex{err: nil, searchResult: &SearchResult{ + Total: 1, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "b", + Score: 2.0, + }, + }, + MaxScore: 2.0, + }} + + sr := NewSearchRequest(NewTermQuery("test")) + expected := &SearchResult{ + Request: sr, + Total: 2, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "b", + Score: 2.0, + }, + &search.DocumentMatch{ + ID: "a", + Score: 1.0, + }, + }, + MaxScore: 2.0, + } + + results, err := MultiSearch(sr, ei1, ei2) + if err != nil { + t.Error(err) + } + // cheat and ensure that Took field matches since it invovles time + expected.Took = results.Took + if !reflect.DeepEqual(results, expected) { + t.Errorf("expected %#v, got %#v", expected, results) + } +} + +// TestMultiSearchSomeError +func TestMultiSearchSomeError(t *testing.T) { + ei1 := &stubIndex{err: nil, searchResult: &SearchResult{ + Total: 1, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 1.0, + }, + }, + Took: 1 * time.Second, + MaxScore: 1.0, + }} + ei2 := &stubIndex{err: fmt.Errorf("deliberate error")} + sr := NewSearchRequest(NewTermQuery("test")) + _, err := MultiSearch(sr, ei1, ei2) + if err == nil { + t.Errorf("expected error, got %v", err) + } +} + +// TestMultiSearchAllError +// reproduces https://github.com/blevesearch/bleve/issues/126 +func TestMultiSearchAllError(t *testing.T) { + ei1 := &stubIndex{err: fmt.Errorf("deliberate error")} + ei2 := &stubIndex{err: fmt.Errorf("deliberate error")} + sr := NewSearchRequest(NewTermQuery("test")) + _, err := MultiSearch(sr, ei1, ei2) + if err == nil { + t.Errorf("expected error, got %v", err) + } +} + +func TestMultiSearchSecondPage(t *testing.T) { + checkRequest := func(sr *SearchRequest) error { + if sr.From != 0 { + return fmt.Errorf("child request from should be 0") + } + if sr.Size != 20 { + return fmt.Errorf("child request size should be 20") + } + return nil + } + + ei1 := &stubIndex{ + searchResult: &SearchResult{}, + checkRequest: checkRequest, + } + ei2 := &stubIndex{ + searchResult: &SearchResult{}, + checkRequest: checkRequest, + } + sr := NewSearchRequestOptions(NewTermQuery("test"), 10, 10, false) + _, err := MultiSearch(sr, ei1, ei2) + if err != nil { + t.Errorf("unexpected error %v", err) + } + +} + +// stubIndex is an Index impl for which all operations +// return the configured error value, unless the +// corresponding operation result value has been +// set, in which case that is returned instead +type stubIndex struct { + err error + searchResult *SearchResult + documentResult *document.Document + docCountResult *uint64 + checkRequest func(*SearchRequest) error +} + +func (i *stubIndex) Index(id string, data interface{}) error { + return i.err +} + +func (i *stubIndex) Delete(id string) error { + return i.err +} + +func (i *stubIndex) Batch(b *Batch) error { + return i.err +} + +func (i *stubIndex) Document(id string) (*document.Document, error) { + if i.documentResult != nil { + return i.documentResult, nil + } + return nil, i.err +} + +func (i *stubIndex) DocCount() (uint64, error) { + if i.docCountResult != nil { + return *i.docCountResult, nil + } + return 0, i.err +} + +func (i *stubIndex) Search(req *SearchRequest) (*SearchResult, error) { + if i.checkRequest != nil { + err := i.checkRequest(req) + if err != nil { + return nil, err + } + } + if i.searchResult != nil { + return i.searchResult, nil + } + return nil, i.err +} + +func (i *stubIndex) Fields() ([]string, error) { + return nil, i.err +} + +func (i *stubIndex) FieldDict(field string) (index.FieldDict, error) { + return nil, i.err +} + +func (i *stubIndex) FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) { + return nil, i.err +} + +func (i *stubIndex) FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) { + return nil, i.err +} + +func (i *stubIndex) DumpAll() chan interface{} { + return nil +} + +func (i *stubIndex) DumpDoc(id string) chan interface{} { + return nil +} + +func (i *stubIndex) DumpFields() chan interface{} { + return nil +} + +func (i *stubIndex) Close() error { + return i.err +} + +func (i *stubIndex) Mapping() *IndexMapping { + return nil +} + +func (i *stubIndex) Stats() *IndexStat { + return nil +} + +func (i *stubIndex) GetInternal(key []byte) ([]byte, error) { + return nil, i.err +} + +func (i *stubIndex) SetInternal(key, val []byte) error { + return i.err +} + +func (i *stubIndex) DeleteInternal(key []byte) error { + return i.err +} + +func (i *stubIndex) Advanced() (index.Index, store.KVStore, error) { + return nil, nil, nil +} + +func (i *stubIndex) NewBatch() *Batch { + return &Batch{} +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_impl.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_impl.go new file mode 100644 index 00000000..07415bc6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_impl.go @@ -0,0 +1,739 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "fmt" + "os" + "sync" + "sync/atomic" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets" +) + +type indexImpl struct { + path string + meta *indexMeta + s store.KVStore + i index.Index + m *IndexMapping + mutex sync.RWMutex + open bool + stats *IndexStat +} + +const storePath = "store" + +var mappingInternalKey = []byte("_mapping") + +func indexStorePath(path string) string { + return path + string(os.PathSeparator) + storePath +} + +func newMemIndex(mapping *IndexMapping) (*indexImpl, error) { + rv := indexImpl{ + path: "", + m: mapping, + meta: newIndexMeta("mem", nil), + stats: &IndexStat{}, + } + + storeConstructor := registry.KVStoreConstructorByName(rv.meta.Storage) + if storeConstructor == nil { + return nil, ErrorUnknownStorageType + } + // now open the store + var err error + rv.s, err = storeConstructor(nil) + if err != nil { + return nil, err + } + + // open the index + rv.i = upside_down.NewUpsideDownCouch(rv.s, Config.analysisQueue) + err = rv.i.Open() + if err != nil { + return nil, err + } + rv.stats.indexStat = rv.i.Stats() + + // now persist the mapping + mappingBytes, err := json.Marshal(mapping) + if err != nil { + return nil, err + } + err = rv.i.SetInternal(mappingInternalKey, mappingBytes) + if err != nil { + return nil, err + } + + // mark the index as open + rv.mutex.Lock() + defer rv.mutex.Unlock() + rv.open = true + return &rv, nil +} + +func newIndexUsing(path string, mapping *IndexMapping, kvstore string, kvconfig map[string]interface{}) (*indexImpl, error) { + // first validate the mapping + err := mapping.validate() + if err != nil { + return nil, err + } + + if path == "" { + return newMemIndex(mapping) + } + + if kvconfig == nil { + kvconfig = map[string]interface{}{} + } + + rv := indexImpl{ + path: path, + m: mapping, + meta: newIndexMeta(kvstore, kvconfig), + stats: &IndexStat{}, + } + storeConstructor := registry.KVStoreConstructorByName(rv.meta.Storage) + if storeConstructor == nil { + return nil, ErrorUnknownStorageType + } + // at this point there is hope that we can be successful, so save index meta + err = rv.meta.Save(path) + if err != nil { + return nil, err + } + kvconfig["create_if_missing"] = true + kvconfig["error_if_exists"] = true + kvconfig["path"] = indexStorePath(path) + + // now create the store + rv.s, err = storeConstructor(kvconfig) + if err != nil { + return nil, err + } + + // open the index + rv.i = upside_down.NewUpsideDownCouch(rv.s, Config.analysisQueue) + err = rv.i.Open() + if err != nil { + return nil, err + } + rv.stats.indexStat = rv.i.Stats() + + // now persist the mapping + mappingBytes, err := json.Marshal(mapping) + if err != nil { + return nil, err + } + err = rv.i.SetInternal(mappingInternalKey, mappingBytes) + if err != nil { + return nil, err + } + + // mark the index as open + rv.mutex.Lock() + defer rv.mutex.Unlock() + rv.open = true + return &rv, nil +} + +func openIndexUsing(path string, runtimeConfig map[string]interface{}) (rv *indexImpl, err error) { + + rv = &indexImpl{ + path: path, + stats: &IndexStat{}, + } + + rv.meta, err = openIndexMeta(path) + if err != nil { + return nil, err + } + + storeConstructor := registry.KVStoreConstructorByName(rv.meta.Storage) + if storeConstructor == nil { + return nil, ErrorUnknownStorageType + } + + storeConfig := rv.meta.Config + if storeConfig == nil { + storeConfig = map[string]interface{}{} + } + + storeConfig["path"] = indexStorePath(path) + storeConfig["create_if_missing"] = false + storeConfig["error_if_exists"] = false + for rck, rcv := range runtimeConfig { + storeConfig[rck] = rcv + } + + // now open the store + rv.s, err = storeConstructor(storeConfig) + if err != nil { + return nil, err + } + + // open the index + rv.i = upside_down.NewUpsideDownCouch(rv.s, Config.analysisQueue) + err = rv.i.Open() + if err != nil { + return nil, err + } + rv.stats.indexStat = rv.i.Stats() + + // now load the mapping + indexReader, err := rv.i.Reader() + if err != nil { + return nil, err + } + defer func() { + if cerr := indexReader.Close(); cerr != nil && err == nil { + err = cerr + } + }() + + mappingBytes, err := indexReader.GetInternal(mappingInternalKey) + if err != nil { + return nil, err + } + + var im IndexMapping + err = json.Unmarshal(mappingBytes, &im) + if err != nil { + return nil, err + } + + // mark the index as open + rv.mutex.Lock() + defer rv.mutex.Unlock() + rv.open = true + + // validate the mapping + err = im.validate() + if err != nil { + // note even if the mapping is invalid + // we still return an open usable index + return rv, err + } + + rv.m = &im + return rv, err +} + +// Advanced returns implementation internals +// necessary ONLY for advanced usage. +func (i *indexImpl) Advanced() (index.Index, store.KVStore, error) { + return i.i, i.s, nil +} + +// Mapping returns the IndexMapping in use by this +// Index. +func (i *indexImpl) Mapping() *IndexMapping { + return i.m +} + +// Index the object with the specified identifier. +// The IndexMapping for this index will determine +// how the object is indexed. +func (i *indexImpl) Index(id string, data interface{}) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + doc := document.NewDocument(id) + err := i.m.mapDocument(doc, data) + if err != nil { + return err + } + err = i.i.Update(doc) + if err != nil { + return err + } + return nil +} + +// Delete entries for the specified identifier from +// the index. +func (i *indexImpl) Delete(id string) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + err := i.i.Delete(id) + if err != nil { + return err + } + return nil +} + +// Batch executes multiple Index and Delete +// operations at the same time. There are often +// significant performance benefits when performing +// operations in a batch. +func (i *indexImpl) Batch(b *Batch) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + return i.i.Batch(b.internal) +} + +// Document is used to find the values of all the +// stored fields for a document in the index. These +// stored fields are put back into a Document object +// and returned. +func (i *indexImpl) Document(id string) (doc *document.Document, err error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + indexReader, err := i.i.Reader() + if err != nil { + return nil, err + } + defer func() { + if cerr := indexReader.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + doc, err = indexReader.Document(id) + if err != nil { + return nil, err + } + return doc, nil +} + +// DocCount returns the number of documents in the +// index. +func (i *indexImpl) DocCount() (uint64, error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return 0, ErrorIndexClosed + } + + return i.i.DocCount() +} + +// Search executes a search request operation. +// Returns a SearchResult object or an error. +func (i *indexImpl) Search(req *SearchRequest) (sr *SearchResult, err error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + searchStart := time.Now() + + if !i.open { + return nil, ErrorIndexClosed + } + + collector := collectors.NewTopScorerSkipCollector(req.Size, req.From) + + // open a reader for this search + indexReader, err := i.i.Reader() + if err != nil { + return nil, fmt.Errorf("error opening index reader %v", err) + } + defer func() { + if cerr := indexReader.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + searcher, err := req.Query.Searcher(indexReader, i.m, req.Explain) + if err != nil { + return nil, err + } + defer func() { + if serr := searcher.Close(); err == nil && serr != nil { + err = serr + } + }() + + if req.Facets != nil { + facetsBuilder := search.NewFacetsBuilder(indexReader) + for facetName, facetRequest := range req.Facets { + if facetRequest.NumericRanges != nil { + // build numeric range facet + facetBuilder := facets.NewNumericFacetBuilder(facetRequest.Field, facetRequest.Size) + for _, nr := range facetRequest.NumericRanges { + facetBuilder.AddRange(nr.Name, nr.Min, nr.Max) + } + facetsBuilder.Add(facetName, facetBuilder) + } else if facetRequest.DateTimeRanges != nil { + // build date range facet + facetBuilder := facets.NewDateTimeFacetBuilder(facetRequest.Field, facetRequest.Size) + dateTimeParser := i.m.dateTimeParserNamed(i.m.DefaultDateTimeParser) + for _, dr := range facetRequest.DateTimeRanges { + dr.ParseDates(dateTimeParser) + facetBuilder.AddRange(dr.Name, dr.Start, dr.End) + } + facetsBuilder.Add(facetName, facetBuilder) + } else { + // build terms facet + facetBuilder := facets.NewTermsFacetBuilder(facetRequest.Field, facetRequest.Size) + facetsBuilder.Add(facetName, facetBuilder) + } + } + collector.SetFacetsBuilder(facetsBuilder) + } + + err = collector.Collect(searcher) + if err != nil { + return nil, err + } + + hits := collector.Results() + + if req.Highlight != nil { + // get the right highlighter + highlighter, err := Config.Cache.HighlighterNamed(Config.DefaultHighlighter) + if err != nil { + return nil, err + } + if req.Highlight.Style != nil { + highlighter, err = Config.Cache.HighlighterNamed(*req.Highlight.Style) + if err != nil { + return nil, err + } + } + if highlighter == nil { + return nil, fmt.Errorf("no highlighter named `%s` registered", *req.Highlight.Style) + } + + for _, hit := range hits { + doc, err := indexReader.Document(hit.ID) + if err == nil { + highlightFields := req.Highlight.Fields + if highlightFields == nil { + // add all fields with matches + highlightFields = make([]string, 0, len(hit.Locations)) + for k := range hit.Locations { + highlightFields = append(highlightFields, k) + } + } + + for _, hf := range highlightFields { + highlighter.BestFragmentsInField(hit, doc, hf, 1) + } + } + } + } + + if len(req.Fields) > 0 { + for _, hit := range hits { + // FIXME avoid loading doc second time + // if we already loaded it for highlighting + doc, err := indexReader.Document(hit.ID) + if err == nil { + for _, f := range req.Fields { + for _, docF := range doc.Fields { + if f == "*" || docF.Name() == f { + var value interface{} + switch docF := docF.(type) { + case *document.TextField: + value = string(docF.Value()) + case *document.NumericField: + num, err := docF.Number() + if err == nil { + value = num + } + case *document.DateTimeField: + datetime, err := docF.DateTime() + if err == nil { + value = datetime.Format(time.RFC3339) + } + } + if value != nil { + hit.AddFieldValue(docF.Name(), value) + } + } + } + } + } + } + } + + atomic.AddUint64(&i.stats.searches, 1) + searchDuration := time.Since(searchStart) + atomic.AddUint64(&i.stats.searchTime, uint64(searchDuration)) + + if searchDuration > Config.SlowSearchLogThreshold { + logger.Printf("slow search took %s - %v", searchDuration, req) + } + + return &SearchResult{ + Request: req, + Hits: hits, + Total: collector.Total(), + MaxScore: collector.MaxScore(), + Took: searchDuration, + Facets: collector.FacetResults(), + }, nil +} + +// Fields returns the name of all the fields this +// Index has operated on. +func (i *indexImpl) Fields() (fields []string, err error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + + indexReader, err := i.i.Reader() + if err != nil { + return nil, err + } + defer func() { + if cerr := indexReader.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + fields, err = indexReader.Fields() + if err != nil { + return nil, err + } + return fields, nil +} + +func (i *indexImpl) FieldDict(field string) (index.FieldDict, error) { + i.mutex.RLock() + + if !i.open { + i.mutex.RUnlock() + return nil, ErrorIndexClosed + } + + indexReader, err := i.i.Reader() + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + fieldDict, err := indexReader.FieldDict(field) + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + return &indexImplFieldDict{ + index: i, + indexReader: indexReader, + fieldDict: fieldDict, + }, nil +} + +func (i *indexImpl) FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) { + i.mutex.RLock() + + if !i.open { + i.mutex.RUnlock() + return nil, ErrorIndexClosed + } + + indexReader, err := i.i.Reader() + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + fieldDict, err := indexReader.FieldDictRange(field, startTerm, endTerm) + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + return &indexImplFieldDict{ + index: i, + indexReader: indexReader, + fieldDict: fieldDict, + }, nil +} + +func (i *indexImpl) FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) { + i.mutex.RLock() + + if !i.open { + i.mutex.RUnlock() + return nil, ErrorIndexClosed + } + + indexReader, err := i.i.Reader() + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + fieldDict, err := indexReader.FieldDictPrefix(field, termPrefix) + if err != nil { + i.mutex.RUnlock() + return nil, err + } + + return &indexImplFieldDict{ + index: i, + indexReader: indexReader, + fieldDict: fieldDict, + }, nil +} + +// DumpAll writes all index rows to a channel. +// INTERNAL: do not rely on this function, it is +// only intended to be used by the debug utilities +func (i *indexImpl) DumpAll() chan interface{} { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + + return i.i.DumpAll() +} + +// DumpFields writes all field rows in the index +// to a channel. +// INTERNAL: do not rely on this function, it is +// only intended to be used by the debug utilities +func (i *indexImpl) DumpFields() chan interface{} { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + return i.i.DumpFields() +} + +// DumpDoc writes all rows in the index associated +// with the specified identifier to a channel. +// INTERNAL: do not rely on this function, it is +// only intended to be used by the debug utilities +func (i *indexImpl) DumpDoc(id string) chan interface{} { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil + } + return i.i.DumpDoc(id) +} + +func (i *indexImpl) Close() error { + i.mutex.Lock() + defer i.mutex.Unlock() + + i.open = false + return i.i.Close() +} + +func (i *indexImpl) Stats() *IndexStat { + return i.stats +} + +func (i *indexImpl) GetInternal(key []byte) (val []byte, err error) { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return nil, ErrorIndexClosed + } + + reader, err := i.i.Reader() + if err != nil { + return nil, err + } + defer func() { + if cerr := reader.Close(); err == nil && cerr != nil { + err = cerr + } + }() + + val, err = reader.GetInternal(key) + if err != nil { + return nil, err + } + return val, nil +} + +func (i *indexImpl) SetInternal(key, val []byte) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + return i.i.SetInternal(key, val) +} + +func (i *indexImpl) DeleteInternal(key []byte) error { + i.mutex.RLock() + defer i.mutex.RUnlock() + + if !i.open { + return ErrorIndexClosed + } + + return i.i.DeleteInternal(key) +} + +// NewBatch creates a new empty batch. +func (i *indexImpl) NewBatch() *Batch { + return &Batch{ + index: i, + internal: index.NewBatch(), + } +} + +type indexImplFieldDict struct { + index *indexImpl + indexReader index.IndexReader + fieldDict index.FieldDict +} + +func (f *indexImplFieldDict) Next() (*index.DictEntry, error) { + return f.fieldDict.Next() +} + +func (f *indexImplFieldDict) Close() error { + defer f.index.mutex.RUnlock() + err := f.fieldDict.Close() + if err != nil { + return err + } + return f.indexReader.Close() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta.go new file mode 100644 index 00000000..e59079b0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta.go @@ -0,0 +1,81 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "io/ioutil" + "os" +) + +const metaFilename = "index_meta.json" + +type indexMeta struct { + Storage string `json:"storage"` + Config map[string]interface{} `json:"config,omitempty"` +} + +func newIndexMeta(storage string, config map[string]interface{}) *indexMeta { + return &indexMeta{ + Storage: storage, + Config: config, + } +} + +func openIndexMeta(path string) (*indexMeta, error) { + if _, err := os.Stat(path); os.IsNotExist(err) { + return nil, ErrorIndexPathDoesNotExist + } + indexMetaPath := indexMetaPath(path) + metaBytes, err := ioutil.ReadFile(indexMetaPath) + if err != nil { + return nil, ErrorIndexMetaMissing + } + var im indexMeta + err = json.Unmarshal(metaBytes, &im) + if err != nil { + return nil, ErrorIndexMetaCorrupt + } + return &im, nil +} + +func (i *indexMeta) Save(path string) (err error) { + indexMetaPath := indexMetaPath(path) + // ensure any necessary parent directories exist + err = os.Mkdir(path, 0700) + if err != nil { + return ErrorIndexPathExists + } + metaBytes, err := json.Marshal(i) + if err != nil { + return err + } + indexMetaFile, err := os.OpenFile(indexMetaPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + if err != nil { + if os.IsExist(err) { + return ErrorIndexPathExists + } + return err + } + defer func() { + if ierr := indexMetaFile.Close(); err == nil && ierr != nil { + err = ierr + } + }() + _, err = indexMetaFile.Write(metaBytes) + if err != nil { + return err + } + return nil +} + +func indexMetaPath(path string) string { + return path + string(os.PathSeparator) + metaFilename +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta_test.go new file mode 100644 index 00000000..4edb2a74 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_meta_test.go @@ -0,0 +1,54 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "os" + "testing" +) + +func TestIndexMeta(t *testing.T) { + var testIndexPath = "doesnotexit.bleve" + defer func() { + err := os.RemoveAll(testIndexPath) + if err != nil { + t.Fatal(err) + } + }() + + // open non-existent meta should give an error + _, err := openIndexMeta(testIndexPath) + if err == nil { + t.Errorf("expected error, got nil") + } + + // create meta + im := &indexMeta{Storage: "boltdb"} + err = im.Save(testIndexPath) + if err != nil { + t.Error(err) + } + im = nil + + // open a meta that exists + im, err = openIndexMeta(testIndexPath) + if err != nil { + t.Error(err) + } + if im.Storage != "boltdb" { + t.Errorf("expected storage 'boltdb', got '%s'", im.Storage) + } + + // save a meta that already exists + err = im.Save(testIndexPath) + if err == nil { + t.Errorf("expected error, got nil") + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_stats.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_stats.go new file mode 100644 index 00000000..b29ec9ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_stats.go @@ -0,0 +1,39 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "sync/atomic" +) + +type IndexStat struct { + indexStat json.Marshaler + searches uint64 + searchTime uint64 +} + +func (is *IndexStat) MarshalJSON() ([]byte, error) { + m := map[string]interface{}{} + m["index"] = is.indexStat + m["searches"] = atomic.LoadUint64(&is.searches) + m["search_time"] = atomic.LoadUint64(&is.searchTime) + return json.Marshal(m) +} + +type IndexStats map[string]*IndexStat + +func (i IndexStats) String() string { + bytes, err := json.Marshal(i) + if err != nil { + return "error marshaling stats" + } + return string(bytes) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/index_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_test.go new file mode 100644 index 00000000..8a0a7fe8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/index_test.go @@ -0,0 +1,609 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "io/ioutil" + "log" + "os" + "reflect" + "strings" + "testing" + "time" +) + +func TestCrud(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + + doca := map[string]interface{}{ + "name": "marty", + "desc": "gophercon india", + } + err = index.Index("a", doca) + if err != nil { + t.Error(err) + } + + docy := map[string]interface{}{ + "name": "jasper", + "desc": "clojure", + } + err = index.Index("y", docy) + if err != nil { + t.Error(err) + } + + err = index.Delete("y") + if err != nil { + t.Error(err) + } + + docx := map[string]interface{}{ + "name": "rose", + "desc": "googler", + } + err = index.Index("x", docx) + if err != nil { + t.Error(err) + } + + err = index.SetInternal([]byte("status"), []byte("pending")) + if err != nil { + t.Error(err) + } + + docb := map[string]interface{}{ + "name": "steve", + "desc": "cbft master", + } + batch := index.NewBatch() + err = batch.Index("b", docb) + if err != nil { + t.Error(err) + } + batch.Delete("x") + batch.SetInternal([]byte("batchi"), []byte("batchv")) + batch.DeleteInternal([]byte("status")) + err = index.Batch(batch) + if err != nil { + t.Error(err) + } + val, err := index.GetInternal([]byte("batchi")) + if err != nil { + t.Error(err) + } + if string(val) != "batchv" { + t.Errorf("expected 'batchv', got '%s'", val) + } + val, err = index.GetInternal([]byte("status")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got '%s'", val) + } + + err = index.SetInternal([]byte("seqno"), []byte("7")) + if err != nil { + t.Error(err) + } + err = index.SetInternal([]byte("status"), []byte("ready")) + if err != nil { + t.Error(err) + } + err = index.DeleteInternal([]byte("status")) + if err != nil { + t.Error(err) + } + val, err = index.GetInternal([]byte("status")) + if err != nil { + t.Error(err) + } + if val != nil { + t.Errorf("expected nil, got '%s'", val) + } + + val, err = index.GetInternal([]byte("seqno")) + if err != nil { + t.Error(err) + } + if string(val) != "7" { + t.Errorf("expected '7', got '%s'", val) + } + + // close the index, open it again, and try some more things + err = index.Close() + if err != nil { + t.Fatal(err) + } + + index, err = Open("testidx") + if err != nil { + t.Fatal(err) + } + defer func() { + err := index.Close() + if err != nil { + t.Fatal(err) + } + }() + + count, err := index.DocCount() + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Errorf("expected doc count 2, got %d", count) + } + + doc, err := index.Document("a") + if err != nil { + t.Fatal(err) + } + if doc == nil { + t.Errorf("expected doc not nil, got nil") + } + foundNameField := false + for _, field := range doc.Fields { + if field.Name() == "name" && string(field.Value()) == "marty" { + foundNameField = true + } + } + if !foundNameField { + t.Errorf("expected to find field named 'name' with value 'marty'") + } + + fields, err := index.Fields() + if err != nil { + t.Fatal(err) + } + expectedFields := map[string]bool{ + "_all": false, + "name": false, + "desc": false, + } + if len(fields) != len(expectedFields) { + t.Fatalf("expected %d fields got %d", len(expectedFields), len(fields)) + } + for _, f := range fields { + expectedFields[f] = true + } + for ef, efp := range expectedFields { + if !efp { + t.Errorf("field %s is missing", ef) + } + } +} + +func TestIndexCreateNewOverExisting(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + err = index.Close() + if err != nil { + t.Fatal(err) + } + index, err = New("testidx", NewIndexMapping()) + if err != ErrorIndexPathExists { + t.Fatalf("expected error index path exists, got %v", err) + } +} + +func TestIndexOpenNonExisting(t *testing.T) { + _, err := Open("doesnotexist") + if err != ErrorIndexPathDoesNotExist { + t.Fatalf("expected error index path does not exist, got %v", err) + } +} + +func TestIndexOpenMetaMissingOrCorrupt(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + err = index.Close() + if err != nil { + t.Fatal(err) + } + + // now intentionally change the storage type + err = ioutil.WriteFile("testidx/index_meta.json", []byte(`{"storage":"mystery"}`), 0666) + if err != nil { + t.Fatal(err) + } + + index, err = Open("testidx") + if err != ErrorUnknownStorageType { + t.Fatalf("expected error unknown storage type, got %v", err) + } + + // now intentionally corrupt the metadata + err = ioutil.WriteFile("testidx/index_meta.json", []byte("corrupted"), 0666) + if err != nil { + t.Fatal(err) + } + + index, err = Open("testidx") + if err != ErrorIndexMetaCorrupt { + t.Fatalf("expected error index metadata corrupted, got %v", err) + } + + // now intentionally remove the metadata + err = os.Remove("testidx/index_meta.json") + if err != nil { + t.Fatal(err) + } + + index, err = Open("testidx") + if err != ErrorIndexMetaMissing { + t.Fatalf("expected error index metadata missing, got %v", err) + } +} + +func TestInMemIndex(t *testing.T) { + + index, err := New("", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + err = index.Close() + if err != nil { + t.Fatal(err) + } +} + +func TestClosedIndex(t *testing.T) { + index, err := New("", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + err = index.Close() + if err != nil { + t.Fatal(err) + } + + err = index.Index("test", "test") + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } + + err = index.Delete("test") + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } + + b := index.NewBatch() + err = index.Batch(b) + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } + + _, err = index.Document("test") + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } + + _, err = index.DocCount() + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } + + _, err = index.Search(NewSearchRequest(NewTermQuery("test"))) + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } + + _, err = index.Fields() + if err != ErrorIndexClosed { + t.Errorf("expected error index closed, got %v", err) + } +} + +func TestSlowSearch(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + defer func() { + // reset logger back to normal + SetLog(log.New(ioutil.Discard, "bleve", log.LstdFlags)) + }() + // set custom logger + var sdw sawDataWriter + SetLog(log.New(&sdw, "bleve", log.LstdFlags)) + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + defer func() { + err := index.Close() + if err != nil { + t.Fatal(err) + } + }() + + Config.SlowSearchLogThreshold = 1 * time.Minute + + query := NewTermQuery("water") + req := NewSearchRequest(query) + _, err = index.Search(req) + if err != nil { + t.Fatal(err) + } + + if sdw.sawData { + t.Errorf("expected to not see slow query logged, but did") + } + + Config.SlowSearchLogThreshold = 1 * time.Microsecond + _, err = index.Search(req) + if err != nil { + t.Fatal(err) + } + + if !sdw.sawData { + t.Errorf("expected to see slow query logged, but didn't") + } +} + +type sawDataWriter struct { + sawData bool +} + +func (s *sawDataWriter) Write(p []byte) (n int, err error) { + s.sawData = true + return len(p), nil +} + +func TestStoredFieldPreserved(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + defer func() { + err := index.Close() + if err != nil { + t.Fatal(err) + } + }() + + doca := map[string]interface{}{ + "name": "Marty", + "desc": "GopherCON India", + } + err = index.Index("a", doca) + if err != nil { + t.Error(err) + } + + q := NewTermQuery("marty") + req := NewSearchRequest(q) + req.Fields = []string{"name", "desc"} + res, err := index.Search(req) + if err != nil { + t.Error(err) + } + + if len(res.Hits) != 1 { + t.Errorf("expected 1 hit, got %d", len(res.Hits)) + } + + if res.Hits[0].Fields["name"] != "Marty" { + t.Errorf("expected 'Marty' got '%s'", res.Hits[0].Fields["name"]) + } + if res.Hits[0].Fields["desc"] != "GopherCON India" { + t.Errorf("expected 'GopherCON India' got '%s'", res.Hits[0].Fields["desc"]) + } + +} + +func TestDict(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + + doca := map[string]interface{}{ + "name": "marty", + "desc": "gophercon india", + } + err = index.Index("a", doca) + if err != nil { + t.Error(err) + } + + docy := map[string]interface{}{ + "name": "jasper", + "desc": "clojure", + } + err = index.Index("y", docy) + if err != nil { + t.Error(err) + } + + docx := map[string]interface{}{ + "name": "rose", + "desc": "googler", + } + err = index.Index("x", docx) + if err != nil { + t.Error(err) + } + + dict, err := index.FieldDict("name") + if err != nil { + t.Error(err) + } + + terms := []string{} + de, err := dict.Next() + for err == nil && de != nil { + terms = append(terms, string(de.Term)) + de, err = dict.Next() + } + + expectedTerms := []string{"jasper", "marty", "rose"} + if !reflect.DeepEqual(terms, expectedTerms) { + t.Errorf("expected %v, got %v", expectedTerms, terms) + } + + err = dict.Close() + if err != nil { + t.Fatal(err) + } + + // test start and end range + dict, err = index.FieldDictRange("name", []byte("marty"), []byte("rose")) + if err != nil { + t.Error(err) + } + + terms = []string{} + de, err = dict.Next() + for err == nil && de != nil { + terms = append(terms, string(de.Term)) + de, err = dict.Next() + } + + expectedTerms = []string{"marty", "rose"} + if !reflect.DeepEqual(terms, expectedTerms) { + t.Errorf("expected %v, got %v", expectedTerms, terms) + } + + err = dict.Close() + if err != nil { + t.Fatal(err) + } + + docz := map[string]interface{}{ + "name": "prefix", + "desc": "bob cat cats catting dog doggy zoo", + } + err = index.Index("z", docz) + if err != nil { + t.Error(err) + } + + dict, err = index.FieldDictPrefix("desc", []byte("cat")) + if err != nil { + t.Error(err) + } + + terms = []string{} + de, err = dict.Next() + for err == nil && de != nil { + terms = append(terms, string(de.Term)) + de, err = dict.Next() + } + + expectedTerms = []string{"cat", "cats", "catting"} + if !reflect.DeepEqual(terms, expectedTerms) { + t.Errorf("expected %v, got %v", expectedTerms, terms) + } + + stats := index.Stats() + if stats == nil { + t.Errorf("expected IndexStat, got nil") + } + + err = dict.Close() + if err != nil { + t.Fatal(err) + } + + err = index.Close() + if err != nil { + t.Fatal(err) + } +} + +func TestBatchString(t *testing.T) { + defer func() { + err := os.RemoveAll("testidx") + if err != nil { + t.Fatal(err) + } + }() + + index, err := New("testidx", NewIndexMapping()) + if err != nil { + t.Fatal(err) + } + + batch := index.NewBatch() + err = batch.Index("a", []byte("{}")) + if err != nil { + t.Fatal(err) + } + batch.Delete("b") + batch.SetInternal([]byte("c"), []byte{}) + batch.DeleteInternal([]byte("d")) + + batchStr := batch.String() + if !strings.HasPrefix(batchStr, "Batch (2 ops, 2 internal ops)") { + t.Errorf("expected to start with Batch (2 ops, 2 internal ops), did not") + } + if !strings.Contains(batchStr, "INDEX - 'a'") { + t.Errorf("expected to contain INDEX - 'a', did not") + } + if !strings.Contains(batchStr, "DELETE - 'b'") { + t.Errorf("expected to contain DELETE - 'b', did not") + } + if !strings.Contains(batchStr, "SET INTERNAL - 'c'") { + t.Errorf("expected to contain SET INTERNAL - 'c', did not") + } + if !strings.Contains(batchStr, "DELETE INTERNAL - 'd'") { + t.Errorf("expected to contain DELETE INTERNAL - 'd', did not") + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_document.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_document.go new file mode 100644 index 00000000..6769b7fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_document.go @@ -0,0 +1,374 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +// A DocumentMapping describes how a type of document +// should be indexed. +// As documents can be hierarchical, named sub-sections +// of documents are mapped using the same structure in +// the Properties field. +// Each value inside a document can be indexed 0 or more +// ways. These index entries are called fields and +// are stored in the Fields field. +// Entire sections of a document can be ignored or +// excluded by setting Enabled to false. +// If not explicitly mapped, default mapping operations +// are used. To disable this automatic handling, set +// Dynamic to false. +type DocumentMapping struct { + Enabled bool `json:"enabled"` + Dynamic bool `json:"dynamic"` + Properties map[string]*DocumentMapping `json:"properties,omitempty"` + Fields []*FieldMapping `json:"fields,omitempty"` + DefaultAnalyzer string `json:"default_analyzer"` +} + +func (dm *DocumentMapping) validate(cache *registry.Cache) error { + var err error + if dm.DefaultAnalyzer != "" { + _, err := cache.AnalyzerNamed(dm.DefaultAnalyzer) + if err != nil { + return err + } + } + for _, property := range dm.Properties { + err = property.validate(cache) + if err != nil { + return err + } + } + for _, field := range dm.Fields { + if field.Analyzer != "" { + _, err = cache.AnalyzerNamed(field.Analyzer) + if err != nil { + return err + } + } + if field.DateFormat != "" { + _, err = cache.DateTimeParserNamed(field.DateFormat) + if err != nil { + return err + } + } + switch field.Type { + case "text", "datetime", "number": + default: + return fmt.Errorf("unknown field type: '%s'", field.Type) + } + } + return nil +} + +func (dm *DocumentMapping) analyzerNameForPath(path string) string { + pathElements := decodePath(path) + last := false + current := dm +OUTER: + for i, pathElement := range pathElements { + if i == len(pathElements)-1 { + last = true + } + for name, subDocMapping := range current.Properties { + for _, field := range subDocMapping.Fields { + if field.Name == "" && name == pathElement { + if last { + return field.Analyzer + } + current = subDocMapping + continue OUTER + } else if field.Name == pathElement { + if last { + return field.Analyzer + } + current = subDocMapping + continue OUTER + } + } + } + return "" + } + return "" +} + +func (dm *DocumentMapping) documentMappingForPath(path string) *DocumentMapping { + pathElements := decodePath(path) + current := dm +OUTER: + for _, pathElement := range pathElements { + for name, subDocMapping := range current.Properties { + for _, field := range subDocMapping.Fields { + if field.Name == "" && name == pathElement { + current = subDocMapping + continue OUTER + } else if field.Name == pathElement { + current = subDocMapping + continue OUTER + } + } + } + return nil + } + return current +} + +// NewDocumentMapping returns a new document mapping +// with all the default values. +func NewDocumentMapping() *DocumentMapping { + return &DocumentMapping{ + Enabled: true, + Dynamic: true, + } +} + +// NewDocumentStaticMapping returns a new document +// mapping that will not automatically index parts +// of a document without an explicit mapping. +func NewDocumentStaticMapping() *DocumentMapping { + return &DocumentMapping{ + Enabled: true, + } +} + +// NewDocumentDisabledMapping returns a new document +// mapping that will not perform any indexing. +func NewDocumentDisabledMapping() *DocumentMapping { + return &DocumentMapping{} +} + +// AddSubDocumentMapping adds the provided DocumentMapping as a sub-mapping +// for the specified named subsection. +func (dm *DocumentMapping) AddSubDocumentMapping(property string, sdm *DocumentMapping) { + if dm.Properties == nil { + dm.Properties = make(map[string]*DocumentMapping) + } + dm.Properties[property] = sdm +} + +// AddFieldMappingsAt adds one or more FieldMappings +// at the named sub-document. If the named sub-document +// doesn't yet exist it is created for you. +// This is a convenience function to make most common +// mappings more concise. +// Otherwise, you would: +// subMapping := NewDocumentMapping() +// subMapping.AddFieldMapping(fieldMapping) +// parentMapping.AddSubDocumentMapping(property, subMapping) +func (dm *DocumentMapping) AddFieldMappingsAt(property string, fms ...*FieldMapping) { + if dm.Properties == nil { + dm.Properties = make(map[string]*DocumentMapping) + } + sdm, ok := dm.Properties[property] + if !ok { + sdm = NewDocumentMapping() + } + for _, fm := range fms { + sdm.AddFieldMapping(fm) + } + dm.Properties[property] = sdm +} + +// AddFieldMapping adds the provided FieldMapping for this section +// of the document. +func (dm *DocumentMapping) AddFieldMapping(fm *FieldMapping) { + if dm.Fields == nil { + dm.Fields = make([]*FieldMapping, 0) + } + dm.Fields = append(dm.Fields, fm) +} + +// UnmarshalJSON deserializes a JSON representation +// of the DocumentMapping. +func (dm *DocumentMapping) UnmarshalJSON(data []byte) error { + var tmp struct { + Enabled *bool `json:"enabled"` + Dynamic *bool `json:"dynamic"` + Properties map[string]*DocumentMapping `json:"properties"` + Fields []*FieldMapping `json:"fields"` + DefaultAnalyzer string `json:"default_analyzer"` + } + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + dm.Enabled = true + if tmp.Enabled != nil { + dm.Enabled = *tmp.Enabled + } + + dm.Dynamic = true + if tmp.Dynamic != nil { + dm.Dynamic = *tmp.Dynamic + } + + dm.DefaultAnalyzer = tmp.DefaultAnalyzer + + if tmp.Properties != nil { + dm.Properties = make(map[string]*DocumentMapping, len(tmp.Properties)) + } + for propName, propMapping := range tmp.Properties { + dm.Properties[propName] = propMapping + } + if tmp.Fields != nil { + dm.Fields = make([]*FieldMapping, len(tmp.Fields)) + } + for i, field := range tmp.Fields { + dm.Fields[i] = field + } + return nil +} + +func (dm *DocumentMapping) defaultAnalyzerName(path []string) string { + rv := "" + current := dm + for _, pathElement := range path { + var ok bool + current, ok = current.Properties[pathElement] + if !ok { + break + } + if current.DefaultAnalyzer != "" { + rv = current.DefaultAnalyzer + } + } + return rv +} + +func (dm *DocumentMapping) walkDocument(data interface{}, path []string, indexes []uint64, context *walkContext) { + val := reflect.ValueOf(data) + typ := val.Type() + switch typ.Kind() { + case reflect.Map: + // FIXME can add support for other map keys in the future + if typ.Key().Kind() == reflect.String { + for _, key := range val.MapKeys() { + fieldName := key.String() + fieldVal := val.MapIndex(key).Interface() + dm.processProperty(fieldVal, append(path, fieldName), indexes, context) + } + } + case reflect.Struct: + for i := 0; i < val.NumField(); i++ { + field := typ.Field(i) + fieldName := field.Name + + // if the field has a JSON name, prefer that + jsonTag := field.Tag.Get("json") + jsonFieldName := parseJSONTagName(jsonTag) + if jsonFieldName == "-" { + continue + } + if jsonFieldName != "" { + fieldName = jsonFieldName + } + + if val.Field(i).CanInterface() { + fieldVal := val.Field(i).Interface() + dm.processProperty(fieldVal, append(path, fieldName), indexes, context) + } + } + case reflect.Slice, reflect.Array: + for i := 0; i < val.Len(); i++ { + if val.Index(i).CanInterface() { + fieldVal := val.Index(i).Interface() + dm.processProperty(fieldVal, path, append(indexes, uint64(i)), context) + } + } + case reflect.Ptr: + ptrElem := val.Elem() + if ptrElem.IsValid() && ptrElem.CanInterface() { + dm.processProperty(ptrElem.Interface(), path, indexes, context) + } + } +} + +func (dm *DocumentMapping) processProperty(property interface{}, path []string, indexes []uint64, context *walkContext) { + pathString := encodePath(path) + // look to see if there is a mapping for this field + subDocMapping := dm.documentMappingForPath(pathString) + + // check to see if we even need to do further processing + if subDocMapping != nil && !subDocMapping.Enabled { + return + } + + propertyValue := reflect.ValueOf(property) + if !propertyValue.IsValid() { + // cannot do anything with the zero value + return + } + propertyType := propertyValue.Type() + switch propertyType.Kind() { + case reflect.String: + propertyValueString := propertyValue.String() + if subDocMapping != nil { + // index by explicit mapping + for _, fieldMapping := range subDocMapping.Fields { + fieldMapping.processString(propertyValueString, pathString, path, indexes, context) + } + } else { + // automatic indexing behavior + + // first see if it can be parsed by the default date parser + dateTimeParser := context.im.dateTimeParserNamed(context.im.DefaultDateTimeParser) + if dateTimeParser != nil { + parsedDateTime, err := dateTimeParser.ParseDateTime(propertyValueString) + if err != nil { + // index as text + fieldMapping := NewTextFieldMapping() + fieldMapping.processString(propertyValueString, pathString, path, indexes, context) + } else { + // index as datetime + fieldMapping := NewDateTimeFieldMapping() + fieldMapping.processTime(parsedDateTime, pathString, path, indexes, context) + } + } + } + case reflect.Float64: + propertyValFloat := propertyValue.Float() + if subDocMapping != nil { + // index by explicit mapping + for _, fieldMapping := range subDocMapping.Fields { + fieldMapping.processFloat64(propertyValFloat, pathString, path, indexes, context) + } + } else { + // automatic indexing behavior + fieldMapping := NewNumericFieldMapping() + fieldMapping.processFloat64(propertyValFloat, pathString, path, indexes, context) + } + case reflect.Struct: + switch property := property.(type) { + case time.Time: + // don't descend into the time struct + if subDocMapping != nil { + // index by explicit mapping + for _, fieldMapping := range subDocMapping.Fields { + fieldMapping.processTime(property, pathString, path, indexes, context) + } + } else { + fieldMapping := NewDateTimeFieldMapping() + fieldMapping.processTime(property, pathString, path, indexes, context) + } + default: + dm.walkDocument(property, path, indexes, context) + } + default: + dm.walkDocument(property, path, indexes, context) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_field.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_field.go new file mode 100644 index 00000000..4dcfd1a9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_field.go @@ -0,0 +1,155 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" +) + +// A FieldMapping describes how a specific item +// should be put into the index. +type FieldMapping struct { + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + Analyzer string `json:"analyzer,omitempty"` + Store bool `json:"store,omitempty"` + Index bool `json:"index,omitempty"` + IncludeTermVectors bool `json:"include_term_vectors,omitempty"` + IncludeInAll bool `json:"include_in_all,omitempty"` + DateFormat string `json:"date_format,omitempty"` +} + +// NewTextFieldMapping returns a default field mapping for text +func NewTextFieldMapping() *FieldMapping { + return &FieldMapping{ + Type: "text", + Store: true, + Index: true, + IncludeTermVectors: true, + IncludeInAll: true, + } +} + +// NewNumericFieldMapping returns a default field mapping for numbers +func NewNumericFieldMapping() *FieldMapping { + return &FieldMapping{ + Type: "number", + Store: true, + Index: true, + IncludeInAll: true, + } +} + +// NewDateTimeFieldMapping returns a default field mapping for dates +func NewDateTimeFieldMapping() *FieldMapping { + return &FieldMapping{ + Type: "datetime", + Store: true, + Index: true, + IncludeInAll: true, + } +} + +// Options returns the indexing options for this field. +func (fm *FieldMapping) Options() document.IndexingOptions { + var rv document.IndexingOptions + if fm.Store { + rv |= document.StoreField + } + if fm.Index { + rv |= document.IndexField + } + if fm.IncludeTermVectors { + rv |= document.IncludeTermVectors + } + return rv +} + +func (fm *FieldMapping) processString(propertyValueString string, pathString string, path []string, indexes []uint64, context *walkContext) { + fieldName := getFieldName(pathString, path, fm) + options := fm.Options() + if fm.Type == "text" { + analyzer := fm.analyzerForField(path, context) + field := document.NewTextFieldCustom(fieldName, indexes, []byte(propertyValueString), options, analyzer) + context.doc.AddField(field) + + if !fm.IncludeInAll { + context.excludedFromAll = append(context.excludedFromAll, fieldName) + } + } else if fm.Type == "datetime" { + dateTimeFormat := context.im.DefaultDateTimeParser + if fm.DateFormat != "" { + dateTimeFormat = fm.DateFormat + } + dateTimeParser := context.im.dateTimeParserNamed(dateTimeFormat) + if dateTimeParser != nil { + parsedDateTime, err := dateTimeParser.ParseDateTime(propertyValueString) + if err != nil { + fm.processTime(parsedDateTime, pathString, path, indexes, context) + } + } + } +} + +func (fm *FieldMapping) processFloat64(propertyValFloat float64, pathString string, path []string, indexes []uint64, context *walkContext) { + fieldName := getFieldName(pathString, path, fm) + if fm.Type == "number" { + options := fm.Options() + field := document.NewNumericFieldWithIndexingOptions(fieldName, indexes, propertyValFloat, options) + context.doc.AddField(field) + + if !fm.IncludeInAll { + context.excludedFromAll = append(context.excludedFromAll, fieldName) + } + } +} + +func (fm *FieldMapping) processTime(propertyValueTime time.Time, pathString string, path []string, indexes []uint64, context *walkContext) { + fieldName := getFieldName(pathString, path, fm) + if fm.Type == "datetime" { + options := fm.Options() + field, err := document.NewDateTimeFieldWithIndexingOptions(fieldName, indexes, propertyValueTime, options) + if err == nil { + context.doc.AddField(field) + } else { + logger.Printf("could not build date %v", err) + } + + if !fm.IncludeInAll { + context.excludedFromAll = append(context.excludedFromAll, fieldName) + } + } +} + +func (fm *FieldMapping) analyzerForField(path []string, context *walkContext) *analysis.Analyzer { + analyzerName := context.dm.defaultAnalyzerName(path) + if analyzerName == "" { + analyzerName = context.im.DefaultAnalyzer + } + if fm.Analyzer != "" { + analyzerName = fm.Analyzer + } + return context.im.analyzerNamed(analyzerName) +} + +func getFieldName(pathString string, path []string, fieldMapping *FieldMapping) string { + fieldName := pathString + if fieldMapping.Name != "" { + parentName := "" + if len(path) > 1 { + parentName = encodePath(path[:len(path)-1]) + pathSeparator + } + fieldName = parentName + fieldMapping.Name + } + return fieldName +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_index.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_index.go new file mode 100644 index 00000000..e5ee4757 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_index.go @@ -0,0 +1,455 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +const defaultTypeField = "_type" +const defaultType = "_default" +const defaultField = "_all" +const defaultAnalyzer = "standard" +const defaultDateTimeParser = "dateTimeOptional" +const defaultByteArrayConverter = "json" + +type customAnalysis struct { + CharFilters map[string]map[string]interface{} `json:"char_filters,omitempty"` + Tokenizers map[string]map[string]interface{} `json:"tokenizers,omitempty"` + TokenMaps map[string]map[string]interface{} `json:"token_maps,omitempty"` + TokenFilters map[string]map[string]interface{} `json:"token_filters,omitempty"` + Analyzers map[string]map[string]interface{} `json:"analyzers,omitempty"` + DateTimeParsers map[string]map[string]interface{} `json:"date_time_parsers,omitempty"` +} + +func (c *customAnalysis) registerAll(i *IndexMapping) error { + for name, config := range c.CharFilters { + _, err := i.cache.DefineCharFilter(name, config) + if err != nil { + return err + } + } + for name, config := range c.Tokenizers { + _, err := i.cache.DefineTokenizer(name, config) + if err != nil { + return err + } + } + for name, config := range c.TokenMaps { + _, err := i.cache.DefineTokenMap(name, config) + if err != nil { + return err + } + } + for name, config := range c.TokenFilters { + _, err := i.cache.DefineTokenFilter(name, config) + if err != nil { + return err + } + } + for name, config := range c.Analyzers { + _, err := i.cache.DefineAnalyzer(name, config) + if err != nil { + return err + } + } + for name, config := range c.DateTimeParsers { + _, err := i.cache.DefineDateTimeParser(name, config) + if err != nil { + return err + } + } + return nil +} + +func newCustomAnalysis() *customAnalysis { + rv := customAnalysis{ + CharFilters: make(map[string]map[string]interface{}), + Tokenizers: make(map[string]map[string]interface{}), + TokenMaps: make(map[string]map[string]interface{}), + TokenFilters: make(map[string]map[string]interface{}), + Analyzers: make(map[string]map[string]interface{}), + DateTimeParsers: make(map[string]map[string]interface{}), + } + return &rv +} + +// An IndexMapping controls how objects are placed +// into an index. +// First the type of the object is determined. +// Once the type is know, the appropriate +// DocumentMapping is selected by the type. +// If no mapping was determined for that type, +// a DefaultMapping will be used. +type IndexMapping struct { + TypeMapping map[string]*DocumentMapping `json:"types,omitempty"` + DefaultMapping *DocumentMapping `json:"default_mapping"` + TypeField string `json:"type_field"` + DefaultType string `json:"default_type"` + DefaultAnalyzer string `json:"default_analyzer"` + DefaultDateTimeParser string `json:"default_datetime_parser"` + DefaultField string `json:"default_field"` + ByteArrayConverter string `json:"byte_array_converter"` + CustomAnalysis *customAnalysis `json:"analysis,omitempty"` + cache *registry.Cache +} + +// AddCustomCharFilter defines a custom char filter for use in this mapping +func (im *IndexMapping) AddCustomCharFilter(name string, config map[string]interface{}) error { + _, err := im.cache.DefineCharFilter(name, config) + if err != nil { + return err + } + im.CustomAnalysis.CharFilters[name] = config + return nil +} + +// AddCustomTokenizer defines a custom tokenizer for use in this mapping +func (im *IndexMapping) AddCustomTokenizer(name string, config map[string]interface{}) error { + _, err := im.cache.DefineTokenizer(name, config) + if err != nil { + return err + } + im.CustomAnalysis.Tokenizers[name] = config + return nil +} + +// AddCustomTokenMap defines a custom token map for use in this mapping +func (im *IndexMapping) AddCustomTokenMap(name string, config map[string]interface{}) error { + _, err := im.cache.DefineTokenMap(name, config) + if err != nil { + return err + } + im.CustomAnalysis.TokenMaps[name] = config + return nil +} + +// AddCustomTokenFilter defines a custom token filter for use in this mapping +func (im *IndexMapping) AddCustomTokenFilter(name string, config map[string]interface{}) error { + _, err := im.cache.DefineTokenFilter(name, config) + if err != nil { + return err + } + im.CustomAnalysis.TokenFilters[name] = config + return nil +} + +// AddCustomAnalyzer defines a custom analyzer for use in this mapping +func (im *IndexMapping) AddCustomAnalyzer(name string, config map[string]interface{}) error { + _, err := im.cache.DefineAnalyzer(name, config) + if err != nil { + return err + } + im.CustomAnalysis.Analyzers[name] = config + return nil +} + +// AddCustomDateTimeParser defines a custom date time parser for use in this mapping +func (im *IndexMapping) AddCustomDateTimeParser(name string, config map[string]interface{}) error { + _, err := im.cache.DefineDateTimeParser(name, config) + if err != nil { + return err + } + im.CustomAnalysis.DateTimeParsers[name] = config + return nil +} + +// NewIndexMapping creates a new IndexMapping that will use all the default indexing rules +func NewIndexMapping() *IndexMapping { + return &IndexMapping{ + TypeMapping: make(map[string]*DocumentMapping), + DefaultMapping: NewDocumentMapping(), + TypeField: defaultTypeField, + DefaultType: defaultType, + DefaultAnalyzer: defaultAnalyzer, + DefaultDateTimeParser: defaultDateTimeParser, + DefaultField: defaultField, + ByteArrayConverter: defaultByteArrayConverter, + CustomAnalysis: newCustomAnalysis(), + cache: registry.NewCache(), + } +} + +// Validate will walk the entire structure ensuring the following +// explicitly named and default analyzers can be built +func (im *IndexMapping) validate() error { + _, err := im.cache.AnalyzerNamed(im.DefaultAnalyzer) + if err != nil { + return err + } + _, err = im.cache.DateTimeParserNamed(im.DefaultDateTimeParser) + if err != nil { + return err + } + err = im.DefaultMapping.validate(im.cache) + if err != nil { + return err + } + for _, docMapping := range im.TypeMapping { + err = docMapping.validate(im.cache) + if err != nil { + return err + } + } + return nil +} + +// AddDocumentMapping sets a custom document mapping for the specified type +func (im *IndexMapping) AddDocumentMapping(doctype string, dm *DocumentMapping) { + im.TypeMapping[doctype] = dm +} + +func (im *IndexMapping) mappingForType(docType string) *DocumentMapping { + docMapping := im.TypeMapping[docType] + if docMapping == nil { + docMapping = im.DefaultMapping + } + return docMapping +} + +// UnmarshalJSON deserializes a JSON representation of the IndexMapping +func (im *IndexMapping) UnmarshalJSON(data []byte) error { + var tmp struct { + TypeMapping map[string]*DocumentMapping `json:"types"` + DefaultMapping *DocumentMapping `json:"default_mapping"` + TypeField string `json:"type_field"` + DefaultType string `json:"default_type"` + DefaultAnalyzer string `json:"default_analyzer"` + DefaultDateTimeParser string `json:"default_datetime_parser"` + DefaultField string `json:"default_field"` + ByteArrayConverter string `json:"byte_array_converter"` + CustomAnalysis *customAnalysis `json:"analysis"` + } + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + im.cache = registry.NewCache() + + im.CustomAnalysis = newCustomAnalysis() + if tmp.CustomAnalysis != nil { + if tmp.CustomAnalysis.CharFilters != nil { + im.CustomAnalysis.CharFilters = tmp.CustomAnalysis.CharFilters + } + if tmp.CustomAnalysis.Tokenizers != nil { + im.CustomAnalysis.Tokenizers = tmp.CustomAnalysis.Tokenizers + } + if tmp.CustomAnalysis.TokenMaps != nil { + im.CustomAnalysis.TokenMaps = tmp.CustomAnalysis.TokenMaps + } + if tmp.CustomAnalysis.TokenFilters != nil { + im.CustomAnalysis.TokenFilters = tmp.CustomAnalysis.TokenFilters + } + if tmp.CustomAnalysis.Analyzers != nil { + im.CustomAnalysis.Analyzers = tmp.CustomAnalysis.Analyzers + } + if tmp.CustomAnalysis.DateTimeParsers != nil { + im.CustomAnalysis.DateTimeParsers = tmp.CustomAnalysis.DateTimeParsers + } + } + + im.TypeField = defaultTypeField + if tmp.TypeField != "" { + im.TypeField = tmp.TypeField + } + + im.DefaultType = defaultType + if tmp.DefaultType != "" { + im.DefaultType = tmp.DefaultType + } + + im.DefaultAnalyzer = defaultAnalyzer + if tmp.DefaultAnalyzer != "" { + im.DefaultAnalyzer = tmp.DefaultAnalyzer + } + + im.DefaultDateTimeParser = defaultDateTimeParser + if tmp.DefaultDateTimeParser != "" { + im.DefaultDateTimeParser = tmp.DefaultDateTimeParser + } + + im.DefaultField = defaultField + if tmp.DefaultField != "" { + im.DefaultField = tmp.DefaultField + } + + im.ByteArrayConverter = defaultByteArrayConverter + if tmp.ByteArrayConverter != "" { + im.ByteArrayConverter = tmp.ByteArrayConverter + } + + im.DefaultMapping = NewDocumentMapping() + if tmp.DefaultMapping != nil { + im.DefaultMapping = tmp.DefaultMapping + } + + im.TypeMapping = make(map[string]*DocumentMapping, len(tmp.TypeMapping)) + for typeName, typeDocMapping := range tmp.TypeMapping { + im.TypeMapping[typeName] = typeDocMapping + } + + err = im.CustomAnalysis.registerAll(im) + if err != nil { + return err + } + + return nil +} + +func (im *IndexMapping) determineType(data interface{}) string { + // first see if the object implements Identifier + classifier, ok := data.(Classifier) + if ok { + return classifier.Type() + } + + // now see if we can find a type using the mapping + typ, ok := mustString(lookupPropertyPath(data, im.TypeField)) + if ok { + return typ + } + + return im.DefaultType +} + +func (im *IndexMapping) mapDocument(doc *document.Document, data interface{}) error { + // see if the top level object is a byte array, and possibly run through a converter + byteArrayData, ok := data.([]byte) + if ok { + byteArrayConverterConstructor := registry.ByteArrayConverterByName(im.ByteArrayConverter) + if byteArrayConverterConstructor != nil { + byteArrayConverter, err := byteArrayConverterConstructor(nil, nil) + if err == nil { + convertedData, err := byteArrayConverter.Convert(byteArrayData) + if err != nil { + return err + } + data = convertedData + } else { + logger.Printf("error creating byte array converter: %v", err) + } + } else { + logger.Printf("no byte array converter named: %s", im.ByteArrayConverter) + } + } + + docType := im.determineType(data) + docMapping := im.mappingForType(docType) + walkContext := im.newWalkContext(doc, docMapping) + docMapping.walkDocument(data, []string{}, []uint64{}, walkContext) + + // see if the _all field was disabled + allMapping := docMapping.documentMappingForPath("_all") + if allMapping == nil || (allMapping.Enabled != false) { + field := document.NewCompositeFieldWithIndexingOptions("_all", true, []string{}, walkContext.excludedFromAll, document.IndexField|document.IncludeTermVectors) + doc.AddField(field) + } + + return nil +} + +type walkContext struct { + doc *document.Document + im *IndexMapping + dm *DocumentMapping + excludedFromAll []string +} + +func (im *IndexMapping) newWalkContext(doc *document.Document, dm *DocumentMapping) *walkContext { + return &walkContext{ + doc: doc, + im: im, + dm: dm, + excludedFromAll: []string{}, + } +} + +// attempts to find the best analyzer to use with only a field name +// will walk all the document types, look for field mappings at the +// provided path, if one exists and it has an explicit analyzer +// that is returned +// nil should be an acceptable return value meaning we don't know +func (im *IndexMapping) analyzerNameForPath(path string) string { + // first we look for explicit mapping on the field + for _, docMapping := range im.TypeMapping { + analyzerName := docMapping.analyzerNameForPath(path) + if analyzerName != "" { + return analyzerName + } + } + // now try the default mapping + pathMapping := im.DefaultMapping.documentMappingForPath(path) + if pathMapping != nil { + if len(pathMapping.Fields) > 0 { + if pathMapping.Fields[0].Analyzer != "" { + return pathMapping.Fields[0].Analyzer + } + } + } + + // next we will try default analyzers for the path + pathDecoded := decodePath(path) + for _, docMapping := range im.TypeMapping { + rv := docMapping.defaultAnalyzerName(pathDecoded) + if rv != "" { + return rv + } + } + + return im.DefaultAnalyzer +} + +func (im *IndexMapping) analyzerNamed(name string) *analysis.Analyzer { + analyzer, err := im.cache.AnalyzerNamed(name) + if err != nil { + logger.Printf("error using analyzer named: %s", name) + return nil + } + return analyzer +} + +func (im *IndexMapping) dateTimeParserNamed(name string) analysis.DateTimeParser { + dateTimeParser, err := im.cache.DateTimeParserNamed(name) + if err != nil { + logger.Printf("error using datetime parser named: %s", name) + return nil + } + return dateTimeParser +} + +func (im *IndexMapping) datetimeParserNameForPath(path string) string { + + // first we look for explicit mapping on the field + for _, docMapping := range im.TypeMapping { + pathMapping := docMapping.documentMappingForPath(path) + if pathMapping != nil { + if len(pathMapping.Fields) > 0 { + if pathMapping.Fields[0].Analyzer != "" { + return pathMapping.Fields[0].Analyzer + } + } + } + } + + return im.DefaultDateTimeParser +} + +func (im *IndexMapping) AnalyzeText(analyzerName string, text []byte) (analysis.TokenStream, error) { + analyzer, err := im.cache.AnalyzerNamed(analyzerName) + if err != nil { + return nil, err + } + return analyzer.Analyze(text), nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_test.go new file mode 100644 index 00000000..6a43305d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/mapping_test.go @@ -0,0 +1,246 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "reflect" + "testing" +) + +var mappingSource = []byte(`{ + "types": { + "beer": { + "properties": { + "name": { + "fields": [ + { + "name": "name", + "type": "text", + "analyzer": "standard", + "store": true, + "index": true, + "include_term_vectors": true, + "include_in_all": true + } + ] + } + } + }, + "brewery": { + } + }, + "type_field": "_type", + "default_type": "_default" +}`) + +func buildMapping() *IndexMapping { + nameFieldMapping := NewTextFieldMapping() + nameFieldMapping.Name = "name" + nameFieldMapping.Analyzer = "standard" + + beerMapping := NewDocumentMapping() + beerMapping.AddFieldMappingsAt("name", nameFieldMapping) + + breweryMapping := NewDocumentMapping() + + mapping := NewIndexMapping() + mapping.AddDocumentMapping("beer", beerMapping) + mapping.AddDocumentMapping("brewery", breweryMapping) + + return mapping +} + +func TestUnmarshalMappingJSON(t *testing.T) { + mapping := buildMapping() + + var indexMapping IndexMapping + err := json.Unmarshal(mappingSource, &indexMapping) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(&indexMapping, mapping) { + t.Errorf("expected %#v,\n got %#v", mapping, &indexMapping) + } +} + +func TestMappingStructWithJSONTags(t *testing.T) { + + mapping := buildMapping() + + x := struct { + NoJSONTag string + Name string `json:"name"` + }{ + Name: "marty", + } + + doc := document.NewDocument("1") + err := mapping.mapDocument(doc, x) + if err != nil { + t.Fatal(err) + } + foundJSONName := false + foundNoJSONName := false + count := 0 + for _, f := range doc.Fields { + if f.Name() == "name" { + foundJSONName = true + } + if f.Name() == "NoJSONTag" { + foundNoJSONName = true + } + count++ + } + if !foundJSONName { + t.Errorf("expected to find field named 'name'") + } + if !foundNoJSONName { + t.Errorf("expected to find field named 'NoJSONTag'") + } + if count != 2 { + t.Errorf("expected to find 2 find, found %d", count) + } +} + +func TestMappingStructWithJSONTagsOneDisabled(t *testing.T) { + + mapping := buildMapping() + + x := struct { + Name string `json:"name"` + Title string `json:"-"` + NoJSONTag string + }{ + Name: "marty", + } + + doc := document.NewDocument("1") + err := mapping.mapDocument(doc, x) + if err != nil { + t.Fatal(err) + } + foundJSONName := false + foundNoJSONName := false + count := 0 + for _, f := range doc.Fields { + if f.Name() == "name" { + foundJSONName = true + } + if f.Name() == "NoJSONTag" { + foundNoJSONName = true + } + count++ + } + if !foundJSONName { + t.Errorf("expected to find field named 'name'") + } + if !foundNoJSONName { + t.Errorf("expected to find field named 'NoJSONTag'") + } + if count != 2 { + t.Errorf("expected to find 2 find, found %d", count) + } +} + +func TestMappingStructWithPointerToString(t *testing.T) { + + mapping := buildMapping() + + name := "marty" + + x := struct { + Name *string + }{ + Name: &name, + } + + doc := document.NewDocument("1") + err := mapping.mapDocument(doc, x) + if err != nil { + t.Fatal(err) + } + found := false + count := 0 + for _, f := range doc.Fields { + if f.Name() == "Name" { + found = true + } + count++ + } + if !found { + t.Errorf("expected to find field named 'Name'") + } + if count != 1 { + t.Errorf("expected to find 1 find, found %d", count) + } +} + +func TestMappingJSONWithNull(t *testing.T) { + + mapping := NewIndexMapping() + + jsonbytes := []byte(`{"name":"marty", "age": null}`) + var jsondoc interface{} + err := json.Unmarshal(jsonbytes, &jsondoc) + if err != nil { + t.Fatal(err) + } + + doc := document.NewDocument("1") + err = mapping.mapDocument(doc, jsondoc) + if err != nil { + t.Fatal(err) + } + found := false + count := 0 + for _, f := range doc.Fields { + if f.Name() == "name" { + found = true + } + count++ + } + if !found { + t.Errorf("expected to find field named 'name'") + } + if count != 1 { + t.Errorf("expected to find 1 find, found %d", count) + } +} + +func TestMappingForPath(t *testing.T) { + + enFieldMapping := NewTextFieldMapping() + enFieldMapping.Analyzer = "en" + + docMappingA := NewDocumentMapping() + docMappingA.AddFieldMappingsAt("name", enFieldMapping) + + customMapping := NewTextFieldMapping() + customMapping.Analyzer = "xyz" + customMapping.Name = "nameCustom" + + docMappingA.AddFieldMappingsAt("author", enFieldMapping, customMapping) + + mapping := NewIndexMapping() + mapping.AddDocumentMapping("a", docMappingA) + + analyzerName := mapping.analyzerNameForPath("name") + if analyzerName != enFieldMapping.Analyzer { + t.Errorf("expected '%s' got '%s'", enFieldMapping.Analyzer, analyzerName) + } + + analyzerName = mapping.analyzerNameForPath("nameCustom") + if analyzerName != customMapping.Analyzer { + t.Errorf("expected '%s' got '%s'", customMapping.Analyzer, analyzerName) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float.go new file mode 100644 index 00000000..a33ea1af --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float.go @@ -0,0 +1,29 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package numeric_util + +import ( + "math" +) + +func Float64ToInt64(f float64) int64 { + fasint := int64(math.Float64bits(f)) + if fasint < 0 { + fasint = fasint ^ 0x7fffffffffffffff + } + return fasint +} + +func Int64ToFloat64(i int64) float64 { + if i < 0 { + i ^= 0x7fffffffffffffff + } + return math.Float64frombits(uint64(i)) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float_test.go new file mode 100644 index 00000000..dc7bf496 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/float_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package numeric_util + +import ( + "testing" +) + +// test that the float/sortable int operations work both ways +// and that the corresponding integers sort the same as +// the original floats would have +func TestSortabledFloat64ToInt64(t *testing.T) { + tests := []struct { + input float64 + }{ + { + input: -4640094584139352638, + }, + { + input: -167.42, + }, + { + input: -1.11, + }, + { + input: 0, + }, + { + input: 3.14, + }, + { + input: 167.42, + }, + } + + var lastInt64 *int64 + for _, test := range tests { + actual := Float64ToInt64(test.input) + if lastInt64 != nil { + // check that this float is greater than the last one + if actual <= *lastInt64 { + t.Errorf("expected greater than prev, this: %d, last %d", actual, *lastInt64) + } + } + lastInt64 = &actual + convertedBack := Int64ToFloat64(actual) + // assert that we got back what we started with + if convertedBack != test.input { + t.Errorf("expected %f, got %f", test.input, convertedBack) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded.go new file mode 100644 index 00000000..263a1cf4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded.go @@ -0,0 +1,74 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package numeric_util + +import ( + "fmt" +) + +const ShiftStartInt64 byte = 0x20 + +// PrefixCoded is a byte array encoding of +// 64-bit numeric values shifted by 0-63 bits +type PrefixCoded []byte + +func NewPrefixCodedInt64(in int64, shift uint) (PrefixCoded, error) { + if shift > 63 { + return nil, fmt.Errorf("cannot shift %d, must be between 0 and 63", shift) + } + + nChars := (((63 - shift) * 37) >> 8) + 1 + rv := make(PrefixCoded, nChars+1) + rv[0] = ShiftStartInt64 + byte(shift) + + sortableBits := int64(uint64(in) ^ 0x8000000000000000) + sortableBits = int64(uint64(sortableBits) >> shift) + for nChars > 0 { + // Store 7 bits per byte for compatibility + // with UTF-8 encoding of terms + rv[nChars] = byte(sortableBits & 0x7f) + nChars-- + sortableBits = int64(uint64(sortableBits) >> 7) + } + return rv, nil +} + +func MustNewPrefixCodedInt64(in int64, shift uint) PrefixCoded { + rv, err := NewPrefixCodedInt64(in, shift) + if err != nil { + panic(err) + } + return rv +} + +// Shift returns the number of bits shifted +// returns 0 if in uninitialized state +func (p PrefixCoded) Shift() (uint, error) { + if len(p) > 0 { + shift := p[0] - ShiftStartInt64 + if shift < 0 || shift < 63 { + return uint(shift), nil + } + } + return 0, fmt.Errorf("invalid prefix coded value") +} + +func (p PrefixCoded) Int64() (int64, error) { + shift, err := p.Shift() + if err != nil { + return 0, err + } + var sortableBits int64 + for _, inbyte := range p[1:] { + sortableBits <<= 7 + sortableBits |= int64(inbyte) + } + return int64(uint64((sortableBits << shift)) ^ 0x8000000000000000), nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded_test.go new file mode 100644 index 00000000..59110f45 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util/prefix_coded_test.go @@ -0,0 +1,98 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package numeric_util + +import ( + "reflect" + "testing" +) + +// these array encoding values have been verified manually +// against the lucene implementation +func TestPrefixCoded(t *testing.T) { + tests := []struct { + input int64 + shift uint + output PrefixCoded + }{ + { + input: 1, + shift: 0, + output: PrefixCoded{0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, + }, + { + input: -1, + shift: 0, + output: PrefixCoded{0x20, 0x0, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}, + }, + { + input: -94582, + shift: 0, + output: PrefixCoded{0x20, 0x0, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7a, 0x1d, 0xa}, + }, + { + input: 314729851, + shift: 0, + output: PrefixCoded{0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x16, 0x9, 0x4a, 0x7b}, + }, + { + input: 314729851, + shift: 4, + output: PrefixCoded{0x24, 0x8, 0x0, 0x0, 0x0, 0x0, 0x9, 0x30, 0x4c, 0x57}, + }, + { + input: 314729851, + shift: 8, + output: PrefixCoded{0x28, 0x40, 0x0, 0x0, 0x0, 0x0, 0x4b, 0x4, 0x65}, + }, + { + input: 314729851, + shift: 16, + output: PrefixCoded{0x30, 0x20, 0x0, 0x0, 0x0, 0x0, 0x25, 0x42}, + }, + { + input: 314729851, + shift: 32, + output: PrefixCoded{0x40, 0x8, 0x0, 0x0, 0x0, 0x0}, + }, + { + input: 1234729851, + shift: 32, + output: PrefixCoded{0x40, 0x8, 0x0, 0x0, 0x0, 0x0}, + }, + } + + for _, test := range tests { + actual, err := NewPrefixCodedInt64(test.input, test.shift) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(actual, test.output) { + t.Errorf("expected %#v, got %#v", test.output, actual) + } + checkedShift, err := actual.Shift() + if err != nil { + t.Error(err) + } + if checkedShift != test.shift { + t.Errorf("expected %d, got %d", test.shift, checkedShift) + } + // if the shift was 0, make sure we can go back to the original + if test.shift == 0 { + backToLong, err := actual.Int64() + if err != nil { + t.Error(err) + } + if backToLong != test.input { + t.Errorf("expected %v, got %v", test.input, backToLong) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query.go new file mode 100644 index 00000000..3d151ff6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query.go @@ -0,0 +1,211 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +// A Query represents a description of the type +// and parameters for a query into the index. +type Query interface { + Boost() float64 + SetBoost(b float64) Query + Field() string + SetField(f string) Query + Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) + Validate() error +} + +// ParseQuery deserializes a JSON representation of +// a Query object. +func ParseQuery(input []byte) (Query, error) { + var tmp map[string]interface{} + err := json.Unmarshal(input, &tmp) + if err != nil { + return nil, err + } + _, isMatchQuery := tmp["match"] + _, hasFuzziness := tmp["fuzziness"] + if hasFuzziness && !isMatchQuery { + var rv fuzzyQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, isTermQuery := tmp["term"] + if isTermQuery { + var rv termQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + if isMatchQuery { + var rv matchQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, isMatchPhraseQuery := tmp["match_phrase"] + if isMatchPhraseQuery { + var rv matchPhraseQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasMust := tmp["must"] + _, hasShould := tmp["should"] + _, hasMustNot := tmp["must_not"] + if hasMust || hasShould || hasMustNot { + var rv booleanQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasTerms := tmp["terms"] + if hasTerms { + var rv phraseQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + for _, tq := range rv.TermQueries { + if tq.Boost() == 0 { + tq.SetBoost(1) + } + } + return &rv, nil + } + _, hasConjuncts := tmp["conjuncts"] + if hasConjuncts { + var rv conjunctionQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasDisjuncts := tmp["disjuncts"] + if hasDisjuncts { + var rv disjunctionQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + + _, hasSyntaxQuery := tmp["query"] + if hasSyntaxQuery { + var rv queryStringQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasMin := tmp["min"] + _, hasMax := tmp["max"] + if hasMin || hasMax { + var rv numericRangeQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasStart := tmp["start"] + _, hasEnd := tmp["end"] + if hasStart || hasEnd { + var rv dateRangeQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasPrefix := tmp["prefix"] + if hasPrefix { + var rv prefixQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + if rv.Boost() == 0 { + rv.SetBoost(1) + } + return &rv, nil + } + _, hasRegexp := tmp["regexp"] + if hasRegexp { + var rv regexpQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + return &rv, nil + } + _, hasWildcard := tmp["wildcard"] + if hasWildcard { + var rv wildcardQuery + err := json.Unmarshal(input, &rv) + if err != nil { + return nil, err + } + return &rv, nil + } + return nil, ErrorUnknownQueryType +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_boolean.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_boolean.go new file mode 100644 index 00000000..d156d2ec --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_boolean.go @@ -0,0 +1,210 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type booleanQuery struct { + Must Query `json:"must,omitempty"` + Should Query `json:"should,omitempty"` + MustNot Query `json:"must_not,omitempty"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewBooleanQuery creates a compound Query composed +// of several other Query objects. +// Result documents must satisfy ALL of the +// must Queries. +// Result documents must satisfy NONE of the must not +// Queries. +// If there are any should queries, result documents +// must satisfy at least one of them. +func NewBooleanQuery(must []Query, should []Query, mustNot []Query) *booleanQuery { + min := 0.0 + if len(should) > 0 { + min = 1.0 + } + return NewBooleanQueryMinShould(must, should, mustNot, min) +} + +// NewBooleanQueryMinShould is the same as +// NewBooleanQuery, only it offers control of the +// minimum number of should queries that must be +// satisfied. +func NewBooleanQueryMinShould(must []Query, should []Query, mustNot []Query, minShould float64) *booleanQuery { + + rv := booleanQuery{ + BoostVal: 1.0, + } + if len(must) > 0 { + rv.Must = NewConjunctionQuery(must) + } + if len(should) > 0 { + rv.Should = NewDisjunctionQueryMin(should, minShould) + } + if len(mustNot) > 0 { + rv.MustNot = NewDisjunctionQuery(mustNot) + } + + return &rv +} + +func (q *booleanQuery) AddMust(m Query) { + if q.Must == nil { + q.Must = NewConjunctionQuery([]Query{}) + } + q.Must.(*conjunctionQuery).AddQuery(m) +} + +func (q *booleanQuery) AddShould(m Query) { + if q.Should == nil { + q.Should = NewDisjunctionQuery([]Query{}) + } + q.Should.(*disjunctionQuery).AddQuery(m) + q.Should.(*disjunctionQuery).SetMin(1) +} + +func (q *booleanQuery) AddMustNot(m Query) { + if q.MustNot == nil { + q.MustNot = NewDisjunctionQuery([]Query{}) + } + q.MustNot.(*disjunctionQuery).AddQuery(m) +} + +func (q *booleanQuery) Boost() float64 { + return q.BoostVal +} + +func (q *booleanQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *booleanQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + var err error + + var mustSearcher search.Searcher + if q.Must != nil { + mustSearcher, err = q.Must.Searcher(i, m, explain) + if err != nil { + return nil, err + } + } + + var shouldSearcher search.Searcher + if q.Should != nil { + shouldSearcher, err = q.Should.Searcher(i, m, explain) + if err != nil { + return nil, err + } + } + + var mustNotSearcher search.Searcher + if q.MustNot != nil { + mustNotSearcher, err = q.MustNot.Searcher(i, m, explain) + if err != nil { + return nil, err + } + } + + return searchers.NewBooleanSearcher(i, mustSearcher, shouldSearcher, mustNotSearcher, explain) +} + +func (q *booleanQuery) Validate() error { + if q.Must != nil { + err := q.Must.Validate() + if err != nil { + return err + } + } + if q.Should != nil { + err := q.Should.Validate() + if err != nil { + return err + } + } + if q.MustNot != nil { + err := q.MustNot.Validate() + if err != nil { + return err + } + } + if q.Must == nil && q.Should == nil { + return ErrorBooleanQueryNeedsMustOrShould + } + return nil +} + +func (q *booleanQuery) UnmarshalJSON(data []byte) error { + tmp := struct { + Must json.RawMessage `json:"must,omitempty"` + Should json.RawMessage `json:"should,omitempty"` + MustNot json.RawMessage `json:"must_not,omitempty"` + BoostVal float64 `json:"boost,omitempty"` + }{} + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + if tmp.Must != nil { + q.Must, err = ParseQuery(tmp.Must) + if err != nil { + return err + } + _, isConjunctionQuery := q.Must.(*conjunctionQuery) + if !isConjunctionQuery { + return fmt.Errorf("must clause must be conjunction") + } + } + + if tmp.Should != nil { + q.Should, err = ParseQuery(tmp.Should) + if err != nil { + return err + } + _, isDisjunctionQuery := q.Should.(*disjunctionQuery) + if !isDisjunctionQuery { + return fmt.Errorf("should clause must be disjunction") + } + } + + if tmp.MustNot != nil { + q.MustNot, err = ParseQuery(tmp.MustNot) + if err != nil { + return err + } + _, isDisjunctionQuery := q.MustNot.(*disjunctionQuery) + if !isDisjunctionQuery { + return fmt.Errorf("must not clause must be disjunction") + } + } + + q.BoostVal = tmp.BoostVal + if q.BoostVal == 0 { + q.BoostVal = 1 + } + return nil +} + +func (q *booleanQuery) Field() string { + return "" +} + +func (q *booleanQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_conjunction.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_conjunction.go new file mode 100644 index 00000000..5599c4b0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_conjunction.go @@ -0,0 +1,94 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type conjunctionQuery struct { + Conjuncts []Query `json:"conjuncts"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewConjunctionQuery creates a new compound Query. +// Result documents must satisfy all of the queries. +func NewConjunctionQuery(conjuncts []Query) *conjunctionQuery { + return &conjunctionQuery{ + Conjuncts: conjuncts, + BoostVal: 1.0, + } +} + +func (q *conjunctionQuery) Boost() float64 { + return q.BoostVal +} + +func (q *conjunctionQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *conjunctionQuery) AddQuery(aq Query) *conjunctionQuery { + q.Conjuncts = append(q.Conjuncts, aq) + return q +} + +func (q *conjunctionQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + ss := make([]search.Searcher, len(q.Conjuncts)) + for in, conjunct := range q.Conjuncts { + var err error + ss[in], err = conjunct.Searcher(i, m, explain) + if err != nil { + return nil, err + } + } + return searchers.NewConjunctionSearcher(i, ss, explain) +} + +func (q *conjunctionQuery) Validate() error { + return nil +} + +func (q *conjunctionQuery) UnmarshalJSON(data []byte) error { + tmp := struct { + Conjuncts []json.RawMessage `json:"conjuncts"` + BoostVal float64 `json:"boost,omitempty"` + }{} + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + q.Conjuncts = make([]Query, len(tmp.Conjuncts)) + for i, term := range tmp.Conjuncts { + query, err := ParseQuery(term) + if err != nil { + return err + } + q.Conjuncts[i] = query + } + q.BoostVal = tmp.BoostVal + if q.BoostVal == 0 { + q.BoostVal = 1 + } + return nil +} + +func (q *conjunctionQuery) Field() string { + return "" +} + +func (q *conjunctionQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_date_range.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_date_range.go new file mode 100644 index 00000000..0efdfb91 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_date_range.go @@ -0,0 +1,117 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "fmt" + "math" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type dateRangeQuery struct { + Start *string `json:"start,omitempty"` + End *string `json:"end,omitempty"` + InclusiveStart *bool `json:"inclusive_start,omitempty"` + InclusiveEnd *bool `json:"inclusive_end,omitempty"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` + DateTimeParser *string `json:"datetime_parser,omitempty"` +} + +// NewDateRangeQuery creates a new Query for ranges +// of date values. +// A DateTimeParser is chosen based on the field. +// Either, but not both endpoints can be nil. +func NewDateRangeQuery(start, end *string) *dateRangeQuery { + return NewDateRangeInclusiveQuery(start, end, nil, nil) +} + +// NewDateRangeInclusiveQuery creates a new Query for ranges +// of date values. +// A DateTimeParser is chosen based on the field. +// Either, but not both endpoints can be nil. +// startInclusive and endInclusive control inclusion of the endpoints. +func NewDateRangeInclusiveQuery(start, end *string, startInclusive, endInclusive *bool) *dateRangeQuery { + return &dateRangeQuery{ + Start: start, + End: end, + InclusiveStart: startInclusive, + InclusiveEnd: endInclusive, + BoostVal: 1.0, + } +} + +func (q *dateRangeQuery) Boost() float64 { + return q.BoostVal +} + +func (q *dateRangeQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *dateRangeQuery) Field() string { + return q.FieldVal +} + +func (q *dateRangeQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *dateRangeQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + + dateTimeParserName := "" + if q.DateTimeParser != nil { + dateTimeParserName = *q.DateTimeParser + } else { + dateTimeParserName = m.datetimeParserNameForPath(q.FieldVal) + } + dateTimeParser := m.dateTimeParserNamed(dateTimeParserName) + if dateTimeParser == nil { + return nil, fmt.Errorf("no datetime parser named '%s' registered", *q.DateTimeParser) + } + + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + + // now parse the endpoints + min := math.Inf(-1) + max := math.Inf(1) + if q.Start != nil && *q.Start != "" { + startTime, err := dateTimeParser.ParseDateTime(*q.Start) + if err != nil { + return nil, err + } + min = numeric_util.Int64ToFloat64(startTime.UnixNano()) + } + if q.End != nil && *q.End != "" { + endTime, err := dateTimeParser.ParseDateTime(*q.End) + if err != nil { + return nil, err + } + max = numeric_util.Int64ToFloat64(endTime.UnixNano()) + } + + return searchers.NewNumericRangeSearcher(i, &min, &max, q.InclusiveStart, q.InclusiveEnd, field, q.BoostVal, explain) +} + +func (q *dateRangeQuery) Validate() error { + if q.Start == nil && q.Start == q.End { + return fmt.Errorf("must specify start or end") + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_disjunction.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_disjunction.go new file mode 100644 index 00000000..d2ab6898 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_disjunction.go @@ -0,0 +1,119 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type disjunctionQuery struct { + Disjuncts []Query `json:"disjuncts"` + BoostVal float64 `json:"boost,omitempty"` + MinVal float64 `json:"min"` +} + +// NewDisjunctionQuery creates a new compound Query. +// Result documents satisfy at least one Query. +func NewDisjunctionQuery(disjuncts []Query) *disjunctionQuery { + return &disjunctionQuery{ + Disjuncts: disjuncts, + BoostVal: 1.0, + } +} + +// NewDisjunctionQueryMin creates a new compound Query. +// Result documents satisfy at least min Queries. +func NewDisjunctionQueryMin(disjuncts []Query, min float64) *disjunctionQuery { + return &disjunctionQuery{ + Disjuncts: disjuncts, + BoostVal: 1.0, + MinVal: min, + } +} + +func (q *disjunctionQuery) Boost() float64 { + return q.BoostVal +} + +func (q *disjunctionQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *disjunctionQuery) AddQuery(aq Query) Query { + q.Disjuncts = append(q.Disjuncts, aq) + return q +} + +func (q *disjunctionQuery) Min() float64 { + return q.MinVal +} + +func (q *disjunctionQuery) SetMin(m float64) Query { + q.MinVal = m + return q +} + +func (q *disjunctionQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + ss := make([]search.Searcher, len(q.Disjuncts)) + for in, disjunct := range q.Disjuncts { + var err error + ss[in], err = disjunct.Searcher(i, m, explain) + if err != nil { + return nil, err + } + } + return searchers.NewDisjunctionSearcher(i, ss, q.MinVal, explain) +} + +func (q *disjunctionQuery) Validate() error { + if int(q.MinVal) > len(q.Disjuncts) { + return ErrorDisjunctionFewerThanMinClauses + } + return nil +} + +func (q *disjunctionQuery) UnmarshalJSON(data []byte) error { + tmp := struct { + Disjuncts []json.RawMessage `json:"disjuncts"` + BoostVal float64 `json:"boost,omitempty"` + MinVal float64 `json:"min"` + }{} + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + q.Disjuncts = make([]Query, len(tmp.Disjuncts)) + for i, term := range tmp.Disjuncts { + query, err := ParseQuery(term) + if err != nil { + return err + } + q.Disjuncts[i] = query + } + q.BoostVal = tmp.BoostVal + if q.BoostVal == 0 { + q.BoostVal = 1 + } + q.MinVal = tmp.MinVal + return nil +} + +func (q *disjunctionQuery) Field() string { + return "" +} + +func (q *disjunctionQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_fuzzy.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_fuzzy.go new file mode 100644 index 00000000..a5ccd8aa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_fuzzy.go @@ -0,0 +1,88 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type fuzzyQuery struct { + Term string `json:"term"` + PrefixVal int `json:"prefix_length"` + FuzzinessVal int `json:"fuzziness"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewFuzzyQuery creates a new Query which finds +// documents containing terms within a specific +// fuzziness of the specified term. +// The default fuzziness is 2. +// +// The current implementation uses Leveshtein edit +// distance as the fuzziness metric. +func NewFuzzyQuery(term string) *fuzzyQuery { + return &fuzzyQuery{ + Term: term, + PrefixVal: 0, + FuzzinessVal: 2, + BoostVal: 1.0, + } +} + +func (q *fuzzyQuery) Boost() float64 { + return q.BoostVal +} + +func (q *fuzzyQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *fuzzyQuery) Field() string { + return q.FieldVal +} + +func (q *fuzzyQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *fuzzyQuery) Fuzziness() int { + return q.FuzzinessVal +} + +func (q *fuzzyQuery) SetFuzziness(f int) Query { + q.FuzzinessVal = f + return q +} + +func (q *fuzzyQuery) Prefix() int { + return q.PrefixVal +} + +func (q *fuzzyQuery) SetPrefix(p int) Query { + q.PrefixVal = p + return q +} + +func (q *fuzzyQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + return searchers.NewFuzzySearcher(i, q.Term, q.PrefixVal, q.FuzzinessVal, field, q.BoostVal, explain) +} + +func (q *fuzzyQuery) Validate() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match.go new file mode 100644 index 00000000..76a94795 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match.go @@ -0,0 +1,128 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type matchQuery struct { + Match string `json:"match"` + FieldVal string `json:"field,omitempty"` + Analyzer string `json:"analyzer,omitempty"` + BoostVal float64 `json:"boost,omitempty"` + PrefixVal int `json:"prefix_length"` + FuzzinessVal int `json:"fuzziness"` +} + +// NewMatchQuery creates a Query for matching text. +// An Analyzer is chosen based on the field. +// Input text is analyzed using this analyzer. +// Token terms resulting from this analysis are +// used to perform term searches. Result documents +// must satisfy at least one of these term searches. +func NewMatchQuery(match string) *matchQuery { + return &matchQuery{ + Match: match, + BoostVal: 1.0, + } +} + +func (q *matchQuery) Boost() float64 { + return q.BoostVal +} + +func (q *matchQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *matchQuery) Field() string { + return q.FieldVal +} + +func (q *matchQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *matchQuery) Fuzziness() int { + return q.FuzzinessVal +} + +func (q *matchQuery) SetFuzziness(f int) Query { + q.FuzzinessVal = f + return q +} + +func (q *matchQuery) Prefix() int { + return q.PrefixVal +} + +func (q *matchQuery) SetPrefix(p int) Query { + q.PrefixVal = p + return q +} + +func (q *matchQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + + analyzerName := "" + if q.Analyzer != "" { + analyzerName = q.Analyzer + } else { + analyzerName = m.analyzerNameForPath(field) + } + analyzer := m.analyzerNamed(analyzerName) + + if analyzer == nil { + return nil, fmt.Errorf("no analyzer named '%s' registered", q.Analyzer) + } + + tokens := analyzer.Analyze([]byte(q.Match)) + if len(tokens) > 0 { + + tqs := make([]Query, len(tokens)) + if q.FuzzinessVal != 0 { + for i, token := range tokens { + query := NewFuzzyQuery(string(token.Term)) + query.SetFuzziness(q.FuzzinessVal) + query.SetPrefix(q.PrefixVal) + query.SetField(field) + query.SetBoost(q.BoostVal) + tqs[i] = query + } + } else { + for i, token := range tokens { + tqs[i] = NewTermQuery(string(token.Term)). + SetField(field). + SetBoost(q.BoostVal) + } + } + + shouldQuery := NewDisjunctionQueryMin(tqs, 1). + SetBoost(q.BoostVal) + + return shouldQuery.Searcher(i, m, explain) + } + noneQuery := NewMatchNoneQuery() + return noneQuery.Searcher(i, m, explain) +} + +func (q *matchQuery) Validate() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_all.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_all.go new file mode 100644 index 00000000..c1d6208d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_all.go @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type matchAllQuery struct { + BoostVal float64 `json:"boost,omitempty"` +} + +// NewMatchAllQuery creates a Query which will +// match all documents in the index. +func NewMatchAllQuery() *matchAllQuery { + return &matchAllQuery{ + BoostVal: 1.0, + } +} + +func (q *matchAllQuery) Boost() float64 { + return q.BoostVal +} + +func (q *matchAllQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *matchAllQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + return searchers.NewMatchAllSearcher(i, q.BoostVal, explain) +} + +func (q *matchAllQuery) Validate() error { + return nil +} + +func (q *matchAllQuery) Field() string { + return "" +} + +func (q *matchAllQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_none.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_none.go new file mode 100644 index 00000000..8408c8c1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_none.go @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type matchNoneQuery struct { + BoostVal float64 `json:"boost,omitempty"` +} + +// NewMatchNoneQuery creates a Query which will not +// match any documents in the index. +func NewMatchNoneQuery() *matchNoneQuery { + return &matchNoneQuery{ + BoostVal: 1.0, + } +} + +func (q *matchNoneQuery) Boost() float64 { + return q.BoostVal +} + +func (q *matchNoneQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *matchNoneQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + return searchers.NewMatchNoneSearcher(i) +} + +func (q *matchNoneQuery) Validate() error { + return nil +} + +func (q *matchNoneQuery) Field() string { + return "" +} + +func (q *matchNoneQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_phrase.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_phrase.go new file mode 100644 index 00000000..a7f66066 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_match_phrase.go @@ -0,0 +1,114 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type matchPhraseQuery struct { + MatchPhrase string `json:"match_phrase"` + FieldVal string `json:"field,omitempty"` + Analyzer string `json:"analyzer,omitempty"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewMatchPhraseQuery creates a new Query object +// for matching phrases in the index. +// An Analyzer is chosen based on the field. +// Input text is analyzed using this analyzer. +// Token terms resulting from this analysis are +// used to build a search phrase. Result documents +// must match this phrase. +func NewMatchPhraseQuery(matchPhrase string) *matchPhraseQuery { + return &matchPhraseQuery{ + MatchPhrase: matchPhrase, + BoostVal: 1.0, + } +} + +func (q *matchPhraseQuery) Boost() float64 { + return q.BoostVal +} + +func (q *matchPhraseQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *matchPhraseQuery) Field() string { + return q.FieldVal +} + +func (q *matchPhraseQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *matchPhraseQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + + analyzerName := "" + if q.Analyzer != "" { + analyzerName = q.Analyzer + } else { + analyzerName = m.analyzerNameForPath(field) + } + analyzer := m.analyzerNamed(analyzerName) + if analyzer == nil { + return nil, fmt.Errorf("no analyzer named '%s' registered", q.Analyzer) + } + + tokens := analyzer.Analyze([]byte(q.MatchPhrase)) + if len(tokens) > 0 { + phrase := tokenStreamToPhrase(tokens) + phraseQuery := NewPhraseQuery(phrase, field).SetBoost(q.BoostVal) + return phraseQuery.Searcher(i, m, explain) + } + noneQuery := NewMatchNoneQuery() + return noneQuery.Searcher(i, m, explain) +} + +func tokenStreamToPhrase(tokens analysis.TokenStream) []string { + firstPosition := int(^uint(0) >> 1) + lastPosition := 0 + for _, token := range tokens { + if token.Position < firstPosition { + firstPosition = token.Position + } + if token.Position > lastPosition { + lastPosition = token.Position + } + } + phraseLen := lastPosition - firstPosition + 1 + if phraseLen > 0 { + rv := make([]string, phraseLen) + for i := 0; i < phraseLen; i++ { + rv[i] = "" + } + for _, token := range tokens { + pos := token.Position - firstPosition + rv[pos] = string(token.Term) + } + return rv + } + return nil +} + +func (q *matchPhraseQuery) Validate() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_numeric_range.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_numeric_range.go new file mode 100644 index 00000000..d45449df --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_numeric_range.go @@ -0,0 +1,81 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type numericRangeQuery struct { + Min *float64 `json:"min,omitempty"` + Max *float64 `json:"max,omitempty"` + InclusiveMin *bool `json:"inclusive_min,omitempty"` + InclusiveMax *bool `json:"inclusive_max,omitempty"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewNumericRangeQuery creates a new Query for ranges +// of date values. +// Either, but not both endpoints can be nil. +// The minimum value is inclusive. +// The maximum value is exclusive. +func NewNumericRangeQuery(min, max *float64) *numericRangeQuery { + return NewNumericRangeInclusiveQuery(min, max, nil, nil) +} + +// NewNumericRangeInclusiveQuery creates a new Query for ranges +// of date values. +// Either, but not both endpoints can be nil. +// Control endpoint inclusion with inclusiveMin, inclusiveMax. +func NewNumericRangeInclusiveQuery(min, max *float64, minInclusive, maxInclusive *bool) *numericRangeQuery { + return &numericRangeQuery{ + Min: min, + Max: max, + InclusiveMin: minInclusive, + InclusiveMax: maxInclusive, + BoostVal: 1.0, + } +} + +func (q *numericRangeQuery) Boost() float64 { + return q.BoostVal +} + +func (q *numericRangeQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *numericRangeQuery) Field() string { + return q.FieldVal +} + +func (q *numericRangeQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *numericRangeQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + return searchers.NewNumericRangeSearcher(i, q.Min, q.Max, q.InclusiveMin, q.InclusiveMax, field, q.BoostVal, explain) +} + +func (q *numericRangeQuery) Validate() error { + if q.Min == nil && q.Min == q.Max { + return ErrorNumericQueryNoBounds + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_phrase.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_phrase.go new file mode 100644 index 00000000..7c755021 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_phrase.go @@ -0,0 +1,108 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type phraseQuery struct { + TermQueries []Query `json:"terms"` + BoostVal float64 `json:"boost,omitempty"` + terms []string +} + +// NewPhraseQuery creates a new Query for finding +// exact term phrases in the index. +// The provided terms must exist in the correct +// order, at the correct index offsets, in the +// specified field. +func NewPhraseQuery(terms []string, field string) *phraseQuery { + termQueries := make([]Query, 0) + for _, term := range terms { + if term != "" { + termQueries = append(termQueries, NewTermQuery(term).SetField(field)) + } + } + return &phraseQuery{ + TermQueries: termQueries, + BoostVal: 1.0, + terms: terms, + } +} + +func (q *phraseQuery) Boost() float64 { + return q.BoostVal +} + +func (q *phraseQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *phraseQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + + conjunctionQuery := NewConjunctionQuery(q.TermQueries) + conjunctionSearcher, err := conjunctionQuery.Searcher(i, m, explain) + if err != nil { + return nil, err + } + return searchers.NewPhraseSearcher(i, conjunctionSearcher.(*searchers.ConjunctionSearcher), q.terms) +} + +func (q *phraseQuery) Validate() error { + if len(q.TermQueries) < 1 { + return ErrorPhraseQueryNoTerms + } + return nil +} + +func (q *phraseQuery) UnmarshalJSON(data []byte) error { + tmp := struct { + Terms []json.RawMessage `json:"terms"` + BoostVal float64 `json:"boost,omitempty"` + }{} + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + q.TermQueries = make([]Query, len(tmp.Terms)) + q.terms = make([]string, 0) + for i, term := range tmp.Terms { + query, err := ParseQuery(term) + if err != nil { + return err + } + q.TermQueries[i] = query + tq, isTermQuery := query.(*termQuery) + if !isTermQuery { + return fmt.Errorf("phrase query can only contain term queries") + } + q.terms = append(q.terms, tq.Term) + } + q.BoostVal = tmp.BoostVal + if q.BoostVal == 0 { + q.BoostVal = 1 + } + return nil +} + +func (q *phraseQuery) Field() string { + return "" +} + +func (q *phraseQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_prefix.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_prefix.go new file mode 100644 index 00000000..3a381979 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_prefix.go @@ -0,0 +1,62 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type prefixQuery struct { + Prefix string `json:"prefix"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewPrefixQuery creates a new Query which finds +// documents containing terms that start with the +// specified prefix. +func NewPrefixQuery(prefix string) *prefixQuery { + return &prefixQuery{ + Prefix: prefix, + BoostVal: 1.0, + } +} + +func (q *prefixQuery) Boost() float64 { + return q.BoostVal +} + +func (q *prefixQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *prefixQuery) Field() string { + return q.FieldVal +} + +func (q *prefixQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *prefixQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + return searchers.NewTermPrefixSearcher(i, q.Prefix, field, q.BoostVal, explain) +} + +func (q *prefixQuery) Validate() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_regexp.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_regexp.go new file mode 100644 index 00000000..83b3eb3d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_regexp.go @@ -0,0 +1,75 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type regexpQuery struct { + Regexp string `json:"regexp"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` + compiled *regexp.Regexp +} + +// NewRegexpQuery creates a new Query which finds +// documents containing terms that match the +// specified regular expression. +func NewRegexpQuery(regexp string) *regexpQuery { + return ®expQuery{ + Regexp: regexp, + BoostVal: 1.0, + } +} + +func (q *regexpQuery) Boost() float64 { + return q.BoostVal +} + +func (q *regexpQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *regexpQuery) Field() string { + return q.FieldVal +} + +func (q *regexpQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *regexpQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + if q.compiled == nil { + var err error + q.compiled, err = regexp.Compile(q.Regexp) + if err != nil { + return nil, err + } + } + + return searchers.NewRegexpSearcher(i, q.compiled, field, q.BoostVal, explain) +} + +func (q *regexpQuery) Validate() error { + var err error + q.compiled, err = regexp.Compile(q.Regexp) + return err +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.go new file mode 100644 index 00000000..c6d4b304 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.go @@ -0,0 +1,59 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type queryStringQuery struct { + Query string `json:"query"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewQueryStringQuery creates a new Query used for +// finding documents that satisfy a query string. The +// query string is a small query language for humans. +func NewQueryStringQuery(query string) *queryStringQuery { + return &queryStringQuery{ + Query: query, + BoostVal: 1.0, + } +} + +func (q *queryStringQuery) Boost() float64 { + return q.BoostVal +} + +func (q *queryStringQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *queryStringQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + newQuery, err := parseQuerySyntax(q.Query, m) + if err != nil { + return nil, err + } + return newQuery.Searcher(i, m, explain) +} + +func (q *queryStringQuery) Validate() error { + return nil +} + +func (q *queryStringQuery) Field() string { + return "" +} + +func (q *queryStringQuery) SetField(f string) Query { + return q +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nex b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nex new file mode 100644 index 00000000..a53ef24b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nex @@ -0,0 +1,41 @@ +/\"((\\\")|(\\\\)|(\\\/)|(\\b)|(\\f)|(\\n)|(\\r)|(\\t)|(\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])|[^\"])*\"/ { + lval.s = yylex.Text()[1:len(yylex.Text())-1] + logDebugTokens("PHRASE - %s", lval.s); + return tPHRASE + } +/\+/ { logDebugTokens("PLUS"); return tPLUS } +/-/ { logDebugTokens("MINUS"); return tMINUS } +/:/ { logDebugTokens("COLON"); return tCOLON } +/\^/ { logDebugTokens("BOOST"); return tBOOST } +/\(/ { logDebugTokens("LPAREN"); return tLPAREN } +/\)/ { logDebugTokens("RPAREN"); return tRPAREN } +/>/ { logDebugTokens("GREATER"); return tGREATER } +/<=~][^\t\n\f\r :^~]*/ { + lval.s = yylex.Text() + logDebugTokens("STRING - %s", lval.s); + return tSTRING + } +// +package bleve + +func logDebugTokens(format string, v ...interface{}) { + if debugLexer { + logger.Printf(format, v...) + } +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nn.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nn.go new file mode 100644 index 00000000..396f8026 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.nn.go @@ -0,0 +1,1362 @@ +package bleve + +import ( + "bufio" + "io" + "strings" +) + +type frame struct { + i int + s string + line, column int +} +type lexer struct { + // The lexer runs in its own goroutine, and communicates via channel 'ch'. + ch chan frame + // We record the level of nesting because the action could return, and a + // subsequent call expects to pick up where it left off. In other words, + // we're simulating a coroutine. + // TODO: Support a channel-based variant that compatible with Go's yacc. + stack []frame + stale bool + + // The 'l' and 'c' fields were added for + // https://github.com/wagerlabs/docker/blob/65694e801a7b80930961d70c69cba9f2465459be/buildfile.nex + // Since then, I introduced the built-in Line() and Column() functions. + l, c int + + // The following line makes it easy for scripts to insert fields in the + // generated code. + // [NEX_END_OF_LEXER_STRUCT] +} + +// newLexerWithInit creates a new lexer object, runs the given callback on it, +// then returns it. +func newLexerWithInit(in io.Reader, initFun func(*lexer)) *lexer { + type dfa struct { + acc []bool // Accepting states. + f []func(rune) int // Transitions. + startf, endf []int // Transitions at start and end of input. + nest []dfa + } + yylex := new(lexer) + if initFun != nil { + initFun(yylex) + } + yylex.ch = make(chan frame) + var scan func(in *bufio.Reader, ch chan frame, family []dfa, line, column int) + scan = func(in *bufio.Reader, ch chan frame, family []dfa, line, column int) { + // Index of DFA and length of highest-precedence match so far. + matchi, matchn := 0, -1 + var buf []rune + n := 0 + checkAccept := func(i int, st int) bool { + // Higher precedence match? DFAs are run in parallel, so matchn is at most len(buf), hence we may omit the length equality check. + if family[i].acc[st] && (matchn < n || matchi > i) { + matchi, matchn = i, n + return true + } + return false + } + var state [][2]int + for i := 0; i < len(family); i++ { + mark := make([]bool, len(family[i].startf)) + // Every DFA starts at state 0. + st := 0 + for { + state = append(state, [2]int{i, st}) + mark[st] = true + // As we're at the start of input, follow all ^ transitions and append to our list of start states. + st = family[i].startf[st] + if -1 == st || mark[st] { + break + } + // We only check for a match after at least one transition. + checkAccept(i, st) + } + } + atEOF := false + for { + if n == len(buf) && !atEOF { + r, _, err := in.ReadRune() + switch err { + case io.EOF: + atEOF = true + case nil: + buf = append(buf, r) + default: + panic(err) + } + } + if !atEOF { + r := buf[n] + n++ + var nextState [][2]int + for _, x := range state { + x[1] = family[x[0]].f[x[1]](r) + if -1 == x[1] { + continue + } + nextState = append(nextState, x) + checkAccept(x[0], x[1]) + } + state = nextState + } else { + dollar: // Handle $. + for _, x := range state { + mark := make([]bool, len(family[x[0]].endf)) + for { + mark[x[1]] = true + x[1] = family[x[0]].endf[x[1]] + if -1 == x[1] || mark[x[1]] { + break + } + if checkAccept(x[0], x[1]) { + // Unlike before, we can break off the search. Now that we're at the end, there's no need to maintain the state of each DFA. + break dollar + } + } + } + state = nil + } + + if state == nil { + lcUpdate := func(r rune) { + if r == '\n' { + line++ + column = 0 + } else { + column++ + } + } + // All DFAs stuck. Return last match if it exists, otherwise advance by one rune and restart all DFAs. + if matchn == -1 { + if len(buf) == 0 { // This can only happen at the end of input. + break + } + lcUpdate(buf[0]) + buf = buf[1:] + } else { + text := string(buf[:matchn]) + buf = buf[matchn:] + matchn = -1 + ch <- frame{matchi, text, line, column} + if len(family[matchi].nest) > 0 { + scan(bufio.NewReader(strings.NewReader(text)), ch, family[matchi].nest, line, column) + } + if atEOF { + break + } + for _, r := range text { + lcUpdate(r) + } + } + n = 0 + for i := 0; i < len(family); i++ { + state = append(state, [2]int{i, 0}) + } + } + } + ch <- frame{-1, "", line, column} + } + go scan(bufio.NewReader(in), yylex.ch, []dfa{ + // \"((\\\")|(\\\\)|(\\\/)|(\\b)|(\\f)|(\\n)|(\\r)|(\\t)|(\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])|[^\"])*\" + {[]bool{false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 34: + return 1 + case 47: + return -1 + case 92: + return -1 + case 98: + return -1 + case 102: + return -1 + case 110: + return -1 + case 114: + return -1 + case 116: + return -1 + case 117: + return -1 + } + switch { + case 97 <= r && r <= 102: + return -1 + case 65 <= r && r <= 70: + return -1 + case 48 <= r && r <= 57: + return -1 + } + return -1 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 2 + case 65 <= r && r <= 70: + return 2 + case 97 <= r && r <= 102: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 2 + case 65 <= r && r <= 70: + return 2 + case 97 <= r && r <= 102: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return -1 + case 47: + return -1 + case 92: + return -1 + case 98: + return -1 + case 102: + return -1 + case 110: + return -1 + case 114: + return -1 + case 116: + return -1 + case 117: + return -1 + } + switch { + case 48 <= r && r <= 57: + return -1 + case 65 <= r && r <= 70: + return -1 + case 97 <= r && r <= 102: + return -1 + } + return -1 + }, + func(r rune) int { + switch r { + case 34: + return 7 + case 47: + return 8 + case 92: + return 12 + case 98: + return 13 + case 102: + return 9 + case 110: + return 10 + case 114: + return 5 + case 116: + return 6 + case 117: + return 11 + } + switch { + case 48 <= r && r <= 57: + return 2 + case 65 <= r && r <= 70: + return 2 + case 97 <= r && r <= 102: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + case 48 <= r && r <= 57: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + case 48 <= r && r <= 57: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 2 + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + case 48 <= r && r <= 57: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 65 <= r && r <= 70: + return 2 + case 97 <= r && r <= 102: + return 2 + case 48 <= r && r <= 57: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + case 48 <= r && r <= 57: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 14 + case 102: + return 14 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 97 <= r && r <= 102: + return 14 + case 48 <= r && r <= 57: + return 14 + case 65 <= r && r <= 70: + return 14 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 7 + case 47: + return 8 + case 92: + return 12 + case 98: + return 13 + case 102: + return 9 + case 110: + return 10 + case 114: + return 5 + case 116: + return 6 + case 117: + return 11 + } + switch { + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + case 48 <= r && r <= 57: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 2 + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 15 + case 102: + return 15 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 97 <= r && r <= 102: + return 15 + case 65 <= r && r <= 70: + return 15 + case 48 <= r && r <= 57: + return 15 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 16 + case 102: + return 16 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 16 + case 97 <= r && r <= 102: + return 16 + case 65 <= r && r <= 70: + return 16 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 17 + case 102: + return 17 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 17 + case 97 <= r && r <= 102: + return 17 + case 65 <= r && r <= 70: + return 17 + } + return 2 + }, + func(r rune) int { + switch r { + case 34: + return 3 + case 47: + return 2 + case 92: + return 4 + case 98: + return 2 + case 102: + return 2 + case 110: + return 2 + case 114: + return 2 + case 116: + return 2 + case 117: + return 2 + } + switch { + case 48 <= r && r <= 57: + return 2 + case 97 <= r && r <= 102: + return 2 + case 65 <= r && r <= 70: + return 2 + } + return 2 + }, + }, []int{ /* Start-of-input transitions */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, []int{ /* End-of-input transitions */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, nil}, + + // \+ + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 43: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 43: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // - + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 45: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // : + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 58: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 58: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // \^ + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 94: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 94: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // \( + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 40: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 40: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // \) + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 41: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 41: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // > + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 62: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 62: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // < + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 60: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 60: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // = + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 61: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 61: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // ~([0-9]|[1-9][0-9]*) + {[]bool{false, false, true, true, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 126: + return 1 + } + switch { + case 48 <= r && r <= 48: + return -1 + case 49 <= r && r <= 57: + return -1 + } + return -1 + }, + func(r rune) int { + switch r { + case 126: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 2 + case 49 <= r && r <= 57: + return 3 + } + return -1 + }, + func(r rune) int { + switch r { + case 126: + return -1 + } + switch { + case 48 <= r && r <= 48: + return -1 + case 49 <= r && r <= 57: + return -1 + } + return -1 + }, + func(r rune) int { + switch r { + case 126: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 4 + case 49 <= r && r <= 57: + return 4 + } + return -1 + }, + func(r rune) int { + switch r { + case 126: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 4 + case 49 <= r && r <= 57: + return 4 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1, -1, -1, -1}, []int{ /* End-of-input transitions */ -1, -1, -1, -1, -1}, nil}, + + // ~ + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 126: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 126: + return -1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // -?([0-9]|[1-9][0-9]*)(\.[0-9][0-9]*)? + {[]bool{false, false, true, true, false, true, true, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 45: + return 1 + case 46: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 2 + case 49 <= r && r <= 57: + return 3 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 2 + case 49 <= r && r <= 57: + return 3 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return 4 + } + switch { + case 48 <= r && r <= 48: + return -1 + case 49 <= r && r <= 57: + return -1 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return 4 + } + switch { + case 48 <= r && r <= 48: + return 5 + case 49 <= r && r <= 57: + return 5 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 6 + case 49 <= r && r <= 57: + return 6 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return 4 + } + switch { + case 48 <= r && r <= 48: + return 5 + case 49 <= r && r <= 57: + return 5 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 7 + case 49 <= r && r <= 57: + return 7 + } + return -1 + }, + func(r rune) int { + switch r { + case 45: + return -1 + case 46: + return -1 + } + switch { + case 48 <= r && r <= 48: + return 7 + case 49 <= r && r <= 57: + return 7 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1, -1, -1, -1, -1, -1, -1}, []int{ /* End-of-input transitions */ -1, -1, -1, -1, -1, -1, -1, -1}, nil}, + + // [ \t\n]+ + {[]bool{false, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 9: + return 1 + case 10: + return 1 + case 32: + return 1 + } + return -1 + }, + func(r rune) int { + switch r { + case 9: + return 1 + case 10: + return 1 + case 32: + return 1 + } + return -1 + }, + }, []int{ /* Start-of-input transitions */ -1, -1}, []int{ /* End-of-input transitions */ -1, -1}, nil}, + + // [^\t\n\f\r :^\+\-><=~][^\t\n\f\r :^~]* + {[]bool{false, true, true}, []func(rune) int{ // Transitions + func(r rune) int { + switch r { + case 9: + return -1 + case 10: + return -1 + case 12: + return -1 + case 13: + return -1 + case 32: + return -1 + case 58: + return -1 + case 60: + return -1 + case 61: + return -1 + case 94: + return -1 + case 126: + return -1 + } + switch { + case 43 <= r && r <= 62: + return -1 + } + return 1 + }, + func(r rune) int { + switch r { + case 9: + return -1 + case 10: + return -1 + case 12: + return -1 + case 13: + return -1 + case 32: + return -1 + case 58: + return -1 + case 60: + return 2 + case 61: + return 2 + case 94: + return -1 + case 126: + return -1 + } + switch { + case 43 <= r && r <= 62: + return 2 + } + return 2 + }, + func(r rune) int { + switch r { + case 9: + return -1 + case 10: + return -1 + case 12: + return -1 + case 13: + return -1 + case 32: + return -1 + case 58: + return -1 + case 60: + return 2 + case 61: + return 2 + case 94: + return -1 + case 126: + return -1 + } + switch { + case 43 <= r && r <= 62: + return 2 + } + return 2 + }, + }, []int{ /* Start-of-input transitions */ -1, -1, -1}, []int{ /* End-of-input transitions */ -1, -1, -1}, nil}, + }, 0, 0) + return yylex +} + +func newLexer(in io.Reader) *lexer { + return newLexerWithInit(in, nil) +} + +// Text returns the matched text. +func (yylex *lexer) Text() string { + return yylex.stack[len(yylex.stack)-1].s +} + +// Line returns the current line number. +// The first line is 0. +func (yylex *lexer) Line() int { + return yylex.stack[len(yylex.stack)-1].line +} + +// Column returns the current column number. +// The first column is 0. +func (yylex *lexer) Column() int { + return yylex.stack[len(yylex.stack)-1].column +} + +func (yylex *lexer) next(lvl int) int { + if lvl == len(yylex.stack) { + l, c := 0, 0 + if lvl > 0 { + l, c = yylex.stack[lvl-1].line, yylex.stack[lvl-1].column + } + yylex.stack = append(yylex.stack, frame{0, "", l, c}) + } + if lvl == len(yylex.stack)-1 { + p := &yylex.stack[lvl] + *p = <-yylex.ch + yylex.stale = false + } else { + yylex.stale = true + } + return yylex.stack[lvl].i +} +func (yylex *lexer) pop() { + yylex.stack = yylex.stack[:len(yylex.stack)-1] +} +func (yylex lexer) Error(e string) { + panic(e) +} + +// Lex runs the lexer. Always returns 0. +// When the -s option is given, this function is not generated; +// instead, the NN_FUN macro runs the lexer. +func (yylex *lexer) Lex(lval *yySymType) int { +OUTER0: + for { + switch yylex.next(0) { + case 0: + { + lval.s = yylex.Text()[1 : len(yylex.Text())-1] + logDebugTokens("PHRASE - %s", lval.s) + return tPHRASE + } + case 1: + { + logDebugTokens("PLUS") + return tPLUS + } + case 2: + { + logDebugTokens("MINUS") + return tMINUS + } + case 3: + { + logDebugTokens("COLON") + return tCOLON + } + case 4: + { + logDebugTokens("BOOST") + return tBOOST + } + case 5: + { + logDebugTokens("LPAREN") + return tLPAREN + } + case 6: + { + logDebugTokens("RPAREN") + return tRPAREN + } + case 7: + { + logDebugTokens("GREATER") + return tGREATER + } + case 8: + { + logDebugTokens("LESS") + return tLESS + } + case 9: + { + logDebugTokens("EQUAL") + return tEQUAL + } + case 10: + { + lval.s = yylex.Text()[1:] + logDebugTokens("TILDENUMBER - %s", lval.s) + return tTILDENUMBER + } + case 11: + { + logDebugTokens("TILDE") + return tTILDE + } + case 12: + { + lval.s = yylex.Text() + logDebugTokens("NUMBER - %s", lval.s) + return tNUMBER + } + case 13: + { + logDebugTokens("WHITESPACE (count=%d)", len(yylex.Text())) /* eat up whitespace */ + } + case 14: + { + lval.s = yylex.Text() + logDebugTokens("STRING - %s", lval.s) + return tSTRING + } + default: + break OUTER0 + } + continue + } + yylex.pop() + + return 0 +} +func logDebugTokens(format string, v ...interface{}) { + if debugLexer { + logger.Printf(format, v...) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y new file mode 100644 index 00000000..54d960f8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y @@ -0,0 +1,217 @@ +%{ +package bleve +import "strconv" + +func logDebugGrammar(format string, v ...interface{}) { + if debugParser { + logger.Printf(format, v...) + } +} +%} + +%union { +s string +n int +f float64 +q Query} + +%token tSTRING tPHRASE tPLUS tMINUS tCOLON tBOOST tLPAREN tRPAREN tNUMBER tSTRING tGREATER tLESS +tEQUAL tTILDE tTILDENUMBER + +%type tSTRING +%type tPHRASE +%type tNUMBER +%type tTILDENUMBER +%type searchBase +%type searchSuffix +%type searchPrefix +%type searchMustMustNot +%type searchBoost + +%% + +input: +searchParts { + logDebugGrammar("INPUT") +}; + +searchParts: +searchPart searchParts { + logDebugGrammar("SEARCH PARTS") +} +| +searchPart { + logDebugGrammar("SEARCH PART") +}; + +searchPart: +searchPrefix searchBase searchSuffix { + query := $2 + query.SetBoost($3) + switch($1) { + case queryShould: + yylex.(*lexerWrapper).query.AddShould(query) + case queryMust: + yylex.(*lexerWrapper).query.AddMust(query) + case queryMustNot: + yylex.(*lexerWrapper).query.AddMustNot(query) + } +}; + + +searchPrefix: +/* empty */ { + $$ = queryShould +} +| +searchMustMustNot { + $$ = $1 +} +; + +searchMustMustNot: +tPLUS { + logDebugGrammar("PLUS") + $$ = queryMust +} +| +tMINUS { + logDebugGrammar("MINUS") + $$ = queryMustNot +}; + +searchBase: +tSTRING { + str := $1 + logDebugGrammar("STRING - %s", str) + q := NewMatchQuery(str) + $$ = q +} +| +tSTRING tTILDE { + str := $1 + logDebugGrammar("FUZZY STRING - %s", str) + q := NewMatchQuery(str) + q.SetFuzziness(1) + $$ = q +} +| +tSTRING tCOLON tSTRING tTILDE { + field := $1 + str := $3 + logDebugGrammar("FIELD - %s FUZZY STRING - %s", field, str) + q := NewMatchQuery(str) + q.SetFuzziness(1) + q.SetField(field) + $$ = q +} +| +tSTRING tTILDENUMBER { + str := $1 + fuzziness, _ := strconv.ParseFloat($2, 64) + logDebugGrammar("FUZZY STRING - %s", str) + q := NewMatchQuery(str) + q.SetFuzziness(int(fuzziness)) + $$ = q +} +| +tSTRING tCOLON tSTRING tTILDENUMBER { + field := $1 + str := $3 + fuzziness, _ := strconv.ParseFloat($4, 64) + logDebugGrammar("FIELD - %s FUZZY-%f STRING - %s", field, fuzziness, str) + q := NewMatchQuery(str) + q.SetFuzziness(int(fuzziness)) + q.SetField(field) + $$ = q +} +| +tNUMBER { + str := $1 + logDebugGrammar("STRING - %s", str) + q := NewMatchQuery(str) + $$ = q +} +| +tPHRASE { + phrase := $1 + logDebugGrammar("PHRASE - %s", phrase) + q := NewMatchPhraseQuery(phrase) + $$ = q +} +| +tSTRING tCOLON tSTRING { + field := $1 + str := $3 + logDebugGrammar("FIELD - %s STRING - %s", field, str) + q := NewMatchQuery(str).SetField(field) + $$ = q +} +| +tSTRING tCOLON tNUMBER { + field := $1 + str := $3 + logDebugGrammar("FIELD - %s STRING - %s", field, str) + q := NewMatchQuery(str).SetField(field) + $$ = q +} +| +tSTRING tCOLON tPHRASE { + field := $1 + phrase := $3 + logDebugGrammar("FIELD - %s PHRASE - %s", field, phrase) + q := NewMatchPhraseQuery(phrase).SetField(field) + $$ = q +} +| +tSTRING tCOLON tGREATER tNUMBER { + field := $1 + min, _ := strconv.ParseFloat($4, 64) + minInclusive := false + logDebugGrammar("FIELD - GREATER THAN %f", min) + q := NewNumericRangeInclusiveQuery(&min, nil, &minInclusive, nil).SetField(field) + $$ = q +} +| +tSTRING tCOLON tGREATER tEQUAL tNUMBER { + field := $1 + min, _ := strconv.ParseFloat($5, 64) + minInclusive := true + logDebugGrammar("FIELD - GREATER THAN OR EQUAL %f", min) + q := NewNumericRangeInclusiveQuery(&min, nil, &minInclusive, nil).SetField(field) + $$ = q +} +| +tSTRING tCOLON tLESS tNUMBER { + field := $1 + max, _ := strconv.ParseFloat($4, 64) + maxInclusive := false + logDebugGrammar("FIELD - LESS THAN %f", max) + q := NewNumericRangeInclusiveQuery(nil, &max, nil, &maxInclusive).SetField(field) + $$ = q +} +| +tSTRING tCOLON tLESS tEQUAL tNUMBER { + field := $1 + max, _ := strconv.ParseFloat($5, 64) + maxInclusive := true + logDebugGrammar("FIELD - LESS THAN OR EQUAL %f", max) + q := NewNumericRangeInclusiveQuery(nil, &max, nil, &maxInclusive).SetField(field) + $$ = q +}; + +searchBoost: +tBOOST tNUMBER { + boost, _ := strconv.ParseFloat($2, 64) + $$ = boost + logDebugGrammar("BOOST %f", boost) +}; + +searchSuffix: +/* empty */ { + $$ = 1.0 +} +| +searchBoost { + +}; \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y.go new file mode 100644 index 00000000..469d7163 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string.y.go @@ -0,0 +1,563 @@ +package bleve + +import __yyfmt__ "fmt" + +//line query_string.y:2 +import "strconv" + +func logDebugGrammar(format string, v ...interface{}) { + if debugParser { + logger.Printf(format, v...) + } +} + +//line query_string.y:12 +type yySymType struct { + yys int + s string + n int + f float64 + q Query +} + +const tSTRING = 57346 +const tPHRASE = 57347 +const tPLUS = 57348 +const tMINUS = 57349 +const tCOLON = 57350 +const tBOOST = 57351 +const tLPAREN = 57352 +const tRPAREN = 57353 +const tNUMBER = 57354 +const tGREATER = 57355 +const tLESS = 57356 +const tEQUAL = 57357 +const tTILDE = 57358 +const tTILDENUMBER = 57359 + +var yyToknames = []string{ + "tSTRING", + "tPHRASE", + "tPLUS", + "tMINUS", + "tCOLON", + "tBOOST", + "tLPAREN", + "tRPAREN", + "tNUMBER", + "tGREATER", + "tLESS", + "tEQUAL", + "tTILDE", + "tTILDENUMBER", +} +var yyStatenames = []string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyMaxDepth = 200 + +//line yacctab:1 +var yyExca = []int{ + -1, 1, + 1, -1, + -2, 0, + -1, 3, + 1, 3, + -2, 5, +} + +const yyNprod = 26 +const yyPrivate = 57344 + +var yyTokenNames []string +var yyStates []string + +const yyLast = 32 + +var yyAct = []int{ + + 17, 25, 26, 20, 22, 32, 31, 29, 16, 18, + 30, 21, 23, 24, 27, 10, 12, 28, 19, 15, + 6, 7, 2, 11, 3, 1, 8, 14, 5, 4, + 13, 9, +} +var yyPact = []int{ + + 14, -1000, -1000, 14, 11, -1000, -1000, -1000, -1000, 10, + -8, -1000, -1000, -1000, -1000, 6, -1000, -1, -1000, -1000, + -15, -1000, -1000, 2, -5, -1000, -1000, -1000, -6, -1000, + -7, -1000, -1000, +} +var yyPgo = []int{ + + 0, 31, 30, 29, 28, 27, 25, 22, 24, +} +var yyR1 = []int{ + + 0, 6, 7, 7, 8, 3, 3, 4, 4, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5, 2, 2, +} +var yyR2 = []int{ + + 0, 1, 2, 1, 3, 0, 1, 1, 1, 1, + 2, 4, 2, 4, 1, 1, 3, 3, 3, 4, + 5, 4, 5, 2, 0, 1, +} +var yyChk = []int{ + + -1000, -6, -7, -8, -3, -4, 6, 7, -7, -1, + 4, 12, 5, -2, -5, 9, 16, 8, 17, 12, + 4, 12, 5, 13, 14, 16, 17, 12, 15, 12, + 15, 12, 12, +} +var yyDef = []int{ + + 5, -2, 1, -2, 0, 6, 7, 8, 2, 24, + 9, 14, 15, 4, 25, 0, 10, 0, 12, 23, + 16, 17, 18, 0, 0, 11, 13, 19, 0, 21, + 0, 20, 22, +} +var yyTok1 = []int{ + + 1, +} +var yyTok2 = []int{ + + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, +} +var yyTok3 = []int{ + 0, +} + +//line yaccpar:1 + +/* parser for yacc output */ + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + // 4 is TOKSTART above + if c >= 4 && c-4 < len(yyToknames) { + if yyToknames[c-4] != "" { + return yyToknames[c-4] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yylex1(lex yyLexer, lval *yySymType) int { + c := 0 + char := lex.Lex(lval) + if char <= 0 { + c = yyTok1[0] + goto out + } + if char < len(yyTok1) { + c = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + c = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + c = yyTok3[i+0] + if c == char { + c = yyTok3[i+1] + goto out + } + } + +out: + if c == 0 { + c = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) + } + return c +} + +func yyParse(yylex yyLexer) int { + var yyn int + var yylval yySymType + var yyVAL yySymType + yyS := make([]yySymType, yyMaxDepth) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yychar := -1 + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + yyn += yychar + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yychar { /* valid shift */ + yychar = -1 + yyVAL = yylval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yychar { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error("syntax error") + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) + } + if yychar == yyEofCode { + goto ret1 + } + yychar = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 1: + //line query_string.y:34 + { + logDebugGrammar("INPUT") + } + case 2: + //line query_string.y:39 + { + logDebugGrammar("SEARCH PARTS") + } + case 3: + //line query_string.y:43 + { + logDebugGrammar("SEARCH PART") + } + case 4: + //line query_string.y:48 + { + query := yyS[yypt-1].q + query.SetBoost(yyS[yypt-0].f) + switch yyS[yypt-2].n { + case queryShould: + yylex.(*lexerWrapper).query.AddShould(query) + case queryMust: + yylex.(*lexerWrapper).query.AddMust(query) + case queryMustNot: + yylex.(*lexerWrapper).query.AddMustNot(query) + } + } + case 5: + //line query_string.y:63 + { + yyVAL.n = queryShould + } + case 6: + //line query_string.y:67 + { + yyVAL.n = yyS[yypt-0].n + } + case 7: + //line query_string.y:73 + { + logDebugGrammar("PLUS") + yyVAL.n = queryMust + } + case 8: + //line query_string.y:78 + { + logDebugGrammar("MINUS") + yyVAL.n = queryMustNot + } + case 9: + //line query_string.y:84 + { + str := yyS[yypt-0].s + logDebugGrammar("STRING - %s", str) + q := NewMatchQuery(str) + yyVAL.q = q + } + case 10: + //line query_string.y:91 + { + str := yyS[yypt-1].s + logDebugGrammar("FUZZY STRING - %s", str) + q := NewMatchQuery(str) + q.SetFuzziness(1) + yyVAL.q = q + } + case 11: + //line query_string.y:99 + { + field := yyS[yypt-3].s + str := yyS[yypt-1].s + logDebugGrammar("FIELD - %s FUZZY STRING - %s", field, str) + q := NewMatchQuery(str) + q.SetFuzziness(1) + q.SetField(field) + yyVAL.q = q + } + case 12: + //line query_string.y:109 + { + str := yyS[yypt-1].s + fuzziness, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + logDebugGrammar("FUZZY STRING - %s", str) + q := NewMatchQuery(str) + q.SetFuzziness(int(fuzziness)) + yyVAL.q = q + } + case 13: + //line query_string.y:118 + { + field := yyS[yypt-3].s + str := yyS[yypt-1].s + fuzziness, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + logDebugGrammar("FIELD - %s FUZZY-%f STRING - %s", field, fuzziness, str) + q := NewMatchQuery(str) + q.SetFuzziness(int(fuzziness)) + q.SetField(field) + yyVAL.q = q + } + case 14: + //line query_string.y:129 + { + str := yyS[yypt-0].s + logDebugGrammar("STRING - %s", str) + q := NewMatchQuery(str) + yyVAL.q = q + } + case 15: + //line query_string.y:136 + { + phrase := yyS[yypt-0].s + logDebugGrammar("PHRASE - %s", phrase) + q := NewMatchPhraseQuery(phrase) + yyVAL.q = q + } + case 16: + //line query_string.y:143 + { + field := yyS[yypt-2].s + str := yyS[yypt-0].s + logDebugGrammar("FIELD - %s STRING - %s", field, str) + q := NewMatchQuery(str).SetField(field) + yyVAL.q = q + } + case 17: + //line query_string.y:151 + { + field := yyS[yypt-2].s + str := yyS[yypt-0].s + logDebugGrammar("FIELD - %s STRING - %s", field, str) + q := NewMatchQuery(str).SetField(field) + yyVAL.q = q + } + case 18: + //line query_string.y:159 + { + field := yyS[yypt-2].s + phrase := yyS[yypt-0].s + logDebugGrammar("FIELD - %s PHRASE - %s", field, phrase) + q := NewMatchPhraseQuery(phrase).SetField(field) + yyVAL.q = q + } + case 19: + //line query_string.y:167 + { + field := yyS[yypt-3].s + min, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + minInclusive := false + logDebugGrammar("FIELD - GREATER THAN %f", min) + q := NewNumericRangeInclusiveQuery(&min, nil, &minInclusive, nil).SetField(field) + yyVAL.q = q + } + case 20: + //line query_string.y:176 + { + field := yyS[yypt-4].s + min, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + minInclusive := true + logDebugGrammar("FIELD - GREATER THAN OR EQUAL %f", min) + q := NewNumericRangeInclusiveQuery(&min, nil, &minInclusive, nil).SetField(field) + yyVAL.q = q + } + case 21: + //line query_string.y:185 + { + field := yyS[yypt-3].s + max, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + maxInclusive := false + logDebugGrammar("FIELD - LESS THAN %f", max) + q := NewNumericRangeInclusiveQuery(nil, &max, nil, &maxInclusive).SetField(field) + yyVAL.q = q + } + case 22: + //line query_string.y:194 + { + field := yyS[yypt-4].s + max, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + maxInclusive := true + logDebugGrammar("FIELD - LESS THAN OR EQUAL %f", max) + q := NewNumericRangeInclusiveQuery(nil, &max, nil, &maxInclusive).SetField(field) + yyVAL.q = q + } + case 23: + //line query_string.y:204 + { + boost, _ := strconv.ParseFloat(yyS[yypt-0].s, 64) + yyVAL.f = boost + logDebugGrammar("BOOST %f", boost) + } + case 24: + //line query_string.y:211 + { + yyVAL.f = 1.0 + } + case 25: + //line query_string.y:215 + { + + } + } + goto yystack /* stack new state and value */ +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser.go new file mode 100644 index 00000000..3b035523 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser.go @@ -0,0 +1,76 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +//go:generate nex query_string.nex +//go:generate sed -i "" -e s/Lexer/lexer/g query_string.nn.go +//go:generate sed -i "" -e s/Newlexer/newLexer/g query_string.nn.go +//go:generate sed -i "" -e s/debuglexer/debugLexer/g query_string.nn.go +//go:generate go fmt query_string.nn.go +//go:generate go tool yacc -o query_string.y.go query_string.y +//go:generate sed -i "" -e 1d query_string.y.go + +package bleve + +import ( + "fmt" + "strings" +) + +var debugParser bool +var debugLexer bool + +func parseQuerySyntax(query string, mapping *IndexMapping) (rq Query, err error) { + lex := newLexerWrapper(newLexer(strings.NewReader(query))) + doParse(lex) + + if len(lex.errs) > 0 { + return nil, fmt.Errorf(strings.Join(lex.errs, "\n")) + } else { + return lex.query, nil + } +} + +func doParse(lex *lexerWrapper) { + defer func() { + r := recover() + if r != nil { + lex.Error("Errors while parsing.") + } + }() + + yyParse(lex) +} + +const ( + queryShould = iota + queryMust + queryMustNot +) + +type lexerWrapper struct { + nex yyLexer + errs []string + query *booleanQuery +} + +func newLexerWrapper(nex yyLexer) *lexerWrapper { + return &lexerWrapper{ + nex: nex, + errs: []string{}, + query: NewBooleanQuery(nil, nil, nil), + } +} + +func (this *lexerWrapper) Lex(lval *yySymType) int { + return this.nex.Lex(lval) +} + +func (this *lexerWrapper) Error(s string) { + this.errs = append(this.errs, s) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser_test.go new file mode 100644 index 00000000..a55efce6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_string_parser_test.go @@ -0,0 +1,247 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "reflect" + "testing" +) + +func TestQuerySyntaxParserValid(t *testing.T) { + tests := []struct { + input string + result Query + mapping *IndexMapping + }{ + { + input: "test", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("test"), + }, + nil), + }, + { + input: `"test phrase 1"`, + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchPhraseQuery("test phrase 1"), + }, + nil), + }, + { + input: "field:test", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("test").SetField("field"), + }, + nil), + }, + { + input: "+field1:test1", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + []Query{ + NewMatchQuery("test1").SetField("field1"), + }, + nil, + nil), + }, + { + input: "-field2:test2", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + nil, + []Query{ + NewMatchQuery("test2").SetField("field2"), + }), + }, + { + input: `field3:"test phrase 2"`, + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchPhraseQuery("test phrase 2").SetField("field3"), + }, + nil), + }, + { + input: `+field4:"test phrase 1"`, + mapping: NewIndexMapping(), + result: NewBooleanQuery( + []Query{ + NewMatchPhraseQuery("test phrase 1").SetField("field4"), + }, + nil, + nil), + }, + { + input: `-field5:"test phrase 2"`, + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + nil, + []Query{ + NewMatchPhraseQuery("test phrase 2").SetField("field5"), + }), + }, + { + input: `+field6:test3 -field7:test4 field8:test5`, + mapping: NewIndexMapping(), + result: NewBooleanQuery( + []Query{ + NewMatchQuery("test3").SetField("field6"), + }, + []Query{ + NewMatchQuery("test5").SetField("field8"), + }, + []Query{ + NewMatchQuery("test4").SetField("field7"), + }), + }, + { + input: "test^3", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("test").SetBoost(3.0), + }, + nil), + }, + { + input: "test^3 other^6", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("test").SetBoost(3.0), + NewMatchQuery("other").SetBoost(6.0), + }, + nil), + }, + { + input: "33", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("33"), + }, + nil), + }, + { + input: "field:33", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("33").SetField("field"), + }, + nil), + }, + { + input: "cat-dog", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("cat-dog"), + }, + nil), + }, + { + input: "watex~", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("watex").SetFuzziness(1), + }, + nil), + }, + { + input: "watex~2", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("watex").SetFuzziness(2), + }, + nil), + }, + { + input: "watex~ 2", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("watex").SetFuzziness(1), + NewMatchQuery("2"), + }, + nil), + }, + { + input: "field:watex~", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("watex").SetFuzziness(1).SetField("field"), + }, + nil), + }, + { + input: "field:watex~2", + mapping: NewIndexMapping(), + result: NewBooleanQuery( + nil, + []Query{ + NewMatchQuery("watex").SetFuzziness(2).SetField("field"), + }, + nil), + }, + } + + for _, test := range tests { + + q, err := parseQuerySyntax(test.input, test.mapping) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(q, test.result) { + t.Errorf("Expected %#v, got %#v: for %s", test.result, q, test.input) + } + } +} + +func TestQuerySyntaxParserInvalid(t *testing.T) { + tests := []struct { + input string + }{ + {"^"}, + {"^5"}, + } + + for _, test := range tests { + _, err := parseQuerySyntax(test.input, NewIndexMapping()) + if err == nil { + t.Errorf("expected error, got nil for `%s`", test.input) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_term.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_term.go new file mode 100644 index 00000000..50db0afe --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_term.go @@ -0,0 +1,61 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +type termQuery struct { + Term string `json:"term"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` +} + +// NewTermQuery creates a new Query for finding an +// exact term match in the index. +func NewTermQuery(term string) *termQuery { + return &termQuery{ + Term: term, + BoostVal: 1.0, + } +} + +func (q *termQuery) Boost() float64 { + return q.BoostVal +} + +func (q *termQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *termQuery) Field() string { + return q.FieldVal +} + +func (q *termQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *termQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + return searchers.NewTermSearcher(i, q.Term, field, q.BoostVal, explain) +} + +func (q *termQuery) Validate() error { + return nil +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_test.go new file mode 100644 index 00000000..df0f5a4d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_test.go @@ -0,0 +1,220 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "reflect" + "testing" +) + +var minNum = 5.1 +var maxNum = 7.1 +var startDate = "2011-01-01" +var endDate = "2012-01-01" + +func TestParseQuery(t *testing.T) { + tests := []struct { + input []byte + output Query + err error + }{ + { + input: []byte(`{"term":"water","field":"desc"}`), + output: NewTermQuery("water").SetField("desc"), + }, + { + input: []byte(`{"match":"beer","field":"desc"}`), + output: NewMatchQuery("beer").SetField("desc"), + }, + { + input: []byte(`{"match_phrase":"light beer","field":"desc"}`), + output: NewMatchPhraseQuery("light beer").SetField("desc"), + }, + { + input: []byte(`{"must":{"conjuncts": [{"match":"beer","field":"desc"}]},"should":{"disjuncts": [{"match":"water","field":"desc"}],"min":1.0},"must_not":{"disjuncts": [{"match":"devon","field":"desc"}]}}`), + output: NewBooleanQuery( + []Query{NewMatchQuery("beer").SetField("desc")}, + []Query{NewMatchQuery("water").SetField("desc")}, + []Query{NewMatchQuery("devon").SetField("desc")}), + }, + { + input: []byte(`{"terms":[{"term":"watered","field":"desc"},{"term":"down","field":"desc"}]}`), + output: NewPhraseQuery([]string{"watered", "down"}, "desc"), + }, + { + input: []byte(`{"query":"+beer \"light beer\" -devon"}`), + output: NewQueryStringQuery(`+beer "light beer" -devon`), + }, + { + input: []byte(`{"min":5.1,"max":7.1,"field":"desc"}`), + output: NewNumericRangeQuery(&minNum, &maxNum).SetField("desc"), + }, + { + input: []byte(`{"start":"` + startDate + `","end":"` + endDate + `","field":"desc"}`), + output: NewDateRangeQuery(&startDate, &endDate).SetField("desc"), + }, + { + input: []byte(`{"prefix":"budwei","field":"desc"}`), + output: NewPrefixQuery("budwei").SetField("desc"), + }, + { + input: []byte(`{"madeitup":"queryhere"}`), + output: nil, + err: ErrorUnknownQueryType, + }, + } + + for i, test := range tests { + actual, err := ParseQuery(test.input) + if err != nil && test.err == nil { + t.Errorf("error %v for %d", err, i) + } else if test.err != nil { + if !reflect.DeepEqual(err, test.err) { + t.Errorf("expected error: %#v, got: %#v", test.err, err) + } + } + + if !reflect.DeepEqual(test.output, actual) { + t.Errorf("expected: %#v, got: %#v", test.output, actual) + // t.Errorf("expected: %#v, got: %#v", test.output.(*BooleanQuery).Should, actual.(*BooleanQuery).Should) + } + } +} + +func TestSetGetField(t *testing.T) { + tests := []struct { + query Query + field string + }{ + { + query: NewTermQuery("water").SetField("desc"), + field: "desc", + }, + { + query: NewMatchQuery("beer").SetField("desc"), + field: "desc", + }, + { + query: NewMatchPhraseQuery("light beer").SetField("desc"), + field: "desc", + }, + { + query: NewNumericRangeQuery(&minNum, &maxNum).SetField("desc"), + field: "desc", + }, + { + query: NewDateRangeQuery(&startDate, &endDate).SetField("desc"), + field: "desc", + }, + { + query: NewPrefixQuery("budwei").SetField("desc"), + field: "desc", + }, + } + + for _, test := range tests { + query := test.query + if query.Field() != test.field { + t.Errorf("expected field '%s', got '%s'", test.field, query.Field()) + } + } +} + +func TestQueryValidate(t *testing.T) { + tests := []struct { + query Query + err error + }{ + { + query: NewTermQuery("water").SetField("desc"), + err: nil, + }, + { + query: NewMatchQuery("beer").SetField("desc"), + err: nil, + }, + { + query: NewMatchPhraseQuery("light beer").SetField("desc"), + err: nil, + }, + { + query: NewNumericRangeQuery(&minNum, &maxNum).SetField("desc"), + err: nil, + }, + { + query: NewNumericRangeQuery(nil, nil).SetField("desc"), + err: ErrorNumericQueryNoBounds, + }, + { + query: NewDateRangeQuery(&startDate, &endDate).SetField("desc"), + err: nil, + }, + { + query: NewPrefixQuery("budwei").SetField("desc"), + err: nil, + }, + { + query: NewQueryStringQuery(`+beer "light beer" -devon`), + err: nil, + }, + { + query: NewPhraseQuery([]string{"watered", "down"}, "desc"), + err: nil, + }, + { + query: NewPhraseQuery([]string{}, "field"), + err: ErrorPhraseQueryNoTerms, + }, + { + query: NewMatchNoneQuery().SetBoost(25), + err: nil, + }, + { + query: NewMatchAllQuery().SetBoost(25), + err: nil, + }, + { + query: NewBooleanQuery( + []Query{NewMatchQuery("beer").SetField("desc")}, + []Query{NewMatchQuery("water").SetField("desc")}, + []Query{NewMatchQuery("devon").SetField("desc")}), + err: nil, + }, + { + query: NewBooleanQuery( + nil, + nil, + []Query{NewMatchQuery("devon").SetField("desc")}), + err: ErrorBooleanQueryNeedsMustOrShould, + }, + { + query: NewBooleanQuery( + []Query{}, + []Query{}, + []Query{NewMatchQuery("devon").SetField("desc")}), + err: ErrorBooleanQueryNeedsMustOrShould, + }, + { + query: NewBooleanQueryMinShould( + []Query{NewMatchQuery("beer").SetField("desc")}, + []Query{NewMatchQuery("water").SetField("desc")}, + []Query{NewMatchQuery("devon").SetField("desc")}, + 2.0), + err: ErrorDisjunctionFewerThanMinClauses, + }, + } + + for _, test := range tests { + actual := test.query.Validate() + if !reflect.DeepEqual(actual, test.err) { + t.Errorf("expected error: %#v got %#v", test.err, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/query_wildcard.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_wildcard.go new file mode 100644 index 00000000..1ed6e67a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/query_wildcard.go @@ -0,0 +1,102 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "regexp" + "strings" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers" +) + +var wildcardRegexpReplacer = strings.NewReplacer( + // characters in the wildcard that must + // be escaped in the regexp + "+", `\+`, + "(", `\(`, + ")", `\)`, + "^", `\^`, + "$", `\$`, + ".", `\.`, + "{", `\{`, + "}", `\}`, + "[", `\[`, + "]", `\]`, + `|`, `\|`, + `\`, `\\`, + // wildcard characters + "*", ".*", + "?", ".") + +type wildcardQuery struct { + Wildcard string `json:"wildcard"` + FieldVal string `json:"field,omitempty"` + BoostVal float64 `json:"boost,omitempty"` + compiled *regexp.Regexp +} + +// NewWildcardQuery creates a new Query which finds +// documents containing terms that match the +// specified wildcard. In the wildcard pattern '*' +// will match any sequence of 0 or more characters, +// and '?' will match any single character. +func NewWildcardQuery(wildcard string) *wildcardQuery { + return &wildcardQuery{ + Wildcard: wildcard, + BoostVal: 1.0, + } +} + +func (q *wildcardQuery) Boost() float64 { + return q.BoostVal +} + +func (q *wildcardQuery) SetBoost(b float64) Query { + q.BoostVal = b + return q +} + +func (q *wildcardQuery) Field() string { + return q.FieldVal +} + +func (q *wildcardQuery) SetField(f string) Query { + q.FieldVal = f + return q +} + +func (q *wildcardQuery) Searcher(i index.IndexReader, m *IndexMapping, explain bool) (search.Searcher, error) { + field := q.FieldVal + if q.FieldVal == "" { + field = m.DefaultField + } + if q.compiled == nil { + var err error + q.compiled, err = q.convertToRegexp() + if err != nil { + return nil, err + } + } + + return searchers.NewRegexpSearcher(i, q.compiled, field, q.BoostVal, explain) +} + +func (q *wildcardQuery) Validate() error { + var err error + q.compiled, err = q.convertToRegexp() + return err +} + +func (q *wildcardQuery) convertToRegexp() (*regexp.Regexp, error) { + regexpString := "^" + wildcardRegexpReplacer.Replace(q.Wildcard) + "$" + return regexp.Compile(regexpString) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/reflect.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/reflect.go new file mode 100644 index 00000000..f299c912 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/reflect.go @@ -0,0 +1,79 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "reflect" + "strings" +) + +func lookupPropertyPath(data interface{}, path string) interface{} { + pathParts := decodePath(path) + + current := data + for _, part := range pathParts { + current = lookupProptyPathPart(current, part) + if current == nil { + break + } + } + + return current +} + +func lookupProptyPathPart(data interface{}, part string) interface{} { + val := reflect.ValueOf(data) + typ := val.Type() + switch typ.Kind() { + case reflect.Map: + // FIXME can add support for other map keys in the future + if typ.Key().Kind() == reflect.String { + key := reflect.ValueOf(part) + entry := val.MapIndex(key) + if entry.IsValid() { + return entry.Interface() + } + } + case reflect.Struct: + field := val.FieldByName(part) + if field.IsValid() && field.CanInterface() { + return field.Interface() + } + } + return nil +} + +const pathSeparator = "." + +func decodePath(path string) []string { + return strings.Split(path, pathSeparator) +} + +func encodePath(pathElements []string) string { + return strings.Join(pathElements, pathSeparator) +} + +func mustString(data interface{}) (string, bool) { + if data != nil { + str, ok := data.(string) + if ok { + return str, true + } + } + return "", false +} + +// parseJSONTagName extracts the JSON field name from a struct tag +func parseJSONTagName(tag string) string { + if idx := strings.Index(tag, ","); idx != -1 { + return tag[:idx] + } + return tag +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/analyzer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/analyzer.go new file mode 100644 index 00000000..4bd91a91 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/analyzer.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterAnalyzer(name string, constructor AnalyzerConstructor) { + _, exists := analyzers[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate analyzer named '%s'", name)) + } + analyzers[name] = constructor +} + +type AnalyzerConstructor func(config map[string]interface{}, cache *Cache) (*analysis.Analyzer, error) +type AnalyzerRegistry map[string]AnalyzerConstructor +type AnalyzerCache map[string]*analysis.Analyzer + +func (c AnalyzerCache) AnalyzerNamed(name string, cache *Cache) (*analysis.Analyzer, error) { + analyzer, cached := c[name] + if cached { + return analyzer, nil + } + analyzerConstructor, registered := analyzers[name] + if !registered { + return nil, fmt.Errorf("no analyzer with name or type '%s' registered", name) + } + analyzer, err := analyzerConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building analyzer: %v", err) + } + c[name] = analyzer + return analyzer, nil +} + +func (c AnalyzerCache) DefineAnalyzer(name string, typ string, config map[string]interface{}, cache *Cache) (*analysis.Analyzer, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("analyzer named '%s' already defined", name) + } + analyzerConstructor, registered := analyzers[typ] + if !registered { + return nil, fmt.Errorf("no analyzer type '%s' registered", typ) + } + analyzer, err := analyzerConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building analyzer: %v", err) + } + c[name] = analyzer + return analyzer, nil +} + +func AnalyzerTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range analyzers { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/byte_array_converter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/byte_array_converter.go new file mode 100644 index 00000000..0a0f4dd7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/byte_array_converter.go @@ -0,0 +1,47 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterByteArrayConverter(name string, constructor ByteArrayConverterConstructor) { + _, exists := byteArrayConverters[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate byte array converter named '%s'", name)) + } + byteArrayConverters[name] = constructor +} + +type ByteArrayConverterConstructor func(config map[string]interface{}, cache *Cache) (analysis.ByteArrayConverter, error) +type ByteArrayConverterRegistry map[string]ByteArrayConverterConstructor + +func ByteArrayConverterByName(name string) ByteArrayConverterConstructor { + return byteArrayConverters[name] +} + +func ByteArrayConverterTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range byteArrayConverters { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/char_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/char_filter.go new file mode 100644 index 00000000..fb796689 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/char_filter.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterCharFilter(name string, constructor CharFilterConstructor) { + _, exists := charFilters[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate char filter named '%s'", name)) + } + charFilters[name] = constructor +} + +type CharFilterConstructor func(config map[string]interface{}, cache *Cache) (analysis.CharFilter, error) +type CharFilterRegistry map[string]CharFilterConstructor +type CharFilterCache map[string]analysis.CharFilter + +func (c CharFilterCache) CharFilterNamed(name string, cache *Cache) (analysis.CharFilter, error) { + charFilter, cached := c[name] + if cached { + return charFilter, nil + } + charFilterConstructor, registered := charFilters[name] + if !registered { + return nil, fmt.Errorf("no char filter with name or type '%s' registered", name) + } + charFilter, err := charFilterConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building char filter: %v", err) + } + c[name] = charFilter + return charFilter, nil +} + +func (c CharFilterCache) DefineCharFilter(name string, typ string, config map[string]interface{}, cache *Cache) (analysis.CharFilter, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("char filter named '%s' already defined", name) + } + charFilterConstructor, registered := charFilters[typ] + if !registered { + return nil, fmt.Errorf("no char filter type '%s' registered", typ) + } + charFilter, err := charFilterConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building char filter: %v", err) + } + c[name] = charFilter + return charFilter, nil +} + +func CharFilterTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range charFilters { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/datetime_parser.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/datetime_parser.go new file mode 100644 index 00000000..ce1d358a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/datetime_parser.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterDateTimeParser(name string, constructor DateTimeParserConstructor) { + _, exists := dateTimeParsers[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate date time parser named '%s'", name)) + } + dateTimeParsers[name] = constructor +} + +type DateTimeParserConstructor func(config map[string]interface{}, cache *Cache) (analysis.DateTimeParser, error) +type DateTimeParserRegistry map[string]DateTimeParserConstructor +type DateTimeParserCache map[string]analysis.DateTimeParser + +func (c DateTimeParserCache) DateTimeParserNamed(name string, cache *Cache) (analysis.DateTimeParser, error) { + dateTimeParser, cached := c[name] + if cached { + return dateTimeParser, nil + } + dateTimeParserConstructor, registered := dateTimeParsers[name] + if !registered { + return nil, fmt.Errorf("no date time parser with name or type '%s' registered", name) + } + dateTimeParser, err := dateTimeParserConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building date time parse: %v", err) + } + c[name] = dateTimeParser + return dateTimeParser, nil +} + +func (c DateTimeParserCache) DefineDateTimeParser(name string, typ string, config map[string]interface{}, cache *Cache) (analysis.DateTimeParser, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("date time parser named '%s' already defined", name) + } + dateTimeParserConstructor, registered := dateTimeParsers[typ] + if !registered { + return nil, fmt.Errorf("no date time parser type '%s' registered", typ) + } + dateTimeParser, err := dateTimeParserConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building date time parser: %v", err) + } + c[name] = dateTimeParser + return dateTimeParser, nil +} + +func DateTimeParserTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range dateTimeParsers { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragment_formatter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragment_formatter.go new file mode 100644 index 00000000..4e7c6fa4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragment_formatter.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +func RegisterFragmentFormatter(name string, constructor FragmentFormatterConstructor) { + _, exists := fragmentFormatters[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate fragment formatter named '%s'", name)) + } + fragmentFormatters[name] = constructor +} + +type FragmentFormatterConstructor func(config map[string]interface{}, cache *Cache) (highlight.FragmentFormatter, error) +type FragmentFormatterRegistry map[string]FragmentFormatterConstructor +type FragmentFormatterCache map[string]highlight.FragmentFormatter + +func (c FragmentFormatterCache) FragmentFormatterNamed(name string, cache *Cache) (highlight.FragmentFormatter, error) { + fragmentFormatter, cached := c[name] + if cached { + return fragmentFormatter, nil + } + fragmentFormatterConstructor, registered := fragmentFormatters[name] + if !registered { + return nil, fmt.Errorf("no fragment formatter with name or type '%s' registered", name) + } + fragmentFormatter, err := fragmentFormatterConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building fragment formatter: %v", err) + } + c[name] = fragmentFormatter + return fragmentFormatter, nil +} + +func (c FragmentFormatterCache) DefineFragmentFormatter(name string, typ string, config map[string]interface{}, cache *Cache) (highlight.FragmentFormatter, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("fragment formatter named '%s' already defined", name) + } + fragmentFormatterConstructor, registered := fragmentFormatters[typ] + if !registered { + return nil, fmt.Errorf("no fragment formatter type '%s' registered", typ) + } + fragmentFormatter, err := fragmentFormatterConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building fragment formatter: %v", err) + } + c[name] = fragmentFormatter + return fragmentFormatter, nil +} + +func FragmentFormatterTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range fragmentFormatters { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragmenter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragmenter.go new file mode 100644 index 00000000..53b4892c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/fragmenter.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +func RegisterFragmenter(name string, constructor FragmenterConstructor) { + _, exists := fragmenters[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate fragmenter named '%s'", name)) + } + fragmenters[name] = constructor +} + +type FragmenterConstructor func(config map[string]interface{}, cache *Cache) (highlight.Fragmenter, error) +type FragmenterRegistry map[string]FragmenterConstructor +type FragmenterCache map[string]highlight.Fragmenter + +func (c FragmenterCache) FragmenterNamed(name string, cache *Cache) (highlight.Fragmenter, error) { + fragmenter, cached := c[name] + if cached { + return fragmenter, nil + } + fragmenterConstructor, registered := fragmenters[name] + if !registered { + return nil, fmt.Errorf("no fragmenter with name or type '%s' registered", name) + } + fragmenter, err := fragmenterConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building fragmenter: %v", err) + } + c[name] = fragmenter + return fragmenter, nil +} + +func (c FragmenterCache) DefineFragmenter(name string, typ string, config map[string]interface{}, cache *Cache) (highlight.Fragmenter, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("fragmenter named '%s' already defined", name) + } + fragmenterConstructor, registered := fragmenters[typ] + if !registered { + return nil, fmt.Errorf("no fragmenter type '%s' registered", typ) + } + fragmenter, err := fragmenterConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building fragmenter: %v", err) + } + c[name] = fragmenter + return fragmenter, nil +} + +func FragmenterTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range fragmenters { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/highlighter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/highlighter.go new file mode 100644 index 00000000..ce641762 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/highlighter.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +func RegisterHighlighter(name string, constructor HighlighterConstructor) { + _, exists := highlighters[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate highlighter named '%s'", name)) + } + highlighters[name] = constructor +} + +type HighlighterConstructor func(config map[string]interface{}, cache *Cache) (highlight.Highlighter, error) +type HighlighterRegistry map[string]HighlighterConstructor +type HighlighterCache map[string]highlight.Highlighter + +func (c HighlighterCache) HighlighterNamed(name string, cache *Cache) (highlight.Highlighter, error) { + highlighter, cached := c[name] + if cached { + return highlighter, nil + } + highlighterConstructor, registered := highlighters[name] + if !registered { + return nil, fmt.Errorf("no highlighter with name or type '%s' registered", name) + } + highlighter, err := highlighterConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building highlighter: %v", err) + } + c[name] = highlighter + return highlighter, nil +} + +func (c HighlighterCache) DefineHighlighter(name string, typ string, config map[string]interface{}, cache *Cache) (highlight.Highlighter, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("highlighter named '%s' already defined", name) + } + highlighterConstructor, registered := highlighters[typ] + if !registered { + return nil, fmt.Errorf("no highlighter type '%s' registered", typ) + } + highlighter, err := highlighterConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building highlighter: %v", err) + } + c[name] = highlighter + return highlighter, nil +} + +func HighlighterTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range highlighters { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/registry.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/registry.go new file mode 100644 index 00000000..999f9b12 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/registry.go @@ -0,0 +1,176 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +var stores = make(KVStoreRegistry, 0) + +var byteArrayConverters = make(ByteArrayConverterRegistry, 0) + +// highlight +var fragmentFormatters = make(FragmentFormatterRegistry, 0) +var fragmenters = make(FragmenterRegistry, 0) +var highlighters = make(HighlighterRegistry, 0) + +// analysis +var charFilters = make(CharFilterRegistry, 0) +var tokenizers = make(TokenizerRegistry, 0) +var tokenMaps = make(TokenMapRegistry, 0) +var tokenFilters = make(TokenFilterRegistry, 0) +var analyzers = make(AnalyzerRegistry, 0) +var dateTimeParsers = make(DateTimeParserRegistry, 0) + +type Cache struct { + CharFilters CharFilterCache + Tokenizers TokenizerCache + TokenMaps TokenMapCache + TokenFilters TokenFilterCache + Analyzers AnalyzerCache + DateTimeParsers DateTimeParserCache + FragmentFormatters FragmentFormatterCache + Fragmenters FragmenterCache + Highlighters HighlighterCache +} + +func NewCache() *Cache { + return &Cache{ + CharFilters: make(CharFilterCache, 0), + Tokenizers: make(TokenizerCache, 0), + TokenMaps: make(TokenMapCache, 0), + TokenFilters: make(TokenFilterCache, 0), + Analyzers: make(AnalyzerCache, 0), + DateTimeParsers: make(DateTimeParserCache, 0), + FragmentFormatters: make(FragmentFormatterCache, 0), + Fragmenters: make(FragmenterCache, 0), + Highlighters: make(HighlighterCache, 0), + } +} + +func typeFromConfig(config map[string]interface{}) (string, error) { + typ, ok := config["type"].(string) + if ok { + return typ, nil + } + return "", fmt.Errorf("unable to determine type") +} + +func (c *Cache) CharFilterNamed(name string) (analysis.CharFilter, error) { + return c.CharFilters.CharFilterNamed(name, c) +} + +func (c *Cache) DefineCharFilter(name string, config map[string]interface{}) (analysis.CharFilter, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.CharFilters.DefineCharFilter(name, typ, config, c) +} + +func (c *Cache) TokenizerNamed(name string) (analysis.Tokenizer, error) { + return c.Tokenizers.TokenizerNamed(name, c) +} + +func (c *Cache) DefineTokenizer(name string, config map[string]interface{}) (analysis.Tokenizer, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.Tokenizers.DefineTokenizer(name, typ, config, c) +} + +func (c *Cache) TokenMapNamed(name string) (analysis.TokenMap, error) { + return c.TokenMaps.TokenMapNamed(name, c) +} + +func (c *Cache) DefineTokenMap(name string, config map[string]interface{}) (analysis.TokenMap, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.TokenMaps.DefineTokenMap(name, typ, config, c) +} + +func (c *Cache) TokenFilterNamed(name string) (analysis.TokenFilter, error) { + return c.TokenFilters.TokenFilterNamed(name, c) +} + +func (c *Cache) DefineTokenFilter(name string, config map[string]interface{}) (analysis.TokenFilter, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.TokenFilters.DefineTokenFilter(name, typ, config, c) +} + +func (c *Cache) AnalyzerNamed(name string) (*analysis.Analyzer, error) { + return c.Analyzers.AnalyzerNamed(name, c) +} + +func (c *Cache) DefineAnalyzer(name string, config map[string]interface{}) (*analysis.Analyzer, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.Analyzers.DefineAnalyzer(name, typ, config, c) +} + +func (c *Cache) DateTimeParserNamed(name string) (analysis.DateTimeParser, error) { + return c.DateTimeParsers.DateTimeParserNamed(name, c) +} + +func (c *Cache) DefineDateTimeParser(name string, config map[string]interface{}) (analysis.DateTimeParser, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.DateTimeParsers.DefineDateTimeParser(name, typ, config, c) +} + +func (c *Cache) FragmentFormatterNamed(name string) (highlight.FragmentFormatter, error) { + return c.FragmentFormatters.FragmentFormatterNamed(name, c) +} + +func (c *Cache) DefineFragmentFormatter(name string, config map[string]interface{}) (highlight.FragmentFormatter, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.FragmentFormatters.DefineFragmentFormatter(name, typ, config, c) +} + +func (c *Cache) FragmenterNamed(name string) (highlight.Fragmenter, error) { + return c.Fragmenters.FragmenterNamed(name, c) +} + +func (c *Cache) DefineFragmenter(name string, config map[string]interface{}) (highlight.Fragmenter, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.Fragmenters.DefineFragmenter(name, typ, config, c) +} + +func (c *Cache) HighlighterNamed(name string) (highlight.Highlighter, error) { + return c.Highlighters.HighlighterNamed(name, c) +} + +func (c *Cache) DefineHighlighter(name string, config map[string]interface{}) (highlight.Highlighter, error) { + typ, err := typeFromConfig(config) + if err != nil { + return nil, err + } + return c.Highlighters.DefineHighlighter(name, typ, config, c) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/store.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/store.go new file mode 100644 index 00000000..51c4c23c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/store.go @@ -0,0 +1,46 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store" +) + +func RegisterKVStore(name string, constructor KVStoreConstructor) { + _, exists := stores[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate store named '%s'", name)) + } + stores[name] = constructor +} + +type KVStoreConstructor func(config map[string]interface{}) (store.KVStore, error) +type KVStoreRegistry map[string]KVStoreConstructor + +func KVStoreConstructorByName(name string) KVStoreConstructor { + return stores[name] +} + +func KVStoreTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range stores { + _, err := cons(emptyConfig) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_filter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_filter.go new file mode 100644 index 00000000..b75a49ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_filter.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterTokenFilter(name string, constructor TokenFilterConstructor) { + _, exists := tokenFilters[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate token filter named '%s'", name)) + } + tokenFilters[name] = constructor +} + +type TokenFilterConstructor func(config map[string]interface{}, cache *Cache) (analysis.TokenFilter, error) +type TokenFilterRegistry map[string]TokenFilterConstructor +type TokenFilterCache map[string]analysis.TokenFilter + +func (c TokenFilterCache) TokenFilterNamed(name string, cache *Cache) (analysis.TokenFilter, error) { + tokenFilter, cached := c[name] + if cached { + return tokenFilter, nil + } + tokenFilterConstructor, registered := tokenFilters[name] + if !registered { + return nil, fmt.Errorf("no token filter with name or type '%s' registered", name) + } + tokenFilter, err := tokenFilterConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building token filter: %v", err) + } + c[name] = tokenFilter + return tokenFilter, nil +} + +func (c TokenFilterCache) DefineTokenFilter(name string, typ string, config map[string]interface{}, cache *Cache) (analysis.TokenFilter, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("token filter named '%s' already defined", name) + } + tokenFilterConstructor, registered := tokenFilters[typ] + if !registered { + return nil, fmt.Errorf("no token filter type '%s' registered", typ) + } + tokenFilter, err := tokenFilterConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building token filter: %v", err) + } + c[name] = tokenFilter + return tokenFilter, nil +} + +func TokenFilterTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range tokenFilters { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_maps.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_maps.go new file mode 100644 index 00000000..97922c45 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/token_maps.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterTokenMap(name string, constructor TokenMapConstructor) { + _, exists := tokenMaps[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate token map named '%s'", name)) + } + tokenMaps[name] = constructor +} + +type TokenMapConstructor func(config map[string]interface{}, cache *Cache) (analysis.TokenMap, error) +type TokenMapRegistry map[string]TokenMapConstructor +type TokenMapCache map[string]analysis.TokenMap + +func (c TokenMapCache) TokenMapNamed(name string, cache *Cache) (analysis.TokenMap, error) { + tokenMap, cached := c[name] + if cached { + return tokenMap, nil + } + tokenMapConstructor, registered := tokenMaps[name] + if !registered { + return nil, fmt.Errorf("no token map with name or type '%s' registered", name) + } + tokenMap, err := tokenMapConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building token map: %v", err) + } + c[name] = tokenMap + return tokenMap, nil +} + +func (c TokenMapCache) DefineTokenMap(name string, typ string, config map[string]interface{}, cache *Cache) (analysis.TokenMap, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("token map named '%s' already defined", name) + } + tokenMapConstructor, registered := tokenMaps[typ] + if !registered { + return nil, fmt.Errorf("no token map type '%s' registered", typ) + } + tokenMap, err := tokenMapConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building token map: %v", err) + } + c[name] = tokenMap + return tokenMap, nil +} + +func TokenMapTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range tokenMaps { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/tokenizer.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/tokenizer.go new file mode 100644 index 00000000..ed148566 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/registry/tokenizer.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package registry + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" +) + +func RegisterTokenizer(name string, constructor TokenizerConstructor) { + _, exists := tokenizers[name] + if exists { + panic(fmt.Errorf("attempted to register duplicate tokenizer named '%s'", name)) + } + tokenizers[name] = constructor +} + +type TokenizerConstructor func(config map[string]interface{}, cache *Cache) (analysis.Tokenizer, error) +type TokenizerRegistry map[string]TokenizerConstructor +type TokenizerCache map[string]analysis.Tokenizer + +func (c TokenizerCache) TokenizerNamed(name string, cache *Cache) (analysis.Tokenizer, error) { + tokenizer, cached := c[name] + if cached { + return tokenizer, nil + } + tokenizerConstructor, registered := tokenizers[name] + if !registered { + return nil, fmt.Errorf("no tokenizer with name or type '%s' registered", name) + } + tokenizer, err := tokenizerConstructor(nil, cache) + if err != nil { + return nil, fmt.Errorf("error building tokenizer: %v", err) + } + c[name] = tokenizer + return tokenizer, nil +} + +func (c TokenizerCache) DefineTokenizer(name string, typ string, config map[string]interface{}, cache *Cache) (analysis.Tokenizer, error) { + _, cached := c[name] + if cached { + return nil, fmt.Errorf("tokenizer named '%s' already defined", name) + } + tokenizerConstructor, registered := tokenizers[typ] + if !registered { + return nil, fmt.Errorf("no tokenizer type '%s' registered", typ) + } + tokenizer, err := tokenizerConstructor(config, cache) + if err != nil { + return nil, fmt.Errorf("error building tokenizer: %v", err) + } + c[name] = tokenizer + return tokenizer, nil +} + +func TokenizerTypesAndInstances() ([]string, []string) { + emptyConfig := map[string]interface{}{} + emptyCache := NewCache() + types := make([]string, 0) + instances := make([]string, 0) + for name, cons := range tokenizers { + _, err := cons(emptyConfig, emptyCache) + if err == nil { + instances = append(instances, name) + } else { + types = append(types, name) + } + } + return types, instances +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search.go new file mode 100644 index 00000000..aa5c1b79 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search.go @@ -0,0 +1,297 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type numericRange struct { + Name string `json:"name,omitempty"` + Min *float64 `json:"min,omitempty"` + Max *float64 `json:"max,omitempty"` +} + +type dateTimeRange struct { + Name string `json:"name,omitempty"` + Start time.Time `json:"start,omitempty"` + End time.Time `json:"end,omitempty"` + startString *string + endString *string +} + +func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) { + if dr.Start.IsZero() && dr.startString != nil { + start, err := dateTimeParser.ParseDateTime(*dr.startString) + if err == nil { + dr.Start = start + } + } + if dr.End.IsZero() && dr.endString != nil { + end, err := dateTimeParser.ParseDateTime(*dr.endString) + if err == nil { + dr.End = end + } + } +} + +func (dr *dateTimeRange) UnmarshalJSON(input []byte) error { + var temp struct { + Name string `json:"name,omitempty"` + Start *string `json:"start,omitempty"` + End *string `json:"end,omitempty"` + } + + err := json.Unmarshal(input, &temp) + if err != nil { + return err + } + + dr.Name = temp.Name + if temp.Start != nil { + dr.startString = temp.Start + } + if temp.End != nil { + dr.endString = temp.End + } + + return nil +} + +// A FacetRequest describes a facet or aggregation +// of the result document set you would like to be +// built. +type FacetRequest struct { + Size int `json:"size"` + Field string `json:"field"` + NumericRanges []*numericRange `json:"numeric_ranges,omitempty"` + DateTimeRanges []*dateTimeRange `json:"date_ranges,omitempty"` +} + +// NewFacetRequest creates a facet on the specified +// field that limits the number of entries to the +// specified size. +func NewFacetRequest(field string, size int) *FacetRequest { + return &FacetRequest{ + Field: field, + Size: size, + } +} + +// AddDateTimeRange adds a bucket to a field +// containing date values. Documents with a +// date value falling into this range are tabulated +// as part of this bucket/range. +func (fr *FacetRequest) AddDateTimeRange(name string, start, end time.Time) { + if fr.DateTimeRanges == nil { + fr.DateTimeRanges = make([]*dateTimeRange, 0, 1) + } + fr.DateTimeRanges = append(fr.DateTimeRanges, &dateTimeRange{Name: name, Start: start, End: end}) +} + +// AddNumericRange adds a bucket to a field +// containing numeric values. Documents with a +// numeric value falling into this range are +// tabulated as part of this bucket/range. +func (fr *FacetRequest) AddNumericRange(name string, min, max *float64) { + if fr.NumericRanges == nil { + fr.NumericRanges = make([]*numericRange, 0, 1) + } + fr.NumericRanges = append(fr.NumericRanges, &numericRange{Name: name, Min: min, Max: max}) +} + +// FacetsRequest groups together all the +// FacetRequest objects for a single query. +type FacetsRequest map[string]*FacetRequest + +// HighlightRequest describes how field matches +// should be highlighted. +type HighlightRequest struct { + Style *string `json:"style"` + Fields []string `json:"fields"` +} + +// NewHighlight creates a default +// HighlightRequest. +func NewHighlight() *HighlightRequest { + return &HighlightRequest{} +} + +// NewHighlightWithStyle creates a HighlightRequest +// with an alternate style. +func NewHighlightWithStyle(style string) *HighlightRequest { + return &HighlightRequest{ + Style: &style, + } +} + +func (h *HighlightRequest) AddField(field string) { + if h.Fields == nil { + h.Fields = make([]string, 0, 1) + } + h.Fields = append(h.Fields, field) +} + +// A SearchRequest describes all the parameters +// needed to search the index. +// Query is required. +// Size/From describe how much and which part of the +// result set to return. +// Highlight describes optional search result +// highlighting. +// Fields describes a list of field values which +// should be retrieved for result documents. +// Facets describe the set of facets to be computed. +// Explain triggers inclusion of additional search +// result score explanations. +// +// A special field named "*" can be used to return all fields. +type SearchRequest struct { + Query Query `json:"query"` + Size int `json:"size"` + From int `json:"from"` + Highlight *HighlightRequest `json:"highlight"` + Fields []string `json:"fields"` + Facets FacetsRequest `json:"facets"` + Explain bool `json:"explain"` +} + +// AddFacet adds a FacetRequest to this SearchRequest +func (r *SearchRequest) AddFacet(facetName string, f *FacetRequest) { + if r.Facets == nil { + r.Facets = make(FacetsRequest, 1) + } + r.Facets[facetName] = f +} + +// UnmarshalJSON deserializes a JSON representation of +// a SearchRequest +func (r *SearchRequest) UnmarshalJSON(input []byte) error { + var temp struct { + Q json.RawMessage `json:"query"` + Size int `json:"size"` + From int `json:"from"` + Highlight *HighlightRequest `json:"highlight"` + Fields []string `json:"fields"` + Facets FacetsRequest `json:"facets"` + Explain bool `json:"explain"` + } + + err := json.Unmarshal(input, &temp) + if err != nil { + return err + } + + r.Size = temp.Size + r.From = temp.From + r.Explain = temp.Explain + r.Highlight = temp.Highlight + r.Fields = temp.Fields + r.Facets = temp.Facets + r.Query, err = ParseQuery(temp.Q) + if err != nil { + return err + } + + if r.Size < 0 { + r.Size = 10 + } + if r.From < 0 { + r.From = 0 + } + + return nil + +} + +// NewSearchRequest creates a new SearchRequest +// for the Query, using default values for all +// other search parameters. +func NewSearchRequest(q Query) *SearchRequest { + return NewSearchRequestOptions(q, 10, 0, false) +} + +// NewSearchRequestOptions creates a new SearchRequest +// for the Query, with the requested size, from +// and explanation search parameters. +func NewSearchRequestOptions(q Query, size, from int, explain bool) *SearchRequest { + return &SearchRequest{ + Query: q, + Size: size, + From: from, + Explain: explain, + } +} + +// A SearchResult describes the results of executing +// a SearchRequest. +type SearchResult struct { + Request *SearchRequest `json:"request"` + Hits search.DocumentMatchCollection `json:"hits"` + Total uint64 `json:"total_hits"` + MaxScore float64 `json:"max_score"` + Took time.Duration `json:"took"` + Facets search.FacetResults `json:"facets"` +} + +func (sr *SearchResult) String() string { + rv := "" + if sr.Total > 0 { + if sr.Request.Size > 0 { + rv = fmt.Sprintf("%d matches, showing %d through %d, took %s\n", sr.Total, sr.Request.From+1, sr.Request.From+len(sr.Hits), sr.Took) + for i, hit := range sr.Hits { + rv += fmt.Sprintf("%5d. %s (%f)\n", i+sr.Request.From+1, hit.ID, hit.Score) + for fragmentField, fragments := range hit.Fragments { + rv += fmt.Sprintf("\t%s\n", fragmentField) + for _, fragment := range fragments { + rv += fmt.Sprintf("\t\t%s\n", fragment) + } + } + for otherFieldName, otherFieldValue := range hit.Fields { + if _, ok := hit.Fragments[otherFieldName]; !ok { + rv += fmt.Sprintf("\t%s\n", otherFieldName) + rv += fmt.Sprintf("\t\t%v\n", otherFieldValue) + } + } + } + } else { + rv = fmt.Sprintf("%d matches, took %s\n", sr.Total, sr.Took) + } + } else { + rv = "No matches" + } + if len(sr.Facets) > 0 { + rv += fmt.Sprintf("Facets:\n") + for fn, f := range sr.Facets { + rv += fmt.Sprintf("%s(%d)\n", fn, f.Total) + for _, t := range f.Terms { + rv += fmt.Sprintf("\t%s(%d)\n", t.Term, t.Count) + } + if f.Other != 0 { + rv += fmt.Sprintf("\tOther(%d)\n", f.Other) + } + } + } + return rv +} + +func (sr *SearchResult) Merge(other *SearchResult) { + sr.Hits = append(sr.Hits, other.Hits...) + sr.Total += other.Total + if other.MaxScore > sr.MaxScore { + sr.MaxScore = other.MaxScore + } + sr.Facets.Merge(other.Facets) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collector.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collector.go new file mode 100644 index 00000000..86e901af --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collector.go @@ -0,0 +1,24 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +import ( + "time" +) + +type Collector interface { + Collect(searcher Searcher) error + Results() DocumentMatchCollection + Total() uint64 + MaxScore() float64 + Took() time.Duration + SetFacetsBuilder(facetsBuilder *FacetsBuilder) + FacetResults() FacetResults +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score.go new file mode 100644 index 00000000..b87ed515 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score.go @@ -0,0 +1,135 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package collectors + +import ( + "container/list" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type TopScoreCollector struct { + k int + skip int + results *list.List + took time.Duration + maxScore float64 + total uint64 + facetsBuilder *search.FacetsBuilder +} + +func NewTopScorerCollector(k int) *TopScoreCollector { + return &TopScoreCollector{ + k: k, + skip: 0, + results: list.New(), + } +} + +func NewTopScorerSkipCollector(k, skip int) *TopScoreCollector { + return &TopScoreCollector{ + k: k, + skip: skip, + results: list.New(), + } +} + +func (tksc *TopScoreCollector) Total() uint64 { + return tksc.total +} + +func (tksc *TopScoreCollector) MaxScore() float64 { + return tksc.maxScore +} + +func (tksc *TopScoreCollector) Took() time.Duration { + return tksc.took +} + +func (tksc *TopScoreCollector) Collect(searcher search.Searcher) error { + startTime := time.Now() + next, err := searcher.Next() + for err == nil && next != nil { + tksc.collectSingle(next) + if tksc.facetsBuilder != nil { + err = tksc.facetsBuilder.Update(next) + if err != nil { + break + } + } + next, err = searcher.Next() + } + // compute search duration + tksc.took = time.Since(startTime) + if err != nil { + return err + } + return nil +} + +func (tksc *TopScoreCollector) collectSingle(dm *search.DocumentMatch) { + // increment total hits + tksc.total++ + + // update max score + if dm.Score > tksc.maxScore { + tksc.maxScore = dm.Score + } + + for e := tksc.results.Front(); e != nil; e = e.Next() { + curr := e.Value.(*search.DocumentMatch) + if dm.Score < curr.Score { + + tksc.results.InsertBefore(dm, e) + // if we just made the list too long + if tksc.results.Len() > (tksc.k + tksc.skip) { + // remove the head + tksc.results.Remove(tksc.results.Front()) + } + return + } + } + // if we got to the end, we still have to add it + tksc.results.PushBack(dm) + if tksc.results.Len() > (tksc.k + tksc.skip) { + // remove the head + tksc.results.Remove(tksc.results.Front()) + } +} + +func (tksc *TopScoreCollector) Results() search.DocumentMatchCollection { + if tksc.results.Len()-tksc.skip > 0 { + rv := make(search.DocumentMatchCollection, tksc.results.Len()-tksc.skip) + i := 0 + skipped := 0 + for e := tksc.results.Back(); e != nil; e = e.Prev() { + if skipped < tksc.skip { + skipped++ + continue + } + rv[i] = e.Value.(*search.DocumentMatch) + i++ + } + return rv + } + return search.DocumentMatchCollection{} +} + +func (tksc *TopScoreCollector) SetFacetsBuilder(facetsBuilder *search.FacetsBuilder) { + tksc.facetsBuilder = facetsBuilder +} + +func (tksc *TopScoreCollector) FacetResults() search.FacetResults { + if tksc.facetsBuilder != nil { + return tksc.facetsBuilder.Results() + } + return search.FacetResults{} +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score_test.go new file mode 100644 index 00000000..055a299e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/collector_top_score_test.go @@ -0,0 +1,249 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package collectors + +import ( + "math/rand" + "strconv" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestTop10Scores(t *testing.T) { + + // a stub search with more than 10 matches + // the top-10 scores are > 10 + // everything else is less than 10 + searcher := &stubSearcher{ + matches: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 11, + }, + &search.DocumentMatch{ + ID: "b", + Score: 9, + }, + &search.DocumentMatch{ + ID: "c", + Score: 11, + }, + &search.DocumentMatch{ + ID: "d", + Score: 9, + }, + &search.DocumentMatch{ + ID: "e", + Score: 11, + }, + &search.DocumentMatch{ + ID: "f", + Score: 9, + }, + &search.DocumentMatch{ + ID: "g", + Score: 11, + }, + &search.DocumentMatch{ + ID: "h", + Score: 9, + }, + &search.DocumentMatch{ + ID: "i", + Score: 11, + }, + &search.DocumentMatch{ + ID: "j", + Score: 11, + }, + &search.DocumentMatch{ + ID: "k", + Score: 11, + }, + &search.DocumentMatch{ + ID: "l", + Score: 99, + }, + &search.DocumentMatch{ + ID: "m", + Score: 11, + }, + &search.DocumentMatch{ + ID: "n", + Score: 11, + }, + }, + } + + collector := NewTopScorerCollector(10) + err := collector.Collect(searcher) + if err != nil { + t.Fatal(err) + } + + maxScore := collector.MaxScore() + if maxScore != 99.0 { + t.Errorf("expected max score 99.0, got %f", maxScore) + } + + total := collector.Total() + if total != 14 { + t.Errorf("expected 14 total results, got %d", total) + } + + results := collector.Results() + + if len(results) != 10 { + t.Fatalf("expected 10 results, got %d", len(results)) + } + + if results[0].ID != "l" { + t.Errorf("expected first result to have ID 'l', got %s", results[0].ID) + } + + if results[0].Score != 99.0 { + t.Errorf("expected highest score to be 99.0, got %f", results[0].Score) + } + + minScore := 1000.0 + for _, result := range results { + if result.Score < minScore { + minScore = result.Score + } + } + + if minScore < 10 { + t.Errorf("expected minimum score to be higher than 10, got %f", minScore) + } +} + +func TestTop10ScoresSkip10(t *testing.T) { + + // a stub search with more than 10 matches + // the top-10 scores are > 10 + // everything else is less than 10 + searcher := &stubSearcher{ + matches: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 11, + }, + &search.DocumentMatch{ + ID: "b", + Score: 9.5, + }, + &search.DocumentMatch{ + ID: "c", + Score: 11, + }, + &search.DocumentMatch{ + ID: "d", + Score: 9, + }, + &search.DocumentMatch{ + ID: "e", + Score: 11, + }, + &search.DocumentMatch{ + ID: "f", + Score: 9, + }, + &search.DocumentMatch{ + ID: "g", + Score: 11, + }, + &search.DocumentMatch{ + ID: "h", + Score: 9, + }, + &search.DocumentMatch{ + ID: "i", + Score: 11, + }, + &search.DocumentMatch{ + ID: "j", + Score: 11, + }, + &search.DocumentMatch{ + ID: "k", + Score: 11, + }, + &search.DocumentMatch{ + ID: "l", + Score: 99, + }, + &search.DocumentMatch{ + ID: "m", + Score: 11, + }, + &search.DocumentMatch{ + ID: "n", + Score: 11, + }, + }, + } + + collector := NewTopScorerSkipCollector(10, 10) + err := collector.Collect(searcher) + if err != nil { + t.Fatal(err) + } + + maxScore := collector.MaxScore() + if maxScore != 99.0 { + t.Errorf("expected max score 99.0, got %f", maxScore) + } + + total := collector.Total() + if total != 14 { + t.Errorf("expected 14 total results, got %d", total) + } + + results := collector.Results() + + if len(results) != 4 { + t.Fatalf("expected 4 results, got %d", len(results)) + } + + if results[0].ID != "b" { + t.Errorf("expected first result to have ID 'b', got %s", results[0].ID) + } + + if results[0].Score != 9.5 { + t.Errorf("expected highest score to be 9.5ß, got %f", results[0].Score) + } +} + +func BenchmarkTop10of100000Scores(b *testing.B) { + + matches := make(search.DocumentMatchCollection, 0, 100000) + for i := 0; i < 100000; i++ { + matches = append(matches, &search.DocumentMatch{ + ID: strconv.Itoa(i), + Score: rand.Float64(), + }) + } + searcher := &stubSearcher{ + matches: matches, + } + + collector := NewTopScorerCollector(10) + b.ResetTimer() + + err := collector.Collect(searcher) + if err != nil { + b.Fatal(err) + } + res := collector.Results() + for _, dm := range res { + b.Logf("%s - %f\n", dm.ID, dm.Score) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/search_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/search_test.go new file mode 100644 index 00000000..ecd2fdce --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/collectors/search_test.go @@ -0,0 +1,60 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package collectors + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type stubSearcher struct { + index int + matches search.DocumentMatchCollection +} + +func (ss *stubSearcher) Next() (*search.DocumentMatch, error) { + if ss.index < len(ss.matches) { + rv := ss.matches[ss.index] + ss.index++ + return rv, nil + } + return nil, nil +} + +func (ss *stubSearcher) Advance(ID string) (*search.DocumentMatch, error) { + + for ss.index < len(ss.matches) && ss.matches[ss.index].ID < ID { + ss.index++ + } + if ss.index < len(ss.matches) { + rv := ss.matches[ss.index] + ss.index++ + return rv, nil + } + return nil, nil +} + +func (ss *stubSearcher) Close() error { + return nil +} + +func (ss *stubSearcher) Weight() float64 { + return 0.0 +} + +func (ss *stubSearcher) SetQueryNorm(float64) { +} + +func (ss *stubSearcher) Count() uint64 { + return uint64(len(ss.matches)) +} + +func (ss *stubSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/explanation.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/explanation.go new file mode 100644 index 00000000..fe2d5870 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/explanation.go @@ -0,0 +1,29 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +import ( + "encoding/json" + "fmt" +) + +type Explanation struct { + Value float64 `json:"value"` + Message string `json:"message"` + Children []*Explanation `json:"children,omitempty"` +} + +func (expl *Explanation) String() string { + js, err := json.MarshalIndent(expl, "", " ") + if err != nil { + return fmt.Sprintf("error serializing explanation to json: %v", err) + } + return string(js) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/benchmark_data.txt b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/benchmark_data.txt new file mode 100644 index 00000000..b012f78c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/benchmark_data.txt @@ -0,0 +1,2909 @@ +Boiling liquid expanding vapor explosion +From Wikipedia, the free encyclopedia +See also: Boiler explosion and Steam explosion + +Flames subsequent to a flammable liquid BLEVE from a tanker. BLEVEs do not necessarily involve fire. + +This article's tone or style may not reflect the encyclopedic tone used on Wikipedia. See Wikipedia's guide to writing better articles for suggestions. (July 2013) +A boiling liquid expanding vapor explosion (BLEVE, /ˈblɛviː/ blev-ee) is an explosion caused by the rupture of a vessel containing a pressurized liquid above its boiling point.[1] +Contents [hide] +1 Mechanism +1.1 Water example +1.2 BLEVEs without chemical reactions +2 Fires +3 Incidents +4 Safety measures +5 See also +6 References +7 External links +Mechanism[edit] + +This section needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed. (July 2013) +There are three characteristics of liquids which are relevant to the discussion of a BLEVE: +If a liquid in a sealed container is boiled, the pressure inside the container increases. As the liquid changes to a gas it expands - this expansion in a vented container would cause the gas and liquid to take up more space. In a sealed container the gas and liquid are not able to take up more space and so the pressure rises. Pressurized vessels containing liquids can reach an equilibrium where the liquid stops boiling and the pressure stops rising. This occurs when no more heat is being added to the system (either because it has reached ambient temperature or has had a heat source removed). +The boiling temperature of a liquid is dependent on pressure - high pressures will yield high boiling temperatures, and low pressures will yield low boiling temperatures. A common simple experiment is to place a cup of water in a vacuum chamber, and then reduce the pressure in the chamber until the water boils. By reducing the pressure the water will boil even at room temperature. This works both ways - if the pressure is increased beyond normal atmospheric pressures, the boiling of hot water could be suppressed far beyond normal temperatures. The cooling system of a modern internal combustion engine is a real-world example. +When a liquid boils it turns into a gas. The resulting gas takes up far more space than the liquid did. +Typically, a BLEVE starts with a container of liquid which is held above its normal, atmospheric-pressure boiling temperature. Many substances normally stored as liquids, such as CO2, oxygen, and other similar industrial gases have boiling temperatures, at atmospheric pressure, far below room temperature. In the case of water, a BLEVE could occur if a pressurized chamber of water is heated far beyond the standard 100 °C (212 °F). That container, because the boiling water pressurizes it, is capable of holding liquid water at very high temperatures. +If the pressurized vessel, containing liquid at high temperature (which may be room temperature, depending on the substance) ruptures, the pressure which prevents the liquid from boiling is lost. If the rupture is catastrophic, where the vessel is immediately incapable of holding any pressure at all, then there suddenly exists a large mass of liquid which is at very high temperature and very low pressure. This causes the entire volume of liquid to instantaneously boil, which in turn causes an extremely rapid expansion. Depending on temperatures, pressures and the substance involved, that expansion may be so rapid that it can be classified as an explosion, fully capable of inflicting severe damage on its surroundings. +Water example[edit] +Imagine, for example, a tank of pressurized liquid water held at 204.4 °C (400 °F). This vessel would normally be pressurized to 1.7 MPa (250 psi) above atmospheric ("gauge") pressure. Were the tank containing the water to split open, there would momentarily exist a volume of liquid water which is +at atmospheric pressure, and +204.4 °C (400 °F). +At atmospheric pressure the boiling point of water is 100 °C (212 °F) - liquid water at atmospheric pressure cannot exist at temperatures higher than 100 °C (212 °F). It is obvious, then, that 204.4 °C (400 °F) liquid water at atmospheric pressure must immediately flash to gas causing an explosion. +BLEVEs without chemical reactions[edit] +It is important to note that a BLEVE need not be a chemical explosion - nor does there need to be a fire - however if a flammable substance is subject to a BLEVE it may also be subject to intense heating, either from an external source of heat which may have caused the vessel to rupture in the first place or from an internal source of localized heating such as skin friction. This heating can cause a flammable substance to ignite, adding a secondary explosion caused by the primary BLEVE. While blast effects of any BLEVE can be devastating, a flammable substance such as propane can add significantly to the danger. +Bleve explosion.svg +While the term BLEVE is most often used to describe the results of a container of flammable liquid rupturing due to fire, a BLEVE can occur even with a non-flammable substance such as water,[2] liquid nitrogen,[3] liquid helium or other refrigerants or cryogens, and therefore is not usually considered a type of chemical explosion. +Fires[edit] +BLEVEs can be caused by an external fire near the storage vessel causing heating of the contents and pressure build-up. While tanks are often designed to withstand great pressure, constant heating can cause the metal to weaken and eventually fail. If the tank is being heated in an area where there is no liquid, it may rupture faster without the liquid to absorb the heat. Gas containers are usually equipped with relief valves that vent off excess pressure, but the tank can still fail if the pressure is not released quickly enough.[1] Relief valves are sized to release pressure fast enough to prevent the pressure from increasing beyond the strength of the vessel, but not so fast as to be the cause of an explosion. An appropriately sized relief valve will allow the liquid inside to boil slowly, maintaining a constant pressure in the vessel until all the liquid has boiled and the vessel empties. +If the substance involved is flammable, it is likely that the resulting cloud of the substance will ignite after the BLEVE has occurred, forming a fireball and possibly a fuel-air explosion, also termed a vapor cloud explosion (VCE). If the materials are toxic, a large area will be contaminated.[4] +Incidents[edit] +The term "BLEVE" was coined by three researchers at Factory Mutual, in the analysis of an accident there in 1957 involving a chemical reactor vessel.[5] +In August 1959 the Kansas City Fire Department suffered its largest ever loss of life in the line of duty, when a 25,000 gallon (95,000 litre) gas tank exploded during a fire on Southwest Boulevard killing five firefighters. This was the first time BLEVE was used to describe a burning fuel tank.[citation needed] +Later incidents included the Cheapside Street Whisky Bond Fire in Glasgow, Scotland in 1960; Feyzin, France in 1966; Crescent City, Illinois in 1970; Kingman, Arizona in 1973; a liquid nitrogen tank rupture[6] at Air Products and Chemicals and Mobay Chemical Company at New Martinsville, West Virginia on January 31, 1978 [1];Texas City, Texas in 1978; Murdock, Illinois in 1983; San Juan Ixhuatepec, Mexico City in 1984; and Toronto, Ontario in 2008. +Safety measures[edit] +[icon] This section requires expansion. (July 2013) +Some fire mitigation measures are listed under liquefied petroleum gas. +See also[edit] +Boiler explosion +Expansion ratio +Explosive boiling or phase explosion +Rapid phase transition +Viareggio train derailment +2008 Toronto explosions +Gas carriers +Los Alfaques Disaster +Lac-Mégantic derailment +References[edit] +^ Jump up to: a b Kletz, Trevor (March 1990). Critical Aspects of Safety and Loss Prevention. London: Butterworth–Heinemann. pp. 43–45. ISBN 0-408-04429-2. +Jump up ^ "Temperature Pressure Relief Valves on Water Heaters: test, inspect, replace, repair guide". Inspect-ny.com. Retrieved 2011-07-12. +Jump up ^ Liquid nitrogen BLEVE demo +Jump up ^ "Chemical Process Safety" (PDF). Retrieved 2011-07-12. +Jump up ^ David F. Peterson, BLEVE: Facts, Risk Factors, and Fallacies, Fire Engineering magazine (2002). +Jump up ^ "STATE EX REL. VAPOR CORP. v. NARICK". Supreme Court of Appeals of West Virginia. 1984-07-12. Retrieved 2014-03-16. +External links[edit] + Look up boiling liquid expanding vapor explosion in Wiktionary, the free dictionary. + Wikimedia Commons has media related to BLEVE. +BLEVE Demo on YouTube — video of a controlled BLEVE demo +huge explosions on YouTube — video of propane and isobutane BLEVEs from a train derailment at Murdock, Illinois (3 September 1983) +Propane BLEVE on YouTube — video of BLEVE from the Toronto propane depot fire +Moscow Ring Road Accident on YouTube - Dozens of LPG tank BLEVEs after a road accident in Moscow +Kingman, AZ BLEVE — An account of the 5 July 1973 explosion in Kingman, with photographs +Propane Tank Explosions — Description of circumstances required to cause a propane tank BLEVE. +Analysis of BLEVE Events at DOE Sites - Details physics and mathematics of BLEVEs. +HID - SAFETY REPORT ASSESSMENT GUIDE: Whisky Maturation Warehouses - The liquor is aged in wooden barrels that can suffer BLEVE. +Categories: ExplosivesFirefightingFireTypes of fireGas technologiesIndustrial fires and explosions +Navigation menu +Create accountLog inArticleTalkReadEditView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +Català +Deutsch +Español +Français +Italiano +עברית +Nederlands +日本語 +Norsk bokmål +Polski +Português +Русский +Suomi +Edit links +This page was last modified on 18 November 2014 at 01:35. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki + + +Thermobaric weapon +From Wikipedia, the free encyclopedia + +Blast from a US Navy fuel air explosive used against a decommissioned ship, USS McNulty, 1972. +A thermobaric weapon is a type of explosive that utilizes oxygen from the surrounding air to generate an intense, high-temperature explosion, and in practice the blast wave such a weapon produces is typically significantly longer in duration than a conventional condensed explosive. The fuel-air bomb is one of the most well-known types of thermobaric weapons. +Most conventional explosives consist of a fuel-oxidizer premix (gunpowder, for example, contains 25% fuel and 75% oxidizer), whereas thermobaric weapons are almost 100% fuel, so thermobaric weapons are significantly more energetic than conventional condensed explosives of equal weight. Their reliance on atmospheric oxygen makes them unsuitable for use underwater, at high altitude, and in adverse weather. They do, however, cause considerably more destruction when used inside confined environments such as tunnels, caves, and bunkers - partly due to the sustained blast wave, and partly by consuming the available oxygen inside those confined spaces. +There are many different types of thermobaric weapons rounds that can be fitted to hand-held launchers.[1] +Contents [hide] +1 Terminology +2 Mechanism +2.1 Fuel-air explosive +2.1.1 Effect +3 Development history +3.1 Soviet and Russian developments +3.2 US developments +4 History +4.1 Military use +4.2 Non-military use +5 See also +6 References +7 External links +Terminology[edit] +The term thermobaric is derived from the Greek words for "heat" and "pressure": thermobarikos (θερμοβαρικός), from thermos (θερμός), hot + baros (βάρος), weight, pressure + suffix -ikos (-ικός), suffix -ic. +Other terms used for this family of weapons are high-impulse thermobaric weapons (HITs), heat and pressure weapons, vacuum bombs, or fuel-air explosives (FAE or FAX). +Mechanism[edit] +In contrast to condensed explosive, where oxidation in a confined region produces a blast front from essentially a point source, a flame front accelerates to a large volume producing pressure fronts both within the mixture of fuel and oxidant and then in the surrounding air.[2] +Thermobaric explosives apply the principles underlying accidental unconfined vapor cloud explosions, which include those from dispersions of flammable dusts and droplets.[3] Previously, such explosions were most often encountered in flour mills and their storage containers, and later in coal mines; but, now, most commonly in discharged oil tankers and refineries, including an incident at Buncefield in the UK in 2005 where the blast wave woke people 150 kilometres (93 mi) from its centre.[4] +A typical weapon consists of a container packed with a fuel substance, in the center of which is a small conventional-explosive "scatter charge". Fuels are chosen on the basis of the exothermicity of their oxidation, ranging from powdered metals, such as aluminium or magnesium, to organic materials, possibly with a self-contained partial oxidant. The most recent development involves the use of nanofuels.[5][6] +A thermobaric bomb's effective yield requires the most appropriate combination of a number of factors; among these are how well the fuel is dispersed, how rapidly it mixes with the surrounding atmosphere, and the initiation of the igniter and its position relative to the container of fuel. In some designs, strong munitions cases allow the blast pressure to be contained long enough for the fuel to be heated up well above its auto-ignition temperature, so that once the container bursts the super-heated fuel will auto-ignite progressively as it comes into contact with atmospheric oxygen.[7][8][9][10][11][12][13][14][15][16][17] +Conventional upper and lower limits of flammability apply to such weapons. Close in, blast from the dispersal charge, compressing and heating the surrounding atmosphere, will have some influence on the lower limit. The upper limit has been demonstrated strongly to influence the ignition of fogs above pools of oil.[18] This weakness may be eliminated by designs where the fuel is preheated well above its ignition temperature, so that its cooling during its dispersion still results in a minimal ignition delay on mixing. The continual combustion of the outer layer of fuel molecules as they come into contact with the air, generates additional heat which maintains the temperature of the interior of the fireball, and thus sustains the detonation.[19][20][21] +In confinement, a series of reflective shock waves are generated,[22][23] which maintain the fireball and can extend its duration to between 10 and 50 ms as exothermic recombination reactions occur.[24] Further damage can result as the gases cool and pressure drops sharply, leading to a partial vacuum. This effect has given rise to the misnomer "vacuum bomb". Piston-type afterburning is also believed to occur in such structures, as flame-fronts accelerate through it.[25][26] +Fuel-air explosive[edit] +A fuel-air explosive (FAE) device consists of a container of fuel and two separate explosive charges. After the munition is dropped or fired, the first explosive charge bursts open the container at a predetermined height and disperses the fuel in a cloud that mixes with atmospheric oxygen (the size of the cloud varies with the size of the munition). The cloud of fuel flows around objects and into structures. The second charge then detonates the cloud, creating a massive blast wave. The blast wave destroys unreinforced buildings and equipment and kills and injures people. The antipersonnel effect of the blast wave is more severe in foxholes, on people with body armor, and in enclosed spaces such as caves, buildings, and bunkers. +Fuel-air explosives were first developed, and used in Vietnam, by the United States. Soviet scientists, however, quickly developed their own FAE weapons, which were reportedly used against China in the Sino-Soviet border conflict and in Afghanistan. Since then, research and development has continued and currently Russian forces field a wide array of third-generation FAE warheads. +Effect[edit] +A Human Rights Watch report of 1 February 2000[27] quotes a study made by the US Defense Intelligence Agency: +The [blast] kill mechanism against living targets is unique–and unpleasant.... What kills is the pressure wave, and more importantly, the subsequent rarefaction [vacuum], which ruptures the lungs.... If the fuel deflagrates but does not detonate, victims will be severely burned and will probably also inhale the burning fuel. Since the most common FAE fuels, ethylene oxide and propylene oxide, are highly toxic, undetonated FAE should prove as lethal to personnel caught within the cloud as most chemical agents. +According to a U.S. Central Intelligence Agency study,[27] "the effect of an FAE explosion within confined spaces is immense. Those near the ignition point are obliterated. Those at the fringe are likely to suffer many internal, and thus invisible injuries, including burst eardrums and crushed inner ear organs, severe concussions, ruptured lungs and internal organs, and possibly blindness." Another Defense Intelligence Agency document speculates that because the "shock and pressure waves cause minimal damage to brain tissue…it is possible that victims of FAEs are not rendered unconscious by the blast, but instead suffer for several seconds or minutes while they suffocate."[28] +Development history[edit] +Soviet and Russian developments[edit] + +A RPO-A rocket and launcher. +The Soviet armed forces extensively developed FAE weapons,[29] such as the RPO-A, and used them in Chechnya.[30] +The Russian armed forces have developed thermobaric ammunition variants for several of their weapons, such as the TGB-7V thermobaric grenade with a lethality radius of 10 metres (33 ft), which can be launched from a RPG-7. The GM-94 is a 43 mm pump-action grenade launcher which is designed mainly to fire thermobaric grenades for close quarters combat. With the grenade weighing 250 grams (8.8 oz) and holding a 160 grams (5.6 oz) explosive mixture, its lethality radius is 3 metres (9.8 ft); however, due to the deliberate "fragmentation-free" design of the grenade, 4 metres (13 ft) is already considered a safe distance.[31] The RPO-A and upgraded RPO-M are infantry-portable RPGs designed to fire thermobaric rockets. The RPO-M, for instance, has a thermobaric warhead with a TNT equivalence of 5.5 kilograms (12 lb) of TNT and destructive capabilities similar to a 152 mm High explosive fragmentation artillery shell.[32][33] The RShG-1 and the RShG-2 are thermobaric variants of the RPG-27 and RPG-26 respectively. The RShG-1 is the more powerful variant, with its warhead having a 10 metres (33 ft) lethality radius and producing about the same effect as 6 kg (13 lb) of TNT.[34] The RMG is a further derivative of the RPG-26 that uses a tandem-charge warhead, whereby the precursor HEAT warhead blasts an opening for the main thermobaric charge to enter and detonate inside.[35] The RMG's precursor HEAT warhead can penetrate 300 mm of reinforced concrete or over 100 mm of Rolled homogeneous armour, thus allowing the 105 millimetres (4.1 in) diameter thermobaric warhead to detonate inside.[36] +The other examples include the SACLOS or millimeter wave radar-guided thermobaric variants of the 9M123 Khrizantema, the 9M133F-1 thermobaric warhead variant of the 9M133 Kornet, and the 9M131F thermobaric warhead variant of the 9K115-2 Metis-M, all of which are anti-tank missiles. The Kornet has since been upgraded to the Kornet-EM, and its thermobaric variant has a maximum range of 10 kilometres (6.2 mi) and has the TNT equivalent of 7 kilograms (15 lb) of TNT.[37] The 300 mm 9M55S thermobaric cluster warhead rocket was built to be fired from the BM-30 Smerch MLRS. A dedicated carrier of thermobaric weapons is the purpose-built TOS-1, a 24-tube MLRS designed to fire 220 mm caliber thermobaric rockets. A full salvo from the TOS-1 will cover a rectangle 200x400 metres.[38] The Iskander-M theatre ballistic missile can also carry a 700 kilograms (1,500 lb) thermobaric warhead.[39] + +The fireball blast from the Russian Air Force's FOAB, the largest Thermobaric device to be detonated. +Many Russian Air Force munitions also have thermobaric variants. The 80 mm S-8 rocket has the S-8DM and S-8DF thermobaric variants. The S-8's larger 122 mm brother, the S-13 rocket, has the S-13D and S-13DF thermobaric variants. The S-13DF's warhead weighs only 32 kg (71 lb) but its power is equivalent to 40 kg (88 lb) of TNT. The KAB-500-OD variant of the KAB-500KR has a 250 kg (550 lb) thermobaric warhead. The ODAB-500PM and ODAB-500PMV unguided bombs carry a 190 kg (420 lb) fuel-air explosive each. The KAB-1500S GLONASS/GPS guided 1,500 kg (3,300 lb) bomb also has a thermobaric variant. Its fireball will cover over a 150-metre (490 ft) radius and its lethality zone is a 500-metre (1,600 ft) radius.[40] The 9M120 Ataka-V and the 9K114 Shturm ATGMs both have thermobaric variants. +In September 2007 Russia exploded the largest thermobaric weapon ever made. The weapon's yield was reportedly greater than that of the smallest dial-a-yield nuclear weapons at their lowest settings.[41][42] Russia named this particular ordnance the "Father of All Bombs" in response to the United States developed "Massive Ordnance Air Blast" (MOAB) bomb whose backronym is the "Mother of All Bombs", and which previously held the accolade of the most powerful non-nuclear weapon in history.[43] The bomb contains an about 7 tons charge of a liquid fuel such as ethylene oxide, mixed with an energetic nanoparticle such as aluminium, surrounding a high explosive burster[44] that when detonated created an explosion equivalent to 44 metric tons of TNT. +US developments[edit] + +A BLU-72/B bomb on a USAF A-1E taking off from Nakhon Phanom, in September 1968. +Current US FAE munitions include: +BLU-73 FAE I +BLU-95 500-lb (FAE-II) +BLU-96 2,000-lb (FAE-II) +CBU-55 FAE I +CBU-72 FAE I +The XM1060 40-mm grenade is a small-arms thermobaric device, which was delivered to U.S. forces in April 2003.[45] Since the 2003 Invasion of Iraq, the US Marine Corps has introduced a thermobaric 'Novel Explosive' (SMAW-NE) round for the Mk 153 SMAW rocket launcher. One team of Marines reported that they had destroyed a large one-story masonry type building with one round from 100 yards (91 m).[46] +The AGM-114N Hellfire II, first used by U.S. forces in 2003 in Iraq, uses a Metal Augmented Charge (MAC) warhead that contains a thermobaric explosive fill using fluoridated aluminium layered between the charge casing and a PBXN-112 explosive mixture. When the PBXN-112 detonates, the aluminium mixture is dispersed and rapidly burns. The resultant sustained high pressure is extremely effective against people and structures.[47] +History[edit] +Military use[edit] + +US Navy BLU-118B being prepared for shipping for use in Afghanistan, 5 March 2002. +The first experiments with thermobaric weapon were conducted in Germany during World War II and were led by Mario Zippermayr. The German bombs used coal dust as fuel and were extensively tested in 1943 and 1944, but did not reach mass production before the war ended. +The TOS-1 system was test fired in Panjshir valley during Soviet war in Afghanistan in the early 1980s.[48] +Unconfirmed reports suggest that Russian military forces used ground delivered thermobaric weapons in the storming of the Russian parliament during the 1993 Russian constitutional crisis and also during the Battle for Grozny (first and second Chechen wars) to attack dug in Chechen fighters. The use of both TOS-1 heavy MLRS and "RPO-A Shmel" shoulder-fired rocket system in the Chechen wars is reported to have occurred.[48][49] +It is theorized that a multitude of hand-held thermobaric weapons were used by the Russian Armed Forces in their efforts to retake the school during the 2004 Beslan school hostage crisis. The RPO-A and either the TGB-7V thermobaric rocket from the RPG-7 or rockets from either the RShG-1 or the RShG-2 is claimed to have been used by the Spetsnaz during the initial storming of the school.[50][51][52] At least 3 and as many as 9 RPO-A casings were later found at the positions of the Spetsnaz.[53][54] The Russian Government later admitted to the use of the RPO-A during the crisis.[55] +According to UK Ministry of Defence, British military forces have also used thermobaric weapons in their AGM-114N Hellfire missiles (carried by Apache helicopters and UAVs) against the Taliban in the War in Afghanistan.[56] +The US military also used thermobaric weapons in Afghanistan. On 3 March 2002, a single 2,000 lb (910 kg) laser guided thermobaric bomb was used by the United States Army against cave complexes in which Al-Qaeda and Taliban fighters had taken refuge in the Gardez region of Afghanistan.[57][58] The SMAW-NE was used by the US Marines during the First Battle of Fallujah and Second Battle of Fallujah. +Reports by the rebel fighters of the Free Syrian Army claim the Syrian Air Force used such weapons against residential area targets occupied by the rebel fighters, as for instance in the Battle for Aleppo[59] and also in Kafar Batna.[60] A United Nations panel of human rights investigators reported that the Syrian government used thermobaric bombs against the rebellious town of Qusayr in March 2013.[61] +Non-military use[edit] +Thermobaric and fuel-air explosives have been used in guerrilla warfare since the 1983 Beirut barracks bombing in Lebanon, which used a gas-enhanced explosive mechanism, probably propane, butane or acetylene.[62] The explosive used by the bombers in the 1993 World Trade Center bombing incorporated the FAE principle, using three tanks of bottled hydrogen gas to enhance the blast.[63][64] Jemaah Islamiyah bombers used a shock-dispersed solid fuel charge,[65] based on the thermobaric principle,[66] to attack the Sari nightclub in the 2002 Bali bombings.[67] +See also[edit] +Bunker buster +Dust explosion +FOAB +Flame fougasse +MOAB +RPO-A +SMAW +References[edit] +Jump up ^ Algeria Isp (2011-10-18). "Libye – l'Otan utilise une bombe FAE | Politique, Algérie". Algeria ISP. Retrieved 2013-04-23. +Jump up ^ Nettleton, J. Occ. Accidents, 1, 149 (1976). +Jump up ^ Strehlow, 14th. Symp. (Int.) Comb. 1189, Comb. Inst. (1973). +Jump up ^ Health and Safety Environmental Agency, 5th. and final report, 2008. +Jump up ^ See Nanofuel/Oxidizers For Energetic Compositions – John D. Sullivan and Charles N. Kingery (1994) High explosive disseminator for a high explosive air bomb. +Jump up ^ Slavica Terzić, Mirjana Dakić Kolundžija, Milovan Azdejković and Gorgi Minov (2004) Compatibility Of Thermobaric Mixtures Based On Isopropyl Nitrate And Metal Powders. +Jump up ^ Meyer, Rudolf; Josef Köhler and Axel Homburg (2007). Explosives. Weinheim: Wiley-VCH. pp. 312. ISBN 3-527-31656-6. OCLC 165404124. +Jump up ^ Howard C. Hornig (1998) Non-focusing active warhead. +Jump up ^ Chris Ludwig (Talley Defense) Verifying Performance of Thermobaric Materials for Small to Medium Caliber Rocket Warheads. +Jump up ^ Martin M.West (1982) Composite high explosives for high energy blast applications. +Jump up ^ Raafat H. Guirguis (2005) Reactively Induced Fragmenting Explosives. +Jump up ^ Michael Dunning, William Andrews and Kevin Jaansalu (2005) The Fragmentation of Metal Cylinders Using Thermobaric Explosives. +Jump up ^ David L. Frost, Fan Zhang, Stephen B. Murray and Susan McCahan Critical Conditions For Ignition Of Metal Particles In A Condensed Explosive. +Jump up ^ The Army Doctrine and Training Bulletin (2001) The Threat from Blast Weapons. +Jump up ^ INTERNATIONAL DEFENCE REVIEW (2004) ENHANCED BLAST AND THERMOBARICS. +Jump up ^ F. Winterberg Conjectured Metastable Super-Explosives formed under High Pressure for Thermonuclear Ignition. +Jump up ^ Zhang, Fan (Medicine Hat, CA) Murray, Stephen Burke (Medicine Hat, CA) Higgins, Andrew (Montreal, CA) (2005) Super compressed detonation method and device to effect such detonation. +Jump up ^ Nettleton, arch. combust.,1,131, (1981). +Jump up ^ Stephen B. Murray Fundamental and Applied Studies of Fuel-Air Detonation. +Jump up ^ John H. Lee (1992) Chemical initiation of detonation in fuel-air explosive clouds. +Jump up ^ Frank E. Lowther (1989) Nuclear-sized explosions without radiation. +Jump up ^ Nettleton, Comb. and Flame, 24,65 (1975). +Jump up ^ Fire Prev. Sci. and Tech. No. 19,4 (1976) +Jump up ^ May L.Chan (2001) Advanced Thermobaric Explosive Compositions. +Jump up ^ New Thermobaric Materials and Weapon Concepts. +Jump up ^ Robert C. Morris (2003) Small Thermobaric Weapons An Unnoticed Threat.[dead link] +^ Jump up to: a b "Backgrounder on Russian Fuel Air Explosives ("Vacuum Bombs") | Human Rights Watch". Hrw.org. 2000-02-01. Retrieved 2013-04-23. +Jump up ^ Defense Intelligence Agency, "Future Threat to the Soldier System, Volume I; Dismounted Soldier--Middle East Threat", September 1993, p. 73. Obtained by Human Rights Watch under the U.S. Freedom of Information Act. +Jump up ^ "Press | Human Rights Watch". Hrw.org. 2008-12-27. Retrieved 2009-07-30. +Jump up ^ Lester W. Grau and Timothy L. Thomas(2000)"Russian Lessons Learned From the Battles For Grozny" +Jump up ^ "Modern Firearms – GM-94". World.guns.ru. 2011-01-24. Retrieved 2011-07-12. +Jump up ^ "New RPO Shmel-M Infantry Rocket Flamethrower Man-Packable Thermobaric Weapon". defensereview.com. 2006-07-19. Retrieved 2012-08-27. +Jump up ^ "Shmel-M: Infantry Rocket-assisted Flamethrower of Enhanced Range and Lethality". Kbptula.ru. Retrieved 2013-12-28. +Jump up ^ "Modern Firearms – RShG-1". World.guns.ru. 2011-01-24. Retrieved 2011-07-12. +Jump up ^ "Modern Firearms – RMG". World.guns.ru. 2011-01-24. Retrieved 2011-07-12. +Jump up ^ "RMG - A new Multi-Purpose Assault Weapon from Bazalt". defense-update.com. Retrieved 2012-08-27. +Jump up ^ "Kornet-EM: Multi-purpose Long-range Missile System". Kbptula.ru. Retrieved 2013-12-28. +Jump up ^ "TOS-1 Heavy flamethrower system". military-today.com. Retrieved 2012-08-27. +Jump up ^ "SS-26". Missilethreat.com. Retrieved 2013-12-28. +Jump up ^ Air Power Australia (2007-07-04). "How to Destroy the Australian Defence Force". Ausairpower.net. Retrieved 2011-07-12. +Jump up ^ "Russia unveils devastating vacuum bomb". ABC News. 2007. Retrieved 2007-09-12. +Jump up ^ "Video of test explosion". BBC News. 2007. Retrieved 2007-09-12. +Jump up ^ Harding, Luke (2007-09-12). "Russia unveils the father of all bombs". London: The Guardian. Retrieved 2007-09-12. +Jump up ^ Berhie, Saba. "Dropping the Big One | Popular Science". Popsci.com. Retrieved 2011-07-12. +Jump up ^ John Pike (2003-04-22). "XM1060 40mm Thermobaric Grenade". Globalsecurity.org. Retrieved 2011-07-12. +Jump up ^ David Hambling (2005) "Marines Quiet About Brutal New Weapon" +Jump up ^ John Pike (2001-09-11). "AGM-114N Metal Augmented Charge (MAC) Thermobaric Hellfire". Globalsecurity.org. Retrieved 2011-07-12. +^ Jump up to: a b John Pike. "TOS-1 Buratino 220mm Multiple Rocket Launcher". Globalsecurity.org. Retrieved 2013-04-23. +Jump up ^ "Foreign Military Studies Office Publications - A 'Crushing' Victory: Fuel-Air Explosives and Grozny 2000". Fmso.leavenworth.army.mil. Retrieved 2013-04-23. +Jump up ^ "Russian forces faulted in Beslan school tragedy". Christian Science Monitor. 1 September 2006. Retrieved 14 February 2007. +Jump up ^ Russia: Independent Beslan Investigation Sparks Controversy, The Jamestown Foundation, 29 August 2006 +Jump up ^ Beslan still a raw nerve for Russia, BBC News, 1 September 2006 +Jump up ^ ACHING TO KNOW, Los Angeles Times, 27 August 2005 +Jump up ^ Searching for Traces of “Shmel” in Beslan School, Kommersant, 12 September 2005 +Jump up ^ A Reversal Over Beslan Only Fuels Speculation, The Moscow Times, 21 July 2005 +Jump up ^ "MoD's Controversial Thermobaric Weapons Use in Afghanistan". Armedforces-int.com. 2008-06-23. Retrieved 2013-04-23. +Jump up ^ "US Uses Bunker-Busting 'Thermobaric' Bomb for First Time". Commondreams.org. 2002-03-03. Retrieved 2013-04-23. +Jump up ^ John Pike. "BLU-118/B Thermobaric Weapon Demonstration / Hard Target Defeat Program". Globalsecurity.org. Retrieved 2013-04-23. +Jump up ^ "Syria rebels say Assad using 'mass-killing weapons' in Aleppo". October 10, 2012. Retrieved November 11, 2012. +Jump up ^ "Dropping Thermobaric Bombs on Residential Areas in Syria_ Nov. 5. 2012". First Post. November 11, 2012. Retrieved November 11, 2012. +Jump up ^ Cumming-Bruce, Nick (2013-06-04). "U.N. Panel Reports Increasing Brutality by Both Sides in Syria". The New York Times. +Jump up ^ Richard J. Grunawalt. Hospital Ships In The War On Terror: Sanctuaries or Targets? (PDF), Naval War College Review, Winter 2005, pp. 110–11. +Jump up ^ Paul Rogers (2000) "Politics in the Next 50 Years: The Changing Nature of International Conflict" +Jump up ^ J. Gilmore Childers, Henry J. DePippo (February 24, 1998). "Senate Judiciary Committee, Subcommittee on Technology, Terrorism, and Government Information hearing on "Foreign Terrorists in America: Five Years After the World Trade Center"". Fas.org. Retrieved 2011-07-12. +Jump up ^ P. Neuwald, H. Reichenbach, A. L. Kuhl (2003). "Shock-Dispersed-Fuel Charges-Combustion in Chambers and Tunnels". +Jump up ^ David Eshel (2006). "Is the world facing Thermobaric Terrorism?".[dead link] +Jump up ^ Wayne Turnbull (2003). "Bali:Preparations". +External links[edit] +Fuel/Air Explosive (FAE) +Thermobaric Explosive (Global Security) +Aspects of thermobaric weaponry (PDF) – Dr. Anna E Wildegger-Gaissmaier, Australian Defence Force Health +Thermobaric warhead for RPG-7 +XM1060 40 mm Thermobaric Grenade (Global Security) +Defense Update: Fuel-Air Explosive Mine Clearing System +Foreign Military Studies Office – A 'Crushing' Victory: Fuel-Air Explosives and Grozny 2000 +Soon to make a comeback in Afghanistan +Russia claims to have tested the most powerful "Vacuum" weapon +Categories: Explosive weaponsAmmunitionThermobaric weaponsAnti-personnel weapons +Navigation menu +Create accountLog inArticleTalkReadEditView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +العربية +Беларуская +Български +Čeština +Deutsch +Español +فارسی +Français +हिन्दी +Italiano +עברית +Latviešu +Македонски +Nederlands +日本語 +Polski +Русский +Suomi +Svenska +Türkçe +Українська +Tiếng Việt +粵語 +中文 +Edit links +This page was last modified on 28 November 2014 at 10:32. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki + + +Gunpowder +From Wikipedia, the free encyclopedia +For other uses, see Gunpowder (disambiguation). +In American English, the term gunpowder also refers broadly to any gun propellant.[1] Gunpowder (black powder) as described in this article is not normally used in modern firearms, which instead use smokeless powders. + +Black powder for muzzleloading rifles and pistols in FFFG granulation size. American Quarter (diameter 24 mm) for comparison. +Gunpowder, also known as black powder, is a chemical explosive—the earliest known. It is a mixture of sulfur, charcoal, and potassium nitrate (saltpeter). The sulfur and charcoal act as fuels, and the saltpeter is an oxidizer.[2][3] Because of its burning properties and the amount of heat and gas volume that it generates, gunpowder has been widely used as a propellant in firearms and as a pyrotechnic composition in fireworks. +Gunpowder is assigned the UN number UN0027 and has a hazard class of 1.1D. It has a flash point of approximately 427–464 °C (801–867 °F). The specific flash point may vary based on the specific composition of the gunpowder. Gunpowder's gravity is 1.70–1.82 (mercury method) orŠ 1.92–2.08 (pycnometer), and it has a pH of 6.0–8.0. It is also considered to be an insoluble material.[4] +Gunpowder was, according to prevailing academic consensus, invented in the 9th century in China,[5][6] and the earliest record of a written formula for gunpowder appears in the 11th century Song Dynasty text, Wujing Zongyao.[7] This discovery led to the invention of fireworks and the earliest gunpowder weapons in China. In the centuries following the Chinese discovery, gunpowder weapons began appearing in the Muslim world, Europe, and India. The technology spread from China through the Middle East or Central Asia, and then into Europe.[8] The earliest Western accounts of gunpowder appear in texts written by English philosopher Roger Bacon in the 13th century.[9] +Gunpowder is classified as a low explosive because of its relatively slow decomposition rate and consequently low brisance. Low explosives deflagrate (i.e., burn) at subsonic speeds, whereas high explosives detonate, producing a supersonic wave. Gunpowder's burning rate increases with pressure, so it bursts containers if contained but otherwise just burns in the open. Ignition of the powder packed behind a bullet must generate enough pressure to force it from the muzzle at high speed, but not enough to rupture the gun barrel. Gunpowder thus makes a good propellant, but is less suitable for shattering rock or fortifications. Gunpowder was widely used to fill artillery shells and in mining and civil engineering to blast rock roughly until the second half of the 19th century, when the first high explosives (nitro-explosives) were discovered. Gunpowder is no longer used in modern explosive military warheads, nor is it used as main explosive in mining operations due to its cost relative to that of newer alternatives such as ammonium nitrate/fuel oil (ANFO).[10] Black powder is still used as a delay element in various munitions where its slow-burning properties are valuable. +Formulations used in blasting rock (such as in quarrying) are called blasting powder. +Contents [hide] +1 History +1.1 China +1.2 Middle East +1.3 Mainland Europe +1.4 Britain and Ireland +1.5 India +1.6 Indonesia +2 Manufacturing technology +3 Composition and characteristics +4 Serpentine +5 Corning +6 Modern types +7 Other types of gunpowder +8 Sulfur-free gunpowder +9 Combustion characteristics +9.1 Advantages +9.2 Disadvantages +9.3 Transportation +10 Other uses +11 See also +12 References +13 External links +History[edit] + +Early Chinese rocket + +A Mongol bomb thrown against a charging Japanese samurai during the Mongol invasions of Japan after founding the Yuan Dynasty, 1281. +Main article: History of gunpowder +Gunpowder was invented in China while taoists attempted to create a potion of immortality. Chinese military forces used gunpowder-based weapons (i.e. rockets, guns, cannons) and explosives (i.e. grenades and different types of bombs) against the Mongols when the Mongols attempted to invade and breach city fortifications on China's northern borders. After the Mongols conquered China and founded the Yuan Dynasty, they used the Chinese gunpowder-based weapons technology in their attempted invasion of Japan; they also used gunpowder to fuel rockets. +The mainstream scholarly consensus is that gunpowder was invented in China, spread through the Middle East, and then into Europe,[8] although there is a dispute over how much the Chinese advancements in gunpowder warfare influenced later advancements in the Middle East and Europe.[11][12] The spread of gunpowder across Asia from China is widely attributed to the Mongols. One of the first examples of Europeans encountering gunpowder and firearms is at the Battle of Mohi in 1241. At this battle the Mongols not only used gunpowder in early Chinese firearms but in the earliest grenades as well. +A major problem confronting the study of the early history of gunpowder is ready access to sources close to the events described. Often enough, the first records potentially describing use of gunpowder in warfare were written several centuries after the fact, and may well have been colored by the contemporary experiences of the chronicler.[13] It is also difficult to accurately translate original alchemy texts, especially medieval Chinese texts that try to explain phenomena through metaphor, into modern scientific language with rigidly defined terminology. The translation difficulty has led to errors or loose interpretations bordering on artistic licence.[14][15] Early writings potentially mentioning gunpowder are sometimes marked by a linguistic process where old words acquired new meanings.[16] For instance, the Arabic word naft transitioned from denoting naphtha to denoting gunpowder, and the Chinese word pao evolved from meaning catapult to referring to cannon.[17] According to science and technology historian Bert S. Hall: "It goes without saying, however, that historians bent on special pleading, or simply with axes of their own to grind, can find rich material in these terminological thickets."[18] +China[edit] +Further information: Wujing Zongyao, Four Great Inventions and List of Chinese inventions + +Chinese Ming Dynasty (1368-1644) matchlock firearms +Saltpeter was known to the Chinese by the mid-1st century AD and there is strong evidence of the use of saltpeter and sulfur in various largely medicinal combinations.[19] A Chinese alchemical text dated 492 noted saltpeter burnt with a purple flame, providing a practical and reliable means of distinguishing it from other inorganic salts, thus enabling alchemists to evaluate and compare purification techniques; the earliest Latin accounts of saltpeter purification are dated after 1200.[20] + +Yuan Dynasty bronze hand cannon from 1332 at th (c. 808); it describes mixing six parts sulfur to six parts saltpeter to one part birthwort herb (which would provide carbon).[21] +The first reference to the incendiary properties of such mixtures is the passage of the Zhenyuan miaodao yaolüe, a Taoist text tentatively dated to the mid-9th century AD:[20] "Some have heated together sulfur, realgar and saltpete with honey; smoke and flames result, so that their hands and faces have been burnt, and even the whole house where they were working burned down."[22] The Chinese word for "gunpowder" is Chinese: 火药/火藥; pinyin: huŏ yào /xuou yɑʊ/, which literally means "Fire Medicine";[23] however this name only came into use some centuries after the mixture's discovery.[24] During the 9th century, Taoist monks or alchemists searching for an elixir of immortality had serendipitously stumbled upon gunpowder.[8][25] The Chinese wasted little time in applying gunpowder to the development of weapons, and in the centuries that followed, they produced a variety of gunpowder weapons, including flamethrowers, rockets, bombs, and land mines, before inventing guns as a projectile weapon.[26] Archaeological evidence of a hand cannon has been excavated in Manchuria dated from the late 1200s[27] and the shells of explosive bombs have been discovered in a shipwreck off the shore of Japan dated from 1281, during the Mongol invasions of Japan.[28] +The Chinese "Wu Ching Tsung Yao" (Complete Essentials from the Military Classics), written by Tseng Kung-Liang between 1040–1044, provides encyclopedia references to a variety of mixtures that included petrochemicals—as well as garlic and honey. A slow match for flame throwing mechanisms using the siphon principle and for fireworks and rockets are mentioned. The mixture formulas in this book do not contain enough saltpeter to create an explosive however; being limited to at most 50% saltpeter, they produce an incendiary.[29] The Essentials was however written by a Song Dynasty court bureaucrat, and there's little evidence that it had any immediate impact on warfare; there is no mention of gunpowder use in the chronicles of the wars against the Tanguts in the eleventh century, and China was otherwise mostly at peace during this century. The first chronicled use of "fire spears" (or "fire lances") is at the siege of De'an in 1132.[30] + +Formula for gunpowder in 1044 Wujing zongyao part I vol 12 + + +Instruction for fire bomb in Wujing zongyao + + +Fire bomb + + +Fire grenade + + +Proto-cannon from the Ming Dynasty text Huolongjing + + +Land mine from the Ming Dynasty text Huolongjing + + +Fire arrow rocket launcher from the Wujing zongyao +Middle East[edit] +Main articles: Inventions in the Islamic world and Alchemy and chemistry in Islam + +The Sultani Cannon, a very heavy bronze breech-loading cannon of type used by Ottoman Empire in the conquest of Constantinople, in 1453. +The Muslims acquired knowledge of gunpowder some time between 1240 and 1280, by which time the Syrian Hasan al-Rammah had written, in Arabic, recipes for gunpowder, instructions for the purification of saltpeter, and descriptions of gunpowder incendiaries. Gunpowder arrived in the Middle East, possibly through India, from China. This is implied by al-Rammah's usage of "terms that suggested he derived his knowledge from Chinese sources" and his references to saltpeter as "Chinese snow" Arabic: ثلج الصين‎ thalj al-ṣīn, fireworks as "Chinese flowers" and rockets as "Chinese arrows".[31] However, because al-Rammah attributes his material to "his father and forefathers", al-Hassan argues that gunpowder became prevalent in Syria and Egypt by "the end of the twelfth century or the beginning of the thirteenth".[32] Persians called saltpeter "Chinese salt" [33][34][35][36][37] or "salt from Chinese salt marshes" (namak shūra chīnī Persian: نمک شوره چيني‎).[38][39] + +A picture of a 15th-century Granadian cannon from the book Al-izz wal rifa'a. +Al-Hassan claims that in the Battle of Ain Jalut of 1260, the Mamluks used against the Mongols in "the first cannon in history" gunpowder formula with near-identical ideal composition ratios for explosive gunpowder.[32] Other historians urge caution regarding claims of Islamic firearms use in the 1204-1324 period as late medieval Arabic texts used the same word for gunpowder, naft, that they used for an earlier incendiary, naphtha.[13][17] Khan claims that it was invading Mongols who introduced gunpowder to the Islamic world[40] and cites Mamluk antagonism towards early musketeers in their infantry as an example of how gunpowder weapons were not always met with open acceptance in the Middle East.[41] Similarly, the refusal of their Qizilbash forces to use firearms contributed to the Safavid rout at Chaldiran in 1514.[41] +The earliest surviving documentary evidence for the use of the hand cannon, considered the oldest type of portable firearm and a forerunner of the handgun, are from several Arabic manuscripts dated to the 14th century.[42] Al-Hassan argues that these are based on earlier originals and that they report hand-held cannons being used by the Mamluks at the Battle of Ain Jalut in 1260.[32] +Hasan al-Rammah included 107 gunpowder recipes in his text al-Furusiyyah wa al-Manasib al-Harbiyya (The Book of Military Horsemanship and Ingenious War Devices), 22 of which are for rockets. If one takes the median of 17 of these 22 compositions for rockets (75% nitrates, 9.06% sulfur, and 15.94% carbon), it is nearly identical to the modern reported ideal gunpowder recipe of 75% potassium nitrate, 10% sulfur, and 15% carbon.[32] +The state-controlled manufacture of gunpowder by the Ottoman Empire through early supply chains to obtain nitre, sulfur and high-quality charcoal from oaks in Anatolia contributed significantly to its expansion the 15th and 18th century. It was not until later in the 19th century when the syndicalist production of Turkish gunpowder was greatly reduced, which coincided with the decline of its military might.[43] +Mainland Europe[edit] +Several sources mention Chinese firearms and gunpowder weapons being deployed by the Mongols against European forces at the Battle of Mohi in 1241.[44][45][46] Professor Kenneth Warren Chase credits the Mongols for introducing into Europe gunpowder and its associated weaponry.[47] +C. F. Temler interprets Peter, Bishop of Leon, as reporting the use of cannons in Seville in 1248.[48] +In Europe, one of the first mentions of gunpowder use appears in a passage found in Roger Bacon's Opus Maius and Opus Tertium in what has been interpreted as being firecrackers. The most telling passage reads: "We have an example of these things (that act on the senses) in [the sound and fire of] that children's toy which is made in many [diverse] parts of the world; i.e., a device no bigger than one's thumb. From the violence of that salt called saltpeter [together with sulfur and willow charcoal, combined into a powder] so horrible a sound is made by the bursting of a thing so small, no more than a bit of parchment [containing it], that we find [the ear assaulted by a noise] exceeding the roar of strong thunder, and a flash brighter than the most brilliant lightning."[9] In the early 20th century, British artillery officer Henry William Lovett Hime proposed that another work tentatively attributed to Bacon, Epistola de Secretis Operibus Artis et Naturae, et de Nullitate Magiae contained an encrypted formula for gunpowder. This claim has been disputed by historians of science including Lynn Thorndike, John Maxson Stillman and George Sarton and by Bacon's editor Robert Steele, both in terms of authenticity of the work, and with respect to the decryption method.[9] In any case, the formula claimed to have been decrypted (7:5:5 saltpeter:charcoal:sulfur) is not useful for firearms use or even firecrackers, burning slowly and producing mostly smoke.[49][50] + +Cannon forged in 1667 at the Fortín de La Galera, Nueva Esparta, Venezuela. +The Liber Ignium, or Book of Fires, attributed to Marcus Graecus, is a collection of incendiary recipes, including some gunpowder recipes. Partington dates the gunpowder recipes to approximately 1300.[51] One recipe for "flying fire" (ingis volatilis) involves saltpeter, sulfur, and colophonium, which, when inserted into a reed or hollow wood, "flies away suddenly and burns up everything." Another recipe, for artificial "thunder", specifies a mixture of one pound native sulfur, two pounds linden or willow charcoal, and six pounds of saltpeter.[52] Another specifies a 1:3:9 ratio.[52] +Some of the gunpowder recipes of De Mirabilibus Mundi of Albertus Magnus are identical to the recipes of the Liber Ignium, and according to Partington, "may have been taken from that work, rather than conversely."[53] Partington suggests that some of the book may have been compiled by Albert's students, "but since it is found in thirteenth century manuscripts, it may well be by Albert."[53] Albertus Magnus died in 1280. +A common German folk-tale is of the German priest/monk named Berthold Schwarz who independently invented gunpowder, thus earning it the German name Schwarzpulver or in English Schwarz's powder. Schwarz is also German for black so this folk-tale, while likely containing elements of truth, is considered problematic. +A major advance in manufacturing began in Europe in the late 14th century when the safety and thoroughness of incorporation was improved by wet grinding; liquid, such as distilled spirits or perhaps the urine of wine-drinking bishops[54] was added during the grinding-together of the ingredients and the moist paste dried afterwards. (The principle of wet mixing to prevent the separation of dry ingredients, invented for gunpowder, is used today in the pharmaceutical industry.[55]) It was also discovered that if the paste was rolled into balls before drying the resulting gunpowder absorbed less water from the air during storage and traveled better. The balls were then crushed in a mortar by the gunner immediately before use, with the old problem of uneven particle size and packing causing unpredictable results. +If the right size particles were chosen, however, the result was a great improvement in power. Forming the damp paste into corn-sized clumps by hand or with the use of a sieve instead of larger balls produced a product after drying that loaded much better, as each tiny piece provided its own surrounding air space that allowed much more rapid combustion than a fine powder. This "corned" gunpowder was from 30% to 300% more powerful. An example is cited where 34 pounds of serpentine was needed to shoot a 47 pound ball, but only 18 pounds of corned powder.[54] The optimum size of the grain depended on its use; larger for large cannon, finer for small arms. Larger cast cannons were easily muzzle-loaded with corned powder using a long-handled ladle. Corned powder also retained the advantage of low moisture absorption, as even tiny grains still had much less surface area to attract water than a floury powder. +During this time, European manufacturers also began regularly purifying saltpeter, using wood ashes containing potassium carbonate to precipitate calcium from their dung liquor, and using ox blood, alum, and slices of turnip to clarify the solution.[54] +Gunpowder-making and metal-smelting and casting for shot and cannon fee was closely held by skilled military tradesmen, who formed guilds that collected dues, tested apprentices, and gave pensions. "Fire workers" were also required to craft fireworks for celebrations of victory or peace. During the Renaissance, two European schools of pyrotechnic thought emerged, one in Italy and the other at Nuremberg, Germany. Vannoccio Biringuccio, born in 1480, was a member of the guild Fraternita di Santa Barbara but broke with the tradition of secrecy by setting down everything he knew in a book titled De la pirotechnia, written in vernacular. The first printed book on either gunpowder or metalworking, it was published posthumously in 1540, with 9 editions over 138 years, and also reprinted by MIT Press in 1966.[54] By the mid-17th century fireworks were used for entertainment on an unprecedented scale in Europe, being popular even at resorts and public gardens.[56] +In 1774 Louis XVI ascended to the throne of France at age 20. After he discovered that France was not self-sufficient in gunpowder, a Gunpowder Administration was established; to head it, the lawyer Antoine Lavoisier was appointed. Although from a bourgeois family, after his degree in law Lavoisier became wealthy from a company set up to collect taxes for the Crown; this allowed him to pursue experimental natural science as a hobby.[57] +Without access to cheap Indian saltpeter (controlled by the British), for hundreds of years France had relied on saltpetermen with royal warrants, the droit de fouille or "right to dig", to seize nitrous-containing soil and demolished walls of barnyards, without compensation to the owners.[58] This caused farmers, the wealthy, or entire villages to bribe the petermen and the associated bureaucracy to leave their buildings alone and the saltpeter uncollected. Lavoisier instituted a crash program to increase saltpeter production, revised (and later eliminated) the droit de fouille, researched best refining and powder manufacturing methods, instituted management and record-keeping, and established pricing that encouraged private investment in works. Although saltpeter from new Prussian-style putrefaction works had not been produced yet (the process taking about 18 months), in only a year France had gunpowder to export. A chief beneficiary of this surplus was the American Revolution. By careful testing and adjusting the proportions and grinding time, powder from mills such as at Essonne outside Paris became the best in the world by 1788, and inexpensive.[58] [59] +Britain and Ireland[edit] + +The old Powder or Pouther magazine dating from 1642, built by order of Charles I. Irvine, North Ayrshire, Scotland +Gunpowder production in Britain appears to have started in the mid 14th century AD with the aim of supplying the English Crown.[60] Records show that gunpowder was being made, in England, in 1346, at the Tower of London; a powder house existed at the Tower in 1461; and in 1515 three King's gunpowder makers worked there.[60] Gunpowder was also being made or stored at other Royal castles, such as Portchester. By the early 14th century, according to N.J.G. Pounds's study The Medieval Castle in England and Wales, many English castles had been deserted and others were crumbling. Their military significance faded except on the borders. Gunpowder had made smaller castles useless.[61] +Henry VIII of England was short of gunpowder when he invaded France in 1544 and England needed to import gunpowder via the port of Antwerp in what is now Belgium.[60] +The English Civil War (1642–1645) led to an expansion of the gunpowder industry, with the repeal of the Royal Patent in August 1641.[60] +Two British physicists, Andrew Noble and Frederick Abel, worked to improve the properties of black powder during the late 19th century. This formed the basis for the Noble-Abel gas equation for internal ballistics.[62] +The introduction of smokeless powder in the late 19th century led to a contraction of the gunpowder industry. After the end of World War I, the majority of the United Kingdom gunpowder manufacturers merged into a single company, "Explosives Trades limited"; and number of sites were closed down, including those in Ireland. This company became Nobel Industries Limited; and in 1926 became a founding member of Imperial Chemical Industries. The Home Office removed gunpowder from its list of Permitted Explosives; and shortly afterwards, on 31 December 1931, the former Curtis & Harvey's Glynneath gunpowder factory at Pontneddfechan, in Wales, closed down, and it was demolished by fire in 1932.[63] + +Gunpowder storing barrels at Martello tower in Point Pleasant Park +The last remaining gunpowder mill at the Royal Gunpowder Factory, Waltham Abbey was damaged by a German parachute mine in 1941 and it never reopened.[64] This was followed by the closure of the gunpowder section at the Royal Ordnance Factory, ROF Chorley, the section was closed and demolished at the end of World War II; and ICI Nobel's Roslin gunpowder factory, which closed in 1954.[64][65] +This left the sole United Kingdom gunpowder factory at ICI Nobel's Ardeer site in Scotland; it too closed in October 1976.[64] Since then gunpowder has been imported into the United Kingdom. In the late 1970s/early 1980s gunpowder was bought from eastern Europe, particularly from what was then the German Democratic Republic and former Yugoslavia. +India[edit] + +In the year 1780 the British began to annex the territories of the Sultanate of Mysore, during the Second Anglo-Mysore War. The British battalion was defeated during the Battle of Guntur, by the forces of Hyder Ali, who effectively utilized Mysorean rockets and Rocket artillery against the closely massed British forces. + +Mughal Emperor Shah Jahan, hunting deer using a Matchlock as the sun sets in the horizon. +Gunpowder and gunpowder weapons were transmitted to India through the Mongol invasions of India.[66][67] The Mongols were defeated by Alauddin Khilji of the Delhi Sultanate, and some of the Mongol soldiers remained in northern India after their conversion to Islam.[67] It was written in the Tarikh-i Firishta (1606–1607) that Nasir ud din Mahmud the ruler of the Delhi Sultanate presented the envoy of the Mongol ruler Hulegu Khan with a dazzling pyrotechnics display upon his arrival in Delhi in 1258 AD. Nasir ud din Mahmud tried to express his strength as a ruler and tried to ward off any Mongol attempt similar to the Siege of Baghdad (1258).[68] Firearms known as top-o-tufak also existed in many Muslim kingdoms in India by as early as 1366 AD.[68] From then on the employment of gunpowder warfare in India was prevalent, with events such as the "Siege of Belgaum" in 1473 by Sultan Muhammad Shah Bahmani.[69] +The shipwrecked Ottoman Admiral Seydi Ali Reis is known to have introduced the earliest type of Matchlock weapons, which the Ottomans used against the Portuguese during the Siege of Diu (1531). After that, a diverse variety of firearms; large guns in particular, became visible in Tanjore, Dacca, Bijapur, and Murshidabad.[70] Guns made of bronze were recovered from Calicut (1504)- the former capital of the Zamorins[71] +The Mughal Emperor Akbar mass-produced matchlocks for the Mughal Army. Akbar is personally known to have shot a leading Rajput commander during the Siege of Chittorgarh.[72] The Mughals began to use Bamboo rockets (mainly for signalling) and employ Sappers: special units that undermined heavy stone fortifications to plant gunpowder charges. +The Mughal Emperor Shah Jahan is known to have introduced much more advanced Matchlocks, their designs were a combination of Ottoman and Mughal designs. Shah Jahan also countered the British and other Europeans in his province of Gujarāt, which supplied Europe saltpeter for use in gunpowder warfare during the 17th century.[73] Bengal and Mālwa participated in saltpeter production.[73] The Dutch, French, Portuguese, and English used Chhapra as a center of saltpeter refining.[73] +Ever since the founding of the Sultanate of Mysore by Hyder Ali, French military officers were employed to train the Mysore Army. Hyder Ali and his son Tipu Sultan were the first to introduce modern Cannons and Muskets, their army was also the first in India to have official uniforms. During the Second Anglo-Mysore War Hyder Ali and his son Tipu Sultan unleashed the Mysorean rockets at their British opponents effectively defeating them on various occasions. The Mysorean rockets inspired the development of the Congreve rocket, which the British widely utilized during the Napoleonic Wars and the War of 1812.[74] +Indonesia[edit] +The Javanese Majapahit Empire was arguably able to encompass much of modern day Indonesia due to its unique mastery of bronze smithing and use of a central arsenal fed by a large number of cottage industries within the immediate region. Documentary and archeological evidence indicate that Arab or Indian traders introduced gunpowder, gonnes, muskets, blunderbusses, and cannons to the Javanese, Acehnese, and Batak via long established commercial trade routes around the early to mid 14th century CE.[75] Portuguese and Spanish invaders were unpleasantly surprised and occasionally even outgunned on occasion.[76] The resurgent Singhasari Empire overtook Sriwijaya and later emerged as the Majapahit whose warfare featured the use of fire-arms and cannonade.[77] Circa 1540 CE the Javanese, always alert for new weapons found the newly arrived Portuguese weaponry superior to that of the locally made variants. Javanese bronze breech-loaded swivel-guns, known as meriam, or erroneously as lantaka, was used widely by the Majapahit navy as well as by pirates and rival lords. The demise of the Majapahit empire and the dispersal of disaffected skilled bronze cannon-smiths to Brunei, modern Sumatra, Malaysia and the Philippines lead to widespread use, especially in the Makassar Strait. +Saltpeter harvesting was recorded by Dutch and German travelers as being common in even the smallest villages and was collected from the decomposition process of large dung hills specifically piled for the purpose. The Dutch punishment for possession of non-permitted gunpowder appears to have been amputation.[78] Ownership and manufacture of gunpowder was later prohibited by the colonial Dutch occupiers.[75] According to a colonel McKenzie quoted in Sir Thomas Stamford Raffles, The History of Java (1817), the purest sulfur was supplied from a crater from a mountain near the straits of Bali.[77] +Manufacturing technology[edit] + +Edge-runner mill in a restored mill, at Eleutherian Mills +For the most powerful black powder meal, a wood charcoal is used. The best wood for the purpose is Pacific willow,[79] but others such as alder or buckthorn can be used. In Great Britain between the 15th to 19th centuries charcoal from alder buckthorn was greatly prized for gunpowder manufacture; cottonwood was used by the American Confederate States.[80] The ingredients are reduced in particle size and mixed as intimately as possible. Originally this was with a mortar-and-pestle or a similarly operating stamping-mill, using copper, bronze or other non-sparking materials, until supplanted by the rotating ball mill principle with non-sparking bronze or lead. Historically, a marble or limestone edge runner mill, running on a limestone bed was used in Great Britain; however, by the mid 19th century AD this had changed to either an iron shod stone wheel or a cast iron wheel running on an iron bed.[81] The mix was dampened with alcohol or water during grinding to prevent accidental ignition. This also helps the extremely soluble saltpeter mix into the microscopic nooks and crannies of the very high surface-area charcoal. +Around the late 14th century AD, European powdermakers first began adding liquid during grinding to improve mixing, reduce dust, and with it the risk of explosion.[82] The powder-makers would then shape the resulting paste of dampened gunpowder, known as mill cake, into corns, or grains, to dry. Not only did corned powder keep better because of its reduced surface area, gunners also found that it was more powerful and easier to load into guns. Before long, powder-makers standardized the process by forcing mill cake through sieves instead of corning powder by hand. +The improvement was based on reducing the surface area of a higher density composition. At the beginning of the 19th century, makers increased density further by static pressing. They shoveled damp mill cake into a two-foot square box, placed this beneath a screw press and reduced it to 1/2 its volume. "Presscake" had the hardness of slate. They broke the dried slabs with hammers or rollers, and sorted the granules with sieves into different grades. In the United States, Irenee du Pont, who had learned the trade from Lavoisier, tumbled the dried grains in rotating barrels to round the edges and increase durability during shipping and handling. (Sharp grains rounded off in transport, producing fine "meal dust" that changed the burning properties.) +Another advance was the manufacture of kiln charcoal by distilling wood in heated iron retorts instead of burning it in earthen pits. Controlling the temperature influenced the power and consistency of the finished gunpowder. In 1863, in response to high prices for Indian saltpeter, DuPont chemists developed a process using potash or mined potassium chloride to convert plentiful Chilean sodium nitrate to potassium nitrate.[83] +During the 18th century gunpowder factories became increasingly dependent on mechanical energy.[84] Despite mechanization, production difficulties related to humidity control, especially during the pressing, were still present in the late 19th century. A paper from 1885 laments that "Gunpowder is such a nervous and sensitive spirit, that in almost every process of manufacture it changes under our hands as the weather changes." Pressing times to the desired density could vary by factor of three depending on the atmospheric humidity.[85] +Composition and characteristics[edit] +The term black powder was coined in the late 19th century, primarily in the United States, to distinguish prior gunpowder formulations from the new smokeless powders and semi-smokeless powders, in cases where these are not referred to as cordite. Semi-smokeless powders featured bulk volume properties that approximated black powder, but had significantly reduced amounts of smoke and combustion products. Smokeless powder has different burning properties (pressure vs. time) and can generate higher pressures and work per gram. This can rupture older weapons designed for black powder. Smokeless powders ranged in color from brownish tan to yellow to white. Most of the bulk semi-smokeless powders ceased to be manufactured in the 1920s.[86][87][88] +Black powder is a granular mixture of +a nitrate, typically potassium nitrate (KNO3), which supplies oxygen for the reaction; +charcoal, which provides carbon and other fuel for the reaction, simplified as carbon (C); +sulfur (S), which, while also serving as a fuel, lowers the temperature required to ignite the mixture, thereby increasing the rate of combustion. +Potassium nitrate is the most important ingredient in terms of both bulk and function because the combustion process releases oxygen from the potassium nitrate, promoting the rapid burning of the other ingredients.[89] To reduce the likelihood of accidental ignition by static electricity, the granules of modern black powder are typically coated with graphite, which prevents the build-up of electrostatic charge. +Charcoal does not consist of pure carbon; rather, it consists of partially pyrolyzed cellulose, in which the wood is not completely decomposed. Carbon differs from charcoal. Whereas charcoal's autoignition temperature is relatively low, carbon's is much greater. Thus, a black powder composition containing pure carbon would burn similarly to a match head, at best.[90] +The current standard composition for the black powders that are manufactured by pyrotechnicians was adopted as long ago as 1780. Proportions by weight are 75% potassium nitrate (known as saltpeter or saltpetre), 15% softwood charcoal, and 10% sulfur.[81] These ratios have varied over the centuries and by country, and can be altered somewhat depending on the purpose of the powder. For instance, power grades of black powder, unsuitable for use in firearms but adequate for blasting rock in quarrying operations, is called blasting powder rather than gunpowder with standard proportions of 70% nitrate, 14% charcoal, and 16% sulfur; blasting powder may be made with the cheaper sodium nitrate substituted for potassium nitrate and proportions may be as low as 40% nitrate, 30% charcoal, and 30% sulfur.[91] In 1857, Lamont DuPont solved the main problem of using cheaper sodium nitrate formulations when he patented DuPont "B" Blasting powder. After manufacturing grains from press-cake in the usual way, his process tumbled the powder with graphite dust for 12 hours. This formed a graphite coating on each grain that reduced its ability to absorb moisture.[92] +French war powder in 1879 used the ratio 75% saltpeter, 12.5% charcoal, 12.5% sulfur. English war powder in 1879 used the ratio 75% saltpeter, 15% charcoal, 10% sulfur.[93] The British Congreve rockets used 62.4% saltpeter, 23.2% charcoal and 14.4% sulfur, but the British Mark VII gunpowder was changed to 65% saltpeter, 20% charcoal and 15% sulfur.[94] The explanation for the wide variety in formulation relates to usage. Powder used for rocketry can use a slower burn rate since it accelerates the projectile for a much longer time—whereas powders for weapons such as flintlocks, cap-locks, or matchlocks need a higher burn rate to accelerate the projectile in a much shorter distance. Cannons usually used lower burn rate powders, because most would burst with higher burn rate powders. +Serpentine[edit] +The original dry-compounded powder used in fifteenth-century Europe was known as "Serpentine", either a reference to Satan[95] or to a common artillery piece that used it.[96] The ingredients were ground together with a mortar and pestle, perhaps for 24 hours,[96] resulting in a fine flour. Vibration during transportation could cause the components to separate again, requiring remixing in the field. Also if the quality of the saltpeter was low (for instance if it was contaminated with highly hygroscopic calcium nitrate), or if the powder was simply old (due to the mildly hygroscopic nature of potassium nitrate), in humid weather it would need to be re-dried. The dust from "repairing" powder in the field was a major hazard. +Loading cannons or bombards before the powder-making advances of the Renaissance was a skilled art. Fine powder loaded haphazardly or too tightly would burn incompletely or too slowly. Typically, the breech-loading powder chamber in the rear of the piece was filled only about half full, the serpentine powder neither too compressed nor too loose, a wooden bung pounded in to seal the chamber from the barrel when assembled, and the projectile placed on. A carefully determined empty space was necessary for the charge to burn effectively. When the cannon was fired through the touchhole, turbulence from the initial surface combustion caused the rest of the powder to be rapidly exposed to the flame.[96] +The advent of much more powerful and easy to use corned powder changed this procedure, but serpentine was used with older guns into the seventeenth century.[97] +Corning[edit] +For gunpowder to explode effectively, the combustible ingredients must be reduced to the smallest possible particle sizes, and thoroughly mixed as possible. Once mixed, however, for better results in a gun, makers discovered that the final product should be in the form of individual, dense, grains that spread the fire quickly from grain to grain, much as straw or twigs catch fire more quickly than a pile of sawdust. +Primarily for safety reasons, size reduction and mixing is done while the ingredients are damp, usually with water. After 1800, instead of forming grains by hand or with sieves, the damp mill-cake was pressed in molds to increase its density and extract the liquid, forming press-cake. The pressing took varying amounts of time, depending on conditions such as atmospheric humidity. The hard, dense product was broken again into tiny pieces, which were separated with sieves to produce a uniform product for each purpose: coarse powders for cannons, finer grained powders for muskets, and the finest for small hand guns and priming.[97] Inappropriately fine-grained powder often caused cannons to burst before the projectile could move down the barrel, due to the high initial spike in pressure.[98] Mammoth powder with large grains made for Rodman's 15-inch cannon reduced the pressure to only 20 percent as high as ordinary cannon powder would have produced.[99] +In the mid-nineteenth century, measurements were made determining that the burning rate within a grain of black powder (or a tightly packed mass) is about 0.20 fps, while the rate of ignition propagation from grain to grain is around 30 fps, over two orders of magnitude faster.[97] +Modern types[edit] +Modern corning first compresses the fine black powder meal into blocks with a fixed density (1.7 g/cm³).[100] In the United States, gunpowder grains were designated F (for fine) or C (for coarse). Grain diameter decreased with a larger number of Fs and increased with a larger number of Cs, ranging from about 2 mm for 7F to 15 mm for 7C. Even larger grains were produced for artillery bore diameters greater than about 17 cm (6.7 in). The standard DuPont Mammoth powder developed by Thomas Rodman and Lammot du Pont for use during the American Civil War had grains averaging 0.6 inches diameter, with edges rounded in a glazing barrel.[99] Other versions had grains the size of golf and tennis balls for use in 20-inch (50-cm) Rodman guns.[101] In 1875 DuPont introduced Hexagonal powder for large artillery, which was pressed using shaped plates with a small center core—about 1.5 inches diameter, like a wagon wheel nut, the center hole widened as the grain burned.[102] By 1882 German makers also produced hexagonal grained powders of a similar size for artillery.[102] +By the late 19th century manufacturing focused on standard grades of black powder from Fg used in large bore rifles and shotguns, through FFg (medium and small-bore arms such as muskets and fusils), FFFg (small-bore rifles and pistols), and FFFFg (extreme small bore, short pistols and most commonly for priming flintlocks).[103] A coarser grade for use in military artillery blanks was designated A-1. These grades were sorted on a system of screens with oversize retained on a mesh of 6 wires per inch, A-1 retained on 10 wires per inch, Fg retained on 14, FFg on 24, FFFg on 46, and FFFFg on 60. Fines designated FFFFFg were usually reprocessed to minimize explosive dust hazards.[104] In the United Kingdom, the main service gunpowders were classified RFG (rifle grained fine) with diameter of one or two millimeters and RLG (rifle grained large) for grain diameters between two and six millimeters.[101] Gunpowder grains can alternatively be categorized by mesh size: the BSS sieve mesh size, being the smallest mesh size, which retains no grains. Recognized grain sizes are Gunpowder G 7, G 20, G 40, and G 90. +Owing to the large market of antique and replica black-powder firearms in the US, modern gunpowder substitutes like Pyrodex, Triple Seven and Black Mag3[105] pellets have been developed since the 1970s. These products, which should not be confused with smokeless powders, aim to produce less fouling (solid residue), while maintaining the traditional volumetric measurement system for charges. Claims of less corrosiveness of these products have been controversial however. New cleaning products for black-powder guns have also been developed for this market.[103] +Other types of gunpowder[edit] +Besides black powder, there are other historically important types of gunpowder. "Brown gunpowder" is cited as composed of 79% nitre, 3% sulfur, and 18% charcoal per 100 of dry powder, with about 2% moisture. Prismatic Brown Powder is a large-grained product the Rottweil Company introduced in 1884 in Germany, which was adopted by the British Royal Navy shortly thereafter. The French navy adopted a fine, 3.1 millimeter, not prismatic grained product called Slow Burning Cocoa (SBC) or "cocoa powder". These brown powders reduced burning rate even further by using as little as 2 percent sulfur and using charcoal made from rye straw that had not been completely charred, hence the brown color.[102] +Lesmok powder was a product developed by DuPont in 1911[106] one of several semi-smokeless products in the industry containing a mixture of black and nitrocellulose powder. It was sold to Winchester and others primarily for .22 and .32 small calibers. Its advantage was that it was believed at the time to be less corrosive than smokeless powders then in use. It was not understood in the U.S. until the 1920s that the actual source of corrosion was the potassium chloride residue from potassium chlorate sensitized primers. The bulkier black powder fouling better disperses primer residue. Failure to mitigate primer corrosion by dispersion caused the false impression that nitrocellulose-based powder caused corrosion.[107] Lesmok had some of the bulk of black powder for dispersing primer residue, but somewhat less total bulk than straight black powder, thus requiring less frequent bore cleaning.[108] It was last sold by Winchester in 1947. +Sulfur-free gunpowder[edit] + +Burst barrel of a muzzle loader pistol replica, which was loaded with nitrocellulose powder instead of black powder and couldn't withstand the higher pressures of the modern propellant +The development of smokeless powders, such as cordite, in the late 19th century created the need for a spark-sensitive priming charge, such as gunpowder. However, the sulfur content of traditional gunpowders caused corrosion problems with Cordite Mk I and this led to the introduction of a range of sulfur-free gunpowders, of varying grain sizes.[64] They typically contain 70.5 parts of saltpeter and 29.5 parts of charcoal.[64] Like black powder, they were produced in different grain sizes. In the United Kingdom, the finest grain was known as sulfur-free mealed powder (SMP). Coarser grains were numbered as sulfur-free gunpowder (SFG n): 'SFG 12', 'SFG 20', 'SFG 40' and 'SFG 90', for example; where the number represents the smallest BSS sieve mesh size, which retained no grains. +Sulfur's main role in gunpowder is to decrease the ignition temperature. A sample reaction for sulfur-free gunpowder would be +6 KNO3 + C7H4O → 3 K2CO3 + 4 CO2 + 2 H2O + 3 N2 +Combustion characteristics[edit] +A simple, commonly cited, chemical equation for the combustion of black powder is +2 KNO3 + S + 3 C → K2S + N2 + 3 CO2. +A balanced, but still simplified, equation is[109] +10 KNO3 + 3 S + 8 C → 2 K2CO3 + 3 K2SO4 + 6 CO2 + 5 N2. +Although charcoal's chemical formula varies, it can be best summed up by its empirical formula: C7H4O. +Therefore, an even more accurate equation of the decomposition of regular black powder with the use of sulfur can be described as: +6 KNO3 + C7H4O + 2 S → K2CO3 + K2SO4 + K2S + 4 CO2 + 2 CO + 2 H2O + 3 N2 +Black powder without the use of sulfur: +10 KNO3 + 2 C7H4O → 5 K2CO3 + 4 CO2 + 5 CO + 4 H2O + 5 N2 +The burning of gunpowder does not take place as a single reaction, however, and the byproducts are not easily predicted. One study's results showed that it produced (in order of descending quantities) 55.91% solid products: potassium carbonate, potassium sulfate, potassium sulfide, sulfur, potassium nitrate, potassium thiocyanate, carbon, ammonium carbonate and 42.98% gaseous products: carbon dioxide, nitrogen, carbon monoxide, hydrogen sulfide, hydrogen, methane, 1.11% water. +Black powder made with less-expensive and more plentiful sodium nitrate (in appropriate proportions) works just as well but is more hygroscopic than powders made from Potassium nitrate—popularly known as saltpeter. Because corned black powder grains made with saltpeter are less affected by moisture in the air, they can be stored unsealed without degradation by humidity. Muzzleloaders have been known to fire after hanging on a wall for decades in a loaded state, provided they remained dry. By contrast, black powder made with sodium nitrate must be kept sealed to remain stable. +Gunpowder contains 3 megajoules per kilogram, and contains its own oxidant. For comparison, the energy density of TNT is 4.7 megajoules per kilogram, and the energy density of gasoline is 47.2 megajoules per kilogram. Gunpowder is a low explosive and as such it does not detonate; rather it deflagrates. Since it contains its own oxidizer and additionally burns faster under pressure, its combustion is capable of rupturing containers such as shell, grenade, or improvised "pipe bomb" or "pressure cooker" casings, forming shrapnel. +Advantages[edit] +In quarrying, high explosives are generally preferred for shattering rock. However, because of its low brisance, black powder causes fewer fractures and results in more usable stone compared to other explosives, making black powder useful for blasting monumental stone such as granite and marble. Black powder is well suited for blank rounds, signal flares, burst charges, and rescue-line launches. Black powder is also used in fireworks for lifting shells, in rockets as fuel, and in certain special effects. +Disadvantages[edit] +Black powder has a low energy density compared to modern "smokeless" powders, and thus to achieve high energy loadings, large amounts of black powder are needed with heavy projectiles. Black powder also produces thick smoke as a byproduct, which in military applications may give a soldier's location away to an enemy observer and may also impair aiming for additional shots. +Combustion converts less than half the mass of black powder to gas. The rest ends up as a thick layer of soot inside the barrel. In addition to being a nuisance, the residue from burnt black powder is hygroscopic and with the addition of moisture absorbed from the air, this residue forms a caustic substance. The soot contains potassium oxide or sodium oxide that turns into potassium hydroxide, or sodium hydroxide, which corrodes wrought iron or steel gun barrels. Black powder arms must be well cleaned both inside and out to remove the residue. The matchlock musket or pistol (an early gun ignition system), as well as the flintlock would often be unusable in wet weather, due to powder in the pan being exposed and dampened. Because of this unreliability, soldiers carrying muskets, known as musketeers, were armed with additional weapons such as swords or pikes. The bayonet was developed to allow the musket to be used as a pike, thus eliminating the need for the soldier to carry a secondary weapon. +Transportation[edit] +The United Nations Model Regulations on the Transportation of Dangerous Goods and national transportation authorities, such as United States Department of Transportation, have classified gunpowder (black powder) as a Group A: Primary explosive substance for shipment because it ignites so easily. Complete manufactured devices containing black powder are usually classified as Group D: Secondary detonating substance, or black powder, or article containing secondary detonating substance, such as firework, class D model rocket engine, etc., for shipment because they are harder to ignite than loose powder. As explosives, they all fall into the category of Class 1. +Other uses[edit] +Besides its use as an explosive, gunpowder has been occasionally employed for other purposes; after the Battle of Aspern-Essling (1809), the surgeon of the Napoleonic Army Larrey combated the lack of food for the wounded under his care by preparing a bouillon of horse meat seasoned with gunpowder for lack of salt.[110][111] It was also used for sterilizing on ships when there was no alcohol. +Jack Tars (British sailors) used gunpowder to create tattoos when ink wasn't available, by pricking the skin and rubbing the powder into the wound in a method known as traumatic tattooing.[112] +Christiaan Huygens experimented with gunpowder in 1673 in an early attempt to build an internal combustion engine, but he did not succeed. Modern attempts to recreate his invention were similarly unsuccessful. +Fireworks use gunpowder as lifting and burst charges, although sometimes other more powerful compositions are added to the burst charge to improve performance in small shells or provide a louder report. Most modern firecrackers no longer contain black powder. +Beginning in the 1930s, gunpowder or smokeless powder was used in rivet guns, stun guns for animals, cable splicers and other industrial construction tools.[113] The "stud gun" drove nails or screws into solid concrete, a function not possible with hydraulic tools. See Powder-actuated tool. Shotguns have been used to eliminate persistent material rings in operating rotary kilns (such as those for cement, lime, phosphate, etc.) and clinker in operating furnaces, and commercial tools make the method more reliable.[114] +Near London in 1853, Captain Shrapnel demonstrated a method for crushing gold-bearing ores by firing them from a cannon into an iron chamber, and "much satisfaction was expressed by all present". He hoped it would be useful on the goldfields of California and Australia. Nothing came of the invention, as continuously-operating crushing machines that achieved more reliable comminution were already coming into use.[115] +See also[edit] +Ballistics +Black powder substitute +Faversham explosives industry +Bulk loaded liquid propellants +Gunpowder magazine +Gunpowder Plot +Berthold Schwarz +Gunpowder warfare +History of gunpowder +Technology of the Song Dynasty +References[edit] +Jump up ^ http://www.merriam-webster.com/dictionary/gunpowder +Jump up ^ Jai Prakash Agrawal (2010). High Energy Materials: Propellants, Explosives and Pyrotechnics. Wiley-VCH. p. 69. ISBN 978-3-527-32610-5. +Jump up ^ David Cressy, Saltpeter: The Mother of Gunpowder (Oxford University Press, 2013) +Jump up ^ Owen Compliance Services. "Black Powder". Material Safety Data Sheet. Retrieved 31 August 2014. +Jump up ^ http://www.history.com/shows/ancient-discoveries/articles/who-built-it-first-2 +Jump up ^ http://chemistry.about.com/od/historyofchemistry/a/gunpowder.htm +Jump up ^ Chase 2003:31 : "the earliest surviving formulas for gunpowder can be found in the Wujing zongyao, a military work from around 1040" +^ Jump up to: a b c Buchanan 2006, p. 2 "With its ninth century AD origins in China, the knowledge of gunpowder emerged from the search by alchemists for the secrets of life, to filter through the channels of Middle Eastern culture, and take root in Europe with consequences that form the context of the studies in this volume." +^ Jump up to: a b c Joseph Needham; Gwei-Djen Lu; Ling Wang (1987). Science and civilisation in China, Volume 5, Part 7. Cambridge University Press. pp. 48–50. ISBN 978-0-521-30358-3. +Jump up ^ Hazel Rossotti (2002). Fire: Servant, Scourge, and Enigma. Courier Dover Publications. pp. 132–137. ISBN 978-0-486-42261-9. +Jump up ^ Jack Kelly Gunpowder: Alchemy, Bombards, and Pyrotechnics: The History of the Explosive that Changed the World, Perseus Books Group: 2005, ISBN 0-465-03722-4, ISBN 978-0-465-03722-3: 272 pages +Jump up ^ St. C. Easton: "Roger Bacon and his Search for a Universal Science", Oxford (1962) +^ Jump up to: a b Gábor Ágoston (2005). Guns for the sultan: military power and the weapons industry in the Ottoman Empire. Cambridge University Press. p. 15. ISBN 978-0-521-84313-3. +Jump up ^ Ingham-Brown, George (1989) The Big Bang: A History of Explosives, Sutton Publishers, ISBN 0-7509-1878-0, ISBN 978-0-7509-1878-7, page vi +Jump up ^ Kelly, Jack (2005) Gunpowder: Alchemy, Bombards, and Pyrotechnics: The History of the Explosive that Changed the World, Perseus Books Group, ISBN 0-465-03722-4, ISBN 978-0-465-03722-3, page 22 +Jump up ^ Bert S. Hall, "Introduction, 1999" pp. xvi–xvii to the reprinting of James Riddick Partington (1960). A history of Greek fire and gunpowder. JHU Press. ISBN 978-0-8018-5954-0. +^ Jump up to: a b Peter Purton (2009). A History of the Late Medieval Siege, 1200–1500. Boydell & Brewer. pp. 108–109. ISBN 978-1-84383-449-6. +Jump up ^ Bert S. Hall, "Introduction, 1999" p. xvii to the reprinting of James Riddick Partington (1960). A history of Greek fire and gunpowder. JHU Press. ISBN 978-0-8018-5954-0. +Jump up ^ Buchanan. "Editor's Introduction: Setting the Context", in Buchanan 2006. +^ Jump up to: a b Chase 2003:31–32 +Jump up ^ Lorge, Peter A. (2008). The Asian military revolution, 1300-2000 : from gunpowder to the bomb (1. publ. ed.). Cambridge: Cambridge University Press. p. 32. ISBN 978052160954-8. +Jump up ^ Kelly 2004:4 +Jump up ^ The Big Book of Trivia Fun, Kidsbooks, 2004 +Jump up ^ Peter Allan Lorge (2008), The Asian military revolution: from gunpowder to the bomb, Cambridge University Press, p. 18, ISBN 978-0-521-60954-8 +Jump up ^ Needham 1986, p. 7 "Without doubt it was in the previous century, around +850, that the early alchemical experiments on the constituents of gunpowder, with its self-contained oxygen, reached their climax in the appearance of the mixture itself." +Jump up ^ Chase 2003:1 "The earliest known formula for gunpowder can be found in a Chinese work dating probably from the 800s. The Chinese wasted little time in applying it to warfare, and they produced a variety of gunpowder weapons, including flamethrowers, rockets, bombs, and land mines, before inventing firearms." +Jump up ^ Chase 2003:1 +Jump up ^ Delgado, James (February 2003). "Relics of the Kamikaze". Archaeology (Archaeological Institute of America) 56 (1). +Jump up ^ Chase 2003:31 +Jump up ^ Peter Allan Lorge (2008), The Asian military revolution: from gunpowder to the bomb, Cambridge University Press, pp. 33–34, ISBN 978-0-521-60954-8 +Jump up ^ Kelly 2004:22 'Around year 1240, Arabs acquired knowledge of saltpeter ("Chinese snow") from the East, perhaps through India. They knew of gunpowder soon afterward. They also learned about fireworks ("Chinese flowers") and rockets ("Chinese arrows"). Arab warriors had acquired fire lances before year 1280. Around that same year, a Syrian named Hasan al-Rammah wrote a book that, as he put it, "treats of machines of fire to be used for amusement or for useful purposes." He talked of rockets, fireworks, fire lances, and other incendiaries, using terms that suggested he derived his knowledge from Chinese sources. He gave instructions for the purification of saltpeter and recipes for making different types of gunpowder.' +^ Jump up to: a b c d Hassan, Ahmad Y. "Transfer of Islamic Technology to the West: Part III". History of Science and Technology in Islam. +Jump up ^ Peter Watson (2006). Ideas: A History of Thought and Invention, from Fire to Freud. HarperCollins. p. 304. ISBN 978-0-06-093564-1. The first use of a metal tube in this context was made around 1280 in the wars between the Song and the Mongols, where a new term, chong, was invented to describe the new horror...Like paper, it reached the West via the Muslims, in this case the writings of the Andalusian botanist Ibn al-Baytar, who died in Damascus in 1248. The Arabic term for saltpetre is 'Chinese snow' while the Persian usage is 'Chinese salt'.28 +Jump up ^ Cathal J. Nolan (2006). The age of wars of religion, 1000–1650: an encyclopedia of global warfare and civilization. Volume 1 of Greenwood encyclopedias of modern world wars. Greenwood Publishing Group. p. 365. ISBN 0-313-33733-0. Retrieved 2011-11-28. In either case, there is linguistic evidence of Chinese origins of the technology: in Damascus, Arabs called the saltpeter used in making gunpowder " Chinese snow," while in Iran it was called "Chinese salt." Whatever the migratory route +Jump up ^ Oliver Frederick Gillilan Hogg (1970). Artillery: its origin, heyday, and decline. Archon Books. p. 123. The Chinese were certainly acquainted with saltpetre, the essential ingredient of gunpowder. They called it Chinese Snow and employed it early in the Christian era in the manufacture of fireworks and rockets. +Jump up ^ Oliver Frederick Gillilan Hogg (1963). English artillery, 1326–1716: being the history of artillery in this country prior to the formation of the Royal Regiment of Artillery. Royal Artillery Institution. p. 42. The Chinese were certainly acquainted with saltpetre, the essential ingredient of gunpowder. They called it Chinese Snow and employed it early in the Christian era in the manufacture of fireworks and rockets. +Jump up ^ Oliver Frederick Gillilan Hogg (1993). Clubs to cannon: warfare and weapons before the introduction of gunpowder (reprint ed.). Barnes & Noble Books. p. 216. ISBN 1-56619-364-8. Retrieved 2011-11-28. The Chinese were certainly acquainted with saltpetre, the essential ingredient of gunpowder. They called it Chinese snow and used it early in the Christian era in the manufacture of fireworks and rockets. +Jump up ^ Partington, J. R. (1960). A History of Greek Fire and Gunpowder (illustrated, reprint ed.). JHU Press. p. 335. ISBN 0801859549. Retrieved 2014-11-21. +Jump up ^ Needham, Joseph; Yu, Ping-Yu (1980). Needham, Joseph, ed. Science and Civilisation in China: Volume 5, Chemistry and Chemical Technology, Part 4, Spagyrical Discovery and Invention: Apparatus, Theories and Gifts. Volume 5 (Issue 4 of Science and Civilisation in China). Contributors Joseph Needham, Lu Gwei-Djen, Nathan Sivin (illustrated, reprint ed.). Cambridge University Press. p. 194. ISBN 052108573X. Retrieved 2014-11-21. +Jump up ^ Khan 1996 +^ Jump up to: a b Khan 2004:6 +Jump up ^ Ancient Discoveries, Episode 12: Machines of the East, History Channel, 2007 (Part 4 and Part 5) +Jump up ^ Nelson, Cameron Rubaloff (2010-07). Manufacture and transportation of gunpowder in the Ottoman Empire: 1400-1800 M.A. Thesis. +Jump up ^ William H. McNeill (1992). The Rise of the West: A History of the Human Community. University of Chicago Press. p. 492. ISBN 0-226-56141-0. Retrieved 29 July 2011. +Jump up ^ Michael Kohn (2006), Dateline Mongolia: An American Journalist in Nomad's Land, RDR Books, p. 28, ISBN 1-57143-155-1, retrieved 29 July 2011 +Jump up ^ Robert Cowley (1993). Robert Cowley, ed. Experience of War (reprint ed.). Random House Inc. p. 86. ISBN 0-440-50553-4. Retrieved 29 July 2011. +Jump up ^ Kenneth Warren Chase (2003). Firearms: a global history to 1700 (illustrated ed.). Cambridge University Press. p. 58. ISBN 0-521-82274-2. Retrieved 29 July 2011. +Jump up ^ C. F. Temler, Historische Abhandlungen der Koniglichen Gesellschaft der Wissenschaften zu Kopenhagen ... ubersetzt ... von V. A. Heinze, Kiel, Dresden and Leipzig, 1782, i, 168, as cited in Partington, p. 228, footnote 6. +Jump up ^ Joseph Needham; Gwei-Djen Lu; Ling Wang (1987). Science and civilisation in China, Volume 5, Part 7. Cambridge University Press. p. 358. ISBN 978-0-521-30358-3. +Jump up ^ Bert S. Hall, "Introduction, 1999" p. xxiv to the reprinting of James Riddick Partington (1960). A history of Greek fire and gunpowder. JHU Press. ISBN 978-0-8018-5954-0. +Jump up ^ Partington 1960:60 +^ Jump up to: a b Partington 1960:48–49, 54 +^ Jump up to: a b Partington 1960:82–83 +^ Jump up to: a b c d Kelly 2004, p.61 +Jump up ^ Molerus, Otto. "History of Civilization in the Western Hemisphere from the Point of View of Particulate Technology, Part 2," Advanced Powder Technology 7 (1996): 161-66 +Jump up ^ Microsoft Encarta Online Encyclopedia 2007 Archived 31 October 2009. +Jump up ^ In 1777 Lavoisier named oxygen, which had earlier been isolated by Priestley; the realization that saltpeter contained this substance was fundamental to understanding gunpowder. +^ Jump up to: a b Kelly 2004, p.164 +Jump up ^ Metzner, Paul (1998), Crescendo of the Virtuoso: Spectacle, Skill, and Self-Promotion in Paris during the Age of Revolution, University of California Press +^ Jump up to: a b c d Cocroft 2000, "Success to the Black Art!". Chapter 1 +Jump up ^ Ross, Charles. The Custom of the Castle: From Malory to Macbeth. Berkeley: University of California Press, c1997. [1] pages 131-130 +Jump up ^ The Noble-Abel Equation of State: Thermodynamic Derivations for Ballistics Modelling +Jump up ^ Pritchard, Tom; Evans, Jack; Johnson, Sydney (1985), The Old Gunpowder Factory at Glynneath, Merthyr Tydfil: Merthyr Tydfil & District Naturalists' Society +^ Jump up to: a b c d e Cocroft 2000, "The demise of gunpowder". Chapter 4 +Jump up ^ MacDougall, Ian (2000). 'Oh, ye had to be careful' : personal recollections by Roslin gunpowder mill and bomb factory workers. East Linton, Scotland: Tuckwell Press in association with the European Ethnological Research Centre and the Scottish Working People's History Trust. ISBN 1-86232-126-4. +Jump up ^ Iqtidar Alam Khan (2004). Gunpowder And Firearms: Warfare In Medieval India. Oxford University Press. ISBN 978-0-19-566526-0. +^ Jump up to: a b Iqtidar Alam Khan (25 April 2008). Historical Dictionary of Medieval India. Scarecrow Press. p. 157. ISBN 978-0-8108-5503-8. +^ Jump up to: a b Khan 2004:9–10 +Jump up ^ Khan 2004:10 +Jump up ^ Partington (Johns Hopkins University Press edition, 1999), 225 +Jump up ^ Partington (Johns Hopkins University Press edition, 1999), 226 +Jump up ^ http://www.youtube.com/watch?v=DTfEDaWMj4o +^ Jump up to: a b c "India." Encyclopædia Britannica. Encyclopedia Britannica 2008 Ultimate Reference Suite. Chicago: Encyclopedia Britannica, 2008. +Jump up ^ "rocket and missile system." Encyclopædia Britannica. Encyclopædia Britannica 2008 Ultimate Reference Suite. Chicago: Encyclopædia Britannica, 2008. +^ Jump up to: a b Dipanegara, P. B. R. Carey, Babad Dipanagara: an account of the outbreak of the Java war, 1825-30 : the Surakarta court version of the Babad Dipanagara with translations into English and Indonesian volume 9: Council of the M.B.R.A.S. by Art Printing Works: 1981. +Jump up ^ Atsushi, Ota (2006). Changes of regime and social dynamics in West Java : society, state, and the outer world of Banten, 1750-1830. Leiden: Brill. ISBN 90-04-15091-9. +^ Jump up to: a b Thomas Stamford Raffles, The History of Java, Oxford University Press, 1965 (originally published in 1817), ISBN 0-19-580347-7 +Jump up ^ Raffles, Thomas Stamford (1978). The History of Java ([Repr.]. ed.). Kuala Lumpur: Oxford University Press. ISBN 0-19-580347-7. +Jump up ^ US Department of Agriculture (1917). Department Bulleting No. 316: Willows: Their growth, use, and importance. The Department. p. 31. +Jump up ^ Kelly 2004, p.200 +^ Jump up to: a b Earl 1978, Chapter 2: The Development of Gunpowder +Jump up ^ Kelly 2004:60–63 +Jump up ^ Kelly 2004, p.199 +Jump up ^ Frangsmyr, Tore, J. L. Heilbron, and Robin E. Rider, editors The Quantifying Spirit in the Eighteenth Century. Berkeley: University of California Press, c1990. http://ark.cdlib.org/ark:/13030/ft6d5nb455/ p. 292. +Jump up ^ C.E. Munroe (1885) "Notes on the literature of explosives no. VIII", Proceedings of the US Naval Institute, no. XI, p. 285 +Jump up ^ The History of the 10.4×38 Swiss Cartridge +Jump up ^ Blackpowder to Pyrodex and Beyond by Randy Wakeman at Chuck Hawks +Jump up ^ The History and Art of Shotshells by Jon Farrar, Nebraskaland Magazine +Jump up ^ Buchanan. "Editor's Introduction: Setting the Context", in Buchanan 2006, p. 4. +Jump up ^ Black Powder Recipes, Ulrich Bretscher +Jump up ^ Julian S. Hatcher, Hatcher's Notebook, Military Service Publishing Company, 1947. Chapter XIII Notes on Gunpowder, pages 300-305. +Jump up ^ Kelly 2004, p.218 +Jump up ^ Book title Workshop Receipts Publisher William Clowes and Son limited Author Ernest Spon. Date 1 August 1873. +Jump up ^ GunpowderTranslation. Academic. Retrieved 2014-08-31. +Jump up ^ Cathal J. Nolan (2006), The age of wars of religion, 1000-1650: an encyclopedia of global warfare and civilization, Greenwood Publishing Group, p. 365, ISBN 978-0-313-33733-8 +^ Jump up to: a b c Kelly 2004, p58 +^ Jump up to: a b c John Francis Guilmartin (2003). Gunpowder & galleys: changing technology & Mediterranean warfare at sea in the 16th century. Conway Maritime Press. pp. 109–110 and 298–300. ISBN 0851779514. +Jump up ^ T.J. Rodman (1861), Reports of experiments on the properties of metals for cannon and the qualities of cannon powder, p. 270 +^ Jump up to: a b Kelly 2004, p.195 +Jump up ^ Tenney L. Davis (1943). The Chemistry of Powder and Explosives (PDF). p. 139. +^ Jump up to: a b Brown, G.I. (1998) The Big Bang: A history of Explosives Sutton Publishing pp.22&32 ISBN 0-7509-1878-0 +^ Jump up to: a b c Kelly 2004, p.224 +^ Jump up to: a b Rodney James (2011). The ABCs of Reloading: The Definitive Guide for Novice to Expert (9 ed.). Krause Publications. pp. 53–59. ISBN 978-1-4402-1396-0. +Jump up ^ Sharpe, Philip B. (1953) Complete Guide to Handloading Funk & Wagnalls p.137 +Jump up ^ Wakeman, Randy. "Blackpowder to Pyrodex and Beyond". Retrieved 31 August 2014. +Jump up ^ "LESMOK POWDER". +Jump up ^ Julian S. Hatcher, Hatcher's Notebook, Stackpole Books, 1962. Chapter XIV, Gun Corrosion and Ammunition Developments, pages 346-349. +Jump up ^ Wakeman, Randy. "Blackpowder to Pyrodex and Beyond". +Jump up ^ Flash! Bang! Whiz!, University of Denver +Jump up ^ Parker, Harold T. (1983). Three Napoleonic battles. (Repr., Durham, 1944. ed.). Durham, NC: Duke Univ. Pr. p. 83. ISBN 0-8223-0547-X. +Jump up ^ Larrey is quoted in French at Dr Béraud, Études Hygiéniques de la chair de cheval comme aliment, Musée des Familles (1841-42). +Jump up ^ Rediker, Marcus (1989). Between the devil and the deep blue sea : merchant seamen, pirates, and the Anglo-American maritime world, 1700-1750 (1st pbk. ed. ed.). Cambridge: Cambridge University Press. p. 12. ISBN 9780521379830. +Jump up ^ "Gunpowder Now Used To Drive Rivets And Splice Cables", April 1932, Popular Science +Jump up ^ "MasterBlaster System". Remington Products. +Jump up ^ Mining Journal 22 January 1853, p. 61 +Benton, Captain James G. (1862). A Course of Instruction in Ordnance and Gunnery (2 ed.). West Point, New York: Thomas Publications. ISBN 1-57747-079-6.. +Brown, G. I. (1998). The Big Bang: A History of Explosives. Sutton Publishing. ISBN 0-7509-1878-0.. +Buchanan, Brenda J., ed. (2006). Gunpowder, Explosives and the State: A Technological History. Aldershot: Ashgate. ISBN 0-7546-5259-9.. +Chase, Kenneth (2003). Firearms: A Global History to 1700. Cambridge University Press. ISBN 0-521-82274-2.. +Cocroft, Wayne (2000). Dangerous Energy: The archaeology of gunpowder and military explosives manufacture. Swindon: English Heritage. ISBN 1-85074-718-0.. +Crosby, Alfred W. (2002). Throwing Fire: Projectile Technology Through History. Cambridge University Press. ISBN 0-521-79158-8.. +Earl, Brian (1978). Cornish Explosives. Cornwall: The Trevithick Society. ISBN 0-904040-13-5.. +al-Hassan, Ahmad Y.. "History of Science and Technology in Islam". |chapter= ignored (help). +Johnson, Norman Gardner. "explosive". Encyclopædia Britannica. Chicago: Encyclopædia Britannica Online.. +Kelly, Jack (2004). Gunpowder: Alchemy, Bombards, & Pyrotechnics: The History of the Explosive that Changed the World. Basic Books. ISBN 0-465-03718-6.. +Khan, Iqtidar Alam (1996). "Coming of Gunpowder to the Islamic World and North India: Spotlight on the Role of the Mongols". Journal of Asian History 30: 41–5.. +Khan, Iqtidar Alam (2004). "Gunpowder and Firearms: Warfare in Medieval India". Oxford University Press. doi:10.1086/ahr.111.3.817.. +Needham, Joseph (1986). "Science & Civilisation in China". V:7: The Gunpowder Epic. Cambridge University Press. ISBN 0-521-30358-3.. +Norris, John (2003). Early Gunpowder Artillery: 1300-1600. Marlborough: The Crowood Press. ISBN 9781861266156.. +Partington, J.R. (1960). A History of Greek Fire and Gunpowder. Cambridge, UK: W. Heffer & Sons.. +Partington, James Riddick; Hall, Bert S. (1999). A History of Greek Fire and Gunpowder. Baltimore: Johns Hopkins University Press. doi:10.1353/tech.2000.0031. ISBN 0-8018-5954-9. +Urbanski, Tadeusz (1967). "Chemistry and Technology of Explosives" III. New York: Pergamon Press.. +External links[edit] + Wikimedia Commons has media related to Gunpowder. + Look up gunpowder in Wiktionary, the free dictionary. +Gun and Gunpowder +The Origins of Gunpowder +Cannons and Gunpowder +Oare Gunpowder Works, Kent, UK +Royal Gunpowder Mills +The DuPont Company on the Brandywine A digital exhibit produced by the Hagley Library that covers the founding and early history of the DuPont Company powder yards in Delaware +"Ulrich Bretschler's Gunpowder Chemistry page". +Video Demonstration of the Medieval Siege Society's Guns, Including showing ignition of gunpowder +Black Powder Recipes +"Dr. Sasse's investigations (and others) found via search at US DTIC.MIL These contain scientific studies of BP properties and details of measurement techniques.". +Categories: GunpowderChinese inventionsExplosivesFirearm propellantsPyrotechnic compositionsRocket fuelsSolid fuels +Navigation menu +Create accountLog inArticleTalkReadEditView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +Afrikaans +العربية +Aragonés +Asturianu +Azərbaycanca +Башҡортса +Беларуская +Беларуская (тарашкевіца)‎ +Български +Bosanski +Brezhoneg +Буряад +Català +Чӑвашла +Čeština +Corsu +Cymraeg +Dansk +Deutsch +Eesti +Ελληνικά +Español +Esperanto +Euskara +فارسی +Français +Gaeilge +Galego +贛語 +Хальмг +한국어 +हिन्दी +Hrvatski +Ilokano +Bahasa Indonesia +Íslenska +Italiano +עברית +Kapampangan +Kiswahili +Kurdî +Latina +Latviešu +Lietuvių +Limburgs +Magyar +Македонски +മലയാളം +مصرى +Монгол +Nederlands +नेपाली +नेपाल भाषा +日本語 +Нохчийн +Norsk bokmål +Norsk nynorsk +Occitan +Oʻzbekcha +پنجابی +Polski +Português +Română +Runa Simi +Русский +Саха тыла +Scots +Shqip +Sicilianu +Simple English +Slovenčina +Slovenščina +کوردی +Српски / srpski +Srpskohrvatski / српскохрватски +Suomi +Svenska +Tagalog +தமிழ் +Татарча/tatarça +ไทย +Türkçe +Українська +اردو +Tiếng Việt +Võro +Winaray +ייִדיש +粵語 +Žemaitėška +中文 +Edit links +This page was last modified on 28 November 2014 at 05:37. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki + + +Smokeless powder +From Wikipedia, the free encyclopedia + +Finnish smokeless powder +Smokeless powder is the name given to a number of propellants used in firearms and artillery that produce negligible smoke when fired, unlike the black powder they replaced. The term is unique to the United States and is generally not used in other English-speaking countries, which initially used proprietary names such as "Ballistite" and "Cordite" but gradually shifted to "propellant" as the generic term. +The basis of the term smokeless is that the combustion products are mainly gaseous, compared to around 55% solid products (mostly potassium carbonate, potassium sulfate, and potassium sulfide) for black powder.[1] Despite its name, smokeless powder is not completely smoke-free;[2] while there may be little noticeable smoke from small-arms ammunition, smoke from artillery fire can be substantial. This article focuses on nitrocellulose formulations, but the term smokeless powder was also used to describe various picrate mixtures with nitrate, chlorate, or dichromate oxidizers during the late 19th century, before the advantages of nitrocellulose became evident.[3] +Since the 14th century[4] gunpowder was not actually a physical "powder," and smokeless powder can only be produced as a pelletized or extruded granular material. Smokeless powder allowed the development of modern semi- and fully automatic firearms and lighter breeches and barrels for artillery. Burnt black powder leaves a thick, heavy fouling that is hygroscopic and causes rusting of the barrel. The fouling left by smokeless powder exhibits none of these properties (though some primer compounds can leave hygroscopic salts that have a similar effect; non-corrosive primer compounds were introduced in the 1920s[5][6]). This makes an autoloading firearm with many moving parts feasible (which would otherwise jam or seize under heavy black powder fouling). +Smokeless powders are classified as, typically, division 1.3 explosives under the UN Recommendations on the transportation of Dangerous goods – Model Regulations, regional regulations (such as ADR) and national regulations (such the United States' ATF). However, they are used as solid propellants; in normal use, they undergo deflagration rather than detonation. +Contents [hide] +1 Background +2 Nitroglycerine and guncotton +3 Propellant improvements +4 Chemical formulations +5 Instability and stabilization +6 Physical variations +7 Smokeless propellant components +8 Manufacturing +9 Flashless propellant +10 See also +11 References +11.1 Notes +11.2 Sources +12 External links +Background[edit] +Military commanders had been complaining since the Napoleonic Wars about the problems of giving orders on a battlefield obscured by the smoke of firing. Verbal commands could not be heard above the noise of the guns, and visual signals could not be seen through the thick smoke from the gunpowder used by the guns. Unless there was a strong wind, after a few shots, soldiers using black powder ammunition would have their view obscured by a huge cloud of smoke. Snipers or other concealed shooters were given away by a cloud of smoke over the firing position. Black powder is also corrosive, making cleaning mandatory after every use. Likewise, black powder's tendency to produce severe fouling caused actions to jam and often made reloading difficult. +Nitroglycerine and guncotton[edit] +Nitroglycerine was synthesized by the Italian chemist Ascanio Sobrero in 1847.[7] It was subsequently developed and manufactured by Alfred Nobel as an industrial explosive, but even then it was unsuitable as a propellant: despite its energetic and smokeless qualities, it detonates instead of deflagrating smoothly, making it more amenable to shattering a gun than propelling a projectile out of it. Nitroglycerine per se is also highly unstable, making it unfit to be carried in battlefield conditions. +A major step forward was the discovery of guncotton, a nitrocellulose-based material, by Swiss chemist Christian Friedrich Schönbein in 1846. He promoted its use as a blasting explosive[8] and sold manufacturing rights to the Austrian Empire. Guncotton was more powerful than gunpowder, but at the same time was once again somewhat more unstable. John Taylor obtained an English patent for guncotton; and John Hall & Sons began manufacture in Faversham. +English interest languished after an explosion destroyed the Faversham factory in 1847. Austrian Baron Wilhelm Lenk von Wolfsberg built two guncotton plants producing artillery propellent, but it too was dangerous under field conditions, and guns that could fire thousands of rounds using gunpowder would reach their service life after only a few hundred shots with the more powerful guncotton. Small arms could not withstand the pressures generated by guncotton at all. +After one of the Austrian factories blew up in 1862, Thomas Prentice & Company began manufacturing guncotton in Stowmarket in 1863; and British War Office chemist Sir Frederick Abel began thorough research at Waltham Abbey Royal Gunpowder Mills leading to a manufacturing process that eliminated the impurities in nitrocellulose making it safer to produce and a stable product safer to handle. Abel patented this process in 1865, when the second Austrian guncotton factory exploded. After the Stowmarket factory exploded in 1871, Waltham Abbey began production of guncotton for torpedo and mine warheads.[9] +Propellant improvements[edit] +In 1863, Prussian artillery captain Johann F. E. Schultze patented a small arms propellent of nitrated hardwood impregnated with saltpetre or barium nitrate. Prentice received an 1866 patent for a sporting powder of nitrated paper manufactured at Stowmarket, but ballistic uniformity suffered as the paper absorbed atmospheric moisture. In 1871, Frederick Volkmann received an Austrian patent for a colloided version of Schultze powder called Collodin, which he manufactured near Vienna for use in sporting firearms. Austrian patents were not published at the time, and the Austrian Empire considered the operation a violation of the government monopoly on explosives manufacture and closed the Volkmann factory in 1875.[9] In 1882, the Explosives Company at Stowmarket patented an improved formulation of nitrated cotton gelatinised by ether-alcohol with nitrates of potassium and barium. These propellants were suitable for shotguns but not rifles.[10] + +Poudre B single-base smokeless powder flakes +In 1884, Paul Vieille invented a smokeless powder called Poudre B (short for poudre blanche—white powder, as distinguished from black powder)[11] made from 68.2% insoluble nitrocellulose, 29.8% soluble nitrocellusose gelatinized with ether and 2% paraffin. This was adopted for the Lebel rifle.[12] It was passed through rollers to form paper thin sheets, which were cut into flakes of the desired size.[11] The resulting propellant, today known as pyrocellulose, contains somewhat less nitrogen than guncotton and is less volatile. A particularly good feature of the propellant is that it will not detonate unless it is compressed, making it very safe to handle under normal conditions. +Vieille's powder revolutionized the effectiveness of small guns, because it gave off almost no smoke and was three times more powerful than black powder. Higher muzzle velocity meant a flatter trajectory and less wind drift and bullet drop, making 1000 meter shots practicable. Since less powder was needed to propel a bullet, the cartridge could be made smaller and lighter. This allowed troops to carry more ammunition for the same weight. Also, it would burn even when wet. Black powder ammunition had to be kept dry and was almost always stored and transported in watertight cartridges. +Other European countries swiftly followed and started using their own versions of Poudre B, the first being Germany and Austria, which introduced new weapons in 1888. Subsequently Poudre B was modified several times with various compounds being added and removed. Krupp began adding diphenylamine as a stabilizer in 1888.[9] +Meanwhile, in 1887, Alfred Nobel obtained an English patent for a smokeless gunpowder he called Ballistite. In this propellant the fibrous structure of cotton (nitro-cellulose) was destroyed by a nitro-glycerine solution instead of a solvent.[13] In England in 1889, a similar powder was patented by Hiram Maxim, and in the USA in 1890 by Hudson Maxim.[14] Ballistite was patented in the United States in 1891. +The Germans adopted ballistite for naval use in 1898, calling it WPC/98. The Italians adopted it as filite, in cord instead of flake form, but realising its drawbacks changed to a formulation with nitroglycerine they called solenite. In 1891 the Russians tasked the chemist Mendeleef with finding a suitable propellant, he created nitrocellulose gelatinised by ether-alcohol, which produced more nitrogen and more uniform colloidal structure than the French use of nitro-cottons in Poudre B. He called it pyro-collodion.[13] +Britain conducted trials on all the various types of propellant brought to their attention, but were dissatisfied with them all and sought something superior to all existing types. In 1889, Sir Frederick Abel, James Dewar and Dr W Kellner patented (Nos 5614 and 11,664 in the names of Abel and Dewar) a new formulation that was manufactured at the Royal Gunpowder Factory at Waltham Abbey. It entered British service in 1891 as Cordite Mark 1. Its main composition was 58% Nitro-glycerine, 37% Guncotton and 3% mineral jelly. A modified version, Cordite MD, entered service in 1901, this increased guncotton to 65% and reduced nitro-glycerine to 30%, this change reduced the combustion temperature and hence erosion and barrel wear. Cordite's advantages over gunpowder were reduced maximum pressure in the chamber (hence lighter breeches, etc.) but longer high pressure. Cordite could be made in any desired shape or size.[15] The creation of cordite led to a lengthy court battle between Nobel, Maxim, and another inventor over alleged British patent infringement. +The Anglo-American Explosives Company began manufacturing its shotgun powder in Oakland, New Jersey in 1890. DuPont began producing guncotton at Carneys Point Township, New Jersey in 1891.[3] Charles E. Munroe of the Naval Torpedo Station in Newport, Rhode Island patented a formulation of guncotton colloided with nitrobenzene, called Indurite, in 1891.[16] Several United States firms began producing smokeless powder when Winchester Repeating Arms Company started loading sporting cartridges with Explosives Company powder in 1893. California Powder Works began producing a mixture of nitroglycerine and nitrocellulose with ammonium picrate as Peyton Powder, Leonard Smokeless Powder Company began producing nitroglycerine-nitrocellulose Ruby powders, Laflin & Rand negotiated a license to produce Ballistite, and DuPont started producing smokeless shotgun powder. The United States Army evaluated 25 varieties of smokeless powder and selected Ruby and Peyton Powders as the most suitable for use in the Krag-Jørgensen service rifle. Ruby was preferred, because tin-plating was required to protect brass cartridge cases from picric acid in the Peyton Powder. Rather than paying the required royalties for Ballistite, Laflin & Rand financed Leonard's reorganization as the American Smokeless Powder Company. United States Army Lieutenant Whistler assisted American Smokeless Powder Company factory superintendent Aspinwall in formulating an improved powder named W.A. for their efforts. W.A. smokeless powder was the standard for United States military service rifles from 1897 until 1908.[3] +In 1897, United States Navy Lieutenant John Bernadou patented a nitrocellulose powder colloided with ether-alcohol.[16] The Navy licensed or sold patents for this formulation to DuPont and the California Powder Works while retaining manufacturing rights for the Naval Powder Factory, Indian Head, Maryland constructed in 1900. The United States Army adopted the Navy single-base formulation in 1908 and began manufacture at Picatinny Arsenal.[3] By that time Laflin & Rand had taken over the American Powder Company to protect their investment, and Laflin & Rand had been purchased by DuPont in 1902.[17] Upon securing a 99-year lease of the Explosives Company in 1903, DuPont enjoyed use of all significant smokeless powder patents in the United States, and was able to optimize production of smokeless powder.[3] When government anti-trust action forced divestiture in 1912, DuPont retained the nitrocellulose smokeless powder formulations used by the United States military and released the double-base formulations used in sporting ammunition to the reorganized Hercules Powder Company. These newer propellants were more stable and thus safer to handle than Poudre B, and also more powerful. +Chemical formulations[edit] +"Double base" redirects here. For the musical instrument, see double bass. +Currently, propellants using nitrocellulose (detonation velocity 7,300 m/s (23,950 ft/s)) (typically an ether-alcohol colloid of nitrocellulose) as the sole explosive propellant ingredient are described as single-base powder.[18] +Propellants mixtures containing nitrocellulose and nitroglycerin (detonation velocity 7,700 m/s (25,260 ft/s)) as explosive propellant ingredients are known as double-base powder.[19] +During the 1930s triple-base propellant containing nitrocellulose, nitroglycerin, and a substantial quantity of nitroguanidine (detonation velocity 8,200 m/s (26,900 ft/s)) as explosive propellant ingredients was developed. These propellant mixtures have reduced flash and flame temperature without sacrificing chamber pressure compared to single and double base propellants, albeit at the cost of more smoke. +In practice, triple base propellants are reserved mainly for large caliber ammunition such as used in (naval) artillery and tank guns. During World War II it had some use by British artillery. After that war it became the standard propellant in all British large caliber ammunition designs except small-arms. Most western nations, except the United States, followed a similar path. +In the late 20th century new propellant formulations started to appear. These are based on nitroguanidine and high explosives of the RDX (detonation velocity 8,750 m/s (28,710 ft/s)) type. +Instability and stabilization[edit] +Nitrocellulose deteriorates with time, yielding acidic byproducts. Those byproducts catalyze the further deterioration, increasing its rate. The released heat, in case of bulk storage of the powder, or too large blocks of solid propellant, can cause self-ignition of the material. Single-base nitrocellulose propellants are hygroscopic and most susceptible to degradation; double-base and triple-base propellants tend to deteriorate more slowly. To neutralize the decomposition products, which could otherwise cause corrosion of metals of the cartridges and gun barrels, calcium carbonate is added to some formulations. +To prevent buildup of the deterioration products, stabilizers are added. Diphenylamine is one of the most common stabilizers used. Nitrated analogs of diphenylamine formed in the process of stabilizing decomposing powder are sometimes used as stabilizers themselves.[20][21] The stabilizers are added in the amount of 0.5–2% of the total amount of the formulation; higher amounts tend to degrade its ballistic properties. The amount of the stabilizer is depleted with time. Propellants in storage should be periodically tested for the amount of stabilizer remaining, as its depletion may lead to auto-ignition of the propellant. +Physical variations[edit] + +Ammunition handloading powders +Smokeless powder may be corned into small spherical balls or extruded into cylinders or strips with many cross-sectional shapes (strips with various rectangular proportions, single or multi-hole cylinders, slotted cylinders) using solvents such as ether. These extrusions can be cut into short ('flakes') or long pieces ('cords' many inches long). Cannon powder has the largest pieces. +The properties of the propellant are greatly influenced by the size and shape of its pieces. The specific surface area of the propellant influences the speed of burning, and the size and shape of the particles determine the specific surface area. By manipulation of the shape it is possible to influence the burning rate and hence the rate at which pressure builds during combustion. Smokeless powder burns only on the surfaces of the pieces. Larger pieces burn more slowly, and the burn rate is further controlled by flame-deterrent coatings that retard burning slightly. The intent is to regulate the burn rate so that a more or less constant pressure is exerted on the propelled projectile as long as it is in the barrel so as to obtain the highest velocity. The perforations stabilize the burn rate because as the outside burns inward (thus shrinking the burning surface area) the inside is burning outward (thus increasing the burning surface area, but faster, so as to fill up the increasing volume of barrel presented by the departing projectile).[22] Fast-burning pistol powders are made by extruding shapes with more area such as flakes or by flattening the spherical granules. Drying is usually performed under a vacuum. The solvents are condensed and recycled. The granules are also coated with graphite to prevent static electricity sparks from causing undesired ignitions.[23] +Faster-burning propellants generate higher temperatures and higher pressures, however they also increase wear on gun barrels. +Smokeless propellant components[edit] +The propellant formulations may contain various energetic and auxiliary components: +Propellants: +Nitrocellulose, an energetic component of most smokeless propellants[24] +Nitroglycerin, an energetic component of double-base and triple-base formulations[24] +Nitroguanidine, a component of triple-base formulations[24] +D1NA (bis-nitroxyethylnitramine)[25] +Fivonite (tetramethylolcyclopentanone)[25] +DGN (di-ethylene glycol dinitrate)[26] +Acetyl cellulose[27] +Deterrents, (or moderants), to slow the burning rate +Centralites (symmetrical diphenyl urea—primarily diethyl or dimethyl)[28][29] +Dibutyl phthalate[24][29] +Dinitrotoluene (toxic, carcinogenic, and obsolete)[24][30] +Akardite (asymmetrical diphenyl urea)[26] +ortho-tolyl urethane[31] +Polyester adipate +Camphor (obsolete)[29] +Stabilizers, to prevent or slow down self-decomposition[32] +Diphenylamine[33] +Petroleum jelly[34] +Calcium carbonate[24] +Magnesium oxide[26] +Sodium bicarbonate[27] +beta-naphthol methyl ether[31] +Amyl alcohol (obsolete)[35] +Aniline (obsolete)[36] +Decoppering additives, to hinder the buildup of copper residues from the gun barrel rifling +Tin metal and compounds (e.g., tin dioxide)[24][37] +Bismuth metal and compounds (e.g., bismuth trioxide, bismuth subcarbonate, bismuth nitrate, bismuth antimonide); the bismuth compounds are favored as copper dissolves in molten bismuth, forming brittle and easily removable alloy +Lead foil and lead compounds, phased out due to toxicity[25] +Flash reducers, to reduce the brightness of the muzzle flash (all have a disadvantage: the production of smoke)[38] +Potassium chloride[39] +Potassium nitrate +Potassium sulfate[24][37] +Potassium hydrogen tartarate (a byproduct of wine production formerly used by French artillery)[39] +Wear reduction additives, to lower the wear of the gun barrel liners[40] +Wax +Talc +Titanium dioxide +Polyurethane jackets over the powder bags, in large guns +Other additives +Ethyl acetate, a solvent for manufacture of spherical powder[34] +Rosin, a surfactant to hold the grain shape of spherical powder +Graphite, a lubricant to cover the grains and prevent them from sticking together, and to dissipate static electricity[23] +Manufacturing[edit] +This section describes procedures used in the United States. See Cordite for alternative procedures formerly used in the United Kingdom. +The United States Navy manufactured single-base tubular powder for naval artillery at Indian Head, Maryland, beginning in 1900. Similar procedures were used for United States Army production at Picatinny Arsenal beginning in 1907[18] and for manufacture of smaller grained Improved Military Rifle (IMR) powders after 1914. Short-fiber cotton linter was boiled in a solution of sodium hydroxide to remove vegetable waxes, and then dried before conversion to nitrocellulose by mixing with concentrated nitric and sulfuric acids. Nitrocellulose still resembles fibrous cotton at this point in the manufacturing process, and was typically identified as pyrocellulose because it would spontaneously ignite in air until unreacted acid was removed. The term guncotton was also used; although some references identify guncotton as a more extensively nitrated and refined product used in torpedo and mine warheads prior to use of TNT.[41] +Unreacted acid was removed from pyrocellulose pulp by a multistage draining and water washing process similar to that used in paper mills during production of chemical woodpulp. Pressurized alcohol removed remaining water from drained pyrocellulose prior to mixing with ether and diphenylamine. The mixture was then fed through a press extruding a long turbular cord form to be cut into grains of the desired length.[42] +Alcohol and ether were then evaporated from "green" powder grains to a remaining solvent concentration between 3 percent for rifle powders and 7 percent for large artillery powder grains. Burning rate is inversely proportional to solvent concentration. Grains were coated with electrically conductive graphite to minimize generation of static electricity during subsequent blending. "Lots" containing more than ten tonnes of powder grains were mixed through a tower arrangement of blending hoppers to minimize ballistic differences. Each blended lot was then subjected to testing to determine the correct loading charge for the desired performance.[43][44] +Military quantities of old smokeless powder were sometimes reworked into new lots of propellants.[45] Through the 1920s Dr. Fred Olsen worked at Picatinny Arsenal experimenting with ways to salvage tons of single-base cannon powder manufactured for World War I. Dr. Olsen was employed by Western Cartridge Company in 1929 and developed a process for manufacturing spherical smokeless powder by 1933.[46] Reworked powder or washed pyrocellulose can be dissolved in ethyl acetate containing small quantities of desired stabilizers and other additives. The resultant syrup, combined with water and surfactants, can be heated and agitated in a pressurized container until the syrup forms an emulsion of small spherical globules of the desired size. Ethyl acetate distills off as pressure is slowly reduced to leave small spheres of nitrocellulose and additives. The spheres can be subsequently modified by adding nitroglycerine to increase energy, flattening between rollers to a uniform minimum dimension, coating with phthalate deterrents to retard ignition, and/or glazing with graphite to improve flow characteristics during blending.[47][48] +Modern smokeless powder is produced in the United States by St. Marks Powder, Inc. owned by General Dynamics.[49] +Flashless propellant[edit] +Muzzle flash is the light emitted in the vicinity of the muzzle by the hot propellant gases and the chemical reactions that follow as the gases mix with the surrounding air. Before projectiles exit a slight pre-flash may occur from gases leaking past the projectiles. Following muzzle exit the heat of gases is usually sufficient to emit visible radiation – the primary flash. The gases expand but as they pass through the Mach disc they are re-compressed to produce an intermediate flash. Hot combustible gases (e.g. hydrogen and carbon-monoxide) may follow when they mix with oxygen in the surrounding air to produce the secondary flash, the brightest. The secondary flash does not usually occur with small-arms.[50] +Nitrocellulose contains insufficient oxygen to completely oxidize its carbon and hydrogen. The oxygen deficit is increased by addition of graphite and organic stabilizers. Products of combustion within the gun barrel include flammable gasses like hydrogen and carbon monoxide. At high temperature, these flammable gasses will ignite when turbulently mixed with atmospheric oxygen beyond the muzzle of the gun. During night engagements the flash produced by ignition can reveal the location of the gun to enemy forces[51] and cause temporary night-blindness among the gun crew by photo-bleaching visual purple.[52] +Flash suppressors are commonly used on small arms to reduce the flash signature, but this approach is not practical for artillery. Artillery muzzle flash up to 150 feet (46 m) from the muzzle has been observed, and can be reflected off clouds and be visible for distances up to 30 miles (48 km).[51] For artillery the most effective method is a propellant that produces a large proportion of inert nitrogen at relatively low temperatures that dilutes the combustible gases. Triple based propellants are used for this because of the nitrogen in the nitroguandine.[53] +Before the use of triple based propellants the usual method of flash reduction was to add inorganic salts like potassium chloride so their specific heat capacity might reduce the temperature of combustion gasses and their finely divided particulate smoke might block visible wavelengths of radiant energy of combustion.[39] +See also[edit] +Portal icon Pyrotechnics portal +Antique guns +Ballistite +Cordite +Firearms +Gunpowder +Nitrocellulose +Small arms +Brown-brown – a drug created by mixing cocaine with cartridge powder +References[edit] +Notes[edit] +Jump up ^ Hatcher, Julian S. and Barr, Al Handloading Hennage Lithograph Company (1951) p.34 +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) p.44 +^ Jump up to: a b c d e Sharpe, Philip B. Complete Guide to Handloading 3rd Edition (1953) Funk & Wagnalls pp.146-149 +Jump up ^ seegunpowder +Jump up ^ Sharpe, Philip B. Complete Guide To Handloading (1953) Funk & Wagnalls p.60 +Jump up ^ Davis, William C., Jr. Handloading (1981) National Rifle Association p.21 +Jump up ^ Davis, Tenney L. The Chemistry of Powder & Explosives (1943) page 195 +Jump up ^ Davis, William C., Jr. Handloading National Rifle Association of America (1981) p.28 +^ Jump up to: a b c Sharpe, Philip B. Complete Guide to Handloading 3rd Edition (1953) Funk & Wagnalls pp.141-144 +Jump up ^ Hogg, Oliver F. G. Artillery: Its Origin, Heyday and Decline (1969) p.138-139 +^ Jump up to: a b Davis, Tenney L. The Chemistry of Powder & Explosives (1943) pages 289–292 +Jump up ^ Hogg, Oliver F. G. Artillery: Its Origin, Heyday and Decline (1969) p.139 +^ Jump up to: a b Hogg, Oliver F. G. Artillery: Its Origin, Heyday and Decline (1969) p.140 +Jump up ^ U.S. Patent 430,212 – Manufacture of explosive – H. S. Maxim +Jump up ^ Hogg, Oliver F. G. Artillery: Its Origin, Heyday and Decline (1969) p.141 +^ Jump up to: a b Davis, Tenney L. The Chemistry of Powder & Explosives (1943) pages 296-297 +Jump up ^ "Laflin & Rand Powder Company". DuPont. Retrieved 2012-02-24. +^ Jump up to: a b Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p.297 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p.298 +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) p.28 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p. 310 +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) pp.41–43 +^ Jump up to: a b Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p.306 +^ Jump up to: a b c d e f g h Campbell, John Naval Weapons of World War Two (1985) p. 5 +^ Jump up to: a b c Campbell, John Naval Weapons of World War Two (1985) p. 104 +^ Jump up to: a b c Campbell, John Naval Weapons of World War Two (1985) p. 221 +^ Jump up to: a b Campbell, John Naval Weapons of World War Two (1985) p. 318 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 317–320 +^ Jump up to: a b c Davis, William C., Jr. Handloading National Rifle Association of America (1981) p.30 +Jump up ^ Davis, William C., Jr. Handloading National Rifle Association of America (1981) p.31 +^ Jump up to: a b Campbell, John Naval Weapons of World War Two (1985) p. 174 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 307–311 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p. 302 +^ Jump up to: a b Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p. 296 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p. 307 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) p. 308 +^ Jump up to: a b Davis, William C., Jr. Handloading National Rifle Association of America (1981) p.32 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 322–327 +^ Jump up to: a b c Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 323–327 +Jump up ^ "USA 16"/50 (40.6 cm) Mark 7". NavWeaps. 2008-11-03. Retrieved 2008-12-05. +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) pages 28–31 +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) pages 31–35 +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) pages 35–41 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 293 & 306 +Jump up ^ Fairfield, A. P., CDR USN Naval Ordnance Lord Baltimore Press (1921) p.39 +Jump up ^ Matunas, E. A. Winchester-Western Ball Powder Loading Data Olin Corporation (1978) p.3 +Jump up ^ Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 328–330 +Jump up ^ Wolfe, Dave Propellant Profiles Volume 1 Wolfe Publishing Company (1982) pages 136–137 +Jump up ^ General Dynamics Commercial Powder Applications. +Jump up ^ Moss G. M., Leeming D. W., Farrar C. L. Military Ballisitcs (1969) pages 55–56 +^ Jump up to: a b Davis, Tenny L. The Chemistry of Powder & Explosives (1943) pages 322–323 +Jump up ^ Milner p.68 +Jump up ^ Moss G. M., Leeming D. W., Farrar C. L. Military Ballisitcs (1969) pages 59–60 +Sources[edit] +Campbell, John (1985). Naval Weapons of World War Two. Naval Institute Press. ISBN 0-87021-459-4. +Davis, Tenney L. (1943). The Chemistry of Powder & Explosives (Angriff Press [1992] ed.). John Wiley & Sons Inc. ISBN 0-913022-00-4. +Davis, William C., Jr. (1981). Handloading. National Rifle Association of America. ISBN 0-935998-34-9. +Fairfield, A. P., CDR USN (1921). Naval Ordnance. Lord Baltimore Press. +Hatcher, Julian S. and Barr, Al (1951). Handloading. Hennage Lithograph Company. +Matunas, E. A. (1978). Winchester-Western Ball Powder Loading Data. Olin Corporation. +Milner, Marc (1985). North Atlantic Run. Naval Institute Press. ISBN 0-87021-450-0. +Wolfe, Dave (1982). Propellant Profiles Volume 1. Wolfe Publishing Company. ISBN 0-935632-10-7. +External links[edit] +The Manufacture of Smokeless Powders and their Forensic Analysis: A Brief Review – Robert M. Heramb, Bruce R. McCord +Hudson Maxim papers (1851-1925) at Hagley Museum and Library. Collection includes material relating to Maxim's patent on the process of making smokeless powder. +Categories: CorditeExplosivesFirearm propellantsSolid fuels +Navigation menu +Create accountLog inArticleTalkReadEditView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +العربية +Български +Dansk +Deutsch +Español +فارسی +Français +Bahasa Indonesia +Íslenska +Italiano +עברית +Nederlands +日本語 +Polski +Português +Русский +Svenska +தமிழ் +中文 +Edit links +This page was last modified on 25 July 2014 at 22:33. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki + + +Deflagration +From Wikipedia, the free encyclopedia + +[hide]This article has multiple issues. Please help improve it or discuss these issues on the talk page. +This article needs additional citations for verification. (April 2011) +This article may be too technical for most readers to understand. (December 2013) + +A log in a fireplace. +Deflagration [1] (Lat: de + flagrare, "to burn down") is a term describing subsonic combustion propagating through heat transfer; hot burning material heats the next layer of cold material and ignites it. Most "fire" found in daily life, from flames to explosions, is deflagration. Deflagration is different from detonation, which is supersonic and propagates through shock. +Contents [hide] +1 Applications +2 Oil/wax fire and water +3 Flame physics +4 Damaging deflagration events +5 See also +6 References +Applications[edit] +In engineering applications, deflagrations are easier to control than detonations. Consequently, they are better suited when the goal is to move an object (a bullet in a gun, or a piston in an internal combustion engine) with the force of the expanding gas. Typical examples of deflagrations are the combustion of a gas-air mixture in a gas stove or a fuel-air mixture in an internal combustion engine, and the rapid burning of gunpowder in a firearm or of pyrotechnic mixtures in fireworks. Deflagration systems and products can also be used in mining, demolition and stone quarrying via gas pressure blasting as a beneficial alternative to high explosives. +Oil/wax fire and water[edit] +Adding water to a burning hydrocarbon such as oil or wax produces a deflagration. The water boils rapidly and ejects the burning material as a fine spray of droplets. A deflagration then occurs as the fine mist of oil ignites and burns extremely rapidly. These are particularly common in chip pan fires, which are responsible for one in five household fires in Britain.[2] +Flame physics[edit] +The underlying flame physics can be understood with the help of an idealized model consisting of a uniform one-dimensional tube of unburnt and burned gaseous fuel, separated by a thin transitional region of width \delta\; in which the burning occurs. The burning region is commonly referred to as the flame or flame front. In equilibrium, thermal diffusion across the flame front is balanced by the heat supplied by burning. +There are two characteristic timescales which are important here. The first is the thermal diffusion timescale \tau_d\;, which is approximately equal to +\tau_d \simeq \delta^2 / \kappa, +where \kappa \; is the thermal diffusivity. The second is the burning timescale \tau_b that strongly decreases with temperature, typically as +\tau_b\propto \exp[\Delta U/(k_B T_f)], +where \Delta U\; is the activation barrier for the burning reaction and T_f\; is the temperature developed as the result of burning; the value of this so-called "flame temperature" can be determined from the laws of thermodynamics. +For a stationary moving deflagration front, these two timescales must be equal: the heat generated by burning is equal to the heat carried away by heat transfer. This makes it possible to calculate the characteristic width \delta\; of the flame front: +\tau_b = \tau_d\;, +thus + \delta \simeq \sqrt {\kappa \tau_b} . +Now, the thermal flame front propagates at a characteristic speed S_l\;, which is simply equal to the flame width divided by the burn time: +S_l \simeq \delta / \tau_b \simeq \sqrt {\kappa / \tau_b} . +This simplified model neglects the change of temperature and thus the burning rate across the deflagration front. This model also neglects the possible influence of turbulence. As a result, this derivation gives only the laminar flame speed -- hence the designation S_l\;. +Damaging deflagration events[edit] +Damage to buildings, equipment and people can result from a large-scale, short-duration deflagration. The potential damage is primarily a function of the total amount of fuel burned in the event (total energy available), the maximum flame velocity that is achieved, and the manner in which the expansion of the combustion gases is contained. +In free-air deflagrations, there is a continuous variation in deflagration effects relative to the maximum flame velocity. When flame velocities are low, the effect of a deflagration is to release heat. Some authors use the term flash fire to describe these low-speed deflagrations. At flame velocities near the speed of sound, the energy released is in the form of pressure and the results resemble a detonation. Between these extremes both heat and pressure are released. +When a low-speed deflagration occurs within a closed vessel or structure, pressure effects can produce damage due to expansion of gases as a secondary effect. The heat released by the deflagration causes the combustion gases and excess air to expand thermally. The net result is that the volume of the vessel or structure must expand to accommodate the hot combustion gases, or the vessel must be strong enough to withstand the additional internal pressure, or it fails, allowing the gases to escape. The risks of deflagration inside waste storage drums is a growing concern in storage facilities. +See also[edit] + Look up deflagration in Wiktionary, the free dictionary. +Pressure piling +References[edit] +Jump up ^ "Glossary D-H". Hutchisonrodway.co.nz. Retrieved 2013-12-29. +Jump up ^ UK Fire Service advice on chip pan fires +Categories: Explosives +Navigation menu +Create accountLog inArticleTalkReadEditView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +Català +Čeština +Deutsch +Español +Français +Italiano +Lietuvių +Nederlands +Norsk bokmål +Polski +Português +Русский +Српски / srpski +Svenska +Edit links +This page was last modified on 2 October 2014 at 16:44. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki + + +United Kingdom +From Wikipedia, the free encyclopedia +This article is about the sovereign state. For the island, see Great Britain. For other uses, see United Kingdom (disambiguation) and UK (disambiguation). +Page semi-protected +United Kingdom of Great +Britain and Northern Ireland[show] + +A flag featuring both cross and saltire in red, white and blue Coat of arms containing shield and crown in centre, flanked by lion and unicorn +Flag Royal coat of arms[nb 1] +Anthem: "God Save the Queen"[nb 2] +MENU0:00 +Two islands to the north-west of continental Europe. Highlighted are the larger island and the north-eastern fifth of the smaller island to the west. +Location of the United Kingdom (dark green) +– in Europe (green & dark grey) +– in the European Union (green) +Capital +and largest city London +51°30′N 0°7′W +Official language +and national language English +Recognised regional +languages Cornish, Irish, Scots, Scottish Gaelic, Ulster-Scots, Welsh[nb 3] +Ethnic groups (2011) 87.1% White +7.0% Asian +3.0% Black +2.0% Mixed +0.9% Other +Demonym British, Briton +Government Unitary parliamentary constitutional monarchy + - Monarch Elizabeth II + - Prime Minister David Cameron +Legislature Parliament + - Upper house House of Lords + - Lower house House of Commons +Formation + - Acts of Union 1707 1 May 1707 + - Acts of Union 1800 1 January 1801 + - Irish Free State Constitution Act 5 December 1922 +Area + - Total 243,610 km2 (80th) +94,060 sq mi + - Water (%) 1.34 +Population + - 2013 estimate 64,100,000[3] (22nd) + - 2011 census 63,181,775[4] (22nd) + - Density 255.6/km2 (51st) +661.9/sq mi +GDP (PPP) 2014 estimate + - Total $2.435 trillion[5] (10th) + - Per capita $37,744[5] (27th) +GDP (nominal) 2014 estimate + - Total $2.848 trillion[5] (6th) + - Per capita $44,141[5] (22nd) +Gini (2012) positive decrease 32.8[6] +medium · 33rd +HDI (2013) Steady 0.892[7] +very high · 14th +Currency Pound sterling (GBP) +Time zone GMT (UTC​) + - Summer (DST) BST (UTC+1) +Date format dd/mm/yyyy (AD) +Drives on the left +Calling code +44 +ISO 3166 code GB +Internet TLD .uk +The United Kingdom of Great Britain and Northern Ireland Listeni/ɡreɪt ˈbrɪt(ə)n ənd ˈnɔːð(ə)n ˈʌɪələnd/, commonly known as the United Kingdom (UK) or Britain, is a sovereign state in Europe. Lying off the north-western coast of the European mainland, the country includes the island of Great Britain (a term also applied loosely to refer to the whole country),[8] the north-eastern part of the island of Ireland, and many smaller islands. Northern Ireland is the only part of the UK that shares a land border with another state: the Republic of Ireland.[nb 4] Apart from this land border, the UK is surrounded by the Atlantic Ocean, with the North Sea in the east and the English Channel in the south. The Irish Sea lies between Great Britain and Ireland. The UK has an area of 243,610 square kilometres (94,060 sq mi), making it the 78th-largest sovereign state in the world and the 11th-largest in Europe. +The United Kingdom is the 22nd-most populous country, with an estimated 64.1 million inhabitants.[3] It is a constitutional monarchy with a parliamentary system of governance.[9][10] Its capital city is London, an important global city and financial centre with the fourth-largest urban area in Europe.[11] The current monarch—since 6 February 1952—is Queen Elizabeth II. The UK consists of four countries: England, Scotland, Wales, and Northern Ireland.[12] The latter three have devolved administrations,[13] each with varying powers,[14][15] based in their capitals, Edinburgh, Cardiff, and Belfast, respectively. Guernsey, Jersey, and the Isle of Man are not part of the United Kingdom, being Crown dependencies with the British Government responsible for defence and international representation.[16] The UK has fourteen Overseas Territories,[17] including the disputed Falkland Islands, Gibraltar, and Indian Ocean Territory. +The relationships among the countries of the United Kingdom have changed over time. Wales was annexed by the Kingdom of England under the Acts of Union of 1536 and 1543. A treaty between England and Scotland resulted in a unified Kingdom of Great Britain in 1707, which in 1801, merged with the Kingdom of Ireland to form the United Kingdom of Great Britain and Ireland. In 1922, five-sixths of Ireland seceded from the country, leaving the present formulation of the United Kingdom of Great Britain and Northern Ireland.[nb 5] British Overseas Territories, formerly colonies, are the remnants of the British Empire which, at its height in the late 19th and early 20th centuries, encompassed almost a quarter of the world's land mass and was the largest empire in history. British influence can be observed in the language, culture, and legal systems of many of its former colonies. +The United Kingdom is a developed country and has the world's sixth-largest economy by nominal GDP and tenth-largest by purchasing power parity. The country is considered to have a high-income economy and is categorised as very high in the Human Development Index, currently ranking 14th in the world. It was the world's first industrialised country and the world's foremost power during the 19th and early 20th centuries.[18][19] The UK remains a great power with considerable economic, cultural, military, scientific, and political influence internationally.[20][21] It is a recognised nuclear weapons state and its military expenditure ranks fifth or sixth in the world.[22][23] The UK has been a permanent member of the United Nations Security Council since its first session in 1946. It has been a member state of the European Union (EU) and its predecessor, the European Economic Community (EEC), since 1973; it is also a member of the Commonwealth of Nations, the Council of Europe, the G7, the G8, the G20, NATO, the Organisation for Economic Co-operation and Development (OECD), and the World Trade Organization (WTO). +Contents [hide] +1 Etymology and terminology +2 History +2.1 Before 1707 +2.2 Since the Acts of Union of 1707 +3 Geography +3.1 Climate +3.2 Administrative divisions +4 Dependencies +5 Politics +5.1 Government +5.2 Devolved administrations +5.3 Law and criminal justice +5.4 Foreign relations +5.5 Military +6 Economy +6.1 Science and technology +6.2 Transport +6.3 Energy +7 Demographics +7.1 Ethnic groups +7.2 Languages +7.3 Religion +7.4 Migration +7.5 Education +7.6 Healthcare +8 Culture +8.1 Literature +8.2 Music +8.3 Visual art +8.4 Cinema +8.5 Media +8.6 Philosophy +8.7 Sport +8.8 Symbols +9 See also +10 Notes +11 References +12 Further reading +13 External links +Etymology and terminology +See also: Britain (placename) and Terminology of the British Isles +The 1707 Acts of Union declared that the kingdoms of England and Scotland were "United into One Kingdom by the Name of Great Britain", though the new state is also referred to in the Acts as the "Kingdom of Great Britain", "United Kingdom of Great Britain" and "United Kingdom".[24][25][nb 6] However, the term "united kingdom" is only found in informal use during the 18th century and the country was only occasionally referred to as he "United Kingdom of Great Britain".[26] The Acts of Union 1800 united the Kingdom of Great Britain and the Kingdom of Ireland in 1801, forming the United Kingdom of Great Britain and Ireland. The name "United Kingdom of Great Britain and Northern Ireland" was adopted following the independence of the Irish Free State, and the partition of Ireland, in 1922, which left Northern Ireland as the only part of the island of Ireland within the UK.[27] +Although the United Kingdom, as a sovereign state, is a country, England, Scotland, Wales, and to a lesser degree, Northern Ireland, are also regarded as countries, though they are not sovereign states.[28][29] Scotland, Wales and Northern Ireland have devolved self-government.[30][31] The British Prime Minister's website has used the phrase "countries within a country" to describe the United Kingdom.[12] Some statistical summaries, such as those for the twelve NUTS 1 regions of the UK, also refer to Scotland, Wales and Northern Ireland as "regions".[32][33] Northern Ireland is also referred to as a "province".[28][34] With regard to Northern Ireland, the descriptive name used "can be controversial, with the choice often revealing one's political preferences."[35] +The term Britain is often used as synonym for the United Kingdom. The term Great Britain, by contrast, refers conventionally to the island of Great Britain, or politically to England, Scotland and Wales in combination.[36][37][38] However, it is sometimes used as a loose synonym for the United Kingdom as a whole.[39][40] GB and GBR are the standard country codes for the United Kingdom (see ISO 3166-2 and ISO 3166-1 alpha-3) and are consequently used by international organisations to refer to the United Kingdom. Additionally, the United Kingdom's Olympic team competes under the name "Great Britain" or "Team GB".[41][42] +The adjective British is commonly used to refer to matters relating to the United Kingdom. The term has no definite legal connotation, but is used in law to refer to UK citizenship and matters to do with nationality.[43] People of the United Kingdom use a number of different terms to describe their national identity and may identify themselves as being British; or as being English, Scottish, Welsh, Northern Irish, or Irish;[44] or as being both.[45] +In 2006, a new design of British passport was introduced. Its first page shows the long form name of the state in English, Welsh and Scottish Gaelic.[46] In Welsh, the long form name of the state is "Teyrnas Unedig Prydain Fawr a Gogledd Iwerddon" with "Teyrnas Unedig" being used as a short form name on government websites.[47] In Scottish Gaelic, the long form is "Rìoghachd Aonaichte Bhreatainn is Èireann a Tuath" and the short form "Rìoghachd Aonaichte". +History +See also: History of the British Isles +Before 1707 + +Stonehenge, in Wiltshire, was erected around 2500 BC. +Main articles: History of England, History of Wales, History of Scotland, History of Ireland and History of the formation of the United Kingdom +Settlement by anatomically modern humans of what was to become the United Kingdom occurred in waves beginning by about 30,000 years ago.[48] By the end of the region's prehistoric period, the population is thought to have belonged, in the main, to a culture termed Insular Celtic, comprising Brythonic Britain and Gaelic Ireland.[49] The Roman conquest, beginning in 43 AD, and the 400-year rule of southern Britain, was followed by an invasion by Germanic Anglo-Saxon settlers, reducing the Brythonic area mainly to what was to become Wales and the historic Kingdom of Strathclyde.[50] Most of the region settled by the Anglo-Saxons became unified as the Kingdom of England in the 10th century.[51] Meanwhile, Gaelic-speakers in north west Britain (with connections to the north-east of Ireland and traditionally supposed to have migrated from there in the 5th century)[52][53] united with the Picts to create the Kingdom of Scotland in the 9th century.[54] +In 1066, the Normans invaded England from France and after its conquest, seized large parts of Wales, conquered much of Ireland and were invited to settle in Scotland, bringing to each country feudalism on the Northern French model and Norman-French culture.[55] The Norman elites greatly influenced, but eventually assimilated with, each of the local cultures.[56] Subsequent medieval English kings completed the conquest of Wales and made an unsuccessful attempt to annex Scotland. Thereafter, Scotland maintained its independence, albeit in near-constant conflict with England. The English monarchs, through inheritance of substantial territories in France and claims to the French crown, were also heavily involved in conflicts in France, most notably the Hundred Years War, while the Kings of Scots were in an alliance with the French during this period.[57] + +The Bayeux Tapestry depicts the Battle of Hastings and the events leading to it. +The early modern period saw religious conflict resulting from the Reformation and the introduction of Protestant state churches in each country.[58] Wales was fully incorporated into the Kingdom of England,[59] and Ireland was constituted as a kingdom in personal union with the English crown.[60] In what was to become Northern Ireland, the lands of the independent Catholic Gaelic nobility were confiscated and given to Protestant settlers from England and Scotland.[61] +In 1603, the kingdoms of England, Scotland and Ireland were united in a personal union when James VI, King of Scots, inherited the crowns of England and Ireland and moved his court from Edinburgh to London; each country nevertheless remained a separate political entity and retained its separate political, legal, and religious institutions.[62][63] +In the mid-17th century, all three kingdoms were involved in a series of connected wars (including the English Civil War) which led to the temporary overthrow of the monarchy and the establishment of the short-lived unitary republic of the Commonwealth of England, Scotland and Ireland.[64][65] +Although the monarchy was restored, it ensured (with the Glorious Revolution of 1688) that, unlike much of the rest of Europe, royal absolutism would not prevail, and a professed Catholic could never accede to the throne. The British constitution would develop on the basis of constitutional monarchy and the parliamentary system.[66] During this period, particularly in England, the development of naval power (and the interest in voyages of discovery) led to the acquisition and settlement of overseas colonies, particularly in North America.[67][68] +Since the Acts of Union of 1707 +Main article: History of the United Kingdom + +The Treaty of Union led to a single united kingdom encompassing all Great Britain. +On 1 May 1707, the united kingdom of Great Britain came into being, the result of Acts of Union being passed by the parliaments of England and Scotland to ratify the 1706 Treaty of Union and so unite the two kingdoms.[69][70][71] +In the 18th century, cabinet government developed under Robert Walpole, in practice the first prime minister (1721–1742). A series of Jacobite Uprisings sought to remove the Protestant House of Hanover from the British throne and restore the Catholic House of Stuart. The Jacobites were finally defeated at the Battle of Culloden in 1746, after which the Scottish Highlanders were brutally suppressed. The British colonies in North America that broke away from Britain in the American War of Independence became the United States of America in 1782. British imperial ambition turned elsewhere, particularly to India.[72] +During the 18th century, Britain was involved in the Atlantic slave trade. British ships transported an estimated 2 million slaves from Africa to the West Indies before banning the trade in 1807.[73] The term 'United Kingdom' became official in 1801 when the parliaments of Britain and Ireland each passed an Act of Union, uniting the two kingdoms and creating the United Kingdom of Great Britain and Ireland.[74] +In the early 19th century, the British-led Industrial Revolution began to transform the country. It slowly led to a shift in political power away from the old Tory and Whig landowning classes towards the new industrialists. An alliance of merchants and industrialists with the Whigs would lead to a new party, the Liberals, with an ideology of free trade and laissez-faire. In 1832 Parliament passed the Great Reform Act, which began the transfer of political power from the aristocracy to the middle classes. In the countryside, enclosure of the land was driving small farmers out. Towns and cities began to swell with a new urban working class. Few ordinary workers had the vote, and they created their own organisations in the form of trade unions. +Painting of a bloody battle. Horses and infantry fight or lie on grass. +The Battle of Waterloo marked the end of the Napoleonic Wars and the start of Pax Britannica. +After the defeat of France in the Revolutionary and Napoleonic Wars (1792–1815), the UK emerged as the principal naval and imperial power of the 19th century (with London the largest city in the world from about 1830).[75] Unchallenged at sea, British dominance was later described as Pax Britannica.[76][77] By the time of the Great Exhibition of 1851, Britain was described as the "workshop of the world".[78] The British Empire was expanded to include India, large parts of Africa and many other territories throughout the world. Alongside the formal control it exerted over its own colonies, British dominance of much of world trade meant that it effectively controlled the economies of many countries, such as China, Argentina and Siam.[79][80] Domestically, political attitudes favoured free trade and laissez-faire policies and a gradual widening of the voting franchise. During the century, the population increased at a dramatic rate, accompanied by rapid urbanisation, causing significant social and economic stresses.[81] After 1875, the UK's industrial monopoly was challenged by Germany and the USA. To seek new markets and sources of raw materials, the Conservative Party under Disraeli launched a period of imperialist expansion in Egypt, South Africa and elsewhere. Canada, Australia and New Zealand became self-governing dominions.[82] +Social reform and home rule for Ireland were important domestic issues after 1900. The Labour Party emerged from an alliance of trade unions and small Socialist groups in 1900, and suffragettes campaigned for women's right to vote before 1914. +Black-and-white photo of two dozen men in military uniforms and metal helmets sitting or standing in a muddy trench. +Infantry of the Royal Irish Rifles during the Battle of the Somme. More than 885,000 British soldiers died on the battlefields of World War I. +The UK fought with France, Russia and (after 1917) the US, against Germany and its allies in World War I (1914–18).[83] The UK armed forces were engaged across much of the British Empire and in several regions of Europe, particularly on the Western front.[84] The high fatalities of trench warfare caused the loss of much of a generation of men, with lasting social effects in the nation and a great disruption in the social order. +After the war, the UK received the League of Nations mandate over a number of former German and Ottoman colonies. The British Empire reached its greatest extent, covering a fifth of the world's land surface and a quarter of its population.[85] However, the UK had suffered 2.5 million casualties and finished the war with a huge national debt.[84] The rise of Irish Nationalism and disputes within Ireland over the terms of Irish Home Rule led eventually to the partition of the island in 1921,[86] and the Irish Free State became independent with Dominion status in 1922. Northern Ireland remained part of the United Kingdom.[87] A wave of strikes in the mid-1920s culminated in the UK General Strike of 1926. The UK had still not recovered from the effects of the war when the Great Depression (1929–32) occurred. This led to considerable unemployment and hardship in the old industrial areas, as well as political and social unrest in the 1930s. A coalition government was formed in 1931.[88] +The UK entered World War II by declaring war on Germany in 1939, after it had invaded Poland and Czechoslovakia. In 1940, Winston Churchill became prime minister and head of a coalition government. Despite the defeat of its European allies in the first year of the war, the UK continued the fight alone against Germany. In 1940, the RAF defeated the German Luftwaffe in a struggle for control of the skies in the Battle of Britain. The UK suffered heavy bombing during the Blitz. There were also eventual hard-fought victories in the Battle of the Atlantic, the North Africa campaign and Burma campaign. UK forces played an important role in the Normandy landings of 1944, achieved with its ally the US. After Germany's defeat, the UK was one of the Big Three powers who met to plan the post-war world; it was an original signatory to the Declaration of the United Nations. The UK became one of the five permanent members of the United Nations Security Council. However, the war left the UK severely weakened and depending financially on Marshall Aid and loans from the United States.[89] +Map of the world. Canada, the eastern United States, countries in east Africa, India, most of Australasia and some other countries are highlighted in pink. +Territories that were at one time part of the British Empire. Current British Overseas Territories are underlined in red. +In the immediate post-war years, the Labour government initiated a radical programme of reforms, which had a significant effect on British society in the following decades.[90] Major industries and public utilities were nationalised, a Welfare State was established, and a comprehensive, publicly funded healthcare system, the National Health Service, was created.[91] The rise of nationalism in the colonies coincided with Britain's now much-diminished economic position, so that a policy of decolonisation was unavoidable. Independence was granted to India and Pakistan in 1947.[92] Over the next three decades, most colonies of the British Empire gained their independence. Many became members of the Commonwealth of Nations.[93] +Although the UK was the third country to develop a nuclear weapons arsenal (with its first atomic bomb test in 1952), the new post-war limits of Britain's international role were illustrated by the Suez Crisis of 1956. The international spread of the English language ensured the continuing international influence of its literature and culture. From the 1960s onward, its popular culture was also influential abroad. As a result of a shortage of workers in the 1950s, the UK government encouraged immigration from Commonwealth countries. In the following decades, the UK became a multi-ethnic society.[94] Despite rising living standards in the late 1950s and 1960s, the UK's economic performance was not as successful as many of its competitors, such as West Germany and Japan. In 1973, the UK joined the European Economic Community (EEC), and when the EEC became the European Union (EU) in 1992, it was one of the 12 founding members. + +After the two vetos of France in 1961 and 1967, the UK entered in the European Union in 1973. In 1975, 67% of Britons voted yes to the permanence in the European Union. +From the late 1960s, Northern Ireland suffered communal and paramilitary violence (sometimes affecting other parts of the UK) conventionally known as the Troubles. It is usually considered to have ended with the Belfast "Good Friday" Agreement of 1998.[95][96][97] +Following a period of widespread economic slowdown and industrial strife in the 1970s, the Conservative Government of the 1980s initiated a radical policy of monetarism, deregulation, particularly of the financial sector (for example, Big Bang in 1986) and labour markets, the sale of state-owned companies (privatisation), and the withdrawal of subsidies to others.[98] This resulted in high unemployment and social unrest, but ultimately also economic growth, particularly in the services sector. From 1984, the economy was helped by the inflow of substantial North Sea oil revenues.[99] +Around the end of the 20th century there were major changes to the governance of the UK with the establishment of devolved administrations for Scotland, Wales and Northern Ireland.[13][100] The statutory incorporation followed acceptance of the European Convention on Human Rights. The UK is still a key global player diplomatically and militarily. It plays leading roles in the EU, UN and NATO. However, controversy surrounds some of Britain's overseas military deployments, particularly in Afghanistan and Iraq.[101] +The 2008 global financial crisis severely affected the UK economy. The coalition government of 2010 introduced austerity measures intended to tackle the substantial public deficits which resulted.[102] In 2014 the Scottish Government held a referendum on Scottish independence, with the majority of voters rejecting the independence proposal and opting to remain within the United Kingdom.[103] +Geography +Main article: Geography of the United Kingdom +Map of United Kingdom showing hilly regions to north and west, and flattest region in the south-east. +The topography of the UK +The total area of the United Kingdom is approximately 243,610 square kilometres (94,060 sq mi). The country occupies the major part of the British Isles[104] archipelago and includes the island of Great Britain, the northeastern one-sixth of the island of Ireland and some smaller surrounding islands. It lies between the North Atlantic Ocean and the North Sea with the south-east coast coming within 22 miles (35 km) of the coast of northern France, from which it is separated by the English Channel.[105] In 1993 10% of the UK was forested, 46% used for pastures and 25% cultivated for agriculture.[106] The Royal Greenwich Observatory in London is the defining point of the Prime Meridian.[107] +The United Kingdom lies between latitudes 49° to 61° N, and longitudes 9° W to 2° E. Northern Ireland shares a 224-mile (360 km) land boundary with the Republic of Ireland.[105] The coastline of Great Britain is 11,073 miles (17,820 km) long.[108] It is connected to continental Europe by the Channel Tunnel, which at 31 miles (50 km) (24 miles (38 km) underwater) is the longest underwater tunnel in the world.[109] +England accounts for just over half of the total area of the UK, covering 130,395 square kilometres (50,350 sq mi).[110] Most of the country consists of lowland terrain,[106] with mountainous terrain north-west of the Tees-Exe line; including the Cumbrian Mountains of the Lake District, the Pennines and limestone hills of the Peak District, Exmoor and Dartmoor. The main rivers and estuaries are the Thames, Severn and the Humber. England's highest mountain is Scafell Pike (978 metres (3,209 ft)) in the Lake District. Its principal rivers are the Severn, Thames, Humber, Tees, Tyne, Tweed, Avon, Exe and Mersey.[106] +Scotland accounts for just under a third of the total area of the UK, covering 78,772 square kilometres (30,410 sq mi)[111] and including nearly eight hundred islands,[112] predominantly west and north of the mainland; notably the Hebrides, Orkney Islands and Shetland Islands. The topography of Scotland is distinguished by the Highland Boundary Fault – a geological rock fracture – which traverses Scotland from Arran in the west to Stonehaven in the east.[113] The faultline separates two distinctively different regions; namely the Highlands to the north and west and the lowlands to the south and east. The more rugged Highland region contains the majority of Scotland's mountainous land, including Ben Nevis which at 1,343 metres (4,406 ft) is the highest point in the British Isles.[114] Lowland areas – especially the narrow waist of land between the Firth of Clyde and the Firth of Forth known as the Central Belt – are flatter and home to most of the population including Glasgow, Scotland's largest city, and Edinburgh, its capital and political centre. +A view of Ben Nevis in the distance, fronted by rolling plains +Ben Nevis, in Scotland, is the highest point in the British Isles +Wales accounts for less than a tenth of the total area of the UK, covering 20,779 square kilometres (8,020 sq mi).[115] Wales is mostly mountainous, though South Wales is less mountainous than North and mid Wales. The main population and industrial areas are in South Wales, consisting of the coastal cities of Cardiff, Swansea and Newport, and the South Wales Valleys to their north. The highest mountains in Wales are in Snowdonia and include Snowdon (Welsh: Yr Wyddfa) which, at 1,085 metres (3,560 ft), is the highest peak in Wales.[106] The 14, or possibly 15, Welsh mountains over 3,000 feet (914 m) high are known collectively as the Welsh 3000s. Wales has over 2,704 kilometres (1,680 miles) of coastline.[116] Several islands lie off the Welsh mainland, the largest of which is Anglesey (Ynys Môn) in the northwest. +Northern Ireland, separated from Great Britain by the Irish Sea and North Channel, has an area of 14,160 square kilometres (5,470 sq mi) and is mostly hilly. It includes Lough Neagh which, at 388 square kilometres (150 sq mi), is the largest lake in the British Isles by area.[117] The highest peak in Northern Ireland is Slieve Donard in the Mourne Mountains at 852 metres (2,795 ft).[106] +Climate +Main article: Climate of the United Kingdom +The United Kingdom has a temperate climate, with plentiful rainfall all year round.[105] The temperature varies with the seasons seldom dropping below −11 °C (12 °F) or rising above 35 °C (95 °F).[118] The prevailing wind is from the south-west and bears frequent spells of mild and wet weather from the Atlantic Ocean,[105] although the eastern parts are mostly sheltered from this wind since the majority of the rain falls over the western regions the eastern parts are therefore the driest. Atlantic currents, warmed by the Gulf Stream, bring mild winters; especially in the west where winters are wet and even more so over high ground. Summers are warmest in the south-east of England, being closest to the European mainland, and coolest in the north. Heavy snowfall can occur in winter and early spring on high ground, and occasionally settles to great depth away from the hills. +Administrative divisions +Main article: Administrative geography of the United Kingdom +Each country of the United Kingdom has its own system of administrative and geographic demarcation, whose origins often pre-date the formation of the United Kingdom. Thus there is "no common stratum of administrative unit encompassing the United Kingdom".[119] Until the 19th century there was little change to those arrangements, but there has since been a constant evolution of role and function.[120] Change did not occur in a uniform manner and the devolution of power over local government to Scotland, Wales and Northern Ireland means that future changes are unlikely to be uniform either. +The organisation of local government in England is complex, with the distribution of functions varying according to local arrangements. Legislation concerning local government in England is the responsibility of the UK parliament and the Government of the United Kingdom, as England has no devolved parliament. The upper-tier subdivisions of England are the nine Government office regions or European Union government office regions.[121] One region, Greater London, has had a directly elected assembly and mayor since 2000 following popular support for the proposal in a referendum.[122] It was intended that other regions would also be given their own elected regional assemblies, but a proposed assembly in the North East region was rejected by a referendum in 2004.[123] Below the regional tier, some parts of England have county councils and district councils and others have unitary authorities; while London consists of 32 London boroughs and the City of London. Councillors are elected by the first-past-the-post system in single-member wards or by the multi-member plurality system in multi-member wards.[124] +For local government purposes, Scotland is divided into 32 council areas, with wide variation in both size and population. The cities of Glasgow, Edinburgh, Aberdeen and Dundee are separate council areas, as is the Highland Council which includes a third of Scotland's area but only just over 200,000 people. Local councils are made up of elected councillors, of whom there are currently 1,222;[125] they are paid a part-time salary. Elections are conducted by single transferable vote in multi-member wards that elect either three or four councillors. Each council elects a Provost, or Convenor, to chair meetings of the council and to act as a figurehead for the area. Councillors are subject to a code of conduct enforced by the Standards Commission for Scotland.[126] The representative association of Scotland's local authorities is the Convention of Scottish Local Authorities (COSLA).[127] +Local government in Wales consists of 22 unitary authorities. These include the cities of Cardiff, Swansea and Newport which are unitary authorities in their own right.[128] Elections are held every four years under the first-past-the-post system.[129] The most recent elections were held in May 2012, except for the Isle of Anglesey. The Welsh Local Government Association represents the interests of local authorities in Wales.[130] +Local government in Northern Ireland has since 1973 been organised into 26 district councils, each elected by single transferable vote. Their powers are limited to services such as collecting waste, controlling dogs and maintaining parks and cemeteries.[131] On 13 March 2008 the executive agreed on proposals to create 11 new councils and replace the present system.[132] The next local elections were postponed until 2016 to facilitate this.[133] +Dependencies + +A view of the Caribbean Sea from the Cayman Islands, one of the world's foremost international financial centres[134] and tourist destinations.[135] +Main articles: British Overseas Territories, Crown dependencies and British Islands +The United Kingdom has sovereignty over seventeen territories which do not form part of the United Kingdom itself: fourteen British Overseas Territories[136] and three Crown dependencies.[137] +The fourteen British Overseas Territories are: Anguilla; Bermuda; the British Antarctic Territory; the British Indian Ocean Territory; the British Virgin Islands; the Cayman Islands; the Falkland Islands; Gibraltar; Montserrat; Saint Helena, Ascension and Tristan da Cunha; the Turks and Caicos Islands; the Pitcairn Islands; South Georgia and the South Sandwich Islands; and Sovereign Base Areas on Cyprus.[138] British claims in Antarctica are not universally recognised.[139] Collectively Britain's overseas territories encompass an approximate land area of 1,727,570 square kilometres (667,018 sq mi) and a population of approximately 260,000 people.[140] They are the remnants of the British Empire and several have specifically voted to remain British territories (Bermuda in 1995, Gibraltar in 2002 and the Falkland Islands in 2013).[141] +The Crown dependencies are possessions of the Crown, as opposed to overseas territories of the UK.[142] They comprise three independently administered jurisdictions: the Channel Islands of Jersey and Guernsey in the English Channel, and the Isle of Man in the Irish Sea. By mutual agreement, the British Government manages the islands' foreign affairs and defence and the UK Parliament has the authority to legislate on their behalf. However, internationally, they are regarded as "territories for which the United Kingdom is responsible".[143] The power to pass legislation affecting the islands ultimately rests with their own respective legislative assemblies, with the assent of the Crown (Privy Council or, in the case of the Isle of Man, in certain circumstances the Lieutenant-Governor).[144] Since 2005 each Crown dependency has had a Chief Minister as its head of government.[145] +Politics +Main articles: Politics of the United Kingdom, Monarchy of the United Kingdom and Elections in the United Kingdom +Elderly lady with a yellow hat and grey hair is smiling in outdoor setting. +Elizabeth II, Queen of the United Kingdom and the other Commonwealth realms +The United Kingdom is a unitary state under a constitutional monarchy. Queen Elizabeth II is the head of state of the UK as well as monarch of fifteen other independent Commonwealth countries. The monarch has "the right to be consulted, the right to encourage, and the right to warn".[146] The United Kingdom is one of only four countries in the world to have an uncodified constitution.[147][nb 7] The Constitution of the United Kingdom thus consists mostly of a collection of disparate written sources, including statutes, judge-made case law and international treaties, together with constitutional conventions. As there is no technical difference between ordinary statutes and "constitutional law", the UK Parliament can perform "constitutional reform" simply by passing Acts of Parliament, and thus has the political power to change or abolish almost any written or unwritten element of the constitution. However, no Parliament can pass laws that future Parliaments cannot change.[148] +Government +Main article: Government of the United Kingdom +The UK has a parliamentary government based on the Westminster system that has been emulated around the world: a legacy of the British Empire. The parliament of the United Kingdom that meets in the Palace of Westminster has two houses; an elected House of Commons and an appointed House of Lords. All bills passed are given Royal Assent before becoming law. +The position of prime minister,[nb 8] the UK's head of government,[149] belongs to the person most likely to command the confidence of the House of Commons; this individual is typically the leader of the political party or coalition of parties that holds the largest number of seats in that chamber. The prime minister chooses a cabinet and they are formally appointed by the monarch to form Her Majesty's Government. By convention, the Queen respects the prime minister's decisions of government.[150] +Large sand-coloured building of Gothic design beside brown river and road bridge. The building has several large towers, including large clock-tower. +The Palace of Westminster, seat of both houses of the Parliament of the United Kingdom +The cabinet is traditionally drawn from members of a prime minister's party or coalition and mostly from the House of Commons but always from both legislative houses, the cabinet being responsible to both. Executive power is exercised by the prime minister and cabinet, all of whom are sworn into the Privy Council of the United Kingdom, and become Ministers of the Crown. The current Prime Minister is David Cameron, who has been in office since 11 May 2010.[151] Cameron is the leader of the Conservative Party and heads a coalition with the Liberal Democrats. For elections to the House of Commons, the UK is currently divided into 650 constituencies,[152] each electing a single member of parliament (MP) by simple plurality. General elections are called by the monarch when the prime minister so advises. The Parliament Acts 1911 and 1949 require that a new election must be called no later than five years after the previous general election.[153] +The UK's three major political parties are the Conservative Party (Tories), the Labour Party and the Liberal Democrats, representing the British traditions of conservatism, socialism and social liberalism, respectively. During the 2010 general election these three parties won 622 out of 650 seats available in the House of Commons.[154][155] Most of the remaining seats were won by parties that contest elections only in one part of the UK: the Scottish National Party (Scotland only); Plaid Cymru (Wales only); and the Alliance Party, Democratic Unionist Party, Social Democratic and Labour Party and Sinn Féin (Northern Ireland only[nb 9]). In accordance with party policy, no elected Sinn Féin members of parliament have ever attended the House of Commons to speak on behalf of their constituents because of the requirement to take an oath of allegiance to the monarch. +Devolved administrations +Main articles: Devolution in the United Kingdom, Northern Ireland Executive, Scottish Government and Welsh Government +Modern one-story building with grass on roof and large sculpted grass area in front. Behind are residential buildings in a mixture of styles. +The Scottish Parliament Building in Holyrood is the seat of the Scottish Parliament. +Scotland, Wales and Northern Ireland each have their own government or executive, led by a First Minister (or, in the case of Northern Ireland, a diarchal First Minister and deputy First Minister), and a devolved unicameral legislature. England, the largest country of the United Kingdom, has no such devolved executive or legislature and is administered and legislated for directly by the UK government and parliament on all issues. This situation has given rise to the so-called West Lothian question which concerns the fact that members of parliament from Scotland, Wales and Northern Ireland can vote, sometimes decisively,[156] on matters that only affect England.[157] The McKay Commission reported on this matter in March 2013 recommending that laws affecting only England should need support from a majority of English members of parliament.[158] +The Scottish Government and Parliament have wide-ranging powers over any matter that has not been specifically reserved to the UK parliament, including education, healthcare, Scots law and local government.[159] At the 2011 elections the Scottish National Party won re-election and achieved an overall majority in the Scottish parliament, with its leader, Alex Salmond, as First Minister of Scotland.[160][161] In 2012, the UK and Scottish governments signed the Edinburgh Agreement setting out the terms for a referendum on Scottish independence in 2014, which was defeated 55% to 45%. +The Welsh Government and the National Assembly for Wales have more limited powers than those devolved to Scotland.[162] The Assembly is able to legislate on devolved matters through Acts of the Assembly, which require no prior consent from Westminster. The 2011 elections resulted in a minority Labour administration led by Carwyn Jones.[163] +The Northern Ireland Executive and Assembly have powers similar to those devolved to Scotland. The Executive is led by a diarchy representing unionist and nationalist members of the Assembly. Currently, Peter Robinson (Democratic Unionist Party) and Martin McGuinness (Sinn Féin) are First Minister and deputy First Minister respectively.[164] Devolution to Northern Ireland is contingent on participation by the Northern Ireland administration in the North-South Ministerial Council, where the Northern Ireland Executive cooperates and develops joint and shared policies with the Government of Ireland. The British and Irish governments co-operate on non-devolved matters affecting Northern Ireland through the British–Irish Intergovernmental Conference, which assumes the responsibilities of the Northern Ireland administration in the event of its non-operation. +The UK does not have a codified constitution and constitutional matters are not among the powers devolved to Scotland, Wales or Northern Ireland. Under the doctrine of parliamentary sovereignty, the UK Parliament could, in theory, therefore, abolish the Scottish Parliament, Welsh Assembly or Northern Ireland Assembly.[165][166] Indeed, in 1972, the UK Parliament unilaterally prorogued the Parliament of Northern Ireland, setting a precedent relevant to contemporary devolved institutions.[167] In practice, it would be politically difficult for the UK Parliament to abolish devolution to the Scottish Parliament and the Welsh Assembly, given the political entrenchment created by referendum decisions.[168] The political constraints placed upon the UK Parliament's power to interfere with devolution in Northern Ireland are even greater than in relation to Scotland and Wales, given that devolution in Northern Ireland rests upon an international agreement with the Government of Ireland.[169] +Law and criminal justice +Main article: Law of the United Kingdom + +The Royal Courts of Justice of England and Wales +The United Kingdom does not have a single legal system, as Article 19 of the 1706 Treaty of Union provided for the continuation of Scotland's separate legal system.[170] Today the UK has three distinct systems of law: English law, Northern Ireland law and Scots law. A new Supreme Court of the United Kingdom came into being in October 2009 to replace the Appellate Committee of the House of Lords.[171][172] The Judicial Committee of the Privy Council, including the same members as the Supreme Court, is the highest court of appeal for several independent Commonwealth countries, the British Overseas Territories and the Crown Dependencies.[173] +Both English law, which applies in England and Wales, and Northern Ireland law are based on common-law principles.[174] The essence of common law is that, subject to statute, the law is developed by judges in courts, applying statute, precedent and common sense to the facts before them to give explanatory judgements of the relevant legal principles, which are reported and binding in future similar cases (stare decisis).[175] The courts of England and Wales are headed by the Senior Courts of England and Wales, consisting of the Court of Appeal, the High Court of Justice (for civil cases) and the Crown Court (for criminal cases). The Supreme Court is the highest court in the land for both criminal and civil appeal cases in England, Wales and Northern Ireland and any decision it makes is binding on every other court in the same jurisdiction, often having a persuasive effect in other jurisdictions.[176] + +The High Court of Justiciary – the supreme criminal court of Scotland. +Scots law is a hybrid system based on both common-law and civil-law principles. The chief courts are the Court of Session, for civil cases,[177] and the High Court of Justiciary, for criminal cases.[178] The Supreme Court of the United Kingdom serves as the highest court of appeal for civil cases under Scots law.[179] Sheriff courts deal with most civil and criminal cases including conducting criminal trials with a jury, known as sheriff solemn court, or with a sheriff and no jury, known as sheriff summary Court.[180] The Scots legal system is unique in having three possible verdicts for a criminal trial: "guilty", "not guilty" and "not proven". Both "not guilty" and "not proven" result in an acquittal.[181] +Crime in England and Wales increased in the period between 1981 and 1995, though since that peak there has been an overall fall of 48% in crime from 1995 to 2007/08,[182] according to crime statistics. The prison population of England and Wales has almost doubled over the same period, to over 80,000, giving England and Wales the highest rate of incarceration in Western Europe at 147 per 100,000.[183] Her Majesty's Prison Service, which reports to the Ministry of Justice, manages most of the prisons within England and Wales. Crime in Scotland fell to its lowest recorded level for 32 years in 2009/10, falling by ten per cent.[184] At the same time Scotland's prison population, at over 8,000,[185] is at record levels and well above design capacity.[186] The Scottish Prison Service, which reports to the Cabinet Secretary for Justice, manages Scotland's prisons. +Foreign relations +Main article: Foreign relations of the United Kingdom + +The Prime Minister of the United Kingdom, David Cameron, and the President of the United States, Barack Obama, during the 2010 G-20 Toronto summit. +The UK is a permanent member of the United Nations Security Council, a member of NATO, the Commonwealth of Nations, G7, G8, G20, the OECD, the WTO, the Council of Europe, the OSCE, and is a member state of the European Union. The UK is said to have a "Special Relationship" with the United States and a close partnership with France—the "Entente cordiale"—and shares nuclear weapons technology with both countries.[187][188] The UK is also closely linked with the Republic of Ireland; the two countries share a Common Travel Area and co-operate through the British-Irish Intergovernmental Conference and the British-Irish Council. Britain's global presence and influence is further amplified through its trading relations, foreign investments, official development assistance and military engagements.[189] +Military + +Troopers of the Blues and Royals during the 2007 Trooping the Colour ceremony +Main article: British Armed Forces +The armed forces of the United Kingdom—officially, Her Majesty's Armed Forces—consist of three professional service branches: the Royal Navy and Royal Marines (forming the Naval Service), the British Army and the Royal Air Force.[190] The forces are managed by the Ministry of Defence and controlled by the Defence Council, chaired by the Secretary of State for Defence. The Commander-in-Chief is the British monarch, Elizabeth II, to whom members of the forces swear an oath of allegiance.[191] The Armed Forces are charged with protecting the UK and its overseas territories, promoting the UK's global security interests and supporting international peacekeeping efforts. They are active and regular participants in NATO, including the Allied Rapid Reaction Corps, as well as the Five Power Defence Arrangements, RIMPAC and other worldwide coalition operations. Overseas garrisons and facilities are maintained in Ascension Island, Belize, Brunei, Canada, Cyprus, Diego Garcia, the Falkland Islands, Germany, Gibraltar, Kenya and Qatar.[192] +The British armed forces played a key role in establishing the British Empire as the dominant world power in the 18th, 19th and early 20th centuries. Throughout its unique history the British forces have seen action in a number of major wars, such as the Seven Years' War, the Napoleonic Wars, the Crimean War, World War I and World War II—as well as many colonial conflicts. By emerging victorious from such conflicts, Britain has often been able to decisively influence world events. Since the end of the British Empire, the UK has nonetheless remained a major military power. Following the end of the Cold War, defence policy has a stated assumption that "the most demanding operations" will be undertaken as part of a coalition.[193] Setting aside the intervention in Sierra Leone, recent UK military operations in Bosnia, Kosovo, Afghanistan, Iraq and, most recently, Libya, have followed this approach. The last time the British military fought alone was the Falklands War of 1982. +According to various sources, including the Stockholm International Peace Research Institute and the International Institute for Strategic Studies, the United Kingdom has the fifth- or sixth-highest military expenditure in the world. Total defence spending currently accounts for around 2.4% of total national GDP.[22][23] +Economy +Main article: Economy of the United Kingdom + +The Bank of England – the central bank of the United Kingdom +The UK has a partially regulated market economy.[194] Based on market exchange rates the UK is today the sixth-largest economy in the world and the third-largest in Europe after Germany and France, having fallen behind France for the first time in over a decade in 2008.[195] HM Treasury, led by the Chancellor of the Exchequer, is responsible for developing and executing the British government's public finance policy and economic policy. The Bank of England is the UK's central bank and is responsible for issuing notes and coins in the nation's currency, the pound sterling. Banks in Scotland and Northern Ireland retain the right to issue their own notes, subject to retaining enough Bank of England notes in reserve to cover their issue. Pound sterling is the world's third-largest reserve currency (after the US Dollar and the Euro).[196] Since 1997 the Bank of England's Monetary Policy Committee, headed by the Governor of the Bank of England, has been responsible for setting interest rates at the level necessary to achieve the overall inflation target for the economy that is set by the Chancellor each year.[197] +The UK service sector makes up around 73% of GDP.[198] London is one of the three "command centres" of the global economy (alongside New York City and Tokyo),[199] it is the world's largest financial centre alongside New York,[200][201][202] and it has the largest city GDP in Europe.[203] Edinburgh is also one of the largest financial centres in Europe.[204] Tourism is very important to the British economy and, with over 27 million tourists arriving in 2004, the United Kingdom is ranked as the sixth major tourist destination in the world and London has the most international visitors of any city in the world.[205][206] The creative industries accounted for 7% GVA in 2005 and grew at an average of 6% per annum between 1997 and 2005.[207] + +The Airbus A350 has its wings and engines manufactured in the UK. +The Industrial Revolution started in the UK with an initial concentration on the textile industry,[208] followed by other heavy industries such as shipbuilding, coal mining and steelmaking.[209][210] +The empire was exploited as an overseas market for British products, allowing the UK to dominate international trade in the 19th century. As other nations industrialised, coupled with economic decline after two world wars, the United Kingdom began to lose its competitive advantage and heavy industry declined, by degrees, throughout the 20th century. Manufacturing remains a significant part of the economy but accounted for only 16.7% of national output in 2003.[211] +The automotive industry is a significant part of the UK manufacturing sector and employs over 800,000 people, with a turnover of some £52 billion, generating £26.6 billion of exports.[212] +The aerospace industry of the UK is the second- or third-largest national aerospace industry in the world depending upon the method of measurement and has an annual turnover of around £20 billion. The wings for the Airbus A380 and the A350 XWB are designed and manufactured at Airbus UK's world-leading Broughton facility, whilst over a quarter of the value of the Boeing 787 comes from UK manufacturers including Eaton (fuel subsystem pumps), Messier-Bugatti-Dowty (the landing gear) and Rolls-Royce (the engines). Other key names include GKN Aerospace – an expert in metallic and composite aerostructures that's involved in almost every civil and military fixed and rotary wing aircraft in production and development today.[213][214][215][216] +BAE Systems - plays a critical role on some of the world's biggest defence aerospace projects. The company makes large sections of the Typhoon Eurofighter at its sub-assembly plant in Salmesbury and assembles the aircraft for the RAF at its Warton Plant, near Preston. It is also a principal subcontractor on the F35 Joint Strike Fighter - the world's largest single defence project - for which it designs and manufactures a range of components including the aft fuselage, vertical and horizontal tail and wing tips and fuel system. As well as this it manufactures the Hawk, the world's most successful jet training aircraft.[216] Airbus UK also manufactures the wings for the A400m military transporter. Rolls-Royce, is the world's second-largest aero-engine manufacturer. Its engines power more than 30 types of commercial aircraft and it has more than 30,000 engines currently in service across both the civil and defence sectors. Agusta Westland designs and manufactures complete helicopters in the UK.[216] +The UK space industry is growing very fast. Worth £9.1bn in 2011 and employing 29,000 people, it is growing at a rate of some 7.5 per cent annually, according to its umbrella organisation, the UK Space Agency. Government strategy is for the space industry to be a £40bn business for the UK by 2030, capturing a 10 per cent share of the $250bn world market for commercial space technology.[216] On 16 July 2013, the British government pledged £60m to the Skylon project: this investment will provide support at a "crucial stage" to allow a full-scale prototype of the SABRE engine to be built. +The pharmaceutical industry plays an important role in the UK economy and the country has the third-highest share of global pharmaceutical R&D expenditures (after the United States and Japan).[217][218] +Agriculture is intensive, highly mechanised and efficient by European standards, producing about 60% of food needs with less than 1.6% of the labour force (535,000 workers).[219] Around two-thirds of production is devoted to livestock, one-third to arable crops. Farmers are subsidised by the EU's Common Agricultural Policy. The UK retains a significant, though much reduced fishing industry. It is also rich in a number of natural resources including coal, petroleum, natural gas, tin, limestone, iron ore, salt, clay, chalk, gypsum, lead, silica and an abundance of arable land. + +The City of London is the world's largest financial centre alongside New York[200][201][202] +In the final quarter of 2008 the UK economy officially entered recession for the first time since 1991.[220] Unemployment increased from 5.2% in May 2008 to 7.6% in May 2009 and by January 2012 the unemployment rate among 18 to 24-year-olds had risen from 11.9% to 22.5%, the highest since current records began in 1992.[221][222] Total UK government debt rose from 44.4% of GDP in 2007 to 82.9% of GDP in 2011.[223] In February 2013, the UK lost its top AAA credit rating for the first time since 1978.[224] +Inflation-adjusted wages in the UK fell by 3.2% between the third quarter of 2010 and the third quarter of 2012.[225] Since the 1980s, economic inequality has grown faster in the UK than in any other developed country.[226] +The poverty line in the UK is commonly defined as being 60% of the median household income.[nb 10] In 2007–2008 13.5 million people, or 22% of the population, lived below this line. This is a higher level of relative poverty than all but four other EU members.[227] In the same year 4.0 million children, 31% of the total, lived in households below the poverty line after housing costs were taken into account. This is a decrease of 400,000 children since 1998–1999.[228] The UK imports 40% of its food supplies.[229] The Office for National Statistics has estimated that in 2011, 14 million people were at risk of poverty or social exclusion, and that one person in 20 (5.1%) was now experiencing "severe material depression,"[230] up from 3 million people in 1977.[231][232] +Science and technology +Main article: Science and technology in the United Kingdom + +Charles Darwin (1809–82), whose theory of evolution by natural selection is the foundation of modern biological sciences +England and Scotland were leading centres of the Scientific Revolution from the 17th century[233] and the United Kingdom led the Industrial Revolution from the 18th century,[208] and has continued to produce scientists and engineers credited with important advances.[234] Major theorists from the 17th and 18th centuries include Isaac Newton, whose laws of motion and illumination of gravity have been seen as a keystone of modern science;[235] from the 19th century Charles Darwin, whose theory of evolution by natural selection was fundamental to the development of modern biology, and James Clerk Maxwell, who formulated classical electromagnetic theory; and more recently Stephen Hawking, who has advanced major theories in the fields of cosmology, quantum gravity and the investigation of black holes.[236] Major scientific discoveries from the 18th century include hydrogen by Henry Cavendish;[237] from the 20th century penicillin by Alexander Fleming,[238] and the structure of DNA, by Francis Crick and others.[239] Major engineering projects and applications by people from the UK in the 18th century include the steam locomotive, developed by Richard Trevithick and Andrew Vivian;[240] from the 19th century the electric motor by Michael Faraday, the incandescent light bulb by Joseph Swan,[241] and the first practical telephone, patented by Alexander Graham Bell;[242] and in the 20th century the world's first working television system by John Logie Baird and others,[243] the jet engine by Frank Whittle, the basis of the modern computer by Alan Turing, and the World Wide Web by Tim Berners-Lee.[244] +Scientific research and development remains important in British universities, with many establishing science parks to facilitate production and co-operation with industry.[245] Between 2004 and 2008 the UK produced 7% of the world's scientific research papers and had an 8% share of scientific citations, the third and second highest in the world (after the United States and China, and the United States, respectively).[246] Scientific journals produced in the UK include Nature, the British Medical Journal and The Lancet.[247] +Transport +Main article: Transport in the United Kingdom + +Heathrow Terminal 5 building. London Heathrow Airport has the most international passenger traffic of any airport in the world.[248][249] +A radial road network totals 29,145 miles (46,904 km) of main roads, 2,173 miles (3,497 km) of motorways and 213,750 miles (344,000 km) of paved roads.[105] In 2009 there were a total of 34 million licensed vehicles in Great Britain.[250] +The UK has a railway network of 10,072 miles (16,209 km) in Great Britain and 189 miles (304 km) in Northern Ireland. Railways in Northern Ireland are operated by NI Railways, a subsidiary of state-owned Translink. In Great Britain, the British Rail network was privatised between 1994 and 1997. Network Rail owns and manages most of the fixed assets (tracks, signals etc.). About 20 privately owned (and foreign state-owned railways including: Deutsche Bahn; SNCF and Nederlandse Spoorwegen) Train Operating Companies (including state-owned East Coast), operate passenger trains and carry over 18,000 passenger trains daily. There are also some 1,000 freight trains in daily operation.[105] The UK government is to spend £30 billion on a new high-speed railway line, HS2, to be operational by 2025.[251] Crossrail, under construction in London, Is Europe's largest construction project with a £15 billion projected cost.[252][253] +In the year from October 2009 to September 2010 UK airports handled a total of 211.4 million passengers.[254] In that period the three largest airports were London Heathrow Airport (65.6 million passengers), Gatwick Airport (31.5 million passengers) and London Stansted Airport (18.9 million passengers).[254] London Heathrow Airport, located 15 miles (24 km) west of the capital, has the most international passenger traffic of any airport in the world[248][249] and is the hub for the UK flag carrier British Airways, as well as for BMI and Virgin Atlantic.[255] +Energy +Main article: Energy in the United Kingdom + +An oil platform in the North Sea +In 2006, the UK was the world's ninth-largest consumer of energy and the 15th-largest producer.[256] The UK is home to a number of large energy companies, including two of the six oil and gas "supermajors" – BP and Royal Dutch Shell – and BG Group.[257][258] In 2011, 40% of the UK's electricity was produced by gas, 30% by coal, 19% by nuclear power and 4.2% by wind, hydro, biofuels and wastes.[259] +In 2009, the UK produced 1.5 million barrels per day (bbl/d) of oil and consumed 1.7 million bbl/d.[260] Production is now in decline and the UK has been a net importer of oil since 2005.[260] In 2010 the UK had around 3.1 billion barrels of proven crude oil reserves, the largest of any EU member state.[260] In 2009, 66.5% of the UK's oil supply was imported.[261] +In 2009, the UK was the 13th-largest producer of natural gas in the world and the largest producer in the EU.[262] Production is now in decline and the UK has been a net importer of natural gas since 2004.[262] In 2009, half of British gas was supplied from imports and this is expected to increase to at least 75% by 2015, as domestic reserves are depleted.[259] +Coal production played a key role in the UK economy in the 19th and 20th centuries. In the mid-1970s, 130 million tonnes of coal was being produced annually, not falling below 100 million tonnes until the early 1980s. During the 1980s and 1990s the industry was scaled back considerably. In 2011, the UK produced 18.3 million tonnes of coal.[263] In 2005 it had proven recoverable coal reserves of 171 million tons.[263] The UK Coal Authority has stated there is a potential to produce between 7 billion tonnes and 16 billion tonnes of coal through underground coal gasification (UCG) or 'fracking',[264] and that, based on current UK coal consumption, such reserves could last between 200 and 400 years.[265] However, environmental and social concerns have been raised over chemicals getting into the water table and minor earthquakes damaging homes.[266][267] +In the late 1990s, nuclear power plants contributed around 25% of total annual electricity generation in the UK, but this has gradually declined as old plants have been shut down and ageing-related problems affect plant availability. In 2012, the UK had 16 reactors normally generating about 19% of its electricity. All but one of the reactors will be retired by 2023. Unlike Germany and Japan, the UK intends to build a new generation of nuclear plants from about 2018.[259] +Demographics +Main article: Demographics of the United Kingdom + +Map of population density in the UK as at the 2011 census. +A census is taken simultaneously in all parts of the UK every ten years.[268] The Office for National Statistics is responsible for collecting data for England and Wales, the General Register Office for Scotland and the Northern Ireland Statistics and Research Agency each being responsible for censuses in their respective countries.[269] In the 2011 census the total population of the United Kingdom was 63,181,775.[270] It is the third-largest in the European Union, the fifth-largest in the Commonwealth and the 21st-largest in the world. 2010 was the third successive year in which natural change contributed more to population growth than net long-term international migration.[271][271] Between 2001 and 2011 the population increased by an average annual rate of approximately 0.7 per cent.[270] This compares to 0.3 per cent per year in the period 1991 to 2001 and 0.2 per cent in the decade 1981 to 1991.[271] The 2011 census also confirmed that the proportion of the population aged 0–14 has nearly halved (31 per cent in 1911 compared to 18 in 2011) and the proportion of older people aged 65 and over has more than trebled (from 5 to 16 per cent).[270] It has been estimated that the number of people aged 100 or over will rise steeply to reach over 626,000 by 2080.[272] +England's population in 2011 was found to be 53 million.[273] It is one of the most densely populated countries in the world, with 383 people resident per square kilometre in mid-2003,[274] with a particular concentration in London and the south-east.[275] The 2011 census put Scotland's population at 5.3 million,[276] Wales at 3.06 million and Northern Ireland at 1.81 million.[273] In percentage terms England has had the fastest growing population of any country of the UK in the period from 2001 to 2011, with an increase of 7.9%. +In 2012 the average total fertility rate (TFR) across the UK was 1.92 children per woman.[277] While a rising birth rate is contributing to current population growth, it remains considerably below the 'baby boom' peak of 2.95 children per woman in 1964,[278] below the replacement rate of 2.1, but higher than the 2001 record low of 1.63.[277] In 2012, Scotland had the lowest TFR at only 1.67, followed by Wales at 1.88, England at 1.94, and Northern Ireland at 2.03.[277] In 2011, 47.3% of births in the UK were to unmarried women.[279] A government figure estimated that there are 3.6 million homosexual people in Britain comprising 6 per cent of the population.[280] +view talk edit +view talk edit +Largest urban areas of the United Kingdom +United Kingdom 2011 census Built-up areas[281][282][283] +Rank Urban area Pop. Principal settlement Rank Urban area Pop. Principal settlement +Greater London Urban Area +Greater London Urban Area +Greater Manchester Urban Area +Greater Manchester Urban Area +1 Greater London Urban Area 9,787,426 London 11 Bristol Urban Area 617,280 Bristol West Midlands Urban Area +West Midlands Urban Area +West Yorkshire Urban Area +West Yorkshire Urban Area +2 Greater Manchester Urban Area 2,553,379 Manchester 12 Belfast Metropolitan Urban Area 579,236 Belfast +3 West Midlands Urban Area 2,440,986 Birmingham 13 Leicester Urban Area 508,916 Leicester +4 West Yorkshire Urban Area 1,777,934 Leeds 14 Edinburgh 488,610 Edinburgh +5 Greater Glasgow 976,970 Glasgow 15 Brighton/Worthing/Littlehampton 474,485 Brighton +6 Liverpool Urban Area 864,122 Liverpool 16 South East Dorset conurbation 466,266 Bournemouth +7 South Hampshire 855,569 Southampton 17 Cardiff Urban Area 390,214 Cardiff +8 Tyneside 774,891 Newcastle 18 Teesside 376,633 Middlesbrough +9 Nottingham Urban Area 729,977 Nottingham 19 The Potteries Urban Area 372,775 Stoke-on-Trent +10 Sheffield Urban Area 685,368 Sheffield 20 Coventry and Bedworth Urban Area 359,262 Coventry + +Ethnic groups + +Map showing the percentage of the population who are not white according to the 2011 census. +Ethnic group 2011 +population 2011 +% +White 55,010,359 87.1 +White: Irish Traveller 63,193 0.1 +Asian or Asian British: Indian 1,451,862 +2.3 +Asian or Asian British: Pakistani 1,173,892 +1.9 +Asian or Asian British: Bangladeshi 451,529 +0.7 +Asian or Asian British: Chinese 433,150 +0.7 +Asian or Asian British: Asian Other 861,815 +1.4 +Asian or Asian British: Total 4,373,339 +7.0 +Black or Black British 1,904,684 +3.0 +British Mixed 1,250,229 +2.0 +Other: Total 580,374 +0.9 +Total[284] 63,182,178 +100 +Historically, indigenous British people were thought to be descended from the various ethnic groups that settled there before the 11th century: the Celts, Romans, Anglo-Saxons, Norse and the Normans. Welsh people could be the oldest ethnic group in the UK.[285] A 2006 genetic study shows that more than 50 per cent of England's gene pool contains Germanic Y chromosomes.[286] Another 2005 genetic analysis indicates that "about 75 per cent of the traceable ancestors of the modern British population had arrived in the British isles by about 6,200 years ago, at the start of the British Neolithic or Stone Age", and that the British broadly share a common ancestry with the Basque people.[287][288][289] +The UK has a history of small-scale non-white immigration, with Liverpool having the oldest Black population in the country dating back to at least the 1730s during the period of the African slave trade,[290] and the oldest Chinese community in Europe, dating to the arrival of Chinese seamen in the 19th century.[291] In 1950 there were probably fewer than 20,000 non-white residents in Britain, almost all born overseas.[292] +Since 1948 substantial immigration from Africa, the Caribbean and South Asia has been a legacy of ties forged by the British Empire. Migration from new EU member states in Central and Eastern Europe since 2004 has resulted in growth in these population groups but, as of 2008, the trend is reversing. Many of these migrants are returning to their home countries, leaving the size of these groups unknown.[293] In 2011, 86% of the population identified themselves as White, meaning 12.9% of the UK population identify themselves as of mixed ethnic minority. +Ethnic diversity varies significantly across the UK. 30.4% of London's population and 37.4% of Leicester's was estimated to be non-white in 2005,[294][295] whereas less than 5% of the populations of North East England, Wales and the South West were from ethnic minorities, according to the 2001 census.[296] In 2011, 26.5% of primary and 22.2% of secondary pupils at state schools in England were members of an ethnic minority.[297] +The non-white British population of England and Wales increased by 38% from 6.6 million in 2001 to 9.1 million in 2009.[298] The fastest-growing group was the mixed-ethnicity population, which doubled from 672,000 in 2001 to 986,600 in 2009. Also in the same period, a decrease of 36,000 white British people was recorded.[299] +Languages +Main article: Languages of the United Kingdom + +The English-speaking world. Countries in dark blue have a majority of native speakers; countries where English is an official but not a majority language are shaded in light blue. English is one of the official languages of the European Union[300] and the United Nations[301] +The UK's de facto official language is English.[302][303] It is estimated that 95% of the UK's population are monolingual English speakers.[304] 5.5% of the population are estimated to speak languages brought to the UK as a result of relatively recent immigration.[304] South Asian languages, including Bengali, Tamil, Punjabi, Hindi and Gujarati, are the largest grouping and are spoken by 2.7% of the UK population.[304] According to the 2011 census, Polish has become the second-largest language spoken in England and has 546,000 speakers.[305] +Four Celtic languages are spoken in the UK: Welsh; Irish; Scottish Gaelic; and Cornish. All are recognised as regional or minority languages, subject to specific measures of protection and promotion under the European Charter for Regional or Minority Languages[2][306] and the Framework Convention for the Protection of National Minorities.[307] In the 2001 Census over a fifth (21%) of the population of Wales said they could speak Welsh,[308] an increase from the 1991 Census (18%).[309] In addition it is estimated that about 200,000 Welsh speakers live in England.[310] In the same census in Northern Ireland 167,487 people (10.4%) stated that they had "some knowledge of Irish" (see Irish language in Northern Ireland), almost exclusively in the nationalist (mainly Catholic) population. Over 92,000 people in Scotland (just under 2% of the population) had some Gaelic language ability, including 72% of those living in the Outer Hebrides.[311] The number of schoolchildren being taught through Welsh, Scottish Gaelic and Irish is increasing.[312] Among emigrant-descended populations some Scottish Gaelic is still spoken in Canada (principally Nova Scotia and Cape Breton Island),[313] and Welsh in Patagonia, Argentina.[314] +Scots, a language descended from early northern Middle English, has limited recognition alongside its regional variant, Ulster Scots in Northern Ireland, without specific commitments to protection and promotion.[2][315] +It is compulsory for pupils to study a second language up to the age of 14 in England,[316] and up to age 16 in Scotland. French and German are the two most commonly taught second languages in England and Scotland. All pupils in Wales are taught Welsh as a second language up to age 16, or are taught in Welsh.[317] +Religion +Main article: Religion in the United Kingdom + +Westminster Abbey is used for the coronation of British monarchs +Forms of Christianity have dominated religious life in what is now the United Kingdom for over 1,400 years.[318] Although a majority of citizens still identify with Christianity in many surveys, regular church attendance has fallen dramatically since the middle of the 20th century,[319] while immigration and demographic change have contributed to the growth of other faiths, most notably Islam.[320] This has led some commentators to variously describe the UK as a multi-faith,[321] secularised,[322] or post-Christian society.[323] +In the 2001 census 71.6% of all respondents indicated that they were Christians, with the next largest faiths (by number of adherents) being Islam (2.8%), Hinduism (1.0%), Sikhism (0.6%), Judaism (0.5%), Buddhism (0.3%) and all other religions (0.3%).[324] 15% of respondents stated that they had no religion, with a further 7% not stating a religious preference.[325] A Tearfund survey in 2007 showed only one in ten Britons actually attend church weekly.[326] Between the 2001 and 2011 census there was a decrease in the amount of people who identified as Christian by 12%, whilst the percentage of those reporting no religious affiliation doubled. This contrasted with growth in the other main religious group categories, with the number of Muslims increasing by the most substantial margin to a total of about 5%.[327] +The Church of England is the established church in England.[328] It retains a representation in the UK Parliament and the British monarch is its Supreme Governor.[329] In Scotland the Presbyterian Church of Scotland is recognised as the national church. It is not subject to state control, and the British monarch is an ordinary member, required to swear an oath to "maintain and preserve the Protestant Religion and Presbyterian Church Government" upon his or her accession.[330][331] The (Anglican) Church in Wales was disestablished in 1920 and, as the (Anglican) Church of Ireland was disestablished in 1870 before the partition of Ireland, there is no established church in Northern Ireland.[332] Although there are no UK-wide data in the 2001 census on adherence to individual Christian denominations, it has been estimated that 62% of Christians are Anglican, 13.5% Catholic, 6% Presbyterian, 3.4% Methodist with small numbers of other Protestant denominations such as Open Brethren, and Orthodox churches.[333] +Migration +Main article: Immigration to the United Kingdom since 1922 +See also: Foreign-born population of the United Kingdom + +Estimated foreign-born population by country of birth, April 2007 – March 2008 +The United Kingdom has experienced successive waves of migration. The Great Famine in Ireland, then part of the United Kingdom, resulted in perhaps a million people migrating to Great Brtain.[334] Unable to return to Poland at the end of World War II, over 120,000 Polish veterans remained in the UK permanently.[335] After World War II, there was significant immigration from the colonies and newly independent former colonies, partly as a legacy of empire and partly driven by labour shortages. Many of these migrants came from the Caribbean and the Indian subcontinent.[336] The British Asian population has increased from 2.2 million in 2001 to over 4.2 million in 2011.[337] +One of the more recent trends in migration has been the arrival of workers from the new EU member states in Eastern Europe. In 2010, there were 7.0 million foreign-born residents in the UK, corresponding to 11.3% of the total population. Of these, 4.76 million (7.7%) were born outside the EU and 2.24 million (3.6%) were born in another EU Member State.[338] The proportion of foreign-born people in the UK remains slightly below that of many other European countries.[339] However, immigration is now contributing to a rising population[340] with arrivals and UK-born children of migrants accounting for about half of the population increase between 1991 and 2001. Analysis of Office for National Statistics (ONS) data shows that a net total of 2.3 million migrants moved to the UK in the 15 years from 1991 to 2006.[341][342] In 2008 it was predicted that migration would add 7 million to the UK population by 2031,[343] though these figures are disputed.[344] The ONS reported that net migration rose from 2009 to 2010 by 21 per cent to 239,000.[345] In 2011 the net increase was 251,000: immigration was 589,000, while the number of people emigrating (for more than 12 months) was 338,000.[346][347] +195,046 foreign nationals became British citizens in 2010,[348] compared to 54,902 in 1999.[348][349] A record 241,192 people were granted permanent settlement rights in 2010, of whom 51 per cent were from Asia and 27 per cent from Africa.[350] 25.5 per cent of babies born in England and Wales in 2011 were born to mothers born outside the UK, according to official statistics released in 2012.[351] +Citizens of the European Union, including those of the UK, have the right to live and work in any EU member state.[352] The UK applied temporary restrictions to citizens of Romania and Bulgaria, which joined the EU in January 2007.[353] Research conducted by the Migration Policy Institute for the Equality and Human Rights Commission suggests that, between May 2004 and September 2009, 1.5 million workers migrated from the new EU member states to the UK, two-thirds of them Polish, but that many subsequently returned home, resulting in a net increase in the number of nationals of the new member states in the UK of some 700,000 over that period.[354][355] The late-2000s recession in the UK reduced the economic incentive for Poles to migrate to the UK,[356] the migration becoming temporary and circular.[357] In 2009, for the first time since enlargement, more nationals of the eight central and eastern European states that had joined the EU in 2004 left the UK than arrived.[358] In 2011, citizens of the new EU member states made up 13% of the immigrants entering the country.[346] + +Estimated number of British citizens living overseas by country, 2006 +The UK government has introduced a points-based immigration system for immigration from outside the European Economic Area to replace former schemes, including the Scottish Government's Fresh Talent Initiative.[359] In June 2010 the UK government introduced a temporary limit of 24,000 on immigration from outside the EU, aiming to discourage applications before a permanent cap was imposed in April 2011.[360] The cap has caused tension within the coalition: business secretary Vince Cable has argued that it is harming British businesses.[361] +Emigration was an important feature of British society in the 19th century. Between 1815 and 1930 around 11.4 million people emigrated from Britain and 7.3 million from Ireland. Estimates show that by the end of the 20th century some 300 million people of British and Irish descent were permanently settled around the globe.[362] Today, at least 5.5 million UK-born people live abroad,[363][364][365] mainly in Australia, Spain, the United States and Canada.[363][366] +Education +Main article: Education in the United Kingdom +See also: Education in England, Education in Northern Ireland, Education in Scotland and Education in Wales + +King's College, part of the University of Cambridge, which was founded in 1209 +Education in the United Kingdom is a devolved matter, with each country having a separate education system. +Whilst education in England is the responsibility of the Secretary of State for Education, the day-to-day administration and funding of state schools is the responsibility of local authorities.[367] Universally free of charge state education was introduced piecemeal between 1870 and 1944.[368][369] Education is now mandatory from ages five to sixteen (15 if born in late July or August). In 2011, the Trends in International Mathematics and Science Study (TIMSS) rated 13–14-year-old pupils in England and Wales 10th in the world for maths and 9th for science.[370] The majority of children are educated in state-sector schools, a small proportion of which select on the grounds of academic ability. Two of the top ten performing schools in terms of GCSE results in 2006 were state-run grammar schools. Over half of students at the leading universities of Cambridge and Oxford had attended state schools.[371] Despite a fall in actual numbers the proportion of children in England attending private schools has risen to over 7%.[372] In 2010, more than 45% of places at the University of Oxford and 40% at the University of Cambridge were taken by students from private schools, even though they educate just 7% of the population.[373] England has the two oldest universities in English-speaking world, Universities of Oxford and Cambridge (jointly known as "Oxbridge") with history of over eight centuries. The United Kingdom has 9 universities featured in the Times Higher Education top 100 rankings, making it second to the United States in terms of representation.[374] + +Queen's University Belfast, built in 1849[375] +Education in Scotland is the responsibility of the Cabinet Secretary for Education and Lifelong Learning, with day-to-day administration and funding of state schools the responsibility of Local Authorities. Two non-departmental public bodies have key roles in Scottish education. The Scottish Qualifications Authority is responsible for the development, accreditation, assessment and certification of qualifications other than degrees which are delivered at secondary schools, post-secondary colleges of further education and other centres.[376] The Learning and Teaching Scotland provides advice, resources and staff development to education professionals.[377] Scotland first legislated for compulsory education in 1496.[378] The proportion of children in Scotland attending private schools is just over 4%, and it has been rising slowly in recent years.[379] Scottish students who attend Scottish universities pay neither tuition fees nor graduate endowment charges, as fees were abolished in 2001 and the graduate endowment scheme was abolished in 2008.[380] +The Welsh Government has responsibility for education in Wales. A significant number of Welsh students are taught either wholly or largely in the Welsh language; lessons in Welsh are compulsory for all until the age of 16.[381] There are plans to increase the provision of Welsh-medium schools as part of the policy of creating a fully bilingual Wales. +Education in Northern Ireland is the responsibility of the Minister of Education and the Minister for Employment and Learning, although responsibility at a local level is administered by five education and library boards covering different geographical areas. The Council for the Curriculum, Examinations & Assessment (CCEA) is the body responsible for advising the government on what should be taught in Northern Ireland's schools, monitoring standards and awarding qualifications.[382] +A government commission's report in 2014 found that privately educated people comprise 7% of the general population of the UK but much larger percentages of the top professions, the most extreme case quoted being 71% of senior judges.[383][384] +Healthcare +Main article: Healthcare in the United Kingdom + +The Royal Aberdeen Children's Hospital, an NHS Scotland specialist children's hospital +Healthcare in the United Kingdom is a devolved matter and each country has its own system of private and publicly funded health care, together with alternative, holistic and complementary treatments. Public healthcare is provided to all UK permanent residents and is mostly free at the point of need, being paid for from general taxation. The World Health Organization, in 2000, ranked the provision of healthcare in the United Kingdom as fifteenth best in Europe and eighteenth in the world.[385][386] +Regulatory bodies are organised on a UK-wide basis such as the General Medical Council, the Nursing and Midwifery Council and non-governmental-based, such as the Royal Colleges. However, political and operational responsibility for healthcare lies with four national executives; healthcare in England is the responsibility of the UK Government; healthcare in Northern Ireland is the responsibility of the Northern Ireland Executive; healthcare in Scotland is the responsibility of the Scottish Government; and healthcare in Wales is the responsibility of the Welsh Assembly Government. Each National Health Service has different policies and priorities, resulting in contrasts.[387][388] +Since 1979 expenditure on healthcare has been increased significantly to bring it closer to the European Union average.[389] The UK spends around 8.4 per cent of its gross domestic product on healthcare, which is 0.5 percentage points below the Organisation for Economic Co-operation and Development average and about one percentage point below the average of the European Union.[390] +Culture +Main article: Culture of the United Kingdom +The culture of the United Kingdom has been influenced by many factors including: the nation's island status; its history as a western liberal democracy and a major power; as well as being a political union of four countries with each preserving elements of distinctive traditions, customs and symbolism. As a result of the British Empire, British influence can be observed in the language, culture and legal systems of many of its former colonies including Australia, Canada, India, Ireland, New Zealand, South Africa and the United States. The substantial cultural influence of the United Kingdom has led it to be described as a "cultural superpower."[391][392] +Literature +Main article: British literature + +The Chandos portrait, believed to depict William Shakespeare +'British literature' refers to literature associated with the United Kingdom, the Isle of Man and the Channel Islands. Most British literature is in the English language. In 2005, some 206,000 books were published in the United Kingdom and in 2006 it was the largest publisher of books in the world.[393] +The English playwright and poet William Shakespeare is widely regarded as the greatest dramatist of all time,[394][395][396] and his contemporaries Christopher Marlowe and Ben Jonson have also been held in continuous high esteem. More recently the playwrights Alan Ayckbourn, Harold Pinter, Michael Frayn, Tom Stoppard and David Edgar have combined elements of surrealism, realism and radicalism. +Notable pre-modern and early-modern English writers include Geoffrey Chaucer (14th century), Thomas Malory (15th century), Sir Thomas More (16th century), John Bunyan (17th century) and John Milton (17th century). In the 18th century Daniel Defoe (author of Robinson Crusoe) and Samuel Richardson were pioneers of the modern novel. In the 19th century there followed further innovation by Jane Austen, the gothic novelist Mary Shelley, the children's writer Lewis Carroll, the Brontë sisters, the social campaigner Charles Dickens, the naturalist Thomas Hardy, the realist George Eliot, the visionary poet William Blake and romantic poet William Wordsworth. 20th-century English writers include the science-fiction novelist H. G. Wells; the writers of children's classics Rudyard Kipling, A. A. Milne (the creator of Winnie-the-Pooh), Roald Dahl and Enid Blyton; the controversial D. H. Lawrence; the modernist Virginia Woolf; the satirist Evelyn Waugh; the prophetic novelist George Orwell; the popular novelists W. Somerset Maugham and Graham Greene; the crime writer Agatha Christie (the best-selling novelist of all time);[397] Ian Fleming (the creator of James Bond); the poets T.S. Eliot, Philip Larkin and Ted Hughes; the fantasy writers J. R. R. Tolkien, C. S. Lewis and J. K. Rowling; the graphic novelist Alan Moore, whose novel Watchmen is often cited by critics as comic's greatest series and graphic novel[398] and one of the best-selling graphic novels ever published.[399] + +A photograph of Victorian era novelist Charles Dickens +Scotland's contributions include the detective writer Arthur Conan Doyle (the creator of Sherlock Holmes), romantic literature by Sir Walter Scott, the children's writer J. M. Barrie, the epic adventures of Robert Louis Stevenson and the celebrated poet Robert Burns. More recently the modernist and nationalist Hugh MacDiarmid and Neil M. Gunn contributed to the Scottish Renaissance. A more grim outlook is found in Ian Rankin's stories and the psychological horror-comedy of Iain Banks. Scotland's capital, Edinburgh, was UNESCO's first worldwide City of Literature.[400] +Britain's oldest known poem, Y Gododdin, was composed in Yr Hen Ogledd (The Old North), most likely in the late 6th century. It was written in Cumbric or Old Welsh and contains the earliest known reference to King Arthur.[401] From around the seventh century, the connection between Wales and the Old North was lost, and the focus of Welsh-language culture shifted to Wales, where Arthurian legend was further developed by Geoffrey of Monmouth.[402] Wales's most celebrated medieval poet, Dafydd ap Gwilym (fl.1320–1370), composed poetry on themes including nature, religion and especially love. He is widely regarded as one of the greatest European poets of his age.[403] Until the late 19th century the majority of Welsh literature was in Welsh and much of the prose was religious in character. Daniel Owen is credited as the first Welsh-language novelist, publishing Rhys Lewis in 1885. The best-known of the Anglo-Welsh poets are both Thomases. Dylan Thomas became famous on both sides of the Atlantic in the mid-20th century. He is remembered for his poetry – his "Do not go gentle into that good night; Rage, rage against the dying of the light." is one of the most quoted couplets of English language verse – and for his 'play for voices', Under Milk Wood. The influential Church in Wales 'poet-priest' and Welsh nationalist R. S. Thomas was nominated for the Nobel Prize in Literature in 1996. Leading Welsh novelists of the twentieth century include Richard Llewellyn and Kate Roberts.[404][405] +Authors of other nationalities, particularly from Commonwealth countries, the Republic of Ireland and the United States, have lived and worked in the UK. Significant examples through the centuries include Jonathan Swift, Oscar Wilde, Bram Stoker, George Bernard Shaw, Joseph Conrad, T.S. Eliot, Ezra Pound and more recently British authors born abroad such as Kazuo Ishiguro and Sir Salman Rushdie.[406][407] +Music +Main article: Music of the United Kingdom +See also: British rock + +The Beatles are the most commercially successful and critically acclaimed band in the history of music, selling over a billion records internationally.[408][409][410] +Various styles of music are popular in the UK from the indigenous folk music of England, Wales, Scotland and Northern Ireland to heavy metal. Notable composers of classical music from the United Kingdom and the countries that preceded it include William Byrd, Henry Purcell, Sir Edward Elgar, Gustav Holst, Sir Arthur Sullivan (most famous for working with the librettist Sir W. S. Gilbert), Ralph Vaughan Williams and Benjamin Britten, pioneer of modern British opera. Sir Peter Maxwell Davies is one of the foremost living composers and current Master of the Queen's Music. The UK is also home to world-renowned symphonic orchestras and choruses such as the BBC Symphony Orchestra and the London Symphony Chorus. Notable conductors include Sir Simon Rattle, John Barbirolli and Sir Malcolm Sargent. Some of the notable film score composers include John Barry, Clint Mansell, Mike Oldfield, John Powell, Craig Armstrong, David Arnold, John Murphy, Monty Norman and Harry Gregson-Williams. George Frideric Handel, although born German, was a naturalised British citizen[411] and some of his best works, such as Messiah, were written in the English language.[412] Andrew Lloyd Webber has achieved enormous worldwide commercial success and is a prolific composer of musical theatre, works which have dominated London's West End for a number of years and have travelled to Broadway in New York.[413] +The Beatles have international sales of over one billion units and are the biggest-selling and most influential band in the history of popular music.[408][409][410][414] Other prominent British contributors to have influenced popular music over the last 50 years include; The Rolling Stones, Led Zeppelin, Pink Floyd, Queen, the Bee Gees, and Elton John, all of whom have world wide record sales of 200 million or more.[415][416][417][418][419][420] The Brit Awards are the BPI's annual music awards, and some of the British recipients of the Outstanding Contribution to Music award include; The Who, David Bowie, Eric Clapton, Rod Stewart and The Police.[421] More recent UK music acts that have had international success include Coldplay, Radiohead, Oasis, Spice Girls, Robbie Williams, Amy Winehouse and Adele.[422] +A number of UK cities are known for their music. Acts from Liverpool have had more UK chart number one hit singles per capita (54) than any other city worldwide.[423] Glasgow's contribution to music was recognised in 2008 when it was named a UNESCO City of Music, one of only three cities in the world to have this honour.[424] +Visual art +Main article: Art of the United Kingdom + +J. M. W. Turner self-portrait, oil on canvas, c. 1799 +The history of British visual art forms part of western art history. Major British artists include: the Romantics William Blake, John Constable, Samuel Palmer and J.M.W. Turner; the portrait painters Sir Joshua Reynolds and Lucian Freud; the landscape artists Thomas Gainsborough and L. S. Lowry; the pioneer of the Arts and Crafts Movement William Morris; the figurative painter Francis Bacon; the Pop artists Peter Blake, Richard Hamilton and David Hockney; the collaborative duo Gilbert and George; the abstract artist Howard Hodgkin; and the sculptors Antony Gormley, Anish Kapoor and Henry Moore. During the late 1980s and 1990s the Saatchi Gallery in London helped to bring to public attention a group of multi-genre artists who would become known as the "Young British Artists": Damien Hirst, Chris Ofili, Rachel Whiteread, Tracey Emin, Mark Wallinger, Steve McQueen, Sam Taylor-Wood and the Chapman Brothers are among the better-known members of this loosely affiliated movement. +The Royal Academy in London is a key organisation for the promotion of the visual arts in the United Kingdom. Major schools of art in the UK include: the six-school University of the Arts London, which includes the Central Saint Martins College of Art and Design and Chelsea College of Art and Design; Goldsmiths, University of London; the Slade School of Fine Art (part of University College London); the Glasgow School of Art; the Royal College of Art; and The Ruskin School of Drawing and Fine Art (part of the University of Oxford). The Courtauld Institute of Art is a leading centre for the teaching of the history of art. Important art galleries in the United Kingdom include the National Gallery, National Portrait Gallery, Tate Britain and Tate Modern (the most-visited modern art gallery in the world, with around 4.7 million visitors per year).[425] +Cinema +Main article: Cinema of the United Kingdom + +Film director Alfred Hitchcock +The United Kingdom has had a considerable influence on the history of the cinema. The British directors Alfred Hitchcock, whose film Vertigo is considered by some critics as the best film of all time,[426] and David Lean are among the most critically acclaimed of all-time.[427] Other important directors including Charlie Chaplin,[428] Michael Powell,[429] Carol Reed[430] and Ridley Scott.[431] Many British actors have achieved international fame and critical success, including: Julie Andrews,[432] Richard Burton,[433] Michael Caine,[434] Charlie Chaplin,[435] Sean Connery,[436] Vivien Leigh,[437] David Niven,[438] Laurence Olivier,[439] Peter Sellers,[440] Kate Winslet,[441] and Daniel Day-Lewis, the only person to win an Oscar in the best actor category three times.[442] Some of the most commercially successful films of all time have been produced in the United Kingdom, including the two highest-grossing film franchises (Harry Potter and James Bond).[443] Ealing Studios has a claim to being the oldest continuously working film studio in the world.[444] +Despite a history of important and successful productions, the industry has often been characterised by a debate about its identity and the level of American and European influence. British producers are active in international co-productions and British actors, directors and crew feature regularly in American films. Many successful Hollywood films have been based on British people, stories or events, including Titanic, The Lord of the Rings, Pirates of the Caribbean. +In 2009, British films grossed around $2 billion worldwide and achieved a market share of around 7% globally and 17% in the United Kingdom.[445] UK box-office takings totalled £944 million in 2009, with around 173 million admissions.[445] The British Film Institute has produced a poll ranking of what it considers to be the 100 greatest British films of all time, the BFI Top 100 British films.[446] The annual British Academy Film Awards, hosted by the British Academy of Film and Television Arts, are the British equivalent of the Oscars.[447] +Media +Main article: Media of the United Kingdom + +Broadcasting House in London, headquarters of the BBC, the oldest and largest broadcaster in the world.[448][449][450] +The BBC, founded in 1922, is the UK's publicly funded radio, television and Internet broadcasting corporation, and is the oldest and largest broadcaster in the world.[448][449][450] It operates numerous television and radio stations in the UK and abroad and its domestic services are funded by the television licence.[451][452] Other major players in the UK media include ITV plc, which operates 11 of the 15 regional television broadcasters that make up the ITV Network,[453] and News Corporation, which owns a number of national newspapers through News International such as the most popular tabloid The Sun and the longest-established daily "broadsheet" The Times,[454] as well as holding a large stake in satellite broadcaster British Sky Broadcasting.[455] London dominates the media sector in the UK: national newspapers and television and radio are largely based there, although Manchester is also a significant national media centre. Edinburgh and Glasgow, and Cardiff, are important centres of newspaper and broadcasting production in Scotland and Wales respectively.[456] The UK publishing sector, including books, directories and databases, journals, magazines and business media, newspapers and news agencies, has a combined turnover of around £20 billion and employs around 167,000 people.[457] +In 2009, it was estimated that individuals viewed a mean of 3.75 hours of television per day and 2.81 hours of radio. In that year the main BBC public service broadcasting channels accounted for an estimated 28.4% of all television viewing; the three main independent channels accounted for 29.5% and the increasingly important other satellite and digital channels for the remaining 42.1%.[458] Sales of newspapers have fallen since the 1970s and in 2009 42% of people reported reading a daily national newspaper.[459] In 2010 82.5% of the UK population were Internet users, the highest proportion amongst the 20 countries with the largest total number of users in that year.[460] +Philosophy +Main article: British philosophy +The United Kingdom is famous for the tradition of 'British Empiricism', a branch of the philosophy of knowledge that states that only knowledge verified by experience is valid, and 'Scottish Philosophy', sometimes referred to as the 'Scottish School of Common Sense'.[461] The most famous philosophers of British Empiricism are John Locke, George Berkeley and David Hume; while Dugald Stewart, Thomas Reid and William Hamilton were major exponents of the Scottish "common sense" school. Two Britons are also notable for a theory of moral philosophy utilitarianism, first used by Jeremy Bentham and later by John Stuart Mill in his short work Utilitarianism.[462][463] Other eminent philosophers from the UK and the unions and countries that preceded it include Duns Scotus, John Lilburne, Mary Wollstonecraft, Sir Francis Bacon, Adam Smith, Thomas Hobbes, William of Ockham, Bertrand Russell and A.J. "Freddie" Ayer. Foreign-born philosophers who settled in the UK include Isaiah Berlin, Karl Marx, Karl Popper and Ludwig Wittgenstein. +Sport +Main article: Sport in the United Kingdom + +Wembley Stadium, London, home of the England national football team, is one of the most expensive stadia ever built.[464] +Major sports, including association football, tennis, rugby union, rugby league, golf, boxing, rowing and cricket, originated or were substantially developed in the UK and the states that preceded it. With the rules and codes of many modern sports invented and codified in late 19th-century Victorian Britain, in 2012, the President of the IOC, Jacques Rogge, stated; "This great, sports-loving country is widely recognized as the birthplace of modern sport. It was here that the concepts of sportsmanship and fair play were first codified into clear rules and regulations. It was here that sport was included as an educational tool in the school curriculum".[465][466] +In most international competitions, separate teams represent England, Scotland and Wales. Northern Ireland and the Republic of Ireland usually field a single team representing all of Ireland, with notable exceptions being association football and the Commonwealth Games. In sporting contexts, the English, Scottish, Welsh and Irish / Northern Irish teams are often referred to collectively as the Home Nations. There are some sports in which a single team represents the whole of United Kingdom, including the Olympics, where the UK is represented by the Great Britain team. The 1908, 1948 and 2012 Summer Olympics were held in London, making it the first city to host the games three times. Britain has participated in every modern Olympic Games to date and is third in the medal count. +A 2003 poll found that football is the most popular sport in the United Kingdom.[467] Each of the Home Nations has its own football association, national team and league system. The English top division, the Premier League, is the most watched football league in the world.[468] The first-ever international football match was contested by England and Scotland on 30 November 1872.[469] England, Scotland, Wales and Northern Ireland compete as separate countries in international competitions.[470] A Great Britain Olympic football team was assembled for the first time to compete in the London 2012 Olympic Games. However, the Scottish, Welsh and Northern Irish football associations declined to participate, fearing that it would undermine their independent status – a fear confirmed by FIFA president Sepp Blatter.[471] + +The Millennium Stadium, Cardiff, opened for the 1999 Rugby World Cup. +Cricket was invented in England. The England cricket team, controlled by the England and Wales Cricket Board,[472] is the only national team in the UK with Test status. Team members are drawn from the main county sides, and include both English and Welsh players. Cricket is distinct from football and rugby where Wales and England field separate national teams, although Wales had fielded its own team in the past. Irish and Scottish players have played for England because neither Scotland nor Ireland have Test status and have only recently started to play in One Day Internationals.[473][474] Scotland, England (and Wales), and Ireland (including Northern Ireland) have competed at the Cricket World Cup, with England reaching the finals on three occasions. There is a professional league championship in which clubs representing 17 English counties and 1 Welsh county compete.[475] +Rugby league is a popular sport in some regions of the UK. It originated in Huddersfield and is generally played in Northern England.[476] A single 'Great Britain Lions' team had competed in the Rugby League World Cup and Test match games, but this changed in 2008 when England, Scotland and Ireland competed as separate nations.[477] Great Britain is still being retained as the full national team for Ashes tours against Australia, New Zealand and France. Super League is the highest level of professional rugby league in the UK and Europe. It consists of 11 teams from Northern England, 1 from London, 1 from Wales and 1 from France. +In rugby union, England, Scotland, Wales, Ireland, France and Italy compete in the Six Nations Championship; the premier international tournament in the northern hemisphere. Sport governing bodies in England, Scotland, Wales and Ireland organise and regulate the game separately.[478] If any of the British teams or the Irish team beat the other three in a tournament, then it is awarded the Triple Crown.[479] + +The Wimbledon Championships, a Grand Slam tennis tournament, is held in Wimbledon, London every June or July. +Thoroughbred racing, which originated under Charles II of England as the "sport of kings", is popular throughout the UK with world-famous races including the Grand National, the Epsom Derby, Royal Ascot and the Cheltenham National Hunt Festival (including the Cheltenham Gold Cup). The UK has proved successful in the international sporting arena in rowing. +The UK is closely associated with motorsport. Many teams and drivers in Formula One (F1) are based in the UK, and the country has won more drivers' and constructors' titles than any other. The UK hosted the very first F1 Grand Prix in 1950 at Silverstone, the current location of the British Grand Prix held each year in July. The country also hosts legs of the Grand Prix motorcycle racing, World Rally Championship and FIA World Endurance Championship. The premier national auto racing event is the British Touring Car Championship (BTCC). Motorcycle road racing has a long tradition with races such as the Isle of Man TT and the North West 200. +Golf is the sixth-most popular sport, by participation, in the UK. Although The Royal and Ancient Golf Club of St Andrews in Scotland is the sport's home course,[480] the world's oldest golf course is actually Musselburgh Links' Old Golf Course.[481] +Snooker is one of the UK's popular sporting exports, with the world championships held annually in Sheffield.[482] The modern game of lawn tennis first originated in the city of Birmingham between 1859 and 1865.[483] The Championships, Wimbledon are international tennis events held in Wimbledon in south London every summer and are regarded as the most prestigious event of the global tennis calendar. In Northern Ireland Gaelic football and hurling are popular team sports, both in terms of participation and spectating, and Irish expatriates in the UK and the US also play them.[484] Shinty (or camanachd) is popular in the Scottish Highlands.[485] +Symbols +Main article: Symbols of the United Kingdom, the Channel Islands and the Isle of Man + +The Statue of Britannia in Plymouth. Britannia is a national personification of the UK. +The flag of the United Kingdom is the Union Flag (also referred to as the Union Jack). It was created in 1606 by the superimposition of the Flag of England on the Flag of Scotland and updated in 1801 with the addition of Saint Patrick's Flag. Wales is not represented in the Union Flag, as Wales had been conquered and annexed to England prior to the formation of the United Kingdom. The possibility of redesigning the Union Flag to include representation of Wales has not been completely ruled out.[486] The national anthem of the United Kingdom is "God Save the King", with "King" replaced with "Queen" in the lyrics whenever the monarch is a woman. +Britannia is a national personification of the United Kingdom, originating from Roman Britain.[487] Britannia is symbolised as a young woman with brown or golden hair, wearing a Corinthian helmet and white robes. She holds Poseidon's three-pronged trident and a shield, bearing the Union Flag. Sometimes she is depicted as riding on the back of a lion. Since the height of the British Empire in the late 19th century, Britannia has often been associated with British maritime dominance, as in the patriotic song "Rule, Britannia!". Up until 2008, the lion symbol was depicted behind Britannia on the British fifty pence coin and on the back of the British ten pence coin. It is also used as a symbol on the non-ceremonial flag of the British Army. The bulldog is sometimes used as a symbol of the United Kingdom and has been associated with Winston Churchill's defiance of Nazi Germany.[488] +See also +Outline of the United Kingdom + United Kingdom – Wikipedia book +Walking in the United Kingdom +Flag of the United Kingdom.svgUnited Kingdom portal Flag of Europe.svgEuropean Union portal Europe green light.pngEurope portal +Notes +Jump up ^ The Royal coat of arms used in Scotland: + Royal Coat of Arms of the United Kingdom (Scotland).svg +Jump up ^ There is no authorised version of the national anthem as the words are a matter of tradition; only the first verse is usually sung.[1] No law was passed making "God Save the Queen" the official anthem. In the English tradition, such laws are not necessary; proclamation and usage are sufficient to make it the national anthem. "God Save the Queen" also serves as the Royal anthem for several other countries, namely certain Commonwealth realms. +Jump up ^ Under the Council of Europe's European Charter for Regional or Minority Languages, Scots, Ulster-Scots, Welsh, Cornish, Irish and Scottish Gaelic, are officially recognised as regional or minority languages by the British government for the purposes of the Charter. See also Languages of the United Kingdom.[2] +Jump up ^ Although Northern Ireland is the only part of the UK that shares a land border with another state, two of its Overseas Territories also share land borders with other states. Gibraltar shares a border with Spain, while the Sovereign Base Areas of Akrotiri and Dhekelia share borders with the Republic of Cyprus, Turkish Republic of Northern Cyprus and UN buffer zone separating the two Cypriot polities. +Jump up ^ The Anglo-Irish Treaty was signed on 6 December 1921 to resolve the Irish War of Independence. Effective one year later, it established the Irish Free State as a separate dominion within the Commonwealth. The UK's current name was adopted in 1927 to reflect the change. +Jump up ^ Compare to section 1 of both of the 1800 Acts of Union which reads: the Kingdoms of Great Britain and Ireland shall...be united into one Kingdom, by the Name of "The United Kingdom of Great Britain and Ireland" +Jump up ^ New Zealand, Israel and San Marino are the other countries with uncodified constitutions. +Jump up ^ Since the early twentieth century the prime minister has held the office of First Lord of the Treasury, and in recent decades has also held the office of Minister for the Civil Service. +Jump up ^ Sinn Féin, an Irish republican party, also contests elections in the Republic of Ireland. +Jump up ^ In 2007–2008, this was calculated to be £115 per week for single adults with no dependent children; £199 per week for couples with no dependent children; £195 per week for single adults with two dependent children under 14; and £279 per week for couples with two dependent children under 14. +References +Jump up ^ National Anthem, British Monarchy official website. Retrieved 16 November 2013. +^ Jump up to: a b c "List of declarations made with respect to treaty No. 148". Council of Europe. Retrieved 12 December 2013. +^ Jump up to: a b "Population Estimates for UK, England and Wales, Scotland and Northern Ireland, Mid-2013". Office for National Statistics. Retrieved 26 June 2014. +Jump up ^ "2011 UK censuses". Office for National Statistics. Retrieved 17 December 2012. +^ Jump up to: a b c d "United Kingdom". International Monetary Fund. Retrieved 1 November 2014. +Jump up ^ "Gini coefficient of equivalised disposable income (source: SILC)". Eurostat Data Explorer. Retrieved 13 August 2013. +Jump up ^ "2014 Human Development Report". 14 March 2013. pp. 22–25. Retrieved 27 July 2014. +Jump up ^ "Definition of Great Britain in English". Oxford University Press. Retrieved 29 October 2014. Great Britain is the name for the island that comprises England, Scotland, and Wales, although the term is also used loosely to refer to the United Kingdom. +Jump up ^ The British Monarchy, What is constitutional monarchy?. Retrieved 17 July 2013 +Jump up ^ CIA, The World Factbook. Retrieved 17 July 2013 +Jump up ^ "The World Factbook". Central Intelligence Agency. 1 February 2014. Retrieved 23 February 2014. +^ Jump up to: a b "Countries within a country". Prime Minister's Office. 10 January 2003. +^ Jump up to: a b "Devolution of powers to Scotland, Wales, and Northern Ireland". United Kingdom Government. Retrieved 17 April 2013. In a similar way to how the government is formed from members from the two Houses of Parliament, members of the devolved legislatures nominate ministers from among themselves to comprise an executive, known as the devolved administrations... +Jump up ^ "Fall in UK university students". BBC News. 29 January 2009. +Jump up ^ "Country Overviews: United Kingdom". Transport Research Knowledge Centre. Retrieved 28 March 2010. +Jump up ^ "Key facts about the United Kingdom". Directgov. Retrieved 3 May 2011. The full title of this country is 'the United Kingdom of Great Britain and Northern Ireland'. 'The UK' is made up of England, Scotland, Wales and Northern Ireland. 'Britain' is used informally, usually meaning the United Kingdom. 'Great Britain' is made up of England, Scotland and Wales. The Channel Islands and the Isle of Man are not part of the UK.[dead link] +Jump up ^ "Working with Overseas Territories". Foreign and Commonwealth Office. Retrieved 3 May 2011. +Jump up ^ Mathias, P. (2001). The First Industrial Nation: the Economic History of Britain, 1700–1914. London: Routledge. ISBN 0-415-26672-6. +Jump up ^ Ferguson, Niall (2004). Empire: The rise and demise of the British world order and the lessons for global power. New York: Basic Books. ISBN 0-465-02328-2. +Jump up ^ Sheridan, Greg (15 May 2010). "Cameron has chance to make UK great again". The Australian (Sydney). Retrieved 23 May 2011. +Jump up ^ Dugan, Emily (18 November 2012). "Britain is now most powerful nation on earth". The Independent (London). Retrieved 18 November 2012. +^ Jump up to: a b "The 15 countries with the highest military expenditure in 2013 (table)" (PDF). Stockholm International Peace Research Institute. Retrieved 4 May 2014. +^ Jump up to: a b The Military Balance 2014: Top 15 Defence Budgets 2013 (IISS) +Jump up ^ "Treaty of Union, 1706". Scots History Online. Retrieved 23 August 2011. +Jump up ^ Barnett, Hilaire; Jago, Robert (2011). Constitutional & Administrative Law (8th ed.). Abingdon: Routledge. p. 165. ISBN 978-0-415-56301-7. +Jump up ^ Gascoigne, Bamber. "History of Great Britain (from 1707)". History World. Retrieved 18 July 2011. +Jump up ^ Cottrell, P. (2008). The Irish Civil War 1922–23. p. 85. ISBN 1-84603-270-9. +^ Jump up to: a b S. Dunn; H. Dawson (2000), An Alphabetical Listing of Word, Name and Place in Northern Ireland and the Living Language of Conflict, Lampeter: Edwin Mellen Press, One specific problem - in both general and particular senses - is to know what to call Northern Ireland itself: in the general sense, it is not a country, or a province, or a state - although some refer to it contemptuously as a statelet: the least controversial word appears to be jurisdiction, but this might change. +Jump up ^ "Changes in the list of subdivision names and code elements". ISO 3166-2. International Organization for Standardization. 15 December 2011. Retrieved 28 May 2012. +Jump up ^ Population Trends, Issues 75–82, p.38, 1994, UK Office of Population Censuses and Surveys +Jump up ^ Life in the United Kingdom: a journey to citizenship, p. 7, United Kingdom Home Office, 2007, ISBN 978-0-11-341313-3. +Jump up ^ "Statistical bulletin: Regional Labour Market Statistics". Retrieved 5 March 2014. +Jump up ^ "13.4% Fall In Earnings Value During Recession". Retrieved 5 March 2014. +Jump up ^ Murphy, Dervla (1979). A Place Apart. London: Penguin. ISBN 978-0-14-005030-1. +Jump up ^ Whyte, John; FitzGerald, Garret (1991). Interpreting Northern Ireland. Oxford: Clarendon Press. ISBN 978-0-19-827380-6. +Jump up ^ "Guardian Unlimited Style Guide". London: Guardian News and Media Limited. 19 December 2008. Retrieved 23 August 2011. +Jump up ^ "BBC style guide (Great Britain)". BBC News. 19 August 2002. Retrieved 23 August 2011. +Jump up ^ "Key facts about the United Kingdom". Government, citizens and rights. HM Government. Retrieved 24 August 2011.[dead link] +Jump up ^ "Merriam-Webster Dictionary Online Definition of ''Great Britain''". Merriam Webster. 31 August 2012. Retrieved 9 April 2013. +Jump up ^ New Oxford American Dictionary: "Great Britain: England, Wales, and Scotland considered as a unit. The name is also often used loosely to refer to the United Kingdom." +Jump up ^ "Great Britain". International Olympic Committee. Retrieved 10 May 2011. +Jump up ^ "Team GB – Our Greatest Team". British Olympic Association. Retrieved 10 May 2011.[dead link] +Jump up ^ Bradley, Anthony Wilfred; Ewing, Keith D. (2007). Constitutional and administrative law 1 (14th ed.). Harlow: Pearson Longman. p. 36. ISBN 978-1-4058-1207-8. +Jump up ^ "Which of these best describes the way you think of yourself?". Northern Ireland Life and Times Survey 2010. ARK – Access Research Knowledge. 2010. Retrieved 1 July 2010. +Jump up ^ Schrijver, Frans (2006). Regionalism after regionalisation: Spain, France and the United Kingdom. Amsterdam University Press. pp. 275–277. ISBN 978-90-5629-428-1. +Jump up ^ Jack, Ian (11 December 2010). "Why I'm saddened by Scotland going Gaelic". The Guardian (London). +Jump up ^ Ffeithiau allweddol am y Deyrnas Unedig : Directgov – Llywodraeth, dinasyddion a hawliau[dead link] +Jump up ^ "Ancient skeleton was 'even older'". BBC News. 30 October 2007. Retrieved 27 April 2011. +Jump up ^ Koch, John T. (2006). Celtic culture: A historical encyclopedia. Santa Barbara, CA: ABC-CLIO. p. 973. ISBN 978-1-85109-440-0. +Jump up ^ Davies, John; Jenkins, Nigel; Baines, Menna; Lynch, Peredur I., eds. (2008). The Welsh Academy Encyclopaedia of Wales. Cardiff: University of Wales Press. p. 915. ISBN 978-0-7083-1953-6. +Jump up ^ "Short Athelstan biography". BBC History. Retrieved 9 April 2013. +Jump up ^ Mackie, J.D. (1991). A History of Scotland. London: Penguin. pp. 18–19. ISBN 978-0-14-013649-4. +Jump up ^ Campbell, Ewan (1999). Saints and Sea-kings: The First Kingdom of the Scots. Edinburgh: Canongate. pp. 8–15. ISBN 0-86241-874-7. +Jump up ^ Haigh, Christopher (1990). The Cambridge Historical Encyclopedia of Great Britain and Ireland. Cambridge University Press. p. 30. ISBN 978-0-521-39552-6. +Jump up ^ Ganshof, F.L. (1996). Feudalism. University of Toronto. p. 165. ISBN 978-0-8020-7158-3. +Jump up ^ Chibnall, Marjorie (1999). The debate on the Norman Conquest. Manchester University Press. pp. 115–122. ISBN 978-0-7190-4913-2. +Jump up ^ Keen, Maurice. "The Hundred Years War". BBC History. +Jump up ^ The Reformation in England and Scotland and Ireland: The Reformation Period & Ireland under Elizabth I, Encyclopædia Britannica Online. +Jump up ^ "British History in Depth – Wales under the Tudors". BBC History. 5 November 2009. Retrieved 21 September 2010. +Jump up ^ Nicholls, Mark (1999). A history of the modern British Isles, 1529–1603: The two kingdoms. Oxford: Blackwell. pp. 171–172. ISBN 978-0-631-19334-0. +Jump up ^ Canny, Nicholas P. (2003). Making Ireland British, 1580–1650. Oxford University Press. pp. 189–200. ISBN 978-0-19-925905-2. +Jump up ^ Ross, D. (2002). Chronology of Scottish History. Glasgow: Geddes & Grosset. p. 56. ISBN 1-85534-380-0 +Jump up ^ Hearn, J. (2002). Claiming Scotland: National Identity and Liberal Culture. Edinburgh University Press. p. 104. ISBN 1-902930-16-9 +Jump up ^ "English Civil Wars". Encyclopaedia Britannica. Retrieved 28 April 2013. +Jump up ^ "Scotland and the Commonwealth: 1651–1660". Archontology.org. 14 March 2010. Retrieved 20 April 2010. +Jump up ^ Lodge, Richard (2007) [1910]. The History of England – From the Restoration to the Death of William III (1660–1702). Read Books. p. 8. ISBN 978-1-4067-0897-4. +Jump up ^ "Tudor Period and the Birth of a Regular Navy". Royal Navy History. Institute of Naval History. Retrieved 24 December 2010.[dead link] +Jump up ^ Canny, Nicholas (1998). The Origins of Empire, The Oxford History of the British Empire Volume I. Oxford University Press. ISBN 0-19-924676-9. +Jump up ^ "Articles of Union with Scotland 1707". UK Parliament. Retrieved 19 October 2008. +Jump up ^ "Acts of Union 1707". UK Parliament. Retrieved 6 January 2011. +Jump up ^ "Treaty (act) of Union 1706". Scottish History online. Retrieved 3 February 2011. +Jump up ^ Library of Congress, The Impact of the American Revolution Abroad, p. 73. +Jump up ^ Loosemore, Jo (2007). Sailing against slavery. BBC Devon. 2007. +Jump up ^ "The Act of Union". Act of Union Virtual Library. Retrieved 15 May 2006. +Jump up ^ Tellier, L.-N. (2009). Urban World History: an Economic and Geographical Perspective. Quebec: PUQ. p. 463. ISBN 2-7605-1588-5. +Jump up ^ Sondhaus, L. (2004). Navies in Modern World History. London: Reaktion Books. p. 9. ISBN 1-86189-202-0. +Jump up ^ Porter, Andrew (1998). The Nineteenth Century, The Oxford History of the British Empire Volume III. Oxford University Press. p. 332. ISBN 0-19-924678-5. +Jump up ^ "The Workshop of the World". BBC History. Retrieved 28 April 2013. +Jump up ^ Porter, Andrew (1998). The Nineteenth Century, The Oxford History of the British Empire Volume III. Oxford University Press. p. 8. ISBN 0-19-924678-5. +Jump up ^ Marshall, P.J. (1996). The Cambridge Illustrated History of the British Empire. Cambridge University Press. pp. 156–57. ISBN 0-521-00254-0. +Jump up ^ Tompson, Richard S. (2003). Great Britain: a reference guide from the Renaissance to the present. New York: Facts on File. p. 63. ISBN 978-0-8160-4474-0. +Jump up ^ Hosch, William L. (2009). World War I: People, Politics, and Power. America at War. New York: Britannica Educational Publishing. p. 21. ISBN 978-1-61530-048-8. +Jump up ^ Turner, John (1988). Britain and the First World War. London: Unwin Hyman. pp. 22–35. ISBN 978-0-04-445109-9. +^ Jump up to: a b Westwell, I.; Cove, D. (eds) (2002). History of World War I, Volume 3. London: Marshall Cavendish. pp. 698 and 705. ISBN 0-7614-7231-2. +Jump up ^ Turner, J. (1988). Britain and the First World War. Abingdon: Routledge. p. 41. ISBN 0-04-445109-1. +Jump up ^ SR&O 1921, No. 533 of 3 May 1921. +Jump up ^ "The Anglo-Irish Treaty, 6 December 1921". CAIN. Retrieved 15 May 2006. +Jump up ^ Rubinstein, W. D. (2004). Capitalism, Culture, and Decline in Britain, 1750–1990. Abingdon: Routledge. p. 11. ISBN 0-415-03719-0. +Jump up ^ "Britain to make its final payment on World War II loan from U.S.". The New York Times. 28 December 2006. Retrieved 25 August 2011. +Jump up ^ Francis, Martin (1997). Ideas and policies under Labour, 1945–1951: Building a new Britain. Manchester University Press. pp. 225–233. ISBN 978-0-7190-4833-3. +Jump up ^ Lee, Stephen J. (1996). Aspects of British political history, 1914–1995. London; New York: Routledge. pp. 173–199. ISBN 978-0-415-13103-2. +Jump up ^ Larres, Klaus (2009). A companion to Europe since 1945. Chichester: Wiley-Blackwell. p. 118. ISBN 978-1-4051-0612-2. +Jump up ^ "Country List". Commonwealth Secretariat. 19 March 2009. Retrieved 11 September 2012.[dead link] +Jump up ^ Julios, Christina (2008). Contemporary British identity: English language, migrants, and public discourse. Studies in migration and diaspora. Aldershot: Ashgate. p. 84. ISBN 978-0-7546-7158-9. +Jump up ^ Aughey, Arthur (2005). The Politics of Northern Ireland: Beyond the Belfast Agreement. London: Routledge. p. 7. ISBN 978-0-415-32788-6. +Jump up ^ "The troubles were over, but the killing continued. Some of the heirs to Ireland's violent traditions refused to give up their inheritance." Holland, Jack (1999). Hope against History: The Course of Conflict in Northern Ireland. New York: Henry Holt. p. 221. ISBN 978-0-8050-6087-4. +Jump up ^ Elliot, Marianne (2007). The Long Road to Peace in Northern Ireland: Peace Lectures from the Institute of Irish Studies at Liverpool University. University of Liverpool Institute of Irish Studies, Liverpool University Press. p. 2. ISBN 1-84631-065-2. +Jump up ^ Dorey, Peter (1995). British politics since 1945. Making contemporary Britain. Oxford: Blackwell. pp. 164–223. ISBN 978-0-631-19075-2. +Jump up ^ Griffiths, Alan; Wall, Stuart (2007). Applied Economics (11th ed.). Harlow: Financial Times Press. p. 6. ISBN 978-0-273-70822-3. Retrieved 26 December 2010. +Jump up ^ Keating, Michael (1 January 1998). "Reforging the Union: Devolution and Constitutional Change in the United Kingdom". Publius: the Journal of Federalism 28 (1): 217. doi:10.1093/oxfordjournals.pubjof.a029948. Retrieved 4 February 2009. +Jump up ^ Jackson, Mike (3 April 2011). "Military action alone will not save Libya". Financial Times (London). +Jump up ^ "United Kingdom country profile". BBC. 24 January 2013. Retrieved 9 April 2013. +Jump up ^ "Scotland to hold independence poll in 2014 – Salmond". BBC News. 10 January 2012. Retrieved 10 January 2012. +Jump up ^ Oxford English Dictionary: "British Isles: a geographical term for the islands comprising Great Britain and Ireland with all their offshore islands including the Isle of Man and the Channel Islands." +^ Jump up to: a b c d e f "United Kingdom". The World Factbook. Central Intelligence Agency. Retrieved 23 September 2008. +^ Jump up to: a b c d e Latimer Clarke Corporation Pty Ltd. "United Kingdom – Atlapedia Online". Atlapedia.com. Retrieved 26 October 2010. +Jump up ^ ROG Learing Team (23 August 2002). "The Prime Meridian at Greenwich". Royal Museums Greenwich. Royal Museums Greenwich. Retrieved 11 September 2012. +Jump up ^ Neal, Clare. "How long is the UK coastline?". British Cartographic Society. Retrieved 26 October 2010. +Jump up ^ "The Channel Tunnel". Eurotunnel. Retrieved 29 November 2010.[dead link] +Jump up ^ "England – Profile". BBC News. 11 February 2010. +Jump up ^ "Scotland Facts". Scotland Online Gateway. Archived from the original on 21 June 2008. Retrieved 16 July 2008. +Jump up ^ Winter, Jon (19 May 2001). "The complete guide to Scottish Islands". The Independent (London). +Jump up ^ "Overview of Highland Boundary Fault". Gazetteer for Scotland. University of Edinburgh. Retrieved 27 December 2010. +Jump up ^ "Ben Nevis Weather". Ben Nevis Weather. Retrieved 26 October 2008. +Jump up ^ "Profile: Wales". BBC News. 9 June 2010. Retrieved 7 November 2010. +Jump up ^ Giles Darkes (26 April 2014). "How long is the UK coastline?". The British Cartographic Society. +Jump up ^ "Geography of Northern Ireland". University of Ulster. Retrieved 22 May 2006. +Jump up ^ "UK climate summaries". Met Office. Retrieved 1 May 2011. +Jump up ^ United Nations Economic and Social Council (August 2007). "Ninth UN Conference on the standardization of Geographical Names". UN Statistics Division. Archived from the original on 1 December 2009. Retrieved 21 October 2008. +Jump up ^ Barlow, I.M. (1991). Metropolitan Government. London: Routledge. ISBN 978-0-415-02099-2. +Jump up ^ "Welcome to the national site of the Government Office Network". Government Offices. Archived from the original on 15 June 2009. Retrieved 3 July 2008. +Jump up ^ "A short history of London government". Greater London Authority. Archived from the original on 21 April 2008. Retrieved 4 October 2008. +Jump up ^ Sherman, Jill; Norfolk, Andrew (5 November 2004). "Prescott's dream in tatters as North East rejects assembly". The Times (London). Retrieved 15 February 2008. The Government is now expected to tear up its twelve-year-old plan to create eight or nine regional assemblies in England to mirror devolution in Scotland and Wales. (subscription required) +Jump up ^ "Local Authority Elections". Local Government Association. Retrieved 3 October 2008.[dead link] +Jump up ^ "STV in Scotland: Local Government Elections 2007". Political Studies Association. Archived from the original on 20 March 2011. Retrieved 2 August 2008. +Jump up ^ Ethical Standards in Public Life framework: "Ethical Standards in Public Life". The Scottish Government. Retrieved 3 October 2008. +Jump up ^ "Who we are". Convention of Scottish Local Authorities. Retrieved 5 July 2011. +Jump up ^ "Local Authorities". The Welsh Assembly Government. Retrieved 31 July 2008. +Jump up ^ "Local government elections in Wales". The Electoral Commission. 2008. Retrieved 8 April 2011. +Jump up ^ "Welsh Local Government Association". Welsh Local Government Association. Retrieved 20 March 2008. +Jump up ^ Devenport, Mark (18 November 2005). "NI local government set for shake-up". BBC News. Retrieved 15 November 2008. +Jump up ^ "Foster announces the future shape of local government" (Press release). Northern Ireland Executive. 13 March 2008. Retrieved 20 October 2008. +Jump up ^ "Local Government elections to be aligned with review of public administration" (Press release). Northern Ireland Office. 25 April 2008. Retrieved 2 August 2008.[dead link] +Jump up ^ "CIBC PWM Global – Introduction to The Cayman Islands". Cibc.com. 11 July 2012. Retrieved 17 August 2012. +Jump up ^ Rappeport, Laurie. "Cayman Islands Tourism". Washington DC: USA Today Travel Tips. Retrieved 9 April 2013. +Jump up ^ "Working with Overseas Territories". Foreign & Commonwealth Office. 6 October 2010. Retrieved 5 November 2010. +Jump up ^ http://www.justice.gov.uk/downloads/about/moj/our-responsibilities/Background_Briefing_on_the_Crown_Dependencies2.pdf +Jump up ^ "Overseas Territories". Foreign & Commonwealth Office. Retrieved 6 September 2010. +Jump up ^ "The World Factbook". CIA. Retrieved 26 December 2010. +Jump up ^ "Country profiles". Foreign & Commonwealth Office. 21 February 2008. Retrieved 6 September 2010.[dead link] +Jump up ^ Davison, Phil (18 August 1995). "Bermudians vote to stay British". The Independent (London). Retrieved 11 September 2012. +Jump up ^ The Committee Office, House of Commons. "House of Commons – Crown Dependencies – Justice Committee". Publications.parliament.uk. Retrieved 7 November 2010. +Jump up ^ Fact sheet on the UK's relationship with the Crown Dependencies – gov.uk, Ministry of Justice. Retrieved 25 August 2014. +Jump up ^ "Profile of Jersey". States of Jersey. Retrieved 31 July 2008. The legislature passes primary legislation, which requires approval by The Queen in Council, and enacts subordinate legislation in many areas without any requirement for Royal Sanction and under powers conferred by primary legislation. +Jump up ^ "Chief Minister to meet Channel Islands counterparts – Isle of Man Public Services" (Press release). Isle of Man Government. 29 May 2012. Retrieved 9 April 2013.[dead link] +Jump up ^ Bagehot, Walter (1867). The English Constitution. London: Chapman and Hall. p. 103. +Jump up ^ Carter, Sarah. "A Guide To the UK Legal System". University of Kent at Canterbury. Retrieved 16 May 2006. +Jump up ^ "Parliamentary sovereignty". UK Parliament. n.d. Archived from the original on 27 May 2012. +Jump up ^ "The Government, Prime Minister and Cabinet". Public services all in one place. Directgov. Retrieved 12 February 2010. +Jump up ^ "Brown is UK's new prime minister". BBC News. 27 June 2007. Retrieved 23 January 2008. +Jump up ^ "David Cameron is UK's new prime minister". BBC News. 11 May 2010. Retrieved 11 May 2010. +Jump up ^ November 2010 "Elections and voting". UK Parliament. Archived from the original on 14 November 2010. Retrieved 14 November 2010. +Jump up ^ November 2010 "The Parliament Acts". UK Parliament. Archived from the original on 14 November 2010. +Jump up ^ "United Kingdom". European Election Database. Norwegian Social Science Data Services. Retrieved 3 July 2010. +Jump up ^ Wainwright, Martin (28 May 2010). "Thirsk and Malton: Conservatives take final seat in parliament". The Guardian (London). Retrieved 3 July 2010. +Jump up ^ "Scots MPs attacked over fees vote". BBC News. 27 January 2004. Retrieved 21 October 2008. +Jump up ^ Taylor, Brian (1 June 1998). "Talking Politics: The West Lothian Question". BBC News. Retrieved 21 October 2008. +Jump up ^ "England-only laws 'need majority from English MPs'". BBC News. 25 March 2013. Retrieved 28 April 2013. +Jump up ^ "Scotland's Parliament – powers and structures". BBC News. 8 April 1999. Retrieved 21 October 2008. +Jump up ^ "Salmond elected as first minister". BBC News. 16 May 2007. Retrieved 21 October 2008. +Jump up ^ "Scottish election: SNP wins election". BBC News. 6 May 2011. +Jump up ^ "Structure and powers of the Assembly". BBC News. 9 April 1999. Retrieved 21 October 2008. +Jump up ^ "Carwyn Jones clinches leadership in Wales". WalesOnline (Media Wales). 1 December 2009. Retrieved 1 December 2009. +Jump up ^ "Devolved Government – Ministers and their departments". Northern Ireland Executive. Archived from the original on 22 August 2007. +Jump up ^ Burrows, N. (1999). "Unfinished Business: The Scotland Act 1998". The Modern Law Review 62 (2): 241–60 [p. 249]. doi:10.1111/1468-2230.00203. The UK Parliament is sovereign and the Scottish Parliament is subordinate. The White Paper had indicated that this was to be the approach taken in the legislation. The Scottish Parliament is not to be seen as a reflection of the settled will of the people of Scotland or of popular sovereignty but as a reflection of its subordination to a higher legal authority. Following the logic of this argument, the power of the Scottish Parliament to legislate can be withdrawn or overridden... +Jump up ^ Elliot, M. (2004). "United Kingdom: Parliamentary sovereignty under pressure". International Journal of Constitutional Law 2 (3): 545–627 [pp. 553–554]. doi:10.1093/icon/2.3.545. Notwithstanding substantial differences among the schemes, an important common factor is that the U.K. Parliament has not renounced legislative sovereignty in relation to the three nations concerned. For example, the Scottish Parliament is empowered to enact primary legislation on all matters, save those in relation to which competence is explicitly denied ... but this power to legislate on what may be termed "devolved matters" is concurrent with the Westminster Parliament's general power to legislate for Scotland on any matter at all, including devolved matters ... In theory, therefore, Westminster may legislate on Scottish devolved matters whenever it chooses... +Jump up ^ Walker, G. (2010). "Scotland, Northern Ireland, and Devolution, 1945–1979". Journal of British Studies 39 (1): 124 & 133. doi:10.1086/644536. +Jump up ^ Gamble, A. "The Constitutional Revolution in the United Kingdom". Publius 36 (1): 19–35 [p. 29]. doi:10.1093/publius/pjj011. The British parliament has the power to abolish the Scottish parliament and the Welsh assembly by a simple majority vote in both houses, but since both were sanctioned by referenda, it would be politically difficult to abolish them without the sanction of a further vote by the people. In this way several of the constitutional measures introduced by the Blair government appear to be entrenched and not subject to a simple exercise of parliamentary sovereignty at Westminster. +Jump up ^ Meehan, E. (1999). "The Belfast Agreement—Its Distinctiveness and Points of Cross-Fertilization in the UK's Devolution Programme". Parliamentary Affairs 52 (1): 19–31 [p. 23]. doi:10.1093/pa/52.1.19. [T]he distinctive involvement of two governments in the Northern Irish problem means that Northern Ireland's new arrangements rest upon an intergovernmental agreement. If this can be equated with a treaty, it could be argued that the forthcoming distribution of power between Westminster and Belfast has similarities with divisions specified in the written constitutions of federal states... Although the Agreement makes the general proviso that Westminster's 'powers to make legislation for Northern Ireland' remains 'unaffected', without an explicit categorical reference to reserved matters, it may be more difficult than in Scotland or Wales for devolved powers to be repatriated. The retraction of devolved powers would not merely entail consultation in Northern Ireland backed implicitly by the absolute power of parliamentary sovereignty but also the renegotiation of an intergovernmental agreement. +Jump up ^ "The Treaty (act) of the Union of Parliament 1706". Scottish History Online. Retrieved 5 October 2008. +Jump up ^ "UK Supreme Court judges sworn in". BBC News. 1 October 2009. +Jump up ^ "Constitutional reform: A Supreme Court for the United Kingdom". Department for Constitutional Affairs. July 2003. Retrieved 13 May 2013. +Jump up ^ "Role of the JCPC". Judicial Committee of the Privy Council. Retrieved 28 April 2013. +Jump up ^ Bainham, Andrew (1998). The international survey of family law: 1996. The Hague: Martinus Nijhoff. p. 298. ISBN 978-90-411-0573-8. +Jump up ^ Adeleye, Gabriel; Acquah-Dadzie, Kofi; Sienkewicz, Thomas; McDonough, James (1999). World dictionary of foreign expressions. Waucojnda, IL: Bolchazy-Carducci. p. 371. ISBN 978-0-86516-423-9. +Jump up ^ "The Australian courts and comparative law". Australian Law Postgraduate Network. Retrieved 28 December 2010. +Jump up ^ "Court of Session – Introduction". Scottish Courts. Retrieved 5 October 2008.[dead link] +Jump up ^ "High Court of Justiciary – Introduction". Scottish Courts. Retrieved 5 October 2008.[dead link] +Jump up ^ "House of Lords – Practice Directions on Permission to Appeal". UK Parliament. Retrieved 22 June 2009. +Jump up ^ "Introduction". Scottish Courts. Retrieved 5 October 2008.[dead link] +Jump up ^ Samuel Bray (2005). "Not proven: introducing a third verdict". The University of Chicago Law Review 72 (4): 1299. Retrieved 30 November 2013. +Jump up ^ "Police-recorded crime down by 9%". BBC News. 17 July 2008. Retrieved 21 October 2008. +Jump up ^ "New record high prison population". BBC News. 8 February 2008. Retrieved 21 October 2008. +Jump up ^ "Crime falls to 32 year low" (Press release). Scottish Government. 7 September 2010. Retrieved 21 April 2011. +Jump up ^ "Prisoner Population at Friday 22 August 2008". Scottish Prison Service. Retrieved 28 August 2008. +Jump up ^ "Scots jail numbers at record high". BBC News. 29 August 2008. Retrieved 21 October 2008. +Jump up ^ Swaine, Jon (13 January 2009). "Barack Obama presidency will strengthen special relationship, says Gordon Brown". The Daily Telegraph (London). Retrieved 3 May 2011. +Jump up ^ Kirchner, E. J.; Sperling, J. (2007). Global Security Governance: Competing Perceptions of Security in the 21st Century. London: Taylor & Francis. p. 100. ISBN 0-415-39162-8 +Jump up ^ The Committee Office, House of Commons (19 February 2009). "DFID's expenditure on development assistance". UK Parliament. Retrieved 28 April 2013. +Jump up ^ "Ministry of Defence". Ministry of Defence. Retrieved 21 February 2012. +Jump up ^ "Speaker addresses Her Majesty Queen Elizabeth II". UK Parliament. 30 March 2012. Retrieved 28 April 2013. +Jump up ^ "House of Commons Hansard". UK Parliament. Retrieved 23 October 2008. +Jump up ^ UK 2005: The Official Yearbook of the United Kingdom of Great Britain and Northern Ireland. Office for National Statistics. p. 89. +Jump up ^ "Principles for Economic Regulation". Department for Business, Innovation & Skills. April 2011. Retrieved 1 May 2011. +Jump up ^ "United Kingdom". International Monetary Fund. Retrieved 1 October 2009. +Jump up ^ Chavez-Dreyfuss, Gertrude (1 April 2008). "Global reserves, dollar share up at end of 2007-IMF". Reuters. Retrieved 21 December 2009. +Jump up ^ "More About the Bank". Bank of England. n.d. Archived from the original on 12 March 2008. +Jump up ^ "Index of Services (experimental)". Office for National Statistics. 7 May 2006. Archived from the original on 7 May 2006. +Jump up ^ Sassen, Saskia (2001). The Global City: New York, London, Tokyo (2nd ed.). Princeton University Press. ISBN 0-691-07866-1. +^ Jump up to: a b "Global Financial Centres 7". Z/Yen. 2010. Retrieved 21 April 2010. +^ Jump up to: a b "Worldwide Centres of Commerce Index 2008". Mastercard. Retrieved 5 July 2011. +^ Jump up to: a b Zumbrun, Joshua (15 July 2008). ""World's Most Economically Powerful Cities".". Forbes (New York). Archived from the original on 19 May 2011. Retrieved 3 October 2010. +Jump up ^ "Global city GDP rankings 2008–2025". PricewaterhouseCoopers. Archived from the original on 19 May 2011. Retrieved 16 November 2010. +Jump up ^ Lazarowicz, Mark (Labour MP) (30 April 2003). "Financial Services Industry". UK Parliament. Retrieved 17 October 2008. +Jump up ^ International Tourism Receipts[dead link]. UNWTO Tourism Highlights, Edition 2005. page 12. World Tourism Organisation. Retrieved 24 May 2006. +Jump up ^ Bremner, Caroline (10 January 2010). "Euromonitor International's Top City Destination Ranking". Euromonitor International. Archived from the original on 19 May 2011. Retrieved 31 May 2011. +Jump up ^ "From the Margins to the Mainstream – Government unveils new action plan for the creative industries". DCMS. 9 March 2007. Retrieved 9 March 2007.[dead link] +^ Jump up to: a b "European Countries – United Kingdom". Europa (web portal). Retrieved 15 December 2010. +Jump up ^ Harrington, James W.; Warf, Barney (1995). Industrial location: Principles, practices, and policy. London: Routledge. p. 121. ISBN 978-0-415-10479-1. +Jump up ^ Spielvogel, Jackson J. (2008). Western Civilization: Alternative Volume: Since 1300. Belmont, CA: Thomson Wadsworth. ISBN 978-0-495-55528-5. +Jump up ^ Hewitt, Patricia (15 July 2004). "TUC Manufacturing Conference". Department of Trade and Industry. Retrieved 16 May 2006. +Jump up ^ "Industry topics". Society of Motor Manufacturers and Traders. 2011. Retrieved 5 July 2011. +Jump up ^ Robertson, David (9 January 2009). "The Aerospace industry has thousands of jobs in peril". The Times (London). Retrieved 9 June 2011. (subscription required) +Jump up ^ "Facts & Figures – 2009". Aerospace & Defence Association of Europe. Retrieved 9 June 2011.[dead link] +Jump up ^ "UK Aerospace Industry Survey – 2010". ADS Group. Retrieved 9 June 2011. +^ Jump up to: a b c d http://www.theengineer.co.uk/aerospace/in-depth/reasons-to-be-cheerful-about-the-uk-aerospace-sector/1017274.article +Jump up ^ "The Pharmaceutical sector in the UK". Department for Business, Innovation & Skills. Retrieved 9 June 2011. +Jump up ^ "Ministerial Industry Strategy Group – Pharmaceutical Industry: Competitiveness and Performance Indicators". Department of Health. Retrieved 9 June 2011.[dead link] +Jump up ^ [1][dead link] +Jump up ^ "UK in recession as economy slides". BBC News. 23 January 2009. Retrieved 23 January 2009. +Jump up ^ "UK youth unemployment at its highest in two decades: 22.5%". MercoPress. 15 April 2012. +Jump up ^ Groom, Brian (19 January 2011). "UK youth unemployment reaches record". Financial Times (London). +Jump up ^ "Release: EU Government Debt and Deficit returns". Office for National Statistics. March 2012. Retrieved 17 August 2012. +Jump up ^ "UK loses top AAA credit rating for first time since 1978". BBC News. 23 February 2013. Retrieved 23 February 2013. +Jump up ^ "Britain sees real wages fall 3.2%". Daily Express (London). 2 March 2013. +Jump up ^ Beckford, Martin (5 December 2011). "Gap between rich and poor growing fastest in Britain". The Daily Telegraph (London). +Jump up ^ "United Kingdom: Numbers in low income". The Poverty Site. Retrieved 25 September 2009. +Jump up ^ "United Kingdom: Children in low income households". The Poverty Site. Retrieved 25 September 2009. +Jump up ^ "Warning of food price hike crisis". BBC News. 4 April 2009. +Jump up ^ Andrews, J. (16 January 2013). "How poor is Britain now". Yahoo! Finance UK +Jump up ^ Glynn, S.; Booth, A. (1996). Modern Britain: An Economic and Social History. London: Routledge. +Jump up ^ "Report highlights 'bleak' poverty levels in the UK" Phys.org, 29 March 2013 +Jump up ^ Gascoin, J. "A reappraisal of the role of the universities in the Scientific Revolution", in Lindberg, David C. and Westman, Robert S., eds (1990), Reappraisals of the Scientific Revolution. Cambridge University Press. p. 248. ISBN 0-521-34804-8. +Jump up ^ Reynolds, E.E.; Brasher, N.H. (1966). Britain in the Twentieth Century, 1900–1964. Cambridge University Press. p. 336. OCLC 474197910 +Jump up ^ Burtt, E.A. (2003) [1924].The Metaphysical Foundations of Modern Science. Mineola, NY: Courier Dover. p. 207. ISBN 0-486-42551-7. +Jump up ^ Hatt, C. (2006). Scientists and Their Discoveries. London: Evans Brothers. pp. 16, 30 and 46. ISBN 0-237-53195-X. +Jump up ^ Jungnickel, C.; McCormmach, R. (1996). Cavendish. American Philosophical Society. ISBN 0-87169-220-1. +Jump up ^ "The Nobel Prize in Physiology or Medicine 1945: Sir Alexander Fleming, Ernst B. Chain, Sir Howard Florey". The Nobel Foundation. Archived from the original on 21 June 2011. +Jump up ^ Hatt, C. (2006). Scientists and Their Discoveries. London: Evans Brothers. p. 56. ISBN 0-237-53195-X. +Jump up ^ James, I. (2010). Remarkable Engineers: From Riquet to Shannon. Cambridge University Press. pp. 33–6. ISBN 0-521-73165-8. +Jump up ^ Bova, Ben (2002) [1932]. The Story of Light. Naperville, IL: Sourcebooks. p. 238. ISBN 978-1-4022-0009-0. +Jump up ^ "Alexander Graham Bell (1847–1922)". Scottish Science Hall of Fame. Archived from the original on 21 June 2011. +Jump up ^ "John Logie Baird (1888–1946)". BBC History. Archived from the original on 21 June 2011. +Jump up ^ Cole, Jeffrey (2011). Ethnic Groups of Europe: An Encyclopedia. Santa Barbara, CA: ABC-CLIO. p. 121. ISBN 1-59884-302-8. +Jump up ^ Castells, M.; Hall, P.; Hall, P.G. (2004). Technopoles of the World: the Making of Twenty-First-Century Industrial Complexes. London: Routledge. pp. 98–100. ISBN 0-415-10015-1. +Jump up ^ "Knowledge, networks and nations: scientific collaborations in the twenty-first century". Royal Society. 2011. Archived from the original on 22 June 2011. +Jump up ^ McCook, Alison. "Is peer review broken?". Reprinted from the Scientist 20(2) 26, 2006. Archived from the original on 21 June 2011. +^ Jump up to: a b "Heathrow 'needs a third runway'". BBC News. 25 June 2008. Retrieved 17 October 2008. +^ Jump up to: a b "Statistics: Top 30 World airports" (Press release). Airports Council International. July 2008. Retrieved 15 October 2008. +Jump up ^ "Transport Statistics Great Britain: 2010". Department for Transport. Archived from the original on 16 December 2010. +Jump up ^ "Major new rail lines considered". BBC News. 21 June 2008. Archived from the original on 9 October 2010. +Jump up ^ "Crossrail's giant tunnelling machines unveiled". BBC News. 2 January 2012. +Jump up ^ Leftly, Mark (29 August 2010). "Crossrail delayed to save £1bn". The Independent on Sunday (London). +^ Jump up to: a b "Size of Reporting Airports October 2009 – September 2010". Civil Aviation Authority. Retrieved 5 December 2010. +Jump up ^ "BMI being taken over by Lufthansa". BBC News. 29 October 2008. Retrieved 23 December 2009. +Jump up ^ "United Kingdom Energy Profile". U.S. Energy Information Administration. Retrieved 4 November 2010. +Jump up ^ Mason, Rowena (24 October 2009). "Let the battle begin over black gold". The Daily Telegraph (London). Retrieved 26 November 2010. +Jump up ^ Heath, Michael (26 November 2010). "RBA Says Currency Containing Prices, Rate Level 'Appropriate' in Near Term". Bloomberg (New York). Retrieved 26 November 2010. +^ Jump up to: a b c "Nuclear Power in the United Kingdom". World Nuclear Association. April 2013. Retrieved 9 April 2013. +^ Jump up to: a b c "United Kingdom – Oil". U.S. Energy Information Administration. Retrieved 4 November 2010.[dead link] +Jump up ^ "Diminishing domestic reserves, escalating imports". EDF Energy. Retrieved 9 April 2013. +^ Jump up to: a b "United Kingdom – Natural Gas". U.S. Energy Information Administration. Retrieved 4 November 2010.[dead link] +^ Jump up to: a b "United Kingdom – Quick Facts Energy Overview". U.S. Energy Information Administration. Retrieved 4 November 2010.[dead link] +Jump up ^ The Coal Authority (10 April 2006). "Coal Reserves in the United Kingdom". The Coal Authority. Archived from the original on 4 January 2009. Retrieved 5 July 2011. +Jump up ^ "England Expert predicts 'coal revolution'". BBC News. 16 October 2007. Retrieved 23 September 2008. +Jump up ^ Watts, Susan (20 March 2012). "Fracking: Concerns over gas extraction regulations". BBC News. Retrieved 9 April 2013. +Jump up ^ "Quit fracking aboot". Friends of the Earth Scotland. Retrieved 9 April 2013. +Jump up ^ "Census Geography". Office for National Statistics. 30 October 2007. Archived from the original on 4 June 2011. Retrieved 14 April 2012. +Jump up ^ "Welcome to the 2011 Census for England and Wales". Office for National Statistics. n.d. Retrieved 11 October 2008. +^ Jump up to: a b c "2011 Census: Population Estimates for the United Kingdom". Office for National Statistics. 27 March 2011. Retrieved 18 December 2012. +^ Jump up to: a b c "Annual Mid-year Population Estimates, 2010". Office for National Statistics. 2011. Retrieved 14 April 2012. +Jump up ^ Batty, David (30 December 2010). "One in six people in the UK today will live to 100, study says". The Guardian (London). +^ Jump up to: a b "2011 UK censuses". Office for National Statistics. Retrieved 18 December 2012. +Jump up ^ "Population: UK population grows to 59.6 million" (Press release). Office for National Statistics. 24 June 2004. Archived from the original on 22 July 2004. Retrieved 14 April 2012. +Jump up ^ Khan, Urmee (16 September 2008). "England is most crowded country in Europe". The Daily Telegraph (London). Retrieved 5 September 2009. +Jump up ^ Carrell, Severin (17 December 2012). "Scotland's population at record high". The Guardian. London. Retrieved 18 December 2012. +^ Jump up to: a b c "Vital Statistics: Population and Health Reference Tables (February 2014 Update): Annual Time Series Data". ONS. Retrieved 27 April 2014. +Jump up ^ Boseley, Sarah (14 July 2008). "The question: What's behind the baby boom?". The Guardian (London). p. 3. Retrieved 28 August 2009. +Jump up ^ Tables, Graphs and Maps Interface (TGM) table. Eurostat (26 February 2013). Retrieved 12 July 2013. +Jump up ^ Campbell, Denis (11 December 2005). "3.6m people in Britain are gay – official". The Observer (London). Retrieved 28 April 2013. +Jump up ^ "2011 Census - Built-up areas". ONS. Retrieved 1 July 2013. +Jump up ^ Mid-2012 Population Estimates for Settlements and Localities in Scotland General Register Office for Scotland +Jump up ^ "Belfast Metropolitan Urban Area NISRA 2005". Retrieved 28 April 2013. +Jump up ^ 2011 Census: KS201UK Ethnic group, local authorities in the United Kingdom, Accessed 21 February 2014 +Jump up ^ "Welsh people could be most ancient in UK, DNA suggests". BBC News. 19 June 2012. Retrieved 28 April 2013. +Jump up ^ Thomas, Mark G. et al. "Evidence for a segregated social structure in early Anglo-Saxon England". Proceedings of the Royal Society B: Biological Sciences 273(1601): 2651–2657. +Jump up ^ Owen, James (19 July 2005). "Review of 'The Tribes of Britain'". National Geographic (Washington DC). +Jump up ^ Oppenheimer, Stephen (October 2006). "Myths of British ancestry" at the Wayback Machine (archived 26 September 2006). Prospect (London). Retrieved 5 November 2010. +Jump up ^ Henderson, Mark (23 October 2009). "Scientist – Griffin hijacked my work to make race claim about 'British aborigines'". The Times (London). Retrieved 26 October 2009. (subscription required) +Jump up ^ Costello, Ray (2001). Black Liverpool: The Early History of Britain's Oldest Black Community 1730–1918. Liverpool: Picton Press. ISBN 1-873245-07-6. +Jump up ^ "Culture and Ethnicity Differences in Liverpool – Chinese Community". Chambré Hardman Trust. Retrieved 26 October 2009. +Jump up ^ Coleman, David; Compton, Paul; Salt, John (2002). "The demographic characteristics of immigrant populations", Council of Europe, p.505. ISBN 92-871-4974-7. +Jump up ^ Mason, Chris (30 April 2008). "'Why I left UK to return to Poland'". BBC News. +Jump up ^ "Resident population estimates by ethnic group (percentages): London". Office for National Statistics. Retrieved 23 April 2008. +Jump up ^ "Resident population estimates by ethnic group (percentages): Leicester". Office for National Statistics. Retrieved 23 April 2008. +Jump up ^ "Census 2001 – Ethnicity and religion in England and Wales". Office for National Statistics. Retrieved 23 April 2008. +Jump up ^ Loveys, Kate (22 June 2011). "One in four primary school pupils are from an ethnic minority and almost a million schoolchildren do not speak English as their first language". Daily Mail (London). Retrieved 28 June 2011. +Jump up ^ Rogers, Simon (19 May 2011). "Non-white British population reaches 9.1 million". The Guardian (London). +Jump up ^ Wallop, Harry (18 May 2011). "Population growth of last decade driven by non-white British". The Daily Telegraph (London). +Jump up ^ "Official EU languages". European Commission. 8 May 2009. Retrieved 16 October 2009. +Jump up ^ "Language Courses in New York". United Nations. 2006. Retrieved 29 November 2010. +Jump up ^ "English language – Government, citizens and rights". Directgov. Retrieved 23 August 2011. +Jump up ^ "Commonwealth Secretariat – UK". Commonwealth Secretariat. Retrieved 23 August 2011. +^ Jump up to: a b c "Languages across Europe: United Kingdom". BBC. Retrieved 4 February 2013. +Jump up ^ Booth, Robert (30 January 2013). "Polish becomes England's second language". The Guardian (London). Retrieved 4 February 2012. +Jump up ^ European Charter for Regional or Minority Languages, Strasbourg, 5.XI.1992 - http://conventions.coe.int/treaty/en/Treaties/Html/148.htm +Jump up ^ Framework Convention for the Protection of National Minorities, Strasbourg, 1.II.1995 - http://conventions.coe.int/Treaty/en/Treaties/Html/157.htm +Jump up ^ National Statistics Online – Welsh Language[dead link]. National Statistics Office. +Jump up ^ "Differences in estimates of Welsh Language Skills". Office for National Statistics. Archived from the original on 12 January 2010. Retrieved 30 December 2008. +Jump up ^ Wynn Thomas, Peter (March 2007). "Welsh today". Voices. BBC. Retrieved 5 July 2011. +Jump up ^ "Scotland's Census 2001 – Gaelic Report". General Register Office for Scotland. Retrieved 28 April 2013. +Jump up ^ "Local UK languages 'taking off'". BBC News. 12 February 2009. +Jump up ^ Edwards, John R. (2010). Minority languages and group identity: cases and categories. John Benjamins. pp. 150–158. ISBN 978-90-272-1866-7. Retrieved 12 March 2011. +Jump up ^ Koch, John T. (2006). Celtic culture: a historical encyclopedia. ABC-CLIO. p. 696. ISBN 978-1-85109-440-0. +Jump up ^ "Language Data – Scots". European Bureau for Lesser-Used Languages. Archived from the original on 23 June 2007. Retrieved 2 November 2008. +Jump up ^ "Fall in compulsory language lessons". BBC News. 4 November 2004. +Jump up ^ "The School Gate for parents in Wales". BBC. Retrieved 28 April 2013. +Jump up ^ Cannon, John, ed. (2nd edn., 2009). A Dictionary of British History. Oxford University Press. p. 144. ISBN 0-19-955037-9. +Jump up ^ Field, Clive D. (November 2009). "British religion in numbers"[dead link]. BRIN Discussion Series on Religious Statistics, Discussion Paper 001. Retrieved 3 June 2011. +Jump up ^ Yilmaz, Ihsan (2005). Muslim Laws, Politics and Society in Modern Nation States: Dynamic Legal Pluralisms in England, Turkey, and Pakistan. Aldershot: Ashgate Publishing. pp. 55–6. ISBN 0-7546-4389-1. +Jump up ^ Brown, Callum G. (2006). Religion and Society in Twentieth-Century Britain. Harlow: Pearson Education. p. 291. ISBN 0-582-47289-X. +Jump up ^ Norris, Pippa; Inglehart, Ronald (2004). Sacred and Secular: Religion and Politics Worldwide. Cambridge University Press. p. 84. ISBN 0-521-83984-X. +Jump up ^ Fergusson, David (2004). Church, State and Civil Society. Cambridge University Press. p. 94. ISBN 0-521-52959-X. +Jump up ^ "UK Census 2001". National Office for Statistics. Archived from the original on 12 March 2007. Retrieved 22 April 2007. +Jump up ^ "Religious Populations". Office for National Statistics. 11 October 2004. Archived from the original on 6 June 2011. +Jump up ^ "United Kingdom: New Report Finds Only One in 10 Attend Church". News.adventist.org. 4 April 2007. Retrieved 12 September 2010. +Jump up ^ Philby, Charlotte (12 December 2012). "Less religious and more ethnically diverse: Census reveals a picture of Britain today". The Independent (London). +Jump up ^ The History of the Church of England. The Church of England. Retrieved 23 November 2008. +Jump up ^ "Queen and Church of England". British Monarchy Media Centre. Archived from the original on 8 October 2006. Retrieved 5 June 2010. +Jump up ^ "Queen and the Church". The British Monarchy (Official Website). Archived from the original on 7 June 2011. +Jump up ^ "How we are organised". Church of Scotland. Archived from the original on 7 June 2011. +Jump up ^ Weller, Paul (2005). Time for a Change: Reconfiguring Religion, State, and Society. London: Continuum. pp. 79–80. ISBN 0567084876. +Jump up ^ Peach, Ceri, "United Kingdom, a major transformation of the religious landscape", in H. Knippenberg. ed. (2005). The Changing Religious Landscape of Europe. Amsterdam: Het Spinhuis. pp. 44–58. ISBN 90-5589-248-3. +Jump up ^ Richards, Eric (2004). Britannia's children: Emigration from England, Scotland, Wales and Ireland since 1600. London: Hambledon, p. 143. ISBN 978-1-85285-441-6. +Jump up ^ Gibney, Matthew J.; Hansen, Randall (2005). Immigration and asylum: from 1900 to the present, ABC-CLIO, p. 630. ISBN 1-57607-796-9 +Jump up ^ "Short history of immigration". BBC. 2005. Retrieved 28 August 2010. +Jump up ^ Rogers, Simon (11 December 2012). "Census 2011 mapped and charted: England & Wales in religion, immigration and race". London: Guardian. Retrieved 11 December 2012. +Jump up ^ 6.5% of the EU population are foreigners and 9.4% are born abroad, Eurostat, Katya Vasileva, 34/2011. +Jump up ^ Muenz, Rainer (June 2006). "Europe: Population and Migration in 2005". Migration Policy Institute. Retrieved 2 April 2007. +Jump up ^ "Immigration and births to non-British mothers pushes British population to record high". London Evening Standard. 21 August 2008. +Jump up ^ Doughty, Steve; Slack, James (3 June 2008). "Third World migrants behind our 2.3m population boom". Daily Mail (London). +Jump up ^ Bentham, Martin (20 October 2008). "Tories call for tougher control of immigration". London Evening Standard. +Jump up ^ "Minister rejects migrant cap plan". BBC News. 8 September 2008. Retrieved 26 April 2011. +Jump up ^ Johnston, Philip (5 January 2007). "Immigration 'far higher' than figures say". The Daily Telegraph (London). Retrieved 20 April 2007. +Jump up ^ Travis, Alan (25 August 2011). "UK net migration rises 21%". The Guardian (London). +^ Jump up to: a b "Migration Statistics Quarterly Report May 2012". Office for National Statistics. 24 May 2012. +Jump up ^ "Migration to UK more than double government target". BBC News. 24 May 2012. +^ Jump up to: a b "Citizenship". Home Office. August 2011. Retrieved 24 October 2011.[dead link] +Jump up ^ Bamber, David (20 December 2000). "Migrant squad to operate in France". The Daily Telegraph (London). +Jump up ^ "Settlement". Home Office. August 2011. Retrieved 24 October 2011.[dead link] +Jump up ^ "Births in England and Wales by parents' country of birth, 2011". Office for National Statistics. 30 August 2012. Retrieved 28 April 2013. +Jump up ^ "Right of Union citizens and their family members to move and reside freely within the territory of the Member States". European Commission. Retrieved 28 April 2013. +Jump up ^ Doward, Jamie; Temko, Ned (23 September 2007). "Home Office shuts the door on Bulgaria and Romania". The Observer (London). p. 2. Retrieved 23 August 2008. +Jump up ^ Sumption, Madeleine; Somerville, Will (January 2010). The UK's new Europeans: Progress and challenges five years after accession. Policy Report (London: Equality and Human Rights Commission). p. 13. ISBN 978-1-84206-252-4. Retrieved 19 January 2010. +Jump up ^ Doward, Jamie; Rogers, Sam (17 January 2010). "Young, self-reliant, educated: portrait of UK's eastern European migrants". The Observer (London). Retrieved 19 January 2010. +Jump up ^ Hopkirk, Elizabeth (20 October 2008). "Packing up for home: Poles hit by UK's economic downturn". London Evening Standard. +Jump up ^ "Migrants to UK 'returning home'". BBC News. 8 September 2009. Retrieved 8 September 2009. +Jump up ^ "UK sees shift in migration trend". BBC News. 27 May 2010. Retrieved 28 May 2010. +Jump up ^ "Fresh Talent: Working in Scotland". London: UK Border Agency. Retrieved 30 October 2010. +Jump up ^ Boxell, James (28 June 2010). "Tories begin consultation on cap for migrants". Financial Times (London). Retrieved 17 September 2010. +Jump up ^ "Vince Cable: Migrant cap is hurting economy". The Guardian (London). Press Association. 17 September 2010. Retrieved 17 September 2010. +Jump up ^ Richards (2004), pp. 6–7. +^ Jump up to: a b Sriskandarajah, Dhananjayan; Drew, Catherine (11 December 2006). "Brits Abroad: Mapping the scale and nature of British emigration". Institute for Public Policy Research. Retrieved 20 January 2007. +Jump up ^ "Brits Abroad: world overview". BBC. n.d. Retrieved 20 April 2007. +Jump up ^ Casciani, Dominic (11 December 2006). "5.5 m Britons 'opt to live abroad'". BBC News. Retrieved 20 April 2007. +Jump up ^ "Brits Abroad: Country-by-country". BBC News. 11 December 2006. +Jump up ^ "Local Authorities". Department for Children, Schools and Families. Retrieved 21 December 2008. +Jump up ^ Gordon, J.C.B. (1981). Verbal Deficit: A Critique. London: Croom Helm. p. 44 note 18. ISBN 978-0-85664-990-5. +Jump up ^ Section 8 ('Duty of local education authorities to secure provision of primary and secondary schools'), Sections 35–40 ('Compulsory attendance at Primary and Secondary Schools') and Section 61 ('Prohibition of fees in schools maintained by local education authorities ...'), Education Act 1944. +Jump up ^ "England's pupils in global top 10". BBC News. 10 December 2008. +Jump up ^ "More state pupils in universities". BBC News. 19 July 2007. +Jump up ^ MacLeod, Donald (9 November 2007). "Private school pupil numbers in decline". The Guardian (London). Retrieved 31 March 2010. +Jump up ^ Frankel, Hannah (3 September 2010). "Is Oxbridge still a preserve of the posh?". TES (London). Retrieved 9 April 2013. +Jump up ^ "World's top 100 universities 2013: their reputations ranked by Times Higher Education". The Guardian (London). 2013. Retrieved 23 October 2014. +Jump up ^ Davenport, F.; Beech, C.; Downs, T.; Hannigan, D. (2006). Ireland. Lonely Planet, 7th edn. ISBN 1-74059-968-3. p. 564. +Jump up ^ "About SQA". Scottish Qualifications Authority. 10 April 2013. Retrieved 28 April 2013. +Jump up ^ "About Learning and Teaching Scotland". Learning and Teaching Scotland. Retrieved 28 April 2013. +Jump up ^ "Brain drain in reverse". Scotland Online Gateway. July 2002. Archived from the original on 4 December 2007. +Jump up ^ "Increase in private school intake". BBC News. 17 April 2007. +Jump up ^ "MSPs vote to scrap endowment fee". BBC News. 28 February 2008. +Jump up ^ What will your child learn?[dead link] The Welsh Assembly Government. Retrieved 22 January 2010. +Jump up ^ CCEA. "About Us – What we do". Council for the Curriculum Examinations & Assessment. Retrieved 28 April 2013. +Jump up ^ Elitist Britain?, Social Mobility and Child Poverty Commission, 28 August 2014 +Jump up ^ Arnett, George (28 August 2014). "Elitism in Britain - breakdown by profession". The Guardian: Datablog. +Jump up ^ Haden, Angela; Campanini, Barbara, eds. (2000). The world health report 2000 – Health systems: improving performance. Geneva: World Health Organisation. ISBN 92-4-156198-X. Retrieved 5 July 2011. +Jump up ^ World Health Organization. "Measuring overall health system performance for 191 countries". New York University. Retrieved 5 July 2011. +Jump up ^ "'Huge contrasts' in devolved NHS". BBC News. 28 August 2008. +Jump up ^ Triggle, Nick (2 January 2008). "NHS now four different systems". BBC News. +Jump up ^ Fisher, Peter. "The NHS from Thatcher to Blair". NHS Consultants Association (International Association of Health Policy). The Budget ... was even more generous to the NHS than had been expected amounting to an annual rise of 7.4% above the rate of inflation for the next 5 years. This would take us to 9.4% of GDP spent on health ie around EU average. +Jump up ^ "OECD Health Data 2009 – How Does the United Kingdom Compare". Paris: Organisation for Economic Co-operation and Development. Retrieved 28 April 2013.[dead link] +Jump up ^ "The cultural superpower: British cultural projection abroad". Journal of the British Politics Society, Norway. Volume 6. No. 1. Winter 2011 +Jump up ^ Sheridan, Greg (15 May 2010). "Cameron has chance to make UK great again". The Australian (Sydney). Retrieved 20 May 2012. +Jump up ^ Goldfarb, Jeffrey (10 May 2006). "Bookish Britain overtakes America as top publisher". RedOrbit (Texas). Reuters. +Jump up ^ "William Shakespeare (English author)". Britannica Online encyclopedia. Retrieved 26 February 2006. +Jump up ^ MSN Encarta Encyclopedia article on Shakespeare. Archived from the original on 9 February 2006. Retrieved 26 February 2006. +Jump up ^ William Shakespeare. Columbia Electronic Encyclopedia. Retrieved 26 February 2006. +Jump up ^ "Mystery of Christie's success is solved". The Daily Telegraph (London). 19 December 2005. Retrieved 14 November 2010. +Jump up ^ "All-Time Essential Comics". IGN. Retrieved 15 August 2013. +Jump up ^ Johnston, Rich."Before Watchmen To Double Up For Hardcover Collections". Bleeding Cool. 10 December 2012. Retrieved 15 August 2013. +Jump up ^ "Edinburgh, UK appointed first UNESCO City of Literature". Unesco. 2004. Retrieved 28 April 2013.[dead link] +Jump up ^ "Early Welsh poetry". BBC Wales. Retrieved 29 December 2010. +Jump up ^ Lang, Andrew (2003) [1913]. History of English Literature from Beowulf to Swinburne. Holicong, PA: Wildside Press. p. 42. ISBN 978-0-8095-3229-2. +Jump up ^ "Dafydd ap Gwilym". Academi website. Academi. 2011. Retrieved 3 January 2011. Dafydd ap Gwilym is widely regarded as one of the greatest Welsh poets of all time, and amongst the leading European poets of the Middle Ages. +Jump up ^ True birthplace of Wales's literary hero. BBC News. Retrieved 28 April 2012 +Jump up ^ Kate Roberts: Biography at the Wayback Machine. BBC Wales. Retrieved 28 April 2012 +Jump up ^ Swift, Jonathan; Fox, Christopher (1995). Gulliver's travels: complete, authoritative text with biographical and historical contexts, critical history, and essays from five contemporary critical perspectives. Basingstoke: Macmillan. p. 10. ISBN 978-0-333-63438-7. +Jump up ^ "Bram Stoker." (PDF). The New York Times. 23 April 1912. Retrieved 1 January 2011. +^ Jump up to: a b "1960–1969". EMI Group. Retrieved 31 May 2008. +^ Jump up to: a b "Paul At Fifty". Time (New York). 8 June 1992. +^ Jump up to: a b Most Successful Group The Guinness Book of Records 1999, p. 230. Retrieved 19 March 2011. +Jump up ^ "British Citizen by Act of Parliament: George Frideric Handel". UK Parliament. 20 July 2009. Retrieved 11 September 2009.[dead link] +Jump up ^ Andrews, John (14 April 2006). "Handel all'inglese". Playbill (New York). Retrieved 11 September 2009. +Jump up ^ Citron, Stephen (2001). Sondheim and Lloyd-Webber: The new musical. London: Chatto & Windus. ISBN 978-1-85619-273-6. +Jump up ^ "Beatles a big hit with downloads". Belfast Telegraph. 25 November 2010. Retrieved 16 May 2011. +Jump up ^ "British rock legends get their own music title for PlayStation3 and PlayStation2" (Press release). EMI. 2 February 2009. +Jump up ^ Khan, Urmee (17 July 2008). "Sir Elton John honoured in Ben and Jerry ice cream". The Daily Telegraph (London). +Jump up ^ Alleyne, Richard (19 April 2008). "Rock group Led Zeppelin to reunite". The Daily Telegraph (London). Retrieved 31 March 2010. +Jump up ^ Fresco, Adam (11 July 2006). "Pink Floyd founder Syd Barrett dies at home". The Times (London). Retrieved 31 March 2010. (subscription required) +Jump up ^ Holton, Kate (17 January 2008). "Rolling Stones sign Universal album deal". Reuters. Retrieved 26 October 2008. +Jump up ^ Walker, Tim (12 May 2008). "Jive talkin': Why Robin Gibb wants more respect for the Bee Gees". The Independent (London). Retrieved 26 October 2008. +Jump up ^ "Brit awards winners list 2012: every winner since 1977". The Guardian (London). Retrieved 28 February 2012. +Jump up ^ Corner, Lewis (16 February 2012). "Adele, Coldplay biggest-selling UK artists worldwide in 2011". Digital Spy. Retrieved 22 March 2012. +Jump up ^ Hughes, Mark (14 January 2008). "A tale of two cities of culture: Liverpool vs Stavanger". The Independent (London). Retrieved 2 August 2009. +Jump up ^ "Glasgow gets city of music honour". BBC News. 20 August 2008. Retrieved 2 August 2009. +Jump up ^ Bayley, Stephen (24 April 2010). "The startling success of Tate Modern". The Times (London). Retrieved 19 January 2011. (subscription required) +Jump up ^ "Vertigo is named 'greatest film of all time'". BBC News. 2 August 2012. Retrieved 18 August 2012. +Jump up ^ "The Directors' Top Ten Directors". British Film Institute. Archived from the original on 27 May 2012. +Jump up ^ "Chaplin, Charles (1889–1977)". British Film Institute. Retrieved 25 January 2011. +Jump up ^ "Powell, Michael (1905–1990)". British Film Institute. Retrieved 25 January 2011. +Jump up ^ "Reed, Carol (1906–1976)". British Film Institute. Retrieved 25 January 2011. +Jump up ^ "Scott, Sir Ridley (1937–)". British Film Institute. Retrieved 25 January 2011. +Jump up ^ "Andrews, Julie (1935–)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Burton, Richard (1925–1984)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Caine, Michael (1933–)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Chaplin, Charles (1889–1977)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Connery, Sean (1930–)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Leigh, Vivien (1913–1967)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Niven, David (1910–1983)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Olivier, Laurence (1907–1989)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Sellers, Peter (1925–1980)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Winslet, Kate (1975–)". British Film Institute. Retrieved 11 December 2010. +Jump up ^ "Daniel Day-Lewis makes Oscar history with third award"'. BBC News. Retrieved 15 August 2013 +Jump up ^ "Harry Potter becomes highest-grossing film franchise". The Guardian (London). 11 September 2007. Retrieved 2 November 2010. +Jump up ^ "History of Ealing Studios". Ealing Studios. Retrieved 5 June 2010. +^ Jump up to: a b "UK film – the vital statistics". UK Film Council. Retrieved 22 October 2010.[dead link] +Jump up ^ "The BFI 100". British Film Institute. 6 September 2006. Archived from the original on 1 April 2011. +Jump up ^ "Baftas fuel Oscars race". BBC News. 26 February 2001. Retrieved 14 February 2011. +^ Jump up to: a b "BBC: World's largest broadcaster & Most trusted media brand". Media Newsline. Archived from the original on 5 October 2010. Retrieved 23 September 2010. +^ Jump up to: a b "Digital licence". Prospect. Retrieved 23 September 2010. +^ Jump up to: a b "About the BBC – What is the BBC". BBC Online. Retrieved 23 September 2010. +Jump up ^ Newswire7 (13 August 2009). "BBC: World's largest broadcaster & Most trusted media brand". Media Newsline. Archived from the original on 17 June 2011. +Jump up ^ "TV Licence Fee: facts & figures". BBC Press Office. April 2010. Archived from the original on 17 June 2011. +Jump up ^ "Publications & Policies: The History of ITV". ITV.com. Archived from the original on 17 June 2011. +Jump up ^ "Publishing". News Corporation. Archived from the original on 17 June 2011. +Jump up ^ "Direct Broadcast Satellite Television". News Corporation. Archived from the original on 17 June 2011. +Jump up ^ William, D. (2010). UK Cities: A Look at Life and Major Cities in England, Scotland, Wales and Northern Ireland. Eastbourne: Gardners Books. ISBN 978-9987-16-021-1, pp. 22, 46, 109 and 145. +Jump up ^ "Publishing". Department of Culture, Media and Sport. Archived from the original on 17 June 2011. +Jump up ^ Ofcom "Communication Market Report 2010", 19 August 2010, pp. 97, 164 and 191 +Jump up ^ "Social Trends: Lifestyles and social participation". Office for National Statistics. 16 February 2010. Archived from the original on 17 June 2011. +Jump up ^ "Top 20 countries with the highest number of Internet users". Internet World Stats. Archived from the original on 17 June 2011. +Jump up ^ Fieser, James, ed. (2000). A bibliography of Scottish common sense philosophy: Sources and origins. Bristol: Thoemmes Press. Retrieved 17 December 2010. +Jump up ^ Palmer, Michael (1999). Moral Problems in Medicine: A Practical Coursebook. Cambridge: Lutterworth Press. p. 66. ISBN 978-0-7188-2978-0. +Jump up ^ Scarre, Geoffrey (1995). Utilitarianism. London: Routledge. p. 82. ISBN 978-0-415-12197-2. +Jump up ^ Gysin, Christian (9 March 2007). "Wembley kick-off: Stadium is ready and England play first game in fortnight". Daily Mail (London). Retrieved 19 March 2007. +Jump up ^ "Opening ceremony of the games of the XXX Olympiad". Olympic.org. Retrieved 30 November 2013 +Jump up ^ "Unparalleled Sporting History" . Reuters. Retrieved 30 November 2013 +Jump up ^ "Rugby Union 'Britain's Second Most Popular Sport'". Ipsos-Mori. 22 December 2003. Retrieved 28 April 2013. +Jump up ^ Ebner, Sarah (2 July 2013). "History and time are key to power of football, says Premier League chief". The Times (London). Retrieved 30 November 2013. +Jump up ^ Mitchell, Paul (November 2005). "The first international football match". BBC Sport Scotland. Retrieved 15 December 2013. +Jump up ^ "Why is there no GB Olympics football team?". BBC Sport. 5 August 2008. Retrieved 31 December 2010. +Jump up ^ "Blatter against British 2012 team". BBC News. 9 March 2008. Retrieved 2 April 2008. +Jump up ^ "About ECB". England and Wales Cricket Board. n.d. Retrieved 28 April 2013. +Jump up ^ McLaughlin, Martyn (4 August 2009). "Howzat happen? England fields a Gaelic-speaking Scotsman in Ashes". The Scotsman (Edinburgh). Retrieved 30 December 2010. +Jump up ^ "Uncapped Joyce wins Ashes call up". BBC Sport. 15 November 2006. Retrieved 30 December 2010. +Jump up ^ "Glamorgan". BBC South East Wales. August 2009. Retrieved 30 December 2010. +Jump up ^ Ardener, Shirley (2007). Professional identities: policy and practice in business and bureaucracy. New York: Berghahn. p. 27. ISBN 978-1-84545-054-0. +Jump up ^ "Official Website of Rugby League World Cup 2008". Archived from the original on 16 October 2007. +Jump up ^ Louw, Jaco; Nesbit, Derrick (2008). The Girlfriends Guide to Rugby. Johannesburg: South Publishers. ISBN 978-0-620-39541-0. +Jump up ^ "Triple Crown". RBS 6 Nations. Retrieved 6 March 2011. +Jump up ^ "Tracking the Field". Ipsos MORI. Archived from the original on 5 February 2009. Retrieved 17 October 2008. +Jump up ^ "Links plays into the record books". BBC News. 17 March 2009. +Jump up ^ Chowdhury, Saj (22 January 2007). "China in Ding's hands". BBC Sport. Retrieved 2 January 2011. +Jump up ^ "Lawn Tennis and Major T.Gem". The Birmingham Civic Society. Archived from the original on 18 August 2011. Retrieved 31 December 2010. +Jump up ^ Gould, Joe (10 April 2007). "The ancient Irish sport of hurling catches on in America". Columbia News Service (Columbia Journalism School). Retrieved 17 May 2011. +Jump up ^ "Shinty". Scottishsport.co.uk. Retrieved 28 April 2013. +Jump up ^ "Welsh dragon call for Union flag". BBC News. 27 November 2007. Retrieved 17 October 2008. +Jump up ^ "Britannia on British Coins". Chard. Retrieved 25 June 2006. +Jump up ^ Baker, Steve (2001). Picturing the Beast. University of Illinois Press. p. 52. ISBN 0-252-07030-5. +Further reading +Hitchens, Peter (2000). The Abolition of Britain: from Winston Churchill to Princess Diana. Second ed. San Francisco, Calif.: Encounter Books. xi, 332 p. ISBN 1-893554-18-X. +Lambert, Richard S. (1964). The Great Heritage: a History of Britain for Canadians. House of Grant, 1964 (and earlier editions and/or printings). +External links +Find more about +United Kingdom +at Wikipedia's sister projects +Search Wiktionary Definitions from Wiktionary +Search Commons Media from Commons +Search Wikinews News stories from Wikinews +Search Wikiquote Quotations from Wikiquote +Search Wikisource Source texts from Wikisource +Search Wikibooks Textbooks from Wikibooks +Search Wikivoyage Travel guide from Wikivoyage +Search Wikiversity Learning resources from Wikiversity +Government +Official website of HM Government +Official website of the British Monarchy +Official Yearbook of the United Kingdom statistics +The official site of the British Prime Minister's Office +General information +United Kingdom from the BBC News +United Kingdom entry at The World Factbook +United Kingdom from UCB Libraries GovPubs +United Kingdom at DMOZ +United Kingdom Encyclopædia Britannica entry +United Kingdom from the OECD +United Kingdom at the EU + Wikimedia Atlas of United Kingdom + Geographic data related to United Kingdom at OpenStreetMap +Key Development Forecasts for the United Kingdom from International Futures +Travel +Official tourist guide to Britain +[hide] v t e +United Kingdom topics +History +Chronology +Formation Georgian era Victorian era Edwardian era World War I Interwar World War II UK since 1945 (Postwar Britain) +By topic +Economic Empire Maritime Military +Geography +Administrative +Countries of the United Kingdom Crown dependencies Overseas territories City status Towns Former colonies +Physical +British Isles terminology Great Britain Geology Northern Ireland Lakes and lochs Mountains Rivers Volcanoes +Resources +Energy/Renewable energy Biodiesel Coal Geothermal Hydraulic frac. Hydroelectricity Marine North Sea oil Solar Wind Food Agriculture Fishing English Scottish Hunting Materials Flora Forestry Mining +Politics +Constitution Courts Elections Foreign relations Judiciary Law Law enforcement Legislation Monarchy monarchs Nationality Parliament House of Commons House of Lords Political parties +Government +Cabinet list Civil service Departments Prime Minister list +Military +Royal Navy Army Royal Air Force Weapons of mass destruction +Economy +Banks Bank of England Budget Economic geography Pound (currency) Stock Exchange Taxation Telecommunications Tourism Transport +Society +Affordability of housing Crime Demography Drug policy Education Ethnic groups Health care Immigration Languages Poverty Food banks Prostitution Public holidays Social care Social structure +Culture +Art Cinema Cuisine Identity Literature Media television Music Religion Sport Symbols Theatre +[show] +Countries of the United Kingdom +Outline Index +Book Category Portal WikiProject +[show] +Gnome-globe.svg Geographic locale +[show] v t e +Member states of the European Union +[show] +International organisations +[show] v t e +English-speaking world +[show] v t e +National personifications +Coordinates: 55°N 3°W +Categories: United KingdomBritish IslandsConstitutional monarchiesCountries in EuropeEnglish-speaking countries and territoriesG20 nationsG7 nationsG8 nationsIsland countriesLiberal democraciesMember states of NATOMember states of the Commonwealth of NationsMember states of the Council of EuropeMember states of the European UnionMember states of the Union for the MediterraneanMember states of the United NationsNorthern EuropeWestern Europe +Navigation menu +Create accountLog inArticleTalkReadView sourceView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +Адыгэбзэ +Afrikaans +Akan +Alemannisch +አማርኛ +Ænglisc +Аҧсшәа +العربية +Aragonés +ܐܪܡܝܐ +Armãneashti +Arpetan +Asturianu +Avañe'ẽ +Авар +Azərbaycanca +বাংলা +Bahasa Banjar +Bân-lâm-gú +Башҡортса +Беларуская +Беларуская (тарашкевіца)‎ +भोजपुरी +Bikol Central +Bislama +Български +Boarisch +བོད་ཡིག +Bosanski +Brezhoneg +Буряад +Català +Чӑвашла +Cebuano +Čeština +Chavacano de Zamboanga +ChiShona +Corsu +Cymraeg +Dansk +Deutsch +ދިވެހިބަސް +Diné bizaad +Dolnoserbski +ཇོང་ཁ +Eesti +Ελληνικά +Emiliàn e rumagnòl +Español +Esperanto +Estremeñu +Euskara +فارسی +Fiji Hindi +Føroyskt +Français +Frysk +Furlan +Gaeilge +Gaelg +Gagauz +Gàidhlig +Galego +贛語 +ગુજરાતી +客家語/Hak-kâ-ngî +Хальмг +한국어 +Hausa +Hawaii +Հայերեն +हिन्दी +Hornjoserbsce +Hrvatski +Ido +Igbo +Ilokano +বিষ্ণুপ্রিয়া মণিপুরী +Bahasa Indonesia +Interlingua +Interlingue +Ирон +IsiZulu +Íslenska +Italiano +עברית +Basa Jawa +Kalaallisut +ಕನ್ನಡ +Kapampangan +Къарачай-малкъар +ქართული +Kaszëbsczi +Қазақша +Kernowek +Kinyarwanda +Kiswahili +Коми +Kongo +Kreyòl ayisyen +Kurdî +Кыргызча +Кырык мары +Ladino +Лезги +ລາວ +Latgaļu +Latina +Latviešu +Lëtzebuergesch +Lietuvių +Ligure +Limburgs +Lingála +Lojban +Lumbaart +Magyar +Македонски +Malagasy +മലയാളം +Malti +Māori +मराठी +მარგალური +مصرى +مازِرونی +Bahasa Melayu +Mìng-dĕ̤ng-ngṳ̄ +Mirandés +Монгол +မြန်မာဘာသာ +Nāhuatl +Dorerin Naoero +Nederlands +Nedersaksies +नेपाली +नेपाल भाषा +日本語 +Napulitano +Нохчийн +Nordfriisk +Norfuk / Pitkern +Norsk bokmål +Norsk nynorsk +Nouormand +Novial +Occitan +Олык марий +ଓଡ଼ିଆ +Oromoo +Oʻzbekcha +ਪੰਜਾਬੀ +Pangasinan +پنجابی +Papiamentu +پښتو +Перем Коми +ភាសាខ្មែរ +Picard +Piemontèis +Tok Pisin +Plattdüütsch +Polski +Ποντιακά +Português +Qırımtatarca +Reo tahiti +Ripoarisch +Română +Romani +Rumantsch +Runa Simi +Русиньскый +Русский +Саха тыла +Sámegiella +संस्कृतम् +Sardu +Scots +Seeltersk +Shqip +Sicilianu +සිංහල +Simple English +SiSwati +Slovenčina +Slovenščina +Словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ +Ślůnski +Soomaaliga +کوردی +Sranantongo +Српски / srpski +Srpskohrvatski / српскохрватски +Basa Sunda +Suomi +Svenska +Tagalog +தமிழ் +Taqbaylit +Tarandíne +Татарча/tatarça +తెలుగు +Tetun +ไทย +Тоҷикӣ +ᏣᎳᎩ +Tsetsêhestâhese +Türkçe +Twi +Удмурт +ᨅᨔ ᨕᨘᨁᨗ +Українська +اردو +ئۇيغۇرچە / Uyghurche +Vahcuengh +Vèneto +Vepsän kel’ +Tiếng Việt +Volapük +Võro +Walon +文言 +West-Vlams +Winaray +Wolof +吴语 +ייִדיש +Yorùbá +粵語 +Zazaki +Zeêuws +Žemaitėška +中文 +Edit links +This page was last modified on 22 November 2014 at 11:19. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki + + +World Trade Organization +From Wikipedia, the free encyclopedia +"WTO" redirects here. For other uses, see WTO (disambiguation). +World Trade Organization (English) +Organisation mondiale du commerce (French) +Organización Mundial del Comercio (Spanish) +World Trade Organization (logo and wordmark).svg +Official logo of WTO +WTO members and observers.svg + Members + Members, dually represented by the EU + Observers + Non-members +Abbreviation WTO +Formation 1 January 1995; 19 years ago +Type International trade organization +Purpose Liberalize international trade +Headquarters Centre William Rappard, Geneva, Switzerland +Coordinates 46.12°N 6.09°ECoordinates: 46.12°N 6.09°E +Region served Worldwide +Membership 160 member states[1] +Official language English, French, Spanish[2] +Director-General Roberto Azevêdo +Budget 196 million Swiss francs (approx. 209 million US$) in 2011.[3] +Staff 640[4] +Website www.wto.org +The World Trade Organization (WTO) is an organization that intends to supervise and liberalize international trade. The organization officially commenced on 1 January 1995 under the Marrakech Agreement, replacing the General Agreement on Tariffs and Trade (GATT), which commenced in 1948.[5] The organization deals with regulation of trade between participating countries by providing a framework for negotiating and formalizing trade agreements and a dispute resolution process aimed at enforcing participants' adherence to WTO agreements, which are signed by representatives of member governments[6]:fol.9–10 and ratified by their parliaments.[7] Most of the issues that the WTO focuses on derive from previous trade negotiations, especially from the Uruguay Round (1986–1994). +The organization is attempting to complete negotiations on the Doha Development Round, which was launched in 2001 with an explicit focus on addressing the needs of developing countries. As of June 2012, the future of the Doha Round remained uncertain: the work programme lists 21 subjects in which the original deadline of 1 January 2005 was missed, and the round is still incomplete.[8] The conflict between free trade on industrial goods and services but retention of protectionism on farm subsidies to domestic agricultural sector (requested by developed countries) and the substantiation of the international liberalization of fair trade on agricultural products (requested by developing countries) remain the major obstacles. These points of contention have hindered any progress to launch new WTO negotiations beyond the Doha Development Round. As a result of this impasse, there has been an increasing number of bilateral free trade agreements signed.[9] As of July 2012, there were various negotiation groups in the WTO system for the current agricultural trade negotiation which is in the condition of stalemate.[10] +WTO's current Director-General is Roberto Azevêdo,[11][12] who leads a staff of over 600 people in Geneva, Switzerland.[13] A trade facilitation agreement known as the Bali Package was reached by all members on 7 December 2013, the first comprehensive agreement in the organization's history.[14][15] +Contents [hide] +1 History +1.1 GATT rounds of negotiations +1.1.1 From Geneva to Tokyo +1.1.2 Uruguay Round +1.2 Ministerial conferences +1.3 Doha Round (Doha Agenda) +2 Functions +3 Principles of the trading system +4 Organizational structure +5 Decision-making +6 Dispute settlement +7 Accession and membership +7.1 Accession process +7.2 Members and observers +8 Agreements +9 Office of director-general +9.1 List of directors-general +10 See also +11 Notes and references +12 External links +History + +The economists Harry White (left) and John Maynard Keynes at the Bretton Woods Conference. Both had been strong advocates of a central-controlled international trade environment and recommended the establishment of three institutions: the IMF (for fiscal and monetary issues); the World Bank (for financial and structural issues); and the ITO (for international economic cooperation).[16] +The WTO's predecessor, the General Agreement on Tariffs and Trade (GATT), was established after World War II in the wake of other new multilateral institutions dedicated to international economic cooperation – notably the Bretton Woods institutions known as the World Bank and the International Monetary Fund. A comparable international institution for trade, named the International Trade Organization was successfully negotiated. The ITO was to be a United Nations specialized agency and would address not only trade barriers but other issues indirectly related to trade, including employment, investment, restrictive business practices, and commodity agreements. But the ITO treaty was not approved by the U.S. and a few other signatories and never went into effect.[17][18][19] +In the absence of an international organization for trade, the GATT would over the years "transform itself" into a de facto international organization.[20] +GATT rounds of negotiations +See also: General Agreement on Tariffs and Trade +The GATT was the only multilateral instrument governing international trade from 1946 until the WTO was established on 1 January 1995.[21] Despite attempts in the mid-1950s and 1960s to create some form of institutional mechanism for international trade, the GATT continued to operate for almost half a century as a semi-institutionalized multilateral treaty regime on a provisional basis.[22] +From Geneva to Tokyo +Seven rounds of negotiations occurred under GATT. The first real GATT trade rounds concentrated on further reducing tariffs. Then, the Kennedy Round in the mid-sixties brought about a GATT anti-dumping Agreement and a section on development. The Tokyo Round during the seventies was the first major attempt to tackle trade barriers that do not take the form of tariffs, and to improve the system, adopting a series of agreements on non-tariff barriers, which in some cases interpreted existing GATT rules, and in others broke entirely new ground. Because these plurilateral agreements were not accepted by the full GATT membership, they were often informally called "codes". Several of these codes were amended in the Uruguay Round, and turned into multilateral commitments accepted by all WTO members. Only four remained plurilateral (those on government procurement, bovine meat, civil aircraft and dairy products), but in 1997 WTO members agreed to terminate the bovine meat and dairy agreements, leaving only two.[21] +Uruguay Round +Main article: Uruguay Round + +During the Doha Round, the US government blamed Brazil and India for being inflexible and the EU for impeding agricultural imports.[23] The then-President of Brazil, Luiz Inácio Lula da Silva (above right), responded to the criticisms by arguing that progress would only be achieved if the richest countries (especially the US and countries in the EU) made deeper cuts in agricultural subsidies and further opened their markets for agricultural goods.[24] +Well before GATT's 40th anniversary, its members concluded that the GATT system was straining to adapt to a new globalizing world economy.[25][26] In response to the problems identified in the 1982 Ministerial Declaration (structural deficiencies, spill-over impacts of certain countries' policies on world trade GATT could not manage etc.), the eighth GATT round – known as the Uruguay Round – was launched in September 1986, in Punta del Este, Uruguay.[25] +It was the biggest negotiating mandate on trade ever agreed: the talks were going to extend the trading system into several new areas, notably trade in services and intellectual property, and to reform trade in the sensitive sectors of agriculture and textiles; all the original GATT articles were up for review.[26] The Final Act concluding the Uruguay Round and officially establishing the WTO regime was signed 15 April 1994, during the ministerial meeting at Marrakesh, Morocco, and hence is known as the Marrakesh Agreement.[27] +The GATT still exists as the WTO's umbrella treaty for trade in goods, updated as a result of the Uruguay Round negotiations (a distinction is made between GATT 1994, the updated parts of GATT, and GATT 1947, the original agreement which is still the heart of GATT 1994).[25] GATT 1994 is not however the only legally binding agreement included via the Final Act at Marrakesh; a long list of about 60 agreements, annexes, decisions and understandings was adopted. The agreements fall into a structure with six main parts: +The Agreement Establishing the WTO +Goods and investment – the Multilateral Agreements on Trade in Goods including the GATT 1994 and the Trade Related Investment Measures (TRIMS) +Services — the General Agreement on Trade in Services +Intellectual property – the Agreement on Trade-Related Aspects of Intellectual Property Rights (TRIPS) +Dispute settlement (DSU) +Reviews of governments' trade policies (TPRM)[28] +In terms of the WTO's principle relating to tariff "ceiling-binding" (No. 3), the Uruguay Round has been successful in increasing binding commitments by both developed and developing countries, as may be seen in the percentages of tariffs bound before and after the 1986–1994 talks.[29] +Ministerial conferences + +The World Trade Organization Ministerial Conference of 1998, in the Palace of Nations (Geneva, Switzerland). +The highest decision-making body of the WTO is the Ministerial Conference, which usually meets every two years. It brings together all members of the WTO, all of which are countries or customs unions. The Ministerial Conference can take decisions on all matters under any of the multilateral trade agreements. The inaugural ministerial conference was held in Singapore in 1996. Disagreements between largely developed and developing economies emerged during this conference over four issues initiated by this conference, which led to them being collectively referred to as the "Singapore issues". The second ministerial conference was held in Geneva in Switzerland. The third conference in Seattle, Washington ended in failure, with massive demonstrations and police and National Guard crowd-control efforts drawing worldwide attention. The fourth ministerial conference was held in Doha in the Persian Gulf nation of Qatar. The Doha Development Round was launched at the conference. The conference also approved the joining of China, which became the 143rd member to join. The fifth ministerial conference was held in Cancún, Mexico, aiming at forging agreement on the Doha round. An alliance of 22 southern states, the G20 developing nations (led by India, China,[30] Brazil, ASEAN led by the Philippines), resisted demands from the North for agreements on the so-called "Singapore issues" and called for an end to agricultural subsidies within the EU and the US. The talks broke down without progress. +The sixth WTO ministerial conference was held in Hong Kong from 13–18 December 2005. It was considered vital if the four-year-old Doha Development Round negotiations were to move forward sufficiently to conclude the round in 2006. In this meeting, countries agreed to phase out all their agricultural export subsidies by the end of 2013, and terminate any cotton export subsidies by the end of 2006. Further concessions to developing countries included an agreement to introduce duty-free, tariff-free access for goods from the Least Developed Countries, following the Everything but Arms initiative of the European Union — but with up to 3% of tariff lines exempted. Other major issues were left for further negotiation to be completed by the end of 2010. The WTO General Council, on 26 May 2009, agreed to hold a seventh WTO ministerial conference session in Geneva from 30 November-3 December 2009. A statement by chairman Amb. Mario Matus acknowledged that the prime purpose was to remedy a breach of protocol requiring two-yearly "regular" meetings, which had lapsed with the Doha Round failure in 2005, and that the "scaled-down" meeting would not be a negotiating session, but "emphasis will be on transparency and open discussion rather than on small group processes and informal negotiating structures". The general theme for discussion was "The WTO, the Multilateral Trading System and the Current Global Economic Environment"[31] +Doha Round (Doha Agenda) +Main article: Doha Development Round + +The Doha Development Round started in 2001 is at an impasse. +The WTO launched the current round of negotiations, the Doha Development Round, at the fourth ministerial conference in Doha, Qatar in November 2001. This was to be an ambitious effort to make globalization more inclusive and help the world's poor, particularly by slashing barriers and subsidies in farming.[32] The initial agenda comprised both further trade liberalization and new rule-making, underpinned by commitments to strengthen substantial assistance to developing countries.[33] +The negotiations have been highly contentious. Disagreements still continue over several key areas including agriculture subsidies, which emerged as critical in July 2006.[34] According to a European Union statement, "The 2008 Ministerial meeting broke down over a disagreement between exporters of agricultural bulk commodities and countries with large numbers of subsistence farmers on the precise terms of a 'special safeguard measure' to protect farmers from surges in imports."[35] The position of the European Commission is that "The successful conclusion of the Doha negotiations would confirm the central role of multilateral liberalisation and rule-making. It would confirm the WTO as a powerful shield against protectionist backsliding."[33] An impasse remains and, as of August 2013, agreement has not been reached, despite intense negotiations at several ministerial conferences and at other sessions. On 27 March 2013, the chairman of agriculture talks announced "a proposal to loosen price support disciplines for developing countries’ public stocks and domestic food aid." He added: “...we are not yet close to agreement—in fact, the substantive discussion of the proposal is only beginning.”[36] +[show]v · t · eGATT and WTO trade rounds[37] +Functions +Among the various functions of the WTO, these are regarded by analysts as the most important: +It oversees the implementation, administration and operation of the covered agreements.[38][39] +It provides a forum for negotiations and for settling disputes.[40][41] +Additionally, it is the WTO's duty to review and propagate the national trade policies, and to ensure the coherence and transparency of trade policies through surveillance in global economic policy-making.[39][41] Another priority of the WTO is the assistance of developing, least-developed and low-income countries in transition to adjust to WTO rules and disciplines through technical cooperation and training.[42] +(i) The WTO shall facilitate the implementation, administration and operation and further the objec­tives of this Agreement and of the Multilateral Trade Agreements, and shall also provide the frame work for the implementation, administration and operation of the multilateral Trade Agreements. +(ii) The WTO shall provide the forum for negotiations among its members concerning their multilateral trade relations in matters dealt with under the Agreement in the Annexes to this Agreement. +(iii) The WTO shall administer the Understanding on Rules and Procedures Governing the Settlement of Disputes. +(iv) The WTO shall administer Trade Policy Review Mechanism. +(v) With a view to achieving greater coherence in global economic policy making, the WTO shall cooperate, as appropriate, with the international Monetary Fund (IMF) and with the International Bank for Reconstruction and Development (IBRD) and its affiliated agencies. [43] +The above five listings are the additional functions of the World Trade Organization. As globalization proceeds in today's society, the necessity of an International Organization to manage the trading systems has been of vital importance. As the trade volume increases, issues such as protectionism, trade barriers, subsidies, violation of intellectual property arise due to the differences in the trading rules of every nation. The World Trade Organization serves as the mediator between the nations when such problems arise. WTO could be referred to as the product of globalization and also as one of the most important organizations in today's globalized society. +The WTO is also a center of economic research and analysis: regular assessments of the global trade picture in its annual publications and research reports on specific topics are produced by the organization.[44] Finally, the WTO cooperates closely with the two other components of the Bretton Woods system, the IMF and the World Bank.[40] +Principles of the trading system +The WTO establishes a framework for trade policies; it does not define or specify outcomes. That is, it is concerned with setting the rules of the trade policy games.[45] Five principles are of particular importance in understanding both the pre-1994 GATT and the WTO: +Non-discrimination. It has two major components: the most favoured nation (MFN) rule, and the national treatment policy. Both are embedded in the main WTO rules on goods, services, and intellectual property, but their precise scope and nature differ across these areas. The MFN rule requires that a WTO member must apply the same conditions on all trade with other WTO members, i.e. a WTO member has to grant the most favorable conditions under which it allows trade in a certain product type to all other WTO members.[45] "Grant someone a special favour and you have to do the same for all other WTO members."[29] National treatment means that imported goods should be treated no less favorably than domestically produced goods (at least after the foreign goods have entered the market) and was introduced to tackle non-tariff barriers to trade (e.g. technical standards, security standards et al. discriminating against imported goods).[45] +Reciprocity. It reflects both a desire to limit the scope of free-riding that may arise because of the MFN rule, and a desire to obtain better access to foreign markets. A related point is that for a nation to negotiate, it is necessary that the gain from doing so be greater than the gain available from unilateral liberalization; reciprocal concessions intend to ensure that such gains will materialise.[46] +Binding and enforceable commitments. The tariff commitments made by WTO members in a multilateral trade negotiation and on accession are enumerated in a schedule (list) of concessions. These schedules establish "ceiling bindings": a country can change its bindings, but only after negotiating with its trading partners, which could mean compensating them for loss of trade. If satisfaction is not obtained, the complaining country may invoke the WTO dispute settlement procedures.[29][46] +Transparency. The WTO members are required to publish their trade regulations, to maintain institutions allowing for the review of administrative decisions affecting trade, to respond to requests for information by other members, and to notify changes in trade policies to the WTO. These internal transparency requirements are supplemented and facilitated by periodic country-specific reports (trade policy reviews) through the Trade Policy Review Mechanism (TPRM).[47] The WTO system tries also to improve predictability and stability, discouraging the use of quotas and other measures used to set limits on quantities of imports.[29] +Safety valves. In specific circumstances, governments are able to restrict trade. The WTO's agreements permit members to take measures to protect not only the environment but also public health, animal health and plant health.[48] +There are three types of provision in this direction: +articles allowing for the use of trade measures to attain non-economic objectives; +articles aimed at ensuring "fair competition"; members must not use environmental protection measures as a means of disguising protectionist policies.[48] +provisions permitting intervention in trade for economic reasons.[47] +Exceptions to the MFN principle also allow for preferential treatment of developing countries, regional free trade areas and customs unions.[6]:fol.93 +Organizational structure +The General Council has the following subsidiary bodies which oversee committees in different areas: +Council for Trade in Goods +There are 11 committees under the jurisdiction of the Goods Council each with a specific task. All members of the WTO participate in the committees. The Textiles Monitoring Body is separate from the other committees but still under the jurisdiction of Goods Council. The body has its own chairman and only 10 members. The body also has several groups relating to textiles.[49] +Council for Trade-Related Aspects of Intellectual Property Rights +Information on intellectual property in the WTO, news and official records of the activities of the TRIPS Council, and details of the WTO's work with other international organizations in the field.[50] +Council for Trade in Services +The Council for Trade in Services operates under the guidance of the General Council and is responsible for overseeing the functioning of the General Agreement on Trade in Services (GATS). It is open to all WTO members, and can create subsidiary bodies as required.[51] +Trade Negotiations Committee +The Trade Negotiations Committee (TNC) is the committee that deals with the current trade talks round. The chair is WTO's director-general. As of June 2012 the committee was tasked with the Doha Development Round.[52] +The Service Council has three subsidiary bodies: financial services, domestic regulations, GATS rules and specific commitments.[49] The council has several different committees, working groups, and working parties.[53] There are committees on the following: Trade and Environment; Trade and Development (Subcommittee on Least-Developed Countries); Regional Trade Agreements; Balance of Payments Restrictions; and Budget, Finance and Administration. There are working parties on the following: Accession. There are working groups on the following: Trade, debt and finance; and Trade and technology transfer. +Decision-making +The WTO describes itself as "a rules-based, member-driven organization — all decisions are made by the member governments, and the rules are the outcome of negotiations among members".[54] The WTO Agreement foresees votes where consensus cannot be reached, but the practice of consensus dominates the process of decision-making.[55] +Richard Harold Steinberg (2002) argues that although the WTO's consensus governance model provides law-based initial bargaining, trading rounds close through power-based bargaining favouring Europe and the U.S., and may not lead to Pareto improvement.[56] +Dispute settlement +Main article: Dispute settlement in the WTO +In 1994, the WTO members agreed on the Understanding on Rules and Procedures Governing the Settlement of Disputes (DSU) annexed to the "Final Act" signed in Marrakesh in 1994.[57] Dispute settlement is regarded by the WTO as the central pillar of the multilateral trading system, and as a "unique contribution to the stability of the global economy".[58] WTO members have agreed that, if they believe fellow-members are violating trade rules, they will use the multilateral system of settling disputes instead of taking action unilaterally.[59] +The operation of the WTO dispute settlement process involves the DSB panels, the Appellate Body, the WTO Secretariat, arbitrators, independent experts and several specialized institutions.[60] Bodies involved in the dispute settlement process, World Trade Organization. +Accession and membership +Main article: World Trade Organization accession and membership +The process of becoming a WTO member is unique to each applicant country, and the terms of accession are dependent upon the country's stage of economic development and current trade regime.[61] The process takes about five years, on average, but it can last more if the country is less than fully committed to the process or if political issues interfere. The shortest accession negotiation was that of the Kyrgyz Republic, while the longest was that of Russia, which, having first applied to join GATT in 1993, was approved for membership in December 2011 and became a WTO member on 22 August 2012.[62] The second longest was that of Vanuatu, whose Working Party on the Accession of Vanuatu was established on 11 July 1995. After a final meeting of the Working Party in October 2001, Vanuatu requested more time to consider its accession terms. In 2008, it indicated its interest to resume and conclude its WTO accession. The Working Party on the Accession of Vanuatu was reconvened informally on 4 April 2011 to discuss Vanuatu's future WTO membership. The re-convened Working Party completed its mandate on 2 May 2011. The General Council formally approved the Accession Package of Vanuatu on 26 October 2011. On 24 August 2012, the WTO welcomed Vanuatu as its 157th member.[63] An offer of accession is only given once consensus is reached among interested parties.[64] +Accession process + +WTO accession progress: + Members (including dual-representation with the European Union) + Draft Working Party Report or Factual Summary adopted + Goods and/or Services offers submitted + Memorandum on Foreign Trade Regime (FTR) submitted + Observer, negotiations to start later or no Memorandum on FTR submitted + Frozen procedures or no negotiations in the last 3 years + No official interaction with the WTO +A country wishing to accede to the WTO submits an application to the General Council, and has to describe all aspects of its trade and economic policies that have a bearing on WTO agreements.[65] The application is submitted to the WTO in a memorandum which is examined by a working party open to all interested WTO Members.[66] +After all necessary background information has been acquired, the working party focuses on issues of discrepancy between the WTO rules and the applicant's international and domestic trade policies and laws. The working party determines the terms and conditions of entry into the WTO for the applicant nation, and may consider transitional periods to allow countries some leeway in complying with the WTO rules.[61] +The final phase of accession involves bilateral negotiations between the applicant nation and other working party members regarding the concessions and commitments on tariff levels and market access for goods and services. The new member's commitments are to apply equally to all WTO members under normal non-discrimination rules, even though they are negotiated bilaterally.[65] +When the bilateral talks conclude, the working party sends to the general council or ministerial conference an accession package, which includes a summary of all the working party meetings, the Protocol of Accession (a draft membership treaty), and lists ("schedules") of the member-to-be's commitments. Once the general council or ministerial conference approves of the terms of accession, the applicant's parliament must ratify the Protocol of Accession before it can become a member.[67] Some countries may have faced tougher and a much longer accession process due to challenges during negotiations with other WTO members, such as Vietnam, whose negotiations took more than 11 years before it became official member in January 2007.[68] +Members and observers +The WTO has 160 members and 24 observer governments.[69] In addition to states, the European Union is a member. WTO members do not have to be full sovereign nation-members. Instead, they must be a customs territory with full autonomy in the conduct of their external commercial relations. Thus Hong Kong has been a member since 1995 (as "Hong Kong, China" since 1997) predating the People's Republic of China, which joined in 2001 after 15 years of negotiations. The Republic of China (Taiwan) acceded to the WTO in 2002 as "Separate Customs Territory of Taiwan, Penghu, Kinmen and Matsu" (Chinese Taipei) despite its disputed status.[70] The WTO Secretariat omits the official titles (such as Counselor, First Secretary, Second Secretary and Third Secretary) of the members of Chinese Taipei's Permanent Mission to the WTO, except for the titles of the Permanent Representative and the Deputy Permanent Representative.[71] +As of 2007, WTO member states represented 96.4% of global trade and 96.7% of global GDP.[72] Iran, followed by Algeria, are the economies with the largest GDP and trade outside the WTO, using 2005 data.[73][74] With the exception of the Holy See, observers must start accession negotiations within five years of becoming observers. A number of international intergovernmental organizations have also been granted observer status to WTO bodies.[75] 14 UN member states have no official affiliation with the WTO. +Agreements +Further information: Uruguay Round +The WTO oversees about 60 different agreements which have the status of international legal texts. Member countries must sign and ratify all WTO agreements on accession.[76] A discussion of some of the most important agreements follows. The Agreement on Agriculture came into effect with the establishment of the WTO at the beginning of 1995. The AoA has three central concepts, or "pillars": domestic support, market access and export subsidies. The General Agreement on Trade in Services was created to extend the multilateral trading system to service sector, in the same way as the General Agreement on Tariffs and Trade (GATT) provided such a system for merchandise trade. The agreement entered into force in January 1995. The Agreement on Trade-Related Aspects of Intellectual Property Rights sets down minimum standards for many forms of intellectual property (IP) regulation. It was negotiated at the end of the Uruguay Round of the General Agreement on Tariffs and Trade (GATT) in 1994.[77] +The Agreement on the Application of Sanitary and Phytosanitary Measures—also known as the SPS Agreement—was negotiated during the Uruguay Round of GATT, and entered into force with the establishment of the WTO at the beginning of 1995. Under the SPS agreement, the WTO sets constraints on members' policies relating to food safety (bacterial contaminants, pesticides, inspection and labelling) as well as animal and plant health (imported pests and diseases). The Agreement on Technical Barriers to Trade is an international treaty of the World Trade Organization. It was negotiated during the Uruguay Round of the General Agreement on Tariffs and Trade, and entered into force with the establishment of the WTO at the end of 1994. The object ensures that technical negotiations and standards, as well as testing and certification procedures, do not create unnecessary obstacles to trade".[78] The Agreement on Customs Valuation, formally known as the Agreement on Implementation of Article VII of GATT, prescribes methods of customs valuation that Members are to follow. Chiefly, it adopts the "transaction value" approach. +In December 2013, the biggest agreement within the WTO was signed and known as the Bali Package.[79] +Office of director-general + +The headquarters of the World Trade Organization, in Geneva, Switzerland. +The procedures for the appointment of the WTO director-general were published in January 2003.[80] Additionally, there are four deputy directors-general. As of 1 October 2013, under director-general Roberto Azevêdo, the four deputy directors-general are Yi Xiaozhun of China, Karl-Ernst Brauner of Germany, Yonov Frederick Agah of Nigeria and David Shark of the United States.[81] +List of directors-general +Source: Official website[82] +Brazil Roberto Azevedo, 2013– +France Pascal Lamy, 2005–2013 +Thailand Supachai Panitchpakdi, 2002–2005 +New Zealand Mike Moore, 1999–2002 +Italy Renato Ruggiero, 1995–1999 +Republic of Ireland Peter Sutherland, 1995 +(Heads of the precursor organization, GATT): +Republic of Ireland Peter Sutherland, 1993–1995 +Switzerland Arthur Dunkel, 1980–1993 +Switzerland Olivier Long, 1968–1980 +United Kingdom Eric Wyndham White, 1948–1968 +See also +Agreement on Trade Related Investment Measures (TRIMS) +Agreement on Trade-Related Aspects of Intellectual Property Rights (TRIPS) +Aide-mémoire non-paper +Anti-globalization movement +Criticism of the World Trade Organization +Foreign Affiliate Trade Statistics +Global administrative law +Globality +Information Technology Agreement +International Trade Centre +Labour Standards in the World Trade Organisation +List of member states of the World Trade Organization +North American Free Trade Agreement (NAFTA) +Subsidy +Swiss Formula +Trade bloc +Washington Consensus +World Trade Report +World Trade Organization Ministerial Conference of 1999 protest activity +China and the World Trade Organization +Notes and references +Jump up ^ Members and Observers at WTO official website +Jump up ^ Languages, Documentation and Information Management Division at WTO official site +Jump up ^ "WTO Secretariat budget for 2011". WTO official site. Retrieved 25 August 2008. +Jump up ^ Understanding the WTO: What We Stand For_ Fact File +Jump up ^ World Trade Organization - UNDERSTANDING THE WTO: BASICS +^ Jump up to: a b Understanding the WTO Handbook at WTO official website. (Note that the document's printed folio numbers do not match the pdf page numbers.) +Jump up ^ Malanczuk, P. (1999). "International Organisations and Space Law: World Trade Organization". Encyclopaedia Britannica 442. p. 305. Bibcode:1999ESASP.442..305M. +Jump up ^ Understanding the WTO: The Doha Agenda +Jump up ^ The Challenges to the World Trade Organization: It’s All About Legitimacy THE BROOKINGS INSTITUTION, Policy Paper 2011-04 +Jump up ^ GROUPS IN THE WTO Updated 1 July 2013 +Jump up ^ Bourcier, Nicolas (21 May 2013). "Roberto Azevedo's WTO appointment gives Brazil a seat at the top table". Guardian Weekly. Retrieved 2 September 2013. +Jump up ^ "Roberto Azevêdo takes over". WTO official website. 1 September 2013. Retrieved 2 September 2013. +Jump up ^ "Overview of the WTO Secretariat". WTO official website. Retrieved 2 September 2013. +Jump up ^ Ninth WTO Ministerial Conference | WTO - MC9 +Jump up ^ BBC News - WTO agrees global trade deal worth $1tn +Jump up ^ A.E. Eckes Jr., US Trade History, 73 +* A. Smithies, Reflections on the Work of Keynes, 578–601 +* N. Warren, Internet and Globalization, 193 +Jump up ^ P. van den Bossche, The Law and Policy of the World Trade Organization, 80 +Jump up ^ Palmeter-Mavroidis, Dispute Settlement, 2 +Jump up ^ Fergusson, Ian F. (9 May 2007). "The World Trade Organization: Background and Issues" (PDF). Congressional Research Service. p. 4. Retrieved 15 August 2008. +Jump up ^ It was contemplated that the GATT would be applied for several years until the ITO came into force. However, since the ITO was never brought into being, the GATT gradually became the focus for international governmental cooperation on trade matters with economist Nicholas Halford overseeing the implementation of GATT in members policies. (P. van den Bossche, The Law and Policy of the World Trade Organization, 81; J.H. Jackson, Managing the Trading System, 134). +^ Jump up to: a b The GATT Years: from Havana to Marrakesh, WTO official site +Jump up ^ Footer, M. E. Analysis of the World Trade Organization, 17 +Jump up ^ B.S. Klapper, With a "Short Window" +Jump up ^ Lula, Time to Get Serious about Agricultural Subsidies +^ Jump up to: a b c P. Gallagher, The First Ten Years of the WTO, 4 +^ Jump up to: a b The Uruguay Round, WTO official site +Jump up ^ "Legal texts – Marrakesh agreement". WTO. Retrieved 30 May 2010. +Jump up ^ Overview: a Navigational Guide, WTO official site. For the complete list of "The Uruguay Round Agreements", see WTO legal texts, WTO official site, and Uruguay Round Agreements, Understandings, Decisions and Declarations, WorldTradeLaw.net +^ Jump up to: a b c d Principles of the Trading System, WTO official site +Jump up ^ "Five Years of China WTO Membership. EU and US Perspectives about China's Compliance with Transparency Commitments and the Transitional Review Mechanism". Papers.ssrn.com. Retrieved 30 May 2010. +Jump up ^ WTO to hold 7th Ministerial Conference on 30 November-2 December 2009 WTO official website +Jump up ^ "In the twilight of Doha". The Economist (The Economist): 65. 27 July 2006. +^ Jump up to: a b European Commission The Doha Round +Jump up ^ Fergusson, Ian F. (18 January 2008). "World Trade Organization Negotiations: The Doha Development Agenda" (PDF). Congressional Research Service. Retrieved 13 April 2012. Page 9 (folio CRS-6) +Jump up ^ WTO trade negotiations: Doha Development Agenda Europa press release, 31 October 2011 +Jump up ^ "Members start negotiating proposal on poor countries’ food stockholding". WTO official website. 27 March 2013. Retrieved 2 September 2013. +Jump up ^ a)The GATT years: from Havana to Marrakesh, World Trade Organization +b)Timeline: World Trade Organization – A chronology of key events, BBC News +c)Brakman-Garretsen-Marrewijk-Witteloostuijn, Nations and Firms in the Global Economy, Chapter 10: Trade and Capital Restriction +Jump up ^ Functions of the WTO, IISD +^ Jump up to: a b Main Functions, WTO official site +^ Jump up to: a b A Bredimas, International Economic Law, II, 17 +^ Jump up to: a b C. Deere, Decision-making in the WTO: Medieval or Up-to-Date? +Jump up ^ WTO Assistance for Developing Countries[dead link], WTO official site +Jump up ^ Sinha, Aparijita. [1]. "What are the functions and objectives of the WTO?". Retrieved on 13 April, 2014. +Jump up ^ Economic research and analysis, WTO official site +^ Jump up to: a b c B. Hoekman, The WTO: Functions and Basic Principles, 42 +^ Jump up to: a b B. Hoekman, The WTO: Functions and Basic Principles, 43 +^ Jump up to: a b B. Hoekman, The WTO: Functions and Basic Principles, 44 +^ Jump up to: a b Understanding the WTO: What we stand for +^ Jump up to: a b "Fourth level: down to the nitty-gritty". WTO official site. Retrieved 18 August 2008. +Jump up ^ "Intellectual property – overview of TRIPS Agreement". Wto.org. 15 April 1994. Retrieved 30 May 2010. +Jump up ^ "The Services Council, its Committees and other subsidiary bodies". WTO official site. Retrieved 14 August 2008. +Jump up ^ "The Trade Negotiations Committee". WTO official site. Retrieved 14 August 2008. +Jump up ^ "WTO organization chart". WTO official site. Retrieved 14 August 2008. +Jump up ^ Decision-making at WTO official site +Jump up ^ Decision-Making in the World Trade Organization Abstract from Journal of International Economic Law at Oxford Journals +Jump up ^ Steinberg, Richard H. "In the Shadow of Law or Power? Consensus-based Bargaining and Outcomes in the GATT/WTO." International Organization. Spring 2002. pp. 339–374. +Jump up ^ Stewart-Dawyer, The WTO Dispute Settlement System, 7 +Jump up ^ S. Panitchpakdi, The WTO at ten, 8. +Jump up ^ Settling Disputes:a Unique Contribution, WTO official site +Jump up ^ "Disputes – Dispute Settlement CBT – WTO Bodies involved in the dispute settlement process – The Dispute Settlement Body (DSB) – Page 1". WTO. 25 July 1996. Retrieved 21 May 2011. +^ Jump up to: a b Accessions Summary, Center for International Development +Jump up ^ Ministerial Conference approves Russia's WTO membership WTO News Item, 16 December 2011 +Jump up ^ Accession status: Vanuatu. WTO. Retrieved on 12 July 2013. +Jump up ^ C. Michalopoulos, WTO Accession, 64 +^ Jump up to: a b Membership, Alliances and Bureaucracy, WTO official site +Jump up ^ C. Michalopoulos, WTO Accession, 62–63 +Jump up ^ How to Become a Member of the WTO, WTO official site +Jump up ^ Napier, Nancy K.; Vuong, Quan Hoang (2013). What we see, why we worry, why we hope: Vietnam going forward. Boise, ID, USA: Boise State University CCI Press. p. 140. ISBN 978-0985530587. +Jump up ^ "Members and Observers". World Trade Organization. 24 August 2012. +Jump up ^ Jackson, J. H. Sovereignty, 109 +Jump up ^ ROC Government Publication +Jump up ^ "Accession in perspective". World Trade Organization. Retrieved 22 December 2013. +Jump up ^ "ANNEX 1. STATISTICAL SURVEY". World Trade Organization. 2005. Retrieved 22 December 2013. +Jump up ^ Arjomandy, Danial (21 November 2013). "Iranian Membership in the World Trade Organization: An Unclear Future". Iranian Studies. Retrieved 22 December 2013. +Jump up ^ International intergovernmental organizations granted observer status to WTO bodies at WTO official website +Jump up ^ "Legal texts – the WTO agreements". WTO. Retrieved 30 May 2010. +Jump up ^ Understanding the WTO - Intellectual property: protection and enforcement. WTO. Retrieved on 29 July 2013. +Jump up ^ "A Summary of the Final Act of the Uruguay Round". Wto.org. Retrieved 30 May 2010. +Jump up ^ Zarocostas, John (7 December 2013). "Global Trade Deal Reached". WWD. Retrieved 8 December 2013. +Jump up ^ "WT/L/509". WTO. Retrieved 18 February 2013. +Jump up ^ "Director-General Elect Azevêdo announces his four Deputy Directors-General". 17 August 2013. Retrieved 2 September 2013. +Jump up ^ "Previous GATT and WTO Directors-General". WTO. Retrieved 21 May 2011. +External links + Wikiquote has quotations related to: World Trade Organization + Wikimedia Commons has media related to World Trade Organization. +Official pages +Official WTO homepage +WTO 10th Anniversary PDF (1.40 MB) — Highlights of the first decade, Annual Report 2005 pages 116–166 +Glossary of terms—a guide to 'WTO-speak' +International Trade Centre — joint UN/WTO agency +Government pages on the WTO +European Union position on the WTO +Media pages on the WTO +World Trade Organization +BBC News — Profile: WTO +Guardian Unlimited — Special Report: The World Trade Organisation ongoing coverage +Non-governmental organization pages on the WTO +Gatt.org — Parody of official WTO page by The Yes Men +Public Citizen +Transnational Institute: Beyond the WTO +[show] v t e +World Trade Organization +[show] v t e +International trade +[show] v t e +International organizations +Authority control +WorldCat VIAF: 149937768 LCCN: no94018277 ISNI: 0000 0001 2296 2735 GND: 2145784-0 SELIBR: 135910 ULAN: 500292980 NDL: 00577475 NKC: kn20010711437 BNE: XX4574846 +Categories: World Trade OrganizationInternational tradeInternational trade organizationsOrganisations based in GenevaOrganizations established in 1995World government +Navigation menu +Create accountLog inArticleTalkReadView sourceView history + +Main page +Contents +Featured content +Current events +Random article +Donate to Wikipedia +Wikimedia Shop +Interaction +Help +About Wikipedia +Community portal +Recent changes +Contact page +Tools +What links here +Related changes +Upload file +Special pages +Permanent link +Page information +Wikidata item +Cite this page +Print/export +Create a book +Download as PDF +Printable version +Languages +Afrikaans +العربية +Aragonés +Asturianu +Azərbaycanca +বাংলা +Bân-lâm-gú +Беларуская +Беларуская (тарашкевіца)‎ +Български +Bosanski +Brezhoneg +Català +Čeština +Cymraeg +Dansk +Deutsch +Eesti +Ελληνικά +Español +Esperanto +Euskara +فارسی +Fiji Hindi +Føroyskt +Français +Frysk +Galego +ગુજરાતી +客家語/Hak-kâ-ngî +한국어 +Հայերեն +हिन्दी +Hrvatski +Ido +Ilokano +Bahasa Indonesia +Íslenska +Italiano +עברית +Basa Jawa +ಕನ್ನಡ +Къарачай-малкъар +ქართული +Қазақша +Kiswahili +Latina +Latviešu +Lietuvių +Magyar +Македонски +മലയാളം +मराठी +مصرى +Bahasa Melayu +Baso Minangkabau +မြန်မာဘာသာ +Nederlands +नेपाली +नेपाल भाषा +日本語 +Нохчийн +Norsk bokmål +Norsk nynorsk +Occitan +Oʻzbekcha +ਪੰਜਾਬੀ +پنجابی +پښتو +ភាសាខ្មែរ +Piemontèis +Polski +Português +Română +Русиньскый +Русский +Саха тыла +Shqip +සිංහල +Simple English +Slovenčina +Slovenščina +کوردی +Српски / srpski +Srpskohrvatski / српскохрватски +Suomi +Svenska +Tagalog +தமிழ் +Татарча/tatarça +తెలుగు +ไทย +Тоҷикӣ +Türkçe +Türkmençe +Українська +اردو +ئۇيغۇرچە / Uyghurche +Tiếng Việt +Winaray +ייִדיש +Yorùbá +粵語 +Žemaitėška +中文 +Edit links +This page was last modified on 22 November 2014 at 14:33. +Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. +Privacy policyAbout WikipediaDisclaimersContact WikipediaDevelopersMobile viewWikimedia Foundation Powered by MediaWiki \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_datetime.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_datetime.go new file mode 100644 index 00000000..a533eaa9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_datetime.go @@ -0,0 +1,147 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package facets + +import ( + "container/list" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type dateTimeRange struct { + start time.Time + end time.Time +} + +type DateTimeFacetBuilder struct { + size int + field string + termsCount map[string]int + total int + missing int + ranges map[string]*dateTimeRange +} + +func NewDateTimeFacetBuilder(field string, size int) *DateTimeFacetBuilder { + return &DateTimeFacetBuilder{ + size: size, + field: field, + termsCount: make(map[string]int), + ranges: make(map[string]*dateTimeRange, 0), + } +} + +func (fb *DateTimeFacetBuilder) AddRange(name string, start, end time.Time) { + r := dateTimeRange{ + start: start, + end: end, + } + fb.ranges[name] = &r +} + +func (fb *DateTimeFacetBuilder) Update(ft index.FieldTerms) { + terms, ok := ft[fb.field] + if ok { + for _, term := range terms { + // only consider the values which are shifted 0 + prefixCoded := numeric_util.PrefixCoded(term) + shift, err := prefixCoded.Shift() + if err == nil && shift == 0 { + i64, err := prefixCoded.Int64() + if err == nil { + t := time.Unix(0, i64) + + // look at each of the ranges for a match + for rangeName, r := range fb.ranges { + + if (r.start.IsZero() || t.After(r.start) || t.Equal(r.start)) && (r.end.IsZero() || t.Before(r.end)) { + + existingCount, existed := fb.termsCount[rangeName] + if existed { + fb.termsCount[rangeName] = existingCount + 1 + } else { + fb.termsCount[rangeName] = 1 + } + fb.total++ + } + } + } + } + } + } else { + fb.missing++ + } +} + +func (fb *DateTimeFacetBuilder) Result() *search.FacetResult { + rv := search.FacetResult{ + Field: fb.field, + Total: fb.total, + Missing: fb.missing, + } + + // FIXME better implementation needed here this is quick and dirty + topN := list.New() + + // walk entries and find top N +OUTER: + for term, count := range fb.termsCount { + dateRange := fb.ranges[term] + tf := &search.DateRangeFacet{ + Name: term, + Count: count, + } + if !dateRange.start.IsZero() { + start := dateRange.start.Format(time.RFC3339Nano) + tf.Start = &start + } + if !dateRange.end.IsZero() { + end := dateRange.end.Format(time.RFC3339Nano) + tf.End = &end + } + + for e := topN.Front(); e != nil; e = e.Next() { + curr := e.Value.(*search.DateRangeFacet) + if tf.Count < curr.Count { + + topN.InsertBefore(tf, e) + // if we just made the list too long + if topN.Len() > fb.size { + // remove the head + topN.Remove(topN.Front()) + } + continue OUTER + } + } + // if we got to the end, we still have to add it + topN.PushBack(tf) + if topN.Len() > fb.size { + // remove the head + topN.Remove(topN.Front()) + } + + } + + // we now have the list of the top N facets + rv.DateRanges = make([]*search.DateRangeFacet, topN.Len()) + i := 0 + notOther := 0 + for e := topN.Back(); e != nil; e = e.Prev() { + rv.DateRanges[i] = e.Value.(*search.DateRangeFacet) + i++ + notOther += e.Value.(*search.DateRangeFacet).Count + } + rv.Other = fb.total - notOther + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric.go new file mode 100644 index 00000000..b7f57ad2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric.go @@ -0,0 +1,120 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package facets + +import ( + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type numericRange struct { + min *float64 + max *float64 +} + +type NumericFacetBuilder struct { + size int + field string + termsCount map[string]int + total int + missing int + ranges map[string]*numericRange +} + +func NewNumericFacetBuilder(field string, size int) *NumericFacetBuilder { + return &NumericFacetBuilder{ + size: size, + field: field, + termsCount: make(map[string]int), + ranges: make(map[string]*numericRange, 0), + } +} + +func (fb *NumericFacetBuilder) AddRange(name string, min, max *float64) { + r := numericRange{ + min: min, + max: max, + } + fb.ranges[name] = &r +} + +func (fb *NumericFacetBuilder) Update(ft index.FieldTerms) { + terms, ok := ft[fb.field] + if ok { + for _, term := range terms { + // only consider the values which are shifted 0 + prefixCoded := numeric_util.PrefixCoded(term) + shift, err := prefixCoded.Shift() + if err == nil && shift == 0 { + i64, err := prefixCoded.Int64() + if err == nil { + f64 := numeric_util.Int64ToFloat64(i64) + + // look at each of the ranges for a match + for rangeName, r := range fb.ranges { + + if (r.min == nil || f64 >= *r.min) && (r.max == nil || f64 < *r.max) { + + existingCount, existed := fb.termsCount[rangeName] + if existed { + fb.termsCount[rangeName] = existingCount + 1 + } else { + fb.termsCount[rangeName] = 1 + } + fb.total++ + } + } + } + } + } + } else { + fb.missing++ + } +} + +func (fb *NumericFacetBuilder) Result() *search.FacetResult { + rv := search.FacetResult{ + Field: fb.field, + Total: fb.total, + Missing: fb.missing, + } + + rv.NumericRanges = make([]*search.NumericRangeFacet, 0, len(fb.termsCount)) + + for term, count := range fb.termsCount { + numericRange := fb.ranges[term] + tf := &search.NumericRangeFacet{ + Name: term, + Count: count, + Min: numericRange.min, + Max: numericRange.max, + } + + rv.NumericRanges = append(rv.NumericRanges, tf) + } + + sort.Sort(rv.NumericRanges) + + // we now have the list of the top N facets + if fb.size < len(rv.NumericRanges) { + rv.NumericRanges = rv.NumericRanges[:fb.size] + } + + notOther := 0 + for _, nr := range rv.NumericRanges { + notOther += nr.Count + } + rv.Other = fb.total - notOther + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric_test.go new file mode 100644 index 00000000..dfa8d77e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_numeric_test.go @@ -0,0 +1,49 @@ +package facets + +import ( + "strconv" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + nu "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" +) + +var pcodedvalues []nu.PrefixCoded + +func init() { + pcodedvalues = []nu.PrefixCoded{nu.PrefixCoded{0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, nu.PrefixCoded{0x20, 0x0, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}, nu.PrefixCoded{0x20, 0x0, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7a, 0x1d, 0xa}, nu.PrefixCoded{0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x16, 0x9, 0x4a, 0x7b}} +} + +func BenchmarkNumericFacet10(b *testing.B) { + numericFacetN(b, 10) +} + +func BenchmarkNumericFacet100(b *testing.B) { + numericFacetN(b, 100) +} + +func BenchmarkNumericFacet1000(b *testing.B) { + numericFacetN(b, 1000) +} + +func numericFacetN(b *testing.B, numTerms int) { + field := "test" + nfb := NewNumericFacetBuilder(field, numTerms) + min, max := 0.0, 9999999998.0 + + for i := 0; i <= numTerms; i++ { + max++ + min-- + + nfb.AddRange("rangename"+strconv.Itoa(i), &min, &max) + + for _, pv := range pcodedvalues { + nfb.Update(index.FieldTerms{field: []string{string(pv)}}) + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + nfb.Result() + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms.go new file mode 100644 index 00000000..22fc49d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms.go @@ -0,0 +1,86 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package facets + +import ( + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type TermsFacetBuilder struct { + size int + field string + termsCount map[string]int + total int + missing int +} + +func NewTermsFacetBuilder(field string, size int) *TermsFacetBuilder { + return &TermsFacetBuilder{ + size: size, + field: field, + termsCount: make(map[string]int), + } +} + +func (fb *TermsFacetBuilder) Update(ft index.FieldTerms) { + terms, ok := ft[fb.field] + if ok { + for _, term := range terms { + existingCount, existed := fb.termsCount[term] + if existed { + fb.termsCount[term] = existingCount + 1 + } else { + fb.termsCount[term] = 1 + } + fb.total++ + } + } else { + fb.missing++ + } +} + +func (fb *TermsFacetBuilder) Result() *search.FacetResult { + rv := search.FacetResult{ + Field: fb.field, + Total: fb.total, + Missing: fb.missing, + } + + rv.Terms = make([]*search.TermFacet, 0, len(fb.termsCount)) + + for term, count := range fb.termsCount { + tf := &search.TermFacet{ + Term: term, + Count: count, + } + + rv.Terms = append(rv.Terms, tf) + } + + sort.Sort(rv.Terms) + + // we now have the list of the top N facets + trimTopN := fb.size + if trimTopN > len(rv.Terms) { + trimTopN = len(rv.Terms) + } + rv.Terms = rv.Terms[:trimTopN] + + notOther := 0 + for _, tf := range rv.Terms { + notOther += tf.Count + } + rv.Other = fb.total - notOther + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms_test.go new file mode 100644 index 00000000..fa54257e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets/facet_builder_terms_test.go @@ -0,0 +1,58 @@ +package facets + +import ( + "io/ioutil" + "regexp" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" +) + +var terms []string + +func init() { + wsRegexp := regexp.MustCompile(`\W+`) + input, err := ioutil.ReadFile("benchmark_data.txt") + if err != nil { + panic(err) + } + terms = wsRegexp.Split(string(input), -1) +} + +func BenchmarkTermsFacet10(b *testing.B) { + termsFacetN(b, 10) +} + +func BenchmarkTermsFacet100(b *testing.B) { + termsFacetN(b, 100) +} + +func BenchmarkTermsFacet1000(b *testing.B) { + termsFacetN(b, 1000) +} + +func BenchmarkTermsFacet10000(b *testing.B) { + termsFacetN(b, 10000) +} + +// func BenchmarkTermsFacet100000(b *testing.B) { +// termsFacetN(b, 100000) +// } + +func termsFacetN(b *testing.B, numTerms int) { + field := "test" + termsLen := len(terms) + tfb := NewTermsFacetBuilder(field, 3) + i := 0 + for len(tfb.termsCount) < numTerms && i <= termsLen { + j := i % termsLen + term := terms[j] + tfb.Update(index.FieldTerms{field: []string{term}}) + i++ + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + tfb.Result() + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder.go new file mode 100644 index 00000000..6ee7b72f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder.go @@ -0,0 +1,212 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +import ( + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" +) + +type FacetBuilder interface { + Update(index.FieldTerms) + Result() *FacetResult +} + +type FacetsBuilder struct { + indexReader index.IndexReader + facets map[string]FacetBuilder +} + +func NewFacetsBuilder(indexReader index.IndexReader) *FacetsBuilder { + return &FacetsBuilder{ + indexReader: indexReader, + facets: make(map[string]FacetBuilder, 0), + } +} + +func (fb *FacetsBuilder) Add(name string, facetBuilder FacetBuilder) { + fb.facets[name] = facetBuilder +} + +func (fb *FacetsBuilder) Update(docMatch *DocumentMatch) error { + fieldTerms, err := fb.indexReader.DocumentFieldTerms(docMatch.ID) + if err != nil { + return err + } + for _, facetBuilder := range fb.facets { + facetBuilder.Update(fieldTerms) + } + return nil +} + +type TermFacet struct { + Term string `json:"term"` + Count int `json:"count"` +} + +type TermFacets []*TermFacet + +func (tf TermFacets) Add(termFacet *TermFacet) TermFacets { + for _, existingTerm := range tf { + if termFacet.Term == existingTerm.Term { + existingTerm.Count += termFacet.Count + return tf + } + } + // if we got here it wasn't already in the existing terms + tf = append(tf, termFacet) + return tf +} + +func (tf TermFacets) Len() int { return len(tf) } +func (tf TermFacets) Swap(i, j int) { tf[i], tf[j] = tf[j], tf[i] } +func (tf TermFacets) Less(i, j int) bool { return tf[i].Count > tf[j].Count } + +type NumericRangeFacet struct { + Name string `json:"name"` + Min *float64 `json:"min,omitempty"` + Max *float64 `json:"max,omitempty"` + Count int `json:"count"` +} + +type NumericRangeFacets []*NumericRangeFacet + +func (nrf NumericRangeFacets) Add(numericRangeFacet *NumericRangeFacet) NumericRangeFacets { + for _, existingNr := range nrf { + if numericRangeFacet.Min == existingNr.Min && numericRangeFacet.Max == existingNr.Max { + existingNr.Count += numericRangeFacet.Count + return nrf + } + } + // if we got here it wasn't already in the existing terms + nrf = append(nrf, numericRangeFacet) + return nrf +} + +func (nrf NumericRangeFacets) Len() int { return len(nrf) } +func (nrf NumericRangeFacets) Swap(i, j int) { nrf[i], nrf[j] = nrf[j], nrf[i] } +func (nrf NumericRangeFacets) Less(i, j int) bool { return nrf[i].Count > nrf[j].Count } + +type DateRangeFacet struct { + Name string `json:"name"` + Start *string `json:"start,omitempty"` + End *string `json:"end,omitempty"` + Count int `json:"count"` +} + +type DateRangeFacets []*DateRangeFacet + +func (drf DateRangeFacets) Add(dateRangeFacet *DateRangeFacet) DateRangeFacets { + for _, existingDr := range drf { + if dateRangeFacet.Start == existingDr.Start && dateRangeFacet.End == existingDr.End { + existingDr.Count += dateRangeFacet.Count + return drf + } + } + // if we got here it wasn't already in the existing terms + drf = append(drf, dateRangeFacet) + return drf +} + +func (drf DateRangeFacets) Len() int { return len(drf) } +func (drf DateRangeFacets) Swap(i, j int) { drf[i], drf[j] = drf[j], drf[i] } +func (drf DateRangeFacets) Less(i, j int) bool { return drf[i].Count > drf[j].Count } + +type FacetResult struct { + Field string `json:"field"` + Total int `json:"total"` + Missing int `json:"missing"` + Other int `json:"other"` + Terms TermFacets `json:"terms,omitempty"` + NumericRanges NumericRangeFacets `json:"numeric_ranges,omitempty"` + DateRanges DateRangeFacets `json:"date_ranges,omitempty"` +} + +func (fr *FacetResult) Merge(other *FacetResult) { + fr.Total += other.Total + fr.Missing += other.Missing + fr.Other += other.Other + if fr.Terms != nil && other.Terms != nil { + for _, term := range other.Terms { + fr.Terms = fr.Terms.Add(term) + } + } + if fr.NumericRanges != nil && other.NumericRanges != nil { + for _, nr := range other.NumericRanges { + fr.NumericRanges = fr.NumericRanges.Add(nr) + } + } + if fr.DateRanges != nil && other.DateRanges != nil { + for _, dr := range other.DateRanges { + fr.DateRanges = fr.DateRanges.Add(dr) + } + } +} + +func (fr *FacetResult) Fixup(size int) { + if fr.Terms != nil { + sort.Sort(fr.Terms) + if len(fr.Terms) > size { + moveToOther := fr.Terms[size:] + for _, mto := range moveToOther { + fr.Other += mto.Count + } + fr.Terms = fr.Terms[0:size] + } + } else if fr.NumericRanges != nil { + sort.Sort(fr.NumericRanges) + if len(fr.NumericRanges) > size { + moveToOther := fr.NumericRanges[size:] + for _, mto := range moveToOther { + fr.Other += mto.Count + } + fr.NumericRanges = fr.NumericRanges[0:size] + } + } else if fr.DateRanges != nil { + sort.Sort(fr.DateRanges) + if len(fr.DateRanges) > size { + moveToOther := fr.DateRanges[size:] + for _, mto := range moveToOther { + fr.Other += mto.Count + } + fr.DateRanges = fr.DateRanges[0:size] + } + } +} + +type FacetResults map[string]*FacetResult + +func (fr FacetResults) Merge(other FacetResults) { + for name, oFacetResult := range other { + facetResult, ok := fr[name] + if ok { + facetResult.Merge(oFacetResult) + } else { + fr[name] = oFacetResult + } + } +} + +func (fr FacetResults) Fixup(name string, size int) { + facetResult, ok := fr[name] + if ok { + facetResult.Fixup(size) + } +} + +func (fb *FacetsBuilder) Results() FacetResults { + fr := make(FacetResults) + for facetName, facetBuilder := range fb.facets { + facetResult := facetBuilder.Result() + fr[facetName] = facetResult + } + return fr +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder_test.go new file mode 100644 index 00000000..7e7b66ef --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/facets_builder_test.go @@ -0,0 +1,301 @@ +package search + +import ( + "reflect" + "testing" +) + +func TestTermFacetResultsMerge(t *testing.T) { + + fr1 := &FacetResult{ + Field: "type", + Total: 100, + Missing: 25, + Other: 25, + Terms: []*TermFacet{ + &TermFacet{ + Term: "blog", + Count: 25, + }, + &TermFacet{ + Term: "comment", + Count: 24, + }, + &TermFacet{ + Term: "feedback", + Count: 1, + }, + }, + } + fr1Only := &FacetResult{ + Field: "category", + Total: 97, + Missing: 22, + Other: 15, + Terms: []*TermFacet{ + &TermFacet{ + Term: "clothing", + Count: 35, + }, + &TermFacet{ + Term: "electronics", + Count: 25, + }, + }, + } + frs1 := FacetResults{ + "types": fr1, + "categories": fr1Only, + } + + fr2 := &FacetResult{ + Field: "type", + Total: 100, + Missing: 25, + Other: 25, + Terms: []*TermFacet{ + &TermFacet{ + Term: "blog", + Count: 25, + }, + &TermFacet{ + Term: "comment", + Count: 22, + }, + &TermFacet{ + Term: "flag", + Count: 3, + }, + }, + } + frs2 := FacetResults{ + "types": fr2, + } + + expectedFr := &FacetResult{ + Field: "type", + Total: 200, + Missing: 50, + Other: 51, + Terms: []*TermFacet{ + &TermFacet{ + Term: "blog", + Count: 50, + }, + &TermFacet{ + Term: "comment", + Count: 46, + }, + &TermFacet{ + Term: "flag", + Count: 3, + }, + }, + } + expectedFrs := FacetResults{ + "types": expectedFr, + "categories": fr1Only, + } + + frs1.Merge(frs2) + frs1.Fixup("types", 3) + if !reflect.DeepEqual(frs1, expectedFrs) { + t.Errorf("expected %v, got %v", expectedFrs, frs1) + } +} + +func TestNumericFacetResultsMerge(t *testing.T) { + + lowmed := 3.0 + medhi := 6.0 + hihigher := 9.0 + + fr1 := &FacetResult{ + Field: "rating", + Total: 100, + Missing: 25, + Other: 25, + NumericRanges: []*NumericRangeFacet{ + &NumericRangeFacet{ + Name: "low", + Max: &lowmed, + Count: 25, + }, + &NumericRangeFacet{ + Name: "med", + Count: 24, + Max: &lowmed, + Min: &medhi, + }, + &NumericRangeFacet{ + Name: "hi", + Count: 1, + Min: &medhi, + Max: &hihigher, + }, + }, + } + frs1 := FacetResults{ + "ratings": fr1, + } + + fr2 := &FacetResult{ + Field: "rating", + Total: 100, + Missing: 25, + Other: 25, + NumericRanges: []*NumericRangeFacet{ + &NumericRangeFacet{ + Name: "low", + Max: &lowmed, + Count: 25, + }, + &NumericRangeFacet{ + Name: "med", + Max: &lowmed, + Min: &medhi, + Count: 22, + }, + &NumericRangeFacet{ + Name: "highest", + Min: &hihigher, + Count: 3, + }, + }, + } + frs2 := FacetResults{ + "ratings": fr2, + } + + expectedFr := &FacetResult{ + Field: "rating", + Total: 200, + Missing: 50, + Other: 51, + NumericRanges: []*NumericRangeFacet{ + &NumericRangeFacet{ + Name: "low", + Count: 50, + Max: &lowmed, + }, + &NumericRangeFacet{ + Name: "med", + Max: &lowmed, + Min: &medhi, + Count: 46, + }, + &NumericRangeFacet{ + Name: "highest", + Min: &hihigher, + Count: 3, + }, + }, + } + expectedFrs := FacetResults{ + "ratings": expectedFr, + } + + frs1.Merge(frs2) + frs1.Fixup("ratings", 3) + if !reflect.DeepEqual(frs1, expectedFrs) { + t.Errorf("expected %#v, got %#v", expectedFrs, frs1) + } +} + +func TestDateFacetResultsMerge(t *testing.T) { + + lowmed := "2010-01-01" + medhi := "2011-01-01" + hihigher := "2012-01-01" + + fr1 := &FacetResult{ + Field: "birthday", + Total: 100, + Missing: 25, + Other: 25, + DateRanges: []*DateRangeFacet{ + &DateRangeFacet{ + Name: "low", + End: &lowmed, + Count: 25, + }, + &DateRangeFacet{ + Name: "med", + Count: 24, + Start: &lowmed, + End: &medhi, + }, + &DateRangeFacet{ + Name: "hi", + Count: 1, + Start: &medhi, + End: &hihigher, + }, + }, + } + frs1 := FacetResults{ + "birthdays": fr1, + } + + fr2 := &FacetResult{ + Field: "birthday", + Total: 100, + Missing: 25, + Other: 25, + DateRanges: []*DateRangeFacet{ + &DateRangeFacet{ + Name: "low", + End: &lowmed, + Count: 25, + }, + &DateRangeFacet{ + Name: "med", + Start: &lowmed, + End: &medhi, + Count: 22, + }, + &DateRangeFacet{ + Name: "highest", + Start: &hihigher, + Count: 3, + }, + }, + } + frs2 := FacetResults{ + "birthdays": fr2, + } + + expectedFr := &FacetResult{ + Field: "birthday", + Total: 200, + Missing: 50, + Other: 51, + DateRanges: []*DateRangeFacet{ + &DateRangeFacet{ + Name: "low", + Count: 50, + End: &lowmed, + }, + &DateRangeFacet{ + Name: "med", + Start: &lowmed, + End: &medhi, + Count: 46, + }, + &DateRangeFacet{ + Name: "highest", + Start: &hihigher, + Count: 3, + }, + }, + } + expectedFrs := FacetResults{ + "birthdays": expectedFr, + } + + frs1.Merge(frs2) + frs1.Fixup("birthdays", 3) + if !reflect.DeepEqual(frs1, expectedFrs) { + t.Errorf("expected %#v, got %#v", expectedFrs, frs1) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi/fragment_formatter_ansi.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi/fragment_formatter_ansi.go new file mode 100644 index 00000000..49d43b7e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi/fragment_formatter_ansi.go @@ -0,0 +1,100 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package ansi + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +const Name = "ansi" + +const DefaultAnsiHighlight = BgYellow + +type FragmentFormatter struct { + color string +} + +func NewFragmentFormatter(color string) *FragmentFormatter { + return &FragmentFormatter{ + color: color, + } +} + +func (a *FragmentFormatter) Format(f *highlight.Fragment, orderedTermLocations highlight.TermLocations) string { + rv := "" + curr := f.Start + for _, termLocation := range orderedTermLocations { + if termLocation == nil { + continue + } + if termLocation.Start < curr { + continue + } + if termLocation.End > f.End { + break + } + // add the stuff before this location + rv += string(f.Orig[curr:termLocation.Start]) + // add the color + rv += a.color + // add the term itself + rv += string(f.Orig[termLocation.Start:termLocation.End]) + // reset the color + rv += Reset + // update current + curr = termLocation.End + } + // add any remaining text after the last token + rv += string(f.Orig[curr:f.End]) + + return rv +} + +// ANSI color control escape sequences. +// Shamelessly copied from https://github.com/sqp/godock/blob/master/libs/log/colors.go +const ( + Reset = "\x1b[0m" + Bright = "\x1b[1m" + Dim = "\x1b[2m" + Underscore = "\x1b[4m" + Blink = "\x1b[5m" + Reverse = "\x1b[7m" + Hidden = "\x1b[8m" + FgBlack = "\x1b[30m" + FgRed = "\x1b[31m" + FgGreen = "\x1b[32m" + FgYellow = "\x1b[33m" + FgBlue = "\x1b[34m" + FgMagenta = "\x1b[35m" + FgCyan = "\x1b[36m" + FgWhite = "\x1b[37m" + BgBlack = "\x1b[40m" + BgRed = "\x1b[41m" + BgGreen = "\x1b[42m" + BgYellow = "\x1b[43m" + BgBlue = "\x1b[44m" + BgMagenta = "\x1b[45m" + BgCyan = "\x1b[46m" + BgWhite = "\x1b[47m" +) + +func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.FragmentFormatter, error) { + color := DefaultAnsiHighlight + colorVal, ok := config["color"].(string) + if ok { + color = colorVal + } + return NewFragmentFormatter(color), nil +} + +func init() { + registry.RegisterFragmentFormatter(Name, Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html.go new file mode 100644 index 00000000..61a7278a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package html + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +const Name = "html" + +const defaultHTMLHighlightBefore = "" +const defaultHTMLHighlightAfter = "" + +type FragmentFormatter struct { + before string + after string +} + +func NewFragmentFormatter(before, after string) *FragmentFormatter { + return &FragmentFormatter{ + before: before, + after: after, + } +} + +func (a *FragmentFormatter) Format(f *highlight.Fragment, orderedTermLocations highlight.TermLocations) string { + rv := "" + curr := f.Start + for _, termLocation := range orderedTermLocations { + if termLocation == nil { + continue + } + if termLocation.Start < curr { + continue + } + if termLocation.End > f.End { + break + } + // add the stuff before this location + rv += string(f.Orig[curr:termLocation.Start]) + // add the color + rv += a.before + // add the term itself + rv += string(f.Orig[termLocation.Start:termLocation.End]) + // reset the color + rv += a.after + // update current + curr = termLocation.End + } + // add any remaining text after the last token + rv += string(f.Orig[curr:f.End]) + + return rv +} + +func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.FragmentFormatter, error) { + before := defaultHTMLHighlightBefore + beforeVal, ok := config["before"].(string) + if ok { + before = beforeVal + } + after := defaultHTMLHighlightAfter + afterVal, ok := config["after"].(string) + if ok { + after = afterVal + } + return NewFragmentFormatter(before, after), nil +} + +func init() { + registry.RegisterFragmentFormatter(Name, Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html_test.go new file mode 100644 index 00000000..f2204ec5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/html/fragment_formatter_html_test.go @@ -0,0 +1,87 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package html + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +func TestHTMLFragmentFormatter1(t *testing.T) { + tests := []struct { + fragment *highlight.Fragment + tlm search.TermLocationMap + output string + }{ + { + fragment: &highlight.Fragment{ + Orig: []byte("the quick brown fox"), + Start: 0, + End: 19, + }, + tlm: search.TermLocationMap{ + "quick": search.Locations{ + &search.Location{ + Pos: 2, + Start: 4, + End: 9, + }, + }, + }, + output: "the quick brown fox", + }, + } + + emHTMLFormatter := NewFragmentFormatter("", "") + for _, test := range tests { + otl := highlight.OrderTermLocations(test.tlm) + result := emHTMLFormatter.Format(test.fragment, otl) + if result != test.output { + t.Errorf("expected `%s`, got `%s`", test.output, result) + } + } +} + +func TestHTMLFragmentFormatter2(t *testing.T) { + tests := []struct { + fragment *highlight.Fragment + tlm search.TermLocationMap + output string + }{ + { + fragment: &highlight.Fragment{ + Orig: []byte("the quick brown fox"), + Start: 0, + End: 19, + }, + tlm: search.TermLocationMap{ + "quick": search.Locations{ + &search.Location{ + Pos: 2, + Start: 4, + End: 9, + }, + }, + }, + output: "the quick brown fox", + }, + } + + emHTMLFormatter := NewFragmentFormatter("", "") + for _, test := range tests { + otl := highlight.OrderTermLocations(test.tlm) + result := emHTMLFormatter.Format(test.fragment, otl) + if result != test.output { + t.Errorf("expected `%s`, got `%s`", test.output, result) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple.go new file mode 100644 index 00000000..1f041128 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple.go @@ -0,0 +1,138 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple + +import ( + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +const Name = "simple" + +const defaultFragmentSize = 200 + +type Fragmenter struct { + fragmentSize int +} + +func NewFragmenter(fragmentSize int) *Fragmenter { + return &Fragmenter{ + fragmentSize: fragmentSize, + } +} + +func (s *Fragmenter) Fragment(orig []byte, ot highlight.TermLocations) []*highlight.Fragment { + rv := make([]*highlight.Fragment, 0) + + maxbegin := 0 +OUTER: + for currTermIndex, termLocation := range ot { + // start with this + // it should be the highest scoring fragment with this term first + start := termLocation.Start + end := start + used := 0 + for end < len(orig) && used < s.fragmentSize { + r, size := utf8.DecodeRune(orig[end:]) + if r == utf8.RuneError { + continue OUTER // bail + } + end += size + used += 1 + } + + // if we still have more characters available to us + // push back towards begining + // without cross maxbegin + for start > 0 && used < s.fragmentSize { + r, size := utf8.DecodeLastRune(orig[0:start]) + if r == utf8.RuneError { + continue OUTER // bail + } + if start-size >= maxbegin { + start -= size + used += 1 + } else { + break + } + } + + // however, we'd rather have the tokens centered more in the frag + // lets try to do that as best we can, without affecting the score + // find the end of the last term in this fragment + minend := end + for _, innerTermLocation := range ot[currTermIndex:] { + if innerTermLocation.End > end { + break + } + minend = innerTermLocation.End + } + + // find the smaller of the two rooms to move + roomToMove := utf8.RuneCount(orig[minend:end]) + roomToMoveStart := 0 + if start >= maxbegin { + roomToMoveStart = utf8.RuneCount(orig[maxbegin:start]) + } + if roomToMoveStart < roomToMove { + roomToMove = roomToMoveStart + } + + offset := roomToMove / 2 + + for offset > 0 { + r, size := utf8.DecodeLastRune(orig[0:start]) + if r == utf8.RuneError { + continue OUTER // bail + } + start -= size + + r, size = utf8.DecodeLastRune(orig[0:end]) + if r == utf8.RuneError { + continue OUTER // bail + } + end -= size + offset-- + } + + rv = append(rv, &highlight.Fragment{Orig: orig, Start: start - offset, End: end - offset}) + // set maxbegin to the end of the current term location + // so that next one won't back up to include it + maxbegin = termLocation.End + + } + if len(ot) == 0 { + // if there were no terms to highlight + // produce a single fragment from the beginning + start := 0 + end := start + s.fragmentSize + if end > len(orig) { + end = len(orig) + } + rv = append(rv, &highlight.Fragment{Orig: orig, Start: start, End: end}) + } + + return rv +} + +func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.Fragmenter, error) { + size := defaultFragmentSize + sizeVal, ok := config["size"].(float64) + if ok { + size = int(sizeVal) + } + return NewFragmenter(size), nil +} + +func init() { + registry.RegisterFragmenter(Name, Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple_test.go new file mode 100644 index 00000000..fee1e712 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple/fragmenter_simple_test.go @@ -0,0 +1,295 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +func TestSimpleFragmenter(t *testing.T) { + + tests := []struct { + orig []byte + fragments []*highlight.Fragment + ot highlight.TermLocations + size int + }{ + { + orig: []byte("this is a test"), + fragments: []*highlight.Fragment{ + &highlight.Fragment{ + Orig: []byte("this is a test"), + Start: 0, + End: 14, + }, + }, + ot: highlight.TermLocations{ + &highlight.TermLocation{ + Term: "test", + Pos: 4, + Start: 10, + End: 14, + }, + }, + size: 100, + }, + { + orig: []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"), + fragments: []*highlight.Fragment{ + &highlight.Fragment{ + Orig: []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"), + Start: 0, + End: 100, + }, + }, + ot: highlight.TermLocations{ + &highlight.TermLocation{ + Term: "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", + Pos: 1, + Start: 0, + End: 100, + }, + }, + size: 100, + }, + { + orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + fragments: []*highlight.Fragment{ + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 0, + End: 100, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 10, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 20, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 30, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 40, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 50, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 60, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 70, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 80, + End: 101, + }, + &highlight.Fragment{ + Orig: []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + Start: 90, + End: 101, + }, + }, + ot: highlight.TermLocations{ + &highlight.TermLocation{ + Term: "0123456789", + Pos: 1, + Start: 0, + End: 10, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 2, + Start: 10, + End: 20, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 3, + Start: 20, + End: 30, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 4, + Start: 30, + End: 40, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 5, + Start: 40, + End: 50, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 6, + Start: 50, + End: 60, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 7, + Start: 60, + End: 70, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 8, + Start: 70, + End: 80, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 9, + Start: 80, + End: 90, + }, + &highlight.TermLocation{ + Term: "0123456789", + Pos: 10, + Start: 90, + End: 100, + }, + }, + size: 100, + }, + { + orig: []byte("[[पानी का स्वाद]] [[नीलेश रघुवंशी]] का कविता संग्रह हैं। इस कृति के लिए उन्हें २००४ में [[केदार सम्मान]] से सम्मानित किया गया है।{{केदार सम्मान से सम्मानित कृतियाँ}}"), + fragments: []*highlight.Fragment{ + &highlight.Fragment{ + Orig: []byte("[[पानी का स्वाद]] [[नीलेश रघुवंशी]] का कविता संग्रह हैं। इस कृति के लिए उन्हें २००४ में [[केदार सम्मान]] से सम्मानित किया गया है।{{केदार सम्मान से सम्मानित कृतियाँ}}"), + Start: 0, + End: 411, + }, + }, + ot: highlight.TermLocations{ + &highlight.TermLocation{ + Term: "पानी", + Pos: 1, + Start: 2, + End: 14, + }, + }, + size: 200, + }, + { + orig: []byte("交换机"), + fragments: []*highlight.Fragment{ + &highlight.Fragment{ + Orig: []byte("交换机"), + Start: 0, + End: 9, + }, + &highlight.Fragment{ + Orig: []byte("交换机"), + Start: 3, + End: 9, + }, + }, + ot: highlight.TermLocations{ + &highlight.TermLocation{ + Term: "交换", + Pos: 1, + Start: 0, + End: 6, + }, + &highlight.TermLocation{ + Term: "换机", + Pos: 2, + Start: 3, + End: 9, + }, + }, + size: 200, + }, + } + + for _, test := range tests { + fragmenter := NewFragmenter(test.size) + fragments := fragmenter.Fragment(test.orig, test.ot) + if !reflect.DeepEqual(fragments, test.fragments) { + t.Errorf("expected %#v, got %#v", test.fragments, fragments) + for _, fragment := range fragments { + t.Logf("frag: %s", fragment.Orig[fragment.Start:fragment.End]) + t.Logf("frag: %d - %d", fragment.Start, fragment.End) + } + } + } +} + +func TestSimpleFragmenterWithSize(t *testing.T) { + + tests := []struct { + orig []byte + fragments []*highlight.Fragment + ot highlight.TermLocations + }{ + { + orig: []byte("this is a test"), + fragments: []*highlight.Fragment{ + &highlight.Fragment{ + Orig: []byte("this is a test"), + Start: 0, + End: 5, + }, + &highlight.Fragment{ + Orig: []byte("this is a test"), + Start: 9, + End: 14, + }, + }, + ot: highlight.TermLocations{ + &highlight.TermLocation{ + Term: "this", + Pos: 1, + Start: 0, + End: 5, + }, + &highlight.TermLocation{ + Term: "test", + Pos: 4, + Start: 10, + End: 14, + }, + }, + }, + } + + fragmenter := NewFragmenter(5) + for _, test := range tests { + fragments := fragmenter.Fragment(test.orig, test.ot) + if !reflect.DeepEqual(fragments, test.fragments) { + t.Errorf("expected %#v, got %#v", test.fragments, fragments) + for _, fragment := range fragments { + t.Logf("frag: %#v", fragment) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighter.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighter.go new file mode 100644 index 00000000..e70880ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighter.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package highlight + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type Fragment struct { + Orig []byte + Start int + End int + Score float64 + Index int // used by heap +} + +func (f *Fragment) Overlaps(other *Fragment) bool { + if other.Start >= f.Start && other.Start < f.End { + return true + } else if f.Start >= other.Start && f.Start < other.End { + return true + } + return false +} + +type Fragmenter interface { + Fragment([]byte, TermLocations) []*Fragment +} + +type FragmentFormatter interface { + Format(f *Fragment, orderedTermLocations TermLocations) string +} + +type FragmentScorer interface { + Score(f *Fragment) float64 +} + +type Highlighter interface { + Fragmenter() Fragmenter + SetFragmenter(Fragmenter) + + FragmentFormatter() FragmentFormatter + SetFragmentFormatter(FragmentFormatter) + + Separator() string + SetSeparator(string) + + BestFragmentInField(*search.DocumentMatch, *document.Document, string) string + BestFragmentsInField(*search.DocumentMatch, *document.Document, string, int) []string +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple.go new file mode 100644 index 00000000..3774b648 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple.go @@ -0,0 +1,44 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +// FragmentScorer will score fragments by how many +// unique terms occur in the fragment with no regard for +// any boost values used in the original query +type FragmentScorer struct { + tlm search.TermLocationMap +} + +func NewFragmentScorer(tlm search.TermLocationMap) *FragmentScorer { + return &FragmentScorer{ + tlm: tlm, + } +} + +func (s *FragmentScorer) Score(f *highlight.Fragment) { + score := 0.0 +OUTER: + for _, locations := range s.tlm { + for _, location := range locations { + if int(location.Start) >= f.Start && int(location.End) <= f.End { + score += 1.0 + // once we find a term in the fragment + // don't care about additional matches + continue OUTER + } + } + } + f.Score = score +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple_test.go new file mode 100644 index 00000000..2e101aee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/fragment_scorer_simple_test.go @@ -0,0 +1,77 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +func TestSimpleFragmentScorer(t *testing.T) { + + tests := []struct { + fragment *highlight.Fragment + tlm search.TermLocationMap + score float64 + }{ + { + fragment: &highlight.Fragment{ + Orig: []byte("cat in the hat"), + Start: 0, + End: 14, + }, + tlm: search.TermLocationMap{ + "cat": search.Locations{ + &search.Location{ + Pos: 0, + Start: 0, + End: 3, + }, + }, + }, + score: 1, + }, + { + fragment: &highlight.Fragment{ + Orig: []byte("cat in the hat"), + Start: 0, + End: 14, + }, + tlm: search.TermLocationMap{ + "cat": search.Locations{ + &search.Location{ + Pos: 1, + Start: 0, + End: 3, + }, + }, + "hat": search.Locations{ + &search.Location{ + Pos: 4, + Start: 11, + End: 14, + }, + }, + }, + score: 2, + }, + } + + for _, test := range tests { + scorer := NewFragmentScorer(test.tlm) + scorer.Score(test.fragment) + if test.fragment.Score != test.score { + t.Errorf("expected score %f, got %f", test.score, test.fragment.Score) + } + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple.go new file mode 100644 index 00000000..de9b587a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple.go @@ -0,0 +1,208 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple + +import ( + "container/heap" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight" +) + +const Name = "simple" +const defaultSeparator = "…" + +type Highlighter struct { + fragmenter highlight.Fragmenter + formatter highlight.FragmentFormatter + sep string +} + +func NewHighlighter(fragmenter highlight.Fragmenter, formatter highlight.FragmentFormatter, separator string) *Highlighter { + return &Highlighter{ + fragmenter: fragmenter, + formatter: formatter, + sep: separator, + } +} + +func (s *Highlighter) Fragmenter() highlight.Fragmenter { + return s.fragmenter +} + +func (s *Highlighter) SetFragmenter(f highlight.Fragmenter) { + s.fragmenter = f +} + +func (s *Highlighter) FragmentFormatter() highlight.FragmentFormatter { + return s.formatter +} + +func (s *Highlighter) SetFragmentFormatter(f highlight.FragmentFormatter) { + s.formatter = f +} + +func (s *Highlighter) Separator() string { + return s.sep +} + +func (s *Highlighter) SetSeparator(sep string) { + s.sep = sep +} + +func (s *Highlighter) BestFragmentInField(dm *search.DocumentMatch, doc *document.Document, field string) string { + fragments := s.BestFragmentsInField(dm, doc, field, 1) + if len(fragments) > 0 { + return fragments[0] + } + return "" +} + +func (s *Highlighter) BestFragmentsInField(dm *search.DocumentMatch, doc *document.Document, field string, num int) []string { + tlm := dm.Locations[field] + orderedTermLocations := highlight.OrderTermLocations(tlm) + scorer := NewFragmentScorer(tlm) + + // score the fragments and put them into a priority queue ordered by score + fq := make(FragmentQueue, 0) + heap.Init(&fq) + for _, f := range doc.Fields { + if f.Name() == field { + _, ok := f.(*document.TextField) + if ok { + fieldData := f.Value() + fragments := s.fragmenter.Fragment(fieldData, orderedTermLocations) + for _, fragment := range fragments { + scorer.Score(fragment) + heap.Push(&fq, fragment) + } + } + } + } + + // now find the N best non-overlapping fragments + bestFragments := make([]*highlight.Fragment, 0) + if len(fq) > 0 { + candidate := heap.Pop(&fq) + OUTER: + for candidate != nil && len(bestFragments) < num { + // see if this overlaps with any of the best already identified + if len(bestFragments) > 0 { + for _, frag := range bestFragments { + if candidate.(*highlight.Fragment).Overlaps(frag) { + if len(fq) < 1 { + break OUTER + } + candidate = heap.Pop(&fq) + continue OUTER + } + } + bestFragments = append(bestFragments, candidate.(*highlight.Fragment)) + } else { + bestFragments = append(bestFragments, candidate.(*highlight.Fragment)) + } + + if len(fq) < 1 { + break + } + candidate = heap.Pop(&fq) + } + } + + // now that we have the best fragments, we can format them + orderedTermLocations.MergeOverlapping() + formattedFragments := make([]string, len(bestFragments)) + for i, fragment := range bestFragments { + formattedFragments[i] = "" + if fragment.Start != 0 { + formattedFragments[i] += s.sep + } + formattedFragments[i] += s.formatter.Format(fragment, orderedTermLocations) + if fragment.End != len(fragment.Orig) { + formattedFragments[i] += s.sep + } + } + + if dm.Fragments == nil { + dm.Fragments = make(search.FieldFragmentMap, 0) + } + if len(formattedFragments) > 0 { + dm.Fragments[field] = formattedFragments + } + + return formattedFragments +} + +// FragmentQueue implements heap.Interface and holds Items. +type FragmentQueue []*highlight.Fragment + +func (fq FragmentQueue) Len() int { return len(fq) } + +func (fq FragmentQueue) Less(i, j int) bool { + // We want Pop to give us the highest, not lowest, priority so we use greater-than here. + return fq[i].Score > fq[j].Score +} + +func (fq FragmentQueue) Swap(i, j int) { + fq[i], fq[j] = fq[j], fq[i] + fq[i].Index = i + fq[j].Index = j +} + +func (fq *FragmentQueue) Push(x interface{}) { + n := len(*fq) + item := x.(*highlight.Fragment) + item.Index = n + *fq = append(*fq, item) +} + +func (fq *FragmentQueue) Pop() interface{} { + old := *fq + n := len(old) + item := old[n-1] + item.Index = -1 // for safety + *fq = old[0 : n-1] + return item +} + +func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.Highlighter, error) { + separator := defaultSeparator + separatorVal, ok := config["separator"].(string) + if ok { + separator = separatorVal + } + + fragmenterName, ok := config["fragmenter"].(string) + if !ok { + return nil, fmt.Errorf("must specify fragmenter") + } + fragmenter, err := cache.FragmenterNamed(fragmenterName) + if err != nil { + return nil, fmt.Errorf("error building fragmenter: %v", err) + } + + formatterName, ok := config["formatter"].(string) + if !ok { + return nil, fmt.Errorf("must specify formatter") + } + formatter, err := cache.FragmentFormatterNamed(formatterName) + if err != nil { + return nil, fmt.Errorf("error building fragment formatter: %v", err) + } + + return NewHighlighter(fragmenter, formatter, separator), nil +} + +func init() { + registry.RegisterHighlighter(Name, Constructor) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple_test.go new file mode 100644 index 00000000..99a46be0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/highlighters/simple/highlighter_simple_test.go @@ -0,0 +1,164 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package simple + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragment_formatters/ansi" + sfrag "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/fragmenters/simple" +) + +const ( + reset = "\x1b[0m" + DefaultAnsiHighlight = "\x1b[43m" +) + +func TestSimpleHighlighter(t *testing.T) { + fragmenter := sfrag.NewFragmenter(100) + formatter := ansi.NewFragmentFormatter(ansi.DefaultAnsiHighlight) + highlighter := NewHighlighter(fragmenter, formatter, defaultSeparator) + + docMatch := search.DocumentMatch{ + ID: "a", + Score: 1.0, + Locations: search.FieldTermLocationMap{ + "desc": search.TermLocationMap{ + "quick": search.Locations{ + &search.Location{ + Pos: 2, + Start: 4, + End: 9, + }, + }, + "fox": search.Locations{ + &search.Location{ + Pos: 4, + Start: 16, + End: 19, + }, + }, + }, + }, + } + + expectedFragment := "the " + DefaultAnsiHighlight + "quick" + reset + " brown " + DefaultAnsiHighlight + "fox" + reset + " jumps over the lazy dog" + doc := document.NewDocument("a").AddField(document.NewTextField("desc", []uint64{}, []byte("the quick brown fox jumps over the lazy dog"))) + + fragment := highlighter.BestFragmentInField(&docMatch, doc, "desc") + if fragment != expectedFragment { + t.Errorf("expected `%s`, got `%s`", expectedFragment, fragment) + } +} + +func TestSimpleHighlighterLonger(t *testing.T) { + + fieldBytes := []byte(`Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sed semper nulla, sed pellentesque urna. Suspendisse potenti. Aliquam dignissim pulvinar erat vel ullamcorper. Nullam sed diam at dolor dapibus varius. Vestibulum at semper nunc. Integer ullamcorper enim ut nisi condimentum lacinia. Nulla ipsum ipsum, dictum in dapibus non, bibendum eget neque. Vestibulum malesuada erat quis malesuada dictum. Mauris luctus viverra lorem, nec hendrerit lacus lacinia ut. Donec suscipit sit amet nisi et dictum. Maecenas ultrices mollis diam, vel commodo libero lobortis nec. Nunc non dignissim dolor. Nulla non tempus risus, eget porttitor lectus. Suspendisse vitae gravida magna, a sagittis urna. Curabitur nec dui volutpat, hendrerit nisi non, adipiscing erat. Maecenas aliquet sem sit amet nibh ultrices accumsan. + +Mauris lobortis sem sed blandit bibendum. In scelerisque eros sed metus aliquet convallis ac eget metus. Donec eget feugiat sem. Quisque venenatis, augue et blandit vulputate, velit odio viverra dolor, eu iaculis eros urna ut nunc. Duis faucibus mattis enim ut ultricies. Donec scelerisque volutpat elit, vel varius ante porttitor vel. Duis neque nulla, ultrices vel est id, molestie semper odio. Maecenas condimentum felis vitae nibh venenatis, ut feugiat risus vehicula. Suspendisse non sapien neque. Etiam et lorem consequat lorem aliquam ullamcorper. Pellentesque id vestibulum neque, at aliquam turpis. Aenean ultrices nec erat sit amet aliquam. Morbi eu sem in augue cursus ullamcorper a sed dolor. Integer et lobortis nulla, sit amet laoreet elit. In elementum, nibh nec volutpat pretium, lectus est pulvinar arcu, vehicula lobortis tellus sem id mauris. Maecenas ac blandit purus, sit amet scelerisque magna. + +In hac habitasse platea dictumst. In lacinia elit non risus venenatis viverra. Nulla vestibulum laoreet turpis ac accumsan. Vivamus eros felis, rhoncus vel interdum bibendum, imperdiet nec diam. Etiam sed eros sed orci pellentesque sagittis. Praesent a fermentum leo. Vivamus ipsum risus, faucibus a dignissim ut, ullamcorper nec risus. Etiam quis adipiscing velit. Nam ac cursus arcu. Sed bibendum lectus quis massa dapibus dapibus. Vestibulum fermentum eros vitae hendrerit condimentum. + +Fusce viverra eleifend iaculis. Maecenas tempor dictum cursus. Mauris faucibus, tortor in bibendum ornare, nibh lorem sollicitudin est, sed consectetur nulla dui imperdiet urna. Fusce aliquet odio fermentum massa mollis, id feugiat lacus egestas. Integer et eleifend metus. Duis neque tellus, vulputate nec dui eu, euismod sodales orci. Vivamus turpis erat, consectetur et pulvinar nec, ornare a quam. Maecenas fermentum, ligula vitae consectetur lobortis, mi lacus fermentum ante, ut semper lacus lectus porta orci. Nulla vehicula sodales eros, in iaculis ante laoreet at. Sed venenatis interdum metus, egestas scelerisque orci laoreet ut. Donec fermentum enim eget nibh blandit laoreet. Proin lacinia adipiscing lorem vel ornare. Donec ullamcorper massa elementum urna varius viverra. Proin pharetra, erat at feugiat rhoncus, velit eros condimentum mi, ac mattis sapien dolor non elit. Aenean viverra purus id tincidunt vulputate. + +Etiam vel augue vel nisl commodo suscipit et ac nisl. Quisque eros diam, porttitor et aliquet sed, vulputate in odio. Aenean feugiat est quis neque vehicula, eget vulputate nunc tempor. Donec quis nulla ut quam feugiat consectetur ut et justo. Nulla congue, metus auctor facilisis scelerisque, nunc risus vulputate urna, in blandit urna nibh et neque. Etiam quis tortor ut nulla dignissim dictum non sed ligula. Vivamus accumsan ligula eget ipsum ultrices, a tincidunt urna blandit. In hac habitasse platea dictumst.`) + + doc := document.NewDocument("a").AddField(document.NewTextField("full", []uint64{}, fieldBytes)) + docMatch := search.DocumentMatch{ + ID: "a", + Score: 1.0, + Locations: search.FieldTermLocationMap{ + "full": search.TermLocationMap{ + "metus": search.Locations{ + &search.Location{ + Pos: 0, + Start: 883, + End: 888, + }, + &search.Location{ + Pos: 0, + Start: 915, + End: 920, + }, + &search.Location{ + Pos: 0, + Start: 2492, + End: 2497, + }, + &search.Location{ + Pos: 0, + Start: 2822, + End: 2827, + }, + &search.Location{ + Pos: 0, + Start: 3417, + End: 3422, + }, + }, + "interdum": search.Locations{ + &search.Location{ + Pos: 0, + Start: 1891, + End: 1899, + }, + &search.Location{ + Pos: 0, + Start: 2813, + End: 2821, + }, + }, + "venenatis": search.Locations{ + &search.Location{ + Pos: 0, + Start: 954, + End: 963, + }, + &search.Location{ + Pos: 0, + Start: 1252, + End: 1261, + }, + &search.Location{ + Pos: 0, + Start: 1795, + End: 1804, + }, + &search.Location{ + Pos: 0, + Start: 2803, + End: 2812, + }, + }, + }, + }, + } + + expectedFragments := []string{ + "…eros, in iaculis ante laoreet at. Sed " + DefaultAnsiHighlight + "venenatis" + reset + " " + DefaultAnsiHighlight + "interdum" + reset + " " + DefaultAnsiHighlight + "metus" + reset + ", egestas scelerisque orci laoreet ut.…", + "… eros sed " + DefaultAnsiHighlight + "metus" + reset + " aliquet convallis ac eget " + DefaultAnsiHighlight + "metus" + reset + ". Donec eget feugiat sem. Quisque " + DefaultAnsiHighlight + "venenatis" + reset + ", augue et…", + "… odio. Maecenas condimentum felis vitae nibh " + DefaultAnsiHighlight + "venenatis" + reset + ", ut feugiat risus vehicula. Suspendisse non s…", + "… id feugiat lacus egestas. Integer et eleifend " + DefaultAnsiHighlight + "metus" + reset + ". Duis neque tellus, vulputate nec dui eu, euism…", + "… accumsan. Vivamus eros felis, rhoncus vel " + DefaultAnsiHighlight + "interdum" + reset + " bibendum, imperdiet nec diam. Etiam sed eros sed…", + } + + fragmenter := sfrag.NewFragmenter(100) + formatter := ansi.NewFragmentFormatter(ansi.DefaultAnsiHighlight) + highlighter := NewHighlighter(fragmenter, formatter, defaultSeparator) + fragments := highlighter.BestFragmentsInField(&docMatch, doc, "full", 5) + + if !reflect.DeepEqual(fragments, expectedFragments) { + t.Errorf("expected %#v, got %#v", expectedFragments, fragments) + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations.go new file mode 100644 index 00000000..e5ec9ca5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations.go @@ -0,0 +1,70 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package highlight + +import ( + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type TermLocation struct { + Term string + Pos int + Start int + End int +} + +func (tl *TermLocation) Overlaps(other *TermLocation) bool { + if other.Start >= tl.Start && other.Start < tl.End { + return true + } else if tl.Start >= other.Start && tl.Start < other.End { + return true + } + return false +} + +type TermLocations []*TermLocation + +func (t TermLocations) Len() int { return len(t) } +func (t TermLocations) Swap(i, j int) { t[i], t[j] = t[j], t[i] } +func (t TermLocations) Less(i, j int) bool { return t[i].Start < t[j].Start } + +func (t TermLocations) MergeOverlapping() { + var lastTl *TermLocation + for i, tl := range t { + if lastTl == nil && tl != nil { + lastTl = tl + } else if lastTl != nil && tl != nil { + if lastTl.Overlaps(tl) { + // ok merge this with previous + lastTl.End = tl.End + t[i] = nil + } + } + } +} + +func OrderTermLocations(tlm search.TermLocationMap) TermLocations { + rv := make(TermLocations, 0) + for term, locations := range tlm { + for _, location := range locations { + tl := TermLocation{ + Term: term, + Pos: int(location.Pos), + Start: int(location.Start), + End: int(location.End), + } + rv = append(rv, &tl) + } + } + sort.Sort(rv) + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations_test.go new file mode 100644 index 00000000..edaf315c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/highlight/term_locations_test.go @@ -0,0 +1,173 @@ +package highlight + +import ( + "reflect" + "testing" +) + +func TestTermLocationOverlaps(t *testing.T) { + + tests := []struct { + left *TermLocation + right *TermLocation + expected bool + }{ + { + left: &TermLocation{ + Start: 0, + End: 5, + }, + right: &TermLocation{ + Start: 3, + End: 7, + }, + expected: true, + }, + { + left: &TermLocation{ + Start: 0, + End: 5, + }, + right: &TermLocation{ + Start: 5, + End: 7, + }, + expected: false, + }, + { + left: &TermLocation{ + Start: 0, + End: 5, + }, + right: &TermLocation{ + Start: 7, + End: 11, + }, + expected: false, + }, + } + + for _, test := range tests { + actual := test.left.Overlaps(test.right) + if actual != test.expected { + t.Errorf("expected %t got %t for %#v", test.expected, actual, test) + } + } +} + +func TestTermLocationsMergeOverlapping(t *testing.T) { + + tests := []struct { + input TermLocations + output TermLocations + }{ + { + input: TermLocations{}, + output: TermLocations{}, + }, + { + input: TermLocations{ + &TermLocation{ + Start: 0, + End: 5, + }, + &TermLocation{ + Start: 7, + End: 11, + }, + }, + output: TermLocations{ + &TermLocation{ + Start: 0, + End: 5, + }, + &TermLocation{ + Start: 7, + End: 11, + }, + }, + }, + { + input: TermLocations{ + &TermLocation{ + Start: 0, + End: 5, + }, + &TermLocation{ + Start: 4, + End: 11, + }, + }, + output: TermLocations{ + &TermLocation{ + Start: 0, + End: 11, + }, + nil, + }, + }, + { + input: TermLocations{ + &TermLocation{ + Start: 0, + End: 5, + }, + &TermLocation{ + Start: 4, + End: 11, + }, + &TermLocation{ + Start: 9, + End: 13, + }, + }, + output: TermLocations{ + &TermLocation{ + Start: 0, + End: 13, + }, + nil, + nil, + }, + }, + { + input: TermLocations{ + &TermLocation{ + Start: 0, + End: 5, + }, + &TermLocation{ + Start: 4, + End: 11, + }, + &TermLocation{ + Start: 9, + End: 13, + }, + &TermLocation{ + Start: 15, + End: 21, + }, + }, + output: TermLocations{ + &TermLocation{ + Start: 0, + End: 13, + }, + nil, + nil, + &TermLocation{ + Start: 15, + End: 21, + }, + }, + }, + } + + for _, test := range tests { + test.input.MergeOverlapping() + if !reflect.DeepEqual(test.input, test.output) { + t.Errorf("expected: %#v got %#v", test.output, test.input) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein.go new file mode 100644 index 00000000..7a647096 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein.go @@ -0,0 +1,91 @@ +package search + +import ( + "math" +) + +func LevenshteinDistance(a, b *string) int { + la := len(*a) + lb := len(*b) + d := make([]int, la+1) + var lastdiag, olddiag, temp int + + for i := 1; i <= la; i++ { + d[i] = i + } + for i := 1; i <= lb; i++ { + d[0] = i + lastdiag = i - 1 + for j := 1; j <= la; j++ { + olddiag = d[j] + min := d[j] + 1 + if (d[j-1] + 1) < min { + min = d[j-1] + 1 + } + if (*a)[j-1] == (*b)[i-1] { + temp = 0 + } else { + temp = 1 + } + if (lastdiag + temp) < min { + min = lastdiag + temp + } + d[j] = min + lastdiag = olddiag + } + } + return d[la] +} + +// levenshteinDistanceMax same as levenshteinDistance but +// attempts to bail early once we know the distance +// will be greater than max +// in which case the first return val will be the max +// and the second will be true, indicating max was exceeded +func LevenshteinDistanceMax(a, b *string, max int) (int, bool) { + la := len(*a) + lb := len(*b) + + ld := int(math.Abs(float64(la - lb))) + if ld > max { + return max, true + } + + d := make([]int, la+1) + var lastdiag, olddiag, temp int + + for i := 1; i <= la; i++ { + d[i] = i + } + for i := 1; i <= lb; i++ { + d[0] = i + lastdiag = i - 1 + rowmin := max + 1 + for j := 1; j <= la; j++ { + olddiag = d[j] + min := d[j] + 1 + if (d[j-1] + 1) < min { + min = d[j-1] + 1 + } + if (*a)[j-1] == (*b)[i-1] { + temp = 0 + } else { + temp = 1 + } + if (lastdiag + temp) < min { + min = lastdiag + temp + } + if min < rowmin { + rowmin = min + } + d[j] = min + + lastdiag = olddiag + } + // after each row if rowmin isnt less than max stop + if rowmin > max { + return max, true + } + } + return d[la], false +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein_test.go new file mode 100644 index 00000000..7547b956 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/levenshtein_test.go @@ -0,0 +1,114 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +import ( + "testing" +) + +func TestLevenshteinDistance(t *testing.T) { + + tests := []struct { + a string + b string + dist int + }{ + { + "water", + "atec", + 2, + }, + { + "water", + "aphex", + 4, + }, + } + + for _, test := range tests { + actual := LevenshteinDistance(&test.a, &test.b) + if actual != test.dist { + t.Errorf("expected %d, got %d for %s and %s", test.dist, actual, test.a, test.b) + } + } +} + +func TestLevenshteinDistanceMax(t *testing.T) { + + tests := []struct { + a string + b string + max int + dist int + exceeded bool + }{ + { + a: "water", + b: "atec", + max: 1, + dist: 1, + exceeded: true, + }, + { + a: "water", + b: "christmas", + max: 3, + dist: 3, + exceeded: true, + }, + { + a: "water", + b: "water", + max: 1, + dist: 0, + exceeded: false, + }, + } + + for _, test := range tests { + actual, exceeded := LevenshteinDistanceMax(&test.a, &test.b, test.max) + if actual != test.dist || exceeded != test.exceeded { + t.Errorf("expected %d %t, got %d %t for %s and %s", test.dist, test.exceeded, actual, exceeded, test.a, test.b) + } + } +} + +// 5 terms that are less than 2 +// 5 terms that are more than 2 +var benchmarkTerms = []string{ + "watex", + "aters", + "wayer", + "wbter", + "yater", + "christmas", + "waterwaterwater", + "watcatdogfish", + "q", + "couchbase", +} + +func BenchmarkLevenshteinDistance(b *testing.B) { + a := "water" + for i := 0; i < b.N; i++ { + for _, t := range benchmarkTerms { + LevenshteinDistance(&a, &t) + } + } +} + +func BenchmarkLevenshteinDistanceMax(b *testing.B) { + a := "water" + for i := 0; i < b.N; i++ { + for _, t := range benchmarkTerms { + LevenshteinDistanceMax(&a, &t, 2) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_conjunction.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_conjunction.go new file mode 100644 index 00000000..a2c11082 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_conjunction.go @@ -0,0 +1,59 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type ConjunctionQueryScorer struct { + explain bool +} + +func NewConjunctionQueryScorer(explain bool) *ConjunctionQueryScorer { + return &ConjunctionQueryScorer{ + explain: explain, + } +} + +func (s *ConjunctionQueryScorer) Score(constituents []*search.DocumentMatch) *search.DocumentMatch { + rv := search.DocumentMatch{ + ID: constituents[0].ID, + } + + var sum float64 + var childrenExplanations []*search.Explanation + if s.explain { + childrenExplanations = make([]*search.Explanation, len(constituents)) + } + + locations := []search.FieldTermLocationMap{} + for i, docMatch := range constituents { + sum += docMatch.Score + if s.explain { + childrenExplanations[i] = docMatch.Expl + } + if docMatch.Locations != nil { + locations = append(locations, docMatch.Locations) + } + } + rv.Score = sum + if s.explain { + rv.Expl = &search.Explanation{Value: sum, Message: "sum of:", Children: childrenExplanations} + } + + if len(locations) == 1 { + rv.Locations = locations[0] + } else if len(locations) > 1 { + rv.Locations = search.MergeLocations(locations) + } + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant.go new file mode 100644 index 00000000..d895ffeb --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant.go @@ -0,0 +1,103 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type ConstantScorer struct { + constant float64 + boost float64 + explain bool + queryNorm float64 + queryWeight float64 + queryWeightExplanation *search.Explanation +} + +func NewConstantScorer(constant float64, boost float64, explain bool) *ConstantScorer { + rv := ConstantScorer{ + explain: explain, + queryWeight: 1.0, + constant: constant, + boost: boost, + } + + return &rv +} + +func (s *ConstantScorer) Weight() float64 { + sum := s.boost + return sum * sum +} + +func (s *ConstantScorer) SetQueryNorm(qnorm float64) { + s.queryNorm = qnorm + + // update the query weight + s.queryWeight = s.boost * s.queryNorm + + if s.explain { + childrenExplanations := make([]*search.Explanation, 2) + childrenExplanations[0] = &search.Explanation{ + Value: s.boost, + Message: "boost", + } + childrenExplanations[1] = &search.Explanation{ + Value: s.queryNorm, + Message: "queryNorm", + } + s.queryWeightExplanation = &search.Explanation{ + Value: s.queryWeight, + Message: fmt.Sprintf("ConstantScore()^%f, product of:", s.boost), + Children: childrenExplanations, + } + } +} + +func (s *ConstantScorer) Score(id string) *search.DocumentMatch { + var scoreExplanation *search.Explanation + + score := s.constant + + if s.explain { + scoreExplanation = &search.Explanation{ + Value: score, + Message: fmt.Sprintf("ConstantScore()"), + } + } + + // if the query weight isn't 1, multiply + if s.queryWeight != 1.0 { + score = score * s.queryWeight + if s.explain { + childExplanations := make([]*search.Explanation, 2) + childExplanations[0] = s.queryWeightExplanation + childExplanations[1] = scoreExplanation + scoreExplanation = &search.Explanation{ + Value: score, + Message: fmt.Sprintf("weight(^%f), product of:", s.boost), + Children: childExplanations, + } + } + } + + rv := search.DocumentMatch{ + ID: id, + Score: score, + } + if s.explain { + rv.Expl = scoreExplanation + } + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant_test.go new file mode 100644 index 00000000..0b438caa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_constant_test.go @@ -0,0 +1,118 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestConstantScorer(t *testing.T) { + + scorer := NewConstantScorer(1, 1, true) + + tests := []struct { + termMatch *index.TermFieldDoc + result *search.DocumentMatch + }{ + // test some simple math + { + termMatch: &index.TermFieldDoc{ + ID: "one", + Freq: 1, + Norm: 1.0, + Vectors: []*index.TermFieldVector{ + &index.TermFieldVector{ + Field: "desc", + Pos: 1, + Start: 0, + End: 4, + }, + }, + }, + result: &search.DocumentMatch{ + ID: "one", + Score: 1.0, + Expl: &search.Explanation{ + Value: 1.0, + Message: "ConstantScore()", + }, + }, + }, + } + + for _, test := range tests { + actual := scorer.Score(test.termMatch.ID) + + if !reflect.DeepEqual(actual, test.result) { + t.Errorf("expected %#v got %#v for %#v", test.result, actual, test.termMatch) + } + } + +} + +func TestConstantScorerWithQueryNorm(t *testing.T) { + + scorer := NewConstantScorer(1, 1, true) + scorer.SetQueryNorm(2.0) + + tests := []struct { + termMatch *index.TermFieldDoc + result *search.DocumentMatch + }{ + { + termMatch: &index.TermFieldDoc{ + ID: "one", + Freq: 1, + Norm: 1.0, + }, + result: &search.DocumentMatch{ + ID: "one", + Score: 2.0, + Expl: &search.Explanation{ + Value: 2.0, + Message: "weight(^1.000000), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 2.0, + Message: "ConstantScore()^1.000000, product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 1, + Message: "boost", + }, + &search.Explanation{ + Value: 2, + Message: "queryNorm", + }, + }, + }, + &search.Explanation{ + Value: 1.0, + Message: "ConstantScore()", + }, + }, + }, + }, + }, + } + + for _, test := range tests { + actual := scorer.Score(test.termMatch.ID) + + if !reflect.DeepEqual(actual, test.result) { + t.Errorf("expected %#v got %#v for %#v", test.result, actual, test.termMatch) + } + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_disjunction.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_disjunction.go new file mode 100644 index 00000000..b7873e27 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_disjunction.go @@ -0,0 +1,71 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type DisjunctionQueryScorer struct { + explain bool +} + +func NewDisjunctionQueryScorer(explain bool) *DisjunctionQueryScorer { + return &DisjunctionQueryScorer{ + explain: explain, + } +} + +func (s *DisjunctionQueryScorer) Score(constituents []*search.DocumentMatch, countMatch, countTotal int) *search.DocumentMatch { + rv := search.DocumentMatch{ + ID: constituents[0].ID, + } + + var sum float64 + var childrenExplanations []*search.Explanation + if s.explain { + childrenExplanations = make([]*search.Explanation, len(constituents)) + } + + locations := []search.FieldTermLocationMap{} + for i, docMatch := range constituents { + sum += docMatch.Score + if s.explain { + childrenExplanations[i] = docMatch.Expl + } + if docMatch.Locations != nil { + locations = append(locations, docMatch.Locations) + } + } + + var rawExpl *search.Explanation + if s.explain { + rawExpl = &search.Explanation{Value: sum, Message: "sum of:", Children: childrenExplanations} + } + + coord := float64(countMatch) / float64(countTotal) + rv.Score = sum * coord + if s.explain { + ce := make([]*search.Explanation, 2) + ce[0] = rawExpl + ce[1] = &search.Explanation{Value: coord, Message: fmt.Sprintf("coord(%d/%d)", countMatch, countTotal)} + rv.Expl = &search.Explanation{Value: rv.Score, Message: "product of:", Children: ce} + } + + if len(locations) == 1 { + rv.Locations = locations[0] + } else if len(locations) > 1 { + rv.Locations = search.MergeLocations(locations) + } + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term.go new file mode 100644 index 00000000..e0045cd0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term.go @@ -0,0 +1,169 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "fmt" + "math" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type TermQueryScorer struct { + queryTerm string + queryField string + queryBoost float64 + docTerm uint64 + docTotal uint64 + idf float64 + explain bool + idfExplanation *search.Explanation + queryNorm float64 + queryWeight float64 + queryWeightExplanation *search.Explanation +} + +func NewTermQueryScorer(queryTerm string, queryField string, queryBoost float64, docTotal, docTerm uint64, explain bool) *TermQueryScorer { + rv := TermQueryScorer{ + queryTerm: queryTerm, + queryField: queryField, + queryBoost: queryBoost, + docTerm: docTerm, + docTotal: docTotal, + idf: 1.0 + math.Log(float64(docTotal)/float64(docTerm+1.0)), + explain: explain, + queryWeight: 1.0, + } + + if explain { + rv.idfExplanation = &search.Explanation{ + Value: rv.idf, + Message: fmt.Sprintf("idf(docFreq=%d, maxDocs=%d)", docTerm, docTotal), + } + } + + return &rv +} + +func (s *TermQueryScorer) Weight() float64 { + sum := s.queryBoost * s.idf + return sum * sum +} + +func (s *TermQueryScorer) SetQueryNorm(qnorm float64) { + s.queryNorm = qnorm + + // update the query weight + s.queryWeight = s.queryBoost * s.idf * s.queryNorm + + if s.explain { + childrenExplanations := make([]*search.Explanation, 3) + childrenExplanations[0] = &search.Explanation{ + Value: s.queryBoost, + Message: "boost", + } + childrenExplanations[1] = s.idfExplanation + childrenExplanations[2] = &search.Explanation{ + Value: s.queryNorm, + Message: "queryNorm", + } + s.queryWeightExplanation = &search.Explanation{ + Value: s.queryWeight, + Message: fmt.Sprintf("queryWeight(%s:%s^%f), product of:", s.queryField, string(s.queryTerm), s.queryBoost), + Children: childrenExplanations, + } + } +} + +func (s *TermQueryScorer) Score(termMatch *index.TermFieldDoc) *search.DocumentMatch { + var scoreExplanation *search.Explanation + + // need to compute score + var tf float64 + if termMatch.Freq < MaxSqrtCache { + tf = SqrtCache[int(termMatch.Freq)] + } else { + tf = math.Sqrt(float64(termMatch.Freq)) + } + score := tf * termMatch.Norm * s.idf + + if s.explain { + childrenExplanations := make([]*search.Explanation, 3) + childrenExplanations[0] = &search.Explanation{ + Value: tf, + Message: fmt.Sprintf("tf(termFreq(%s:%s)=%d", s.queryField, string(s.queryTerm), termMatch.Freq), + } + childrenExplanations[1] = &search.Explanation{ + Value: termMatch.Norm, + Message: fmt.Sprintf("fieldNorm(field=%s, doc=%s)", s.queryField, termMatch.ID), + } + childrenExplanations[2] = s.idfExplanation + scoreExplanation = &search.Explanation{ + Value: score, + Message: fmt.Sprintf("fieldWeight(%s:%s in %s), product of:", s.queryField, string(s.queryTerm), termMatch.ID), + Children: childrenExplanations, + } + } + + // if the query weight isn't 1, multiply + if s.queryWeight != 1.0 { + score = score * s.queryWeight + if s.explain { + childExplanations := make([]*search.Explanation, 2) + childExplanations[0] = s.queryWeightExplanation + childExplanations[1] = scoreExplanation + scoreExplanation = &search.Explanation{ + Value: score, + Message: fmt.Sprintf("weight(%s:%s^%f in %s), product of:", s.queryField, string(s.queryTerm), s.queryBoost, termMatch.ID), + Children: childExplanations, + } + } + } + + rv := search.DocumentMatch{ + ID: termMatch.ID, + Score: score, + } + if s.explain { + rv.Expl = scoreExplanation + } + + if termMatch.Vectors != nil && len(termMatch.Vectors) > 0 { + + rv.Locations = make(search.FieldTermLocationMap) + for _, v := range termMatch.Vectors { + tlm := rv.Locations[v.Field] + if tlm == nil { + tlm = make(search.TermLocationMap) + } + + loc := search.Location{ + Pos: float64(v.Pos), + Start: float64(v.Start), + End: float64(v.End), + } + + locations := tlm[s.queryTerm] + if locations == nil { + locations = make(search.Locations, 1) + locations[0] = &loc + } else { + locations = append(locations, &loc) + } + tlm[s.queryTerm] = locations + + rv.Locations[v.Field] = tlm + } + + } + + return &rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term_test.go new file mode 100644 index 00000000..ec6b6c72 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/scorer_term_test.go @@ -0,0 +1,241 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "math" + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestTermScorer(t *testing.T) { + + var docTotal uint64 = 100 + var docTerm uint64 = 9 + var queryTerm = "beer" + var queryField = "desc" + var queryBoost = 1.0 + scorer := NewTermQueryScorer(queryTerm, queryField, queryBoost, docTotal, docTerm, true) + idf := 1.0 + math.Log(float64(docTotal)/float64(docTerm+1.0)) + + tests := []struct { + termMatch *index.TermFieldDoc + result *search.DocumentMatch + }{ + // test some simple math + { + termMatch: &index.TermFieldDoc{ + ID: "one", + Freq: 1, + Norm: 1.0, + Vectors: []*index.TermFieldVector{ + &index.TermFieldVector{ + Field: "desc", + Pos: 1, + Start: 0, + End: 4, + }, + }, + }, + result: &search.DocumentMatch{ + ID: "one", + Score: math.Sqrt(1.0) * idf, + Expl: &search.Explanation{ + Value: math.Sqrt(1.0) * idf, + Message: "fieldWeight(desc:beer in one), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 1, + Message: "tf(termFreq(desc:beer)=1", + }, + &search.Explanation{ + Value: 1, + Message: "fieldNorm(field=desc, doc=one)", + }, + &search.Explanation{ + Value: idf, + Message: "idf(docFreq=9, maxDocs=100)", + }, + }, + }, + Locations: search.FieldTermLocationMap{ + "desc": search.TermLocationMap{ + "beer": search.Locations{ + &search.Location{ + Pos: 1, + Start: 0, + End: 4, + }, + }, + }, + }, + }, + }, + // test the same thing again (score should be cached this time) + { + termMatch: &index.TermFieldDoc{ + ID: "one", + Freq: 1, + Norm: 1.0, + }, + result: &search.DocumentMatch{ + ID: "one", + Score: math.Sqrt(1.0) * idf, + Expl: &search.Explanation{ + Value: math.Sqrt(1.0) * idf, + Message: "fieldWeight(desc:beer in one), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 1, + Message: "tf(termFreq(desc:beer)=1", + }, + &search.Explanation{ + Value: 1, + Message: "fieldNorm(field=desc, doc=one)", + }, + &search.Explanation{ + Value: idf, + Message: "idf(docFreq=9, maxDocs=100)", + }, + }, + }, + }, + }, + // test a case where the sqrt isn't precalculated + { + termMatch: &index.TermFieldDoc{ + ID: "one", + Freq: 65, + Norm: 1.0, + }, + result: &search.DocumentMatch{ + ID: "one", + Score: math.Sqrt(65) * idf, + Expl: &search.Explanation{ + Value: math.Sqrt(65) * idf, + Message: "fieldWeight(desc:beer in one), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: math.Sqrt(65), + Message: "tf(termFreq(desc:beer)=65", + }, + &search.Explanation{ + Value: 1, + Message: "fieldNorm(field=desc, doc=one)", + }, + &search.Explanation{ + Value: idf, + Message: "idf(docFreq=9, maxDocs=100)", + }, + }, + }, + }, + }, + } + + for _, test := range tests { + actual := scorer.Score(test.termMatch) + + if !reflect.DeepEqual(actual, test.result) { + t.Errorf("expected %#v got %#v for %#v", test.result, actual, test.termMatch) + } + } + +} + +func TestTermScorerWithQueryNorm(t *testing.T) { + + var docTotal uint64 = 100 + var docTerm uint64 = 9 + var queryTerm = "beer" + var queryField = "desc" + var queryBoost = 3.0 + scorer := NewTermQueryScorer(queryTerm, queryField, queryBoost, docTotal, docTerm, true) + idf := 1.0 + math.Log(float64(docTotal)/float64(docTerm+1.0)) + + scorer.SetQueryNorm(2.0) + + expectedQueryWeight := 3 * idf * 3 * idf + actualQueryWeight := scorer.Weight() + if expectedQueryWeight != actualQueryWeight { + t.Errorf("expected query weight %f, got %f", expectedQueryWeight, actualQueryWeight) + } + + tests := []struct { + termMatch *index.TermFieldDoc + result *search.DocumentMatch + }{ + { + termMatch: &index.TermFieldDoc{ + ID: "one", + Freq: 1, + Norm: 1.0, + }, + result: &search.DocumentMatch{ + ID: "one", + Score: math.Sqrt(1.0) * idf * 3.0 * idf * 2.0, + Expl: &search.Explanation{ + Value: math.Sqrt(1.0) * idf * 3.0 * idf * 2.0, + Message: "weight(desc:beer^3.000000 in one), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 2.0 * idf * 3.0, + Message: "queryWeight(desc:beer^3.000000), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 3, + Message: "boost", + }, + &search.Explanation{ + Value: idf, + Message: "idf(docFreq=9, maxDocs=100)", + }, + &search.Explanation{ + Value: 2, + Message: "queryNorm", + }, + }, + }, + &search.Explanation{ + Value: math.Sqrt(1.0) * idf, + Message: "fieldWeight(desc:beer in one), product of:", + Children: []*search.Explanation{ + &search.Explanation{ + Value: 1, + Message: "tf(termFreq(desc:beer)=1", + }, + &search.Explanation{ + Value: 1, + Message: "fieldNorm(field=desc, doc=one)", + }, + &search.Explanation{ + Value: idf, + Message: "idf(docFreq=9, maxDocs=100)", + }, + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + actual := scorer.Score(test.termMatch) + + if !reflect.DeepEqual(actual, test.result) { + t.Errorf("expected %#v got %#v for %#v", test.result, actual, test.termMatch) + } + } + +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/sqrt_cache.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/sqrt_cache.go new file mode 100644 index 00000000..f93d27cc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers/sqrt_cache.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package scorers + +import ( + "math" +) + +var SqrtCache map[int]float64 + +const MaxSqrtCache = 64 + +func init() { + SqrtCache = make(map[int]float64, MaxSqrtCache) + for i := 0; i < MaxSqrtCache; i++ { + SqrtCache[i] = math.Sqrt(float64(i)) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/search.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/search.go new file mode 100644 index 00000000..8eb473dd --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/search.go @@ -0,0 +1,81 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +type Location struct { + Pos float64 `json:"pos"` + Start float64 `json:"start"` + End float64 `json:"end"` +} + +type Locations []*Location + +type TermLocationMap map[string]Locations + +func (t TermLocationMap) AddLocation(term string, location *Location) { + existingLocations, exists := t[term] + if exists { + existingLocations = append(existingLocations, location) + t[term] = existingLocations + } else { + locations := make(Locations, 1) + locations[0] = location + t[term] = locations + } +} + +type FieldTermLocationMap map[string]TermLocationMap + +type FieldFragmentMap map[string][]string + +type DocumentMatch struct { + ID string `json:"id"` + Score float64 `json:"score"` + Expl *Explanation `json:"explanation,omitempty"` + Locations FieldTermLocationMap `json:"locations,omitempty"` + Fragments FieldFragmentMap `json:"fragments,omitempty"` + Fields map[string]interface{} `json:"fields,omitempty"` +} + +func (dm *DocumentMatch) AddFieldValue(name string, value interface{}) { + if dm.Fields == nil { + dm.Fields = make(map[string]interface{}) + } + existingVal, ok := dm.Fields[name] + if ok { + valSlice, ok := existingVal.([]interface{}) + if ok { + // already a slice, append to it + valSlice = append(valSlice, value) + } else { + // create a slice + valSlice = []interface{}{existingVal, value} + } + dm.Fields[name] = valSlice + } else { + dm.Fields[name] = value + } +} + +type DocumentMatchCollection []*DocumentMatch + +func (c DocumentMatchCollection) Len() int { return len(c) } +func (c DocumentMatchCollection) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c DocumentMatchCollection) Less(i, j int) bool { return c[i].Score > c[j].Score } + +type Searcher interface { + Next() (*DocumentMatch, error) + Advance(ID string) (*DocumentMatch, error) + Close() error + Weight() float64 + SetQueryNorm(float64) + Count() uint64 + Min() int +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/base_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/base_test.go new file mode 100644 index 00000000..1951bd1b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/base_test.go @@ -0,0 +1,80 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "math" + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/analysis/tokenizers/regexp_tokenizer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down" +) + +var twoDocIndex index.Index //= upside_down.NewUpsideDownCouch(inmem.MustOpen()) + +func init() { + inMemStore, _ := inmem.New() + analysisQueue := upside_down.NewAnalysisQueue(1) + twoDocIndex = upside_down.NewUpsideDownCouch(inMemStore, analysisQueue) + err := twoDocIndex.Open() + if err != nil { + panic(err) + } + for _, doc := range twoDocIndexDocs { + err := twoDocIndex.Update(doc) + if err != nil { + panic(err) + } + } +} + +// create a simpler analyzer which will support these tests +var testAnalyzer = &analysis.Analyzer{ + Tokenizer: regexp_tokenizer.NewRegexpTokenizer(regexp.MustCompile(`\w+`)), +} + +// sets up some mock data used in many tests in this package +var twoDocIndexDescIndexingOptions = document.DefaultTextIndexingOptions | document.IncludeTermVectors + +var twoDocIndexDocs = []*document.Document{ + // must have 4/4 beer + document.NewDocument("1"). + AddField(document.NewTextField("name", []uint64{}, []byte("marty"))). + AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("beer beer beer beer"), twoDocIndexDescIndexingOptions, testAnalyzer)). + AddField(document.NewTextFieldWithAnalyzer("street", []uint64{}, []byte("couchbase way"), testAnalyzer)), + // must have 1/4 beer + document.NewDocument("2"). + AddField(document.NewTextField("name", []uint64{}, []byte("steve"))). + AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("angst beer couch database"), twoDocIndexDescIndexingOptions, testAnalyzer)). + AddField(document.NewTextFieldWithAnalyzer("street", []uint64{}, []byte("couchbase way"), testAnalyzer)). + AddField(document.NewTextFieldWithAnalyzer("title", []uint64{}, []byte("mister"), testAnalyzer)), + // must have 1/4 beer + document.NewDocument("3"). + AddField(document.NewTextField("name", []uint64{}, []byte("dustin"))). + AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("apple beer column dank"), twoDocIndexDescIndexingOptions, testAnalyzer)). + AddField(document.NewTextFieldWithAnalyzer("title", []uint64{}, []byte("mister"), testAnalyzer)), + // must have 65/65 beer + document.NewDocument("4"). + AddField(document.NewTextField("name", []uint64{}, []byte("ravi"))). + AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer beer"), twoDocIndexDescIndexingOptions, testAnalyzer)), + // must have 0/x beer + document.NewDocument("5"). + AddField(document.NewTextField("name", []uint64{}, []byte("bobert"))). + AddField(document.NewTextFieldCustom("desc", []uint64{}, []byte("water"), twoDocIndexDescIndexingOptions, testAnalyzer)). + AddField(document.NewTextFieldWithAnalyzer("title", []uint64{}, []byte("mister"), testAnalyzer)), +} + +func scoresCloseEnough(a, b float64) bool { + return math.Abs(a-b) < 0.001 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/ordered_searchers_list.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/ordered_searchers_list.go new file mode 100644 index 00000000..b46e2f57 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/ordered_searchers_list.go @@ -0,0 +1,30 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type OrderedSearcherList []search.Searcher + +// sort.Interface + +func (otrl OrderedSearcherList) Len() int { + return len(otrl) +} + +func (otrl OrderedSearcherList) Less(i, j int) bool { + return otrl[i].Count() < otrl[j].Count() +} + +func (otrl OrderedSearcherList) Swap(i, j int) { + otrl[i], otrl[j] = otrl[j], otrl[i] +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean.go new file mode 100644 index 00000000..0ee1fe4a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean.go @@ -0,0 +1,335 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "math" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers" +) + +type BooleanSearcher struct { + initialized bool + indexReader index.IndexReader + mustSearcher search.Searcher + shouldSearcher search.Searcher + mustNotSearcher search.Searcher + queryNorm float64 + currMust *search.DocumentMatch + currShould *search.DocumentMatch + currMustNot *search.DocumentMatch + currentID string + min uint64 + scorer *scorers.ConjunctionQueryScorer +} + +func NewBooleanSearcher(indexReader index.IndexReader, mustSearcher search.Searcher, shouldSearcher search.Searcher, mustNotSearcher search.Searcher, explain bool) (*BooleanSearcher, error) { + // build our searcher + rv := BooleanSearcher{ + indexReader: indexReader, + mustSearcher: mustSearcher, + shouldSearcher: shouldSearcher, + mustNotSearcher: mustNotSearcher, + scorer: scorers.NewConjunctionQueryScorer(explain), + } + rv.computeQueryNorm() + return &rv, nil +} + +func (s *BooleanSearcher) computeQueryNorm() { + // first calculate sum of squared weights + sumOfSquaredWeights := 0.0 + if s.mustSearcher != nil { + sumOfSquaredWeights += s.mustSearcher.Weight() + } + if s.shouldSearcher != nil { + sumOfSquaredWeights += s.shouldSearcher.Weight() + } + + // now compute query norm from this + s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights) + // finally tell all the downstream searchers the norm + if s.mustSearcher != nil { + s.mustSearcher.SetQueryNorm(s.queryNorm) + } + if s.shouldSearcher != nil { + s.shouldSearcher.SetQueryNorm(s.queryNorm) + } +} + +func (s *BooleanSearcher) initSearchers() error { + var err error + // get all searchers pointing at their first match + if s.mustSearcher != nil { + s.currMust, err = s.mustSearcher.Next() + if err != nil { + return err + } + } + + if s.shouldSearcher != nil { + s.currShould, err = s.shouldSearcher.Next() + if err != nil { + return err + } + } + + if s.mustNotSearcher != nil { + s.currMustNot, err = s.mustNotSearcher.Next() + if err != nil { + return err + } + } + + if s.mustSearcher != nil && s.currMust != nil { + s.currentID = s.currMust.ID + } else if s.mustSearcher == nil && s.currShould != nil { + s.currentID = s.currShould.ID + } else { + s.currentID = "" + } + + s.initialized = true + return nil +} + +func (s *BooleanSearcher) advanceNextMust() error { + var err error + + if s.mustSearcher != nil { + s.currMust, err = s.mustSearcher.Next() + if err != nil { + return err + } + } else if s.mustSearcher == nil { + s.currShould, err = s.shouldSearcher.Next() + if err != nil { + return err + } + } + + if s.mustSearcher != nil && s.currMust != nil { + s.currentID = s.currMust.ID + } else if s.mustSearcher == nil && s.currShould != nil { + s.currentID = s.currShould.ID + } else { + s.currentID = "" + } + return nil +} + +func (s *BooleanSearcher) Weight() float64 { + var rv float64 + if s.mustSearcher != nil { + rv += s.mustSearcher.Weight() + } + if s.shouldSearcher != nil { + rv += s.shouldSearcher.Weight() + } + + return rv +} + +func (s *BooleanSearcher) SetQueryNorm(qnorm float64) { + if s.mustSearcher != nil { + s.mustSearcher.SetQueryNorm(qnorm) + } + if s.shouldSearcher != nil { + s.shouldSearcher.SetQueryNorm(qnorm) + } +} + +func (s *BooleanSearcher) Next() (*search.DocumentMatch, error) { + + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + + var err error + var rv *search.DocumentMatch + + for s.currentID != "" { + if s.currMustNot != nil && s.currMustNot.ID < s.currentID { + // advance must not searcher to our candidate entry + s.currMustNot, err = s.mustNotSearcher.Advance(s.currentID) + if err != nil { + return nil, err + } + if s.currMustNot != nil && s.currMustNot.ID == s.currentID { + // the candidate is excluded + err = s.advanceNextMust() + if err != nil { + return nil, err + } + continue + } + } else if s.currMustNot != nil && s.currMustNot.ID == s.currentID { + // the candidate is excluded + err = s.advanceNextMust() + if err != nil { + return nil, err + } + continue + } + + if s.currShould != nil && s.currShould.ID < s.currentID { + // advance should searcher to our candidate entry + s.currShould, err = s.shouldSearcher.Advance(s.currentID) + if err != nil { + return nil, err + } + if s.currShould != nil && s.currShould.ID == s.currentID { + // score bonus matches should + var cons []*search.DocumentMatch + if s.currMust != nil { + cons = []*search.DocumentMatch{ + s.currMust, + s.currShould, + } + } else { + cons = []*search.DocumentMatch{ + s.currShould, + } + } + rv = s.scorer.Score(cons) + err = s.advanceNextMust() + if err != nil { + return nil, err + } + break + } else if s.shouldSearcher.Min() == 0 { + // match is OK anyway + rv = s.scorer.Score([]*search.DocumentMatch{s.currMust}) + err = s.advanceNextMust() + if err != nil { + return nil, err + } + break + } + } else if s.currShould != nil && s.currShould.ID == s.currentID { + // score bonus matches should + var cons []*search.DocumentMatch + if s.currMust != nil { + cons = []*search.DocumentMatch{ + s.currMust, + s.currShould, + } + } else { + cons = []*search.DocumentMatch{ + s.currShould, + } + } + rv = s.scorer.Score(cons) + err = s.advanceNextMust() + if err != nil { + return nil, err + } + break + } else if s.shouldSearcher == nil || s.shouldSearcher.Min() == 0 { + // match is OK anyway + rv = s.scorer.Score([]*search.DocumentMatch{s.currMust}) + err = s.advanceNextMust() + if err != nil { + return nil, err + } + break + } + + err = s.advanceNextMust() + if err != nil { + return nil, err + } + } + return rv, nil +} + +func (s *BooleanSearcher) Advance(ID string) (*search.DocumentMatch, error) { + + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + + var err error + if s.mustSearcher != nil { + s.currMust, err = s.mustSearcher.Advance(ID) + if err != nil { + return nil, err + } + } + if s.shouldSearcher != nil { + s.currShould, err = s.shouldSearcher.Advance(ID) + if err != nil { + return nil, err + } + } + if s.mustNotSearcher != nil { + s.currMustNot, err = s.mustNotSearcher.Advance(ID) + if err != nil { + return nil, err + } + } + + if s.mustSearcher != nil && s.currMust != nil { + s.currentID = s.currMust.ID + } else if s.mustSearcher == nil && s.currShould != nil { + s.currentID = s.currShould.ID + } else { + s.currentID = "" + } + + return s.Next() +} + +func (s *BooleanSearcher) Count() uint64 { + + // for now return a worst case + var sum uint64 + if s.mustSearcher != nil { + sum += s.mustSearcher.Count() + } + if s.shouldSearcher != nil { + sum += s.shouldSearcher.Count() + } + return sum +} + +func (s *BooleanSearcher) Close() error { + if s.mustSearcher != nil { + err := s.mustSearcher.Close() + if err != nil { + return err + } + } + if s.shouldSearcher != nil { + err := s.shouldSearcher.Close() + if err != nil { + return err + } + } + if s.mustNotSearcher != nil { + err := s.mustNotSearcher.Close() + if err != nil { + return err + } + } + return nil +} + +func (s *BooleanSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean_test.go new file mode 100644 index 00000000..b49b2a1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_boolean_test.go @@ -0,0 +1,364 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestBooleanSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // test 0 + beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher}, true) + if err != nil { + t.Fatal(err) + } + martyTermSearcher, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + shouldSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, true) + if err != nil { + t.Fatal(err) + } + steveTermSearcher, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustNotSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher}, 0, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher, shouldSearcher, mustNotSearcher, true) + if err != nil { + t.Fatal(err) + } + + // test 1 + martyTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + shouldSearcher2, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, true) + if err != nil { + t.Fatal(err) + } + steveTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustNotSearcher2, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher2}, 0, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher2, err := NewBooleanSearcher(twoDocIndexReader, nil, shouldSearcher2, mustNotSearcher2, true) + if err != nil { + t.Fatal(err) + } + + // test 2 + steveTermSearcher3, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustNotSearcher3, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher3}, 0, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher3, err := NewBooleanSearcher(twoDocIndexReader, nil, nil, mustNotSearcher3, true) + if err != nil { + t.Fatal(err) + } + + // test 3 + beerTermSearcher4, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher4, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher4}, true) + if err != nil { + t.Fatal(err) + } + steveTermSearcher4, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustNotSearcher4, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher4}, 0, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher4, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher4, nil, mustNotSearcher4, true) + if err != nil { + t.Fatal(err) + } + + // test 4 + beerTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher5, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher5}, true) + if err != nil { + t.Fatal(err) + } + steveTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + martyTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustNotSearcher5, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher5, martyTermSearcher5}, 0, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher5, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher5, nil, mustNotSearcher5, true) + if err != nil { + t.Fatal(err) + } + + // test 5 + beerTermSearcher6, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher6, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher6}, true) + if err != nil { + t.Fatal(err) + } + martyTermSearcher6, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher6, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + shouldSearcher6, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher6, dustinTermSearcher6}, 2, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher6, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher6, shouldSearcher6, nil, true) + if err != nil { + t.Fatal(err) + } + + // test 6 + beerTermSearcher7, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher7, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher7}, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher7, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher7, nil, nil, true) + if err != nil { + t.Fatal(err) + } + martyTermSearcher7, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 5.0, true) + if err != nil { + t.Fatal(err) + } + conjunctionSearcher7, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher7, booleanSearcher7}, true) + + // test 7 + beerTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher8, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher8}, true) + if err != nil { + t.Fatal(err) + } + martyTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + shouldSearcher8, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher8, dustinTermSearcher8}, 0, true) + if err != nil { + t.Fatal(err) + } + steveTermSearcher8, err := NewTermSearcher(twoDocIndexReader, "steve", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustNotSearcher8, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{steveTermSearcher8}, 0, true) + if err != nil { + t.Fatal(err) + } + booleanSearcher8, err := NewBooleanSearcher(twoDocIndexReader, mustSearcher8, shouldSearcher8, mustNotSearcher8, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher8a, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 5.0, true) + if err != nil { + t.Fatal(err) + } + conjunctionSearcher8, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{booleanSearcher8, dustinTermSearcher8a}, true) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + results []*search.DocumentMatch + }{ + { + searcher: booleanSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 0.9818005051949021, + }, + &search.DocumentMatch{ + ID: "3", + Score: 0.808709699395535, + }, + &search.DocumentMatch{ + ID: "4", + Score: 0.34618161159873423, + }, + }, + }, + { + searcher: booleanSearcher2, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 0.6775110856165737, + }, + &search.DocumentMatch{ + ID: "3", + Score: 0.6775110856165737, + }, + }, + }, + // no MUST or SHOULD clauses yields no results + { + searcher: booleanSearcher3, + results: []*search.DocumentMatch{}, + }, + { + searcher: booleanSearcher4, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "3", + Score: 0.5, + }, + &search.DocumentMatch{ + ID: "4", + Score: 1.0, + }, + }, + }, + { + searcher: booleanSearcher5, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "3", + Score: 0.5, + }, + &search.DocumentMatch{ + ID: "4", + Score: 1.0, + }, + }, + }, + { + searcher: booleanSearcher6, + results: []*search.DocumentMatch{}, + }, + // test a conjunction query with a nested boolean + { + searcher: conjunctionSearcher7, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 2.0097428702814377, + }, + }, + }, + { + searcher: conjunctionSearcher8, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "3", + Score: 2.0681575785068107, + }, + }, + }, + } + + for testIndex, test := range tests { + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if !scoresCloseEnough(next.Score, test.results[i].Score) { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction.go new file mode 100644 index 00000000..420bc47d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction.go @@ -0,0 +1,197 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "math" + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers" +) + +type ConjunctionSearcher struct { + initialized bool + indexReader index.IndexReader + searchers OrderedSearcherList + explain bool + queryNorm float64 + currs []*search.DocumentMatch + currentID string + scorer *scorers.ConjunctionQueryScorer +} + +func NewConjunctionSearcher(indexReader index.IndexReader, qsearchers []search.Searcher, explain bool) (*ConjunctionSearcher, error) { + // build the downstream searchers + searchers := make(OrderedSearcherList, len(qsearchers)) + for i, searcher := range qsearchers { + searchers[i] = searcher + } + // sort the searchers + sort.Sort(searchers) + // build our searcher + rv := ConjunctionSearcher{ + indexReader: indexReader, + explain: explain, + searchers: searchers, + currs: make([]*search.DocumentMatch, len(searchers)), + scorer: scorers.NewConjunctionQueryScorer(explain), + } + rv.computeQueryNorm() + return &rv, nil +} + +func (s *ConjunctionSearcher) computeQueryNorm() { + // first calculate sum of squared weights + sumOfSquaredWeights := 0.0 + for _, termSearcher := range s.searchers { + sumOfSquaredWeights += termSearcher.Weight() + } + // now compute query norm from this + s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights) + // finally tell all the downstream searchers the norm + for _, termSearcher := range s.searchers { + termSearcher.SetQueryNorm(s.queryNorm) + } +} + +func (s *ConjunctionSearcher) initSearchers() error { + var err error + // get all searchers pointing at their first match + for i, termSearcher := range s.searchers { + s.currs[i], err = termSearcher.Next() + if err != nil { + return err + } + } + + if len(s.currs) > 0 { + if s.currs[0] != nil { + s.currentID = s.currs[0].ID + } else { + s.currentID = "" + } + } + + s.initialized = true + return nil +} + +func (s *ConjunctionSearcher) Weight() float64 { + var rv float64 + for _, searcher := range s.searchers { + rv += searcher.Weight() + } + return rv +} + +func (s *ConjunctionSearcher) SetQueryNorm(qnorm float64) { + for _, searcher := range s.searchers { + searcher.SetQueryNorm(qnorm) + } +} + +func (s *ConjunctionSearcher) Next() (*search.DocumentMatch, error) { + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + var rv *search.DocumentMatch + var err error +OUTER: + for s.currentID != "" { + for i, termSearcher := range s.searchers { + if s.currs[i] != nil && s.currs[i].ID != s.currentID { + if s.currentID < s.currs[i].ID { + s.currentID = s.currs[i].ID + continue OUTER + } + // this reader doesn't have the currentID, try to advance + s.currs[i], err = termSearcher.Advance(s.currentID) + if err != nil { + return nil, err + } + if s.currs[i] == nil { + s.currentID = "" + continue OUTER + } + if s.currs[i].ID != s.currentID { + // we just advanced, so it doesn't match, it must be greater + // no need to call next + s.currentID = s.currs[i].ID + continue OUTER + } + } else if s.currs[i] == nil { + s.currentID = "" + continue OUTER + } + } + // if we get here, a doc matched all readers, sum the score and add it + rv = s.scorer.Score(s.currs) + + // prepare for next entry + s.currs[0], err = s.searchers[0].Next() + if err != nil { + return nil, err + } + if s.currs[0] == nil { + s.currentID = "" + } else { + s.currentID = s.currs[0].ID + } + // don't continue now, wait for the next call to Next() + break + } + return rv, nil +} + +func (s *ConjunctionSearcher) Advance(ID string) (*search.DocumentMatch, error) { + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + var err error + for i, searcher := range s.searchers { + s.currs[i], err = searcher.Advance(ID) + if err != nil { + return nil, err + } + } + s.currentID = ID + return s.Next() +} + +func (s *ConjunctionSearcher) Count() uint64 { + // for now return a worst case + var sum uint64 + for _, searcher := range s.searchers { + sum += searcher.Count() + } + return sum +} + +func (s *ConjunctionSearcher) Close() error { + for _, searcher := range s.searchers { + err := searcher.Close() + if err != nil { + return err + } + } + return nil +} + +func (s *ConjunctionSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction_test.go new file mode 100644 index 00000000..14999b43 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_conjunction_test.go @@ -0,0 +1,212 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestConjunctionSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + // test 0 + beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + martyTermSearcher, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 5.0, true) + if err != nil { + t.Fatal(err) + } + beerAndMartySearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher, martyTermSearcher}, true) + if err != nil { + t.Fatal(err) + } + + // test 1 + angstTermSearcher, err := NewTermSearcher(twoDocIndexReader, "angst", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + beerTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + angstAndBeerSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{angstTermSearcher, beerTermSearcher2}, true) + if err != nil { + t.Fatal(err) + } + + // test 2 + beerTermSearcher3, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + jackTermSearcher, err := NewTermSearcher(twoDocIndexReader, "jack", "name", 5.0, true) + if err != nil { + t.Fatal(err) + } + beerAndJackSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher3, jackTermSearcher}, true) + if err != nil { + t.Fatal(err) + } + + // test 3 + beerTermSearcher4, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + misterTermSearcher, err := NewTermSearcher(twoDocIndexReader, "mister", "title", 5.0, true) + if err != nil { + t.Fatal(err) + } + beerAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher4, misterTermSearcher}, true) + if err != nil { + t.Fatal(err) + } + + // test 4 + couchbaseTermSearcher, err := NewTermSearcher(twoDocIndexReader, "couchbase", "street", 1.0, true) + if err != nil { + t.Fatal(err) + } + misterTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "mister", "title", 5.0, true) + if err != nil { + t.Fatal(err) + } + couchbaseAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{couchbaseTermSearcher, misterTermSearcher2}, true) + if err != nil { + t.Fatal(err) + } + + // test 5 + beerTermSearcher5, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 5.0, true) + if err != nil { + t.Fatal(err) + } + couchbaseTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "couchbase", "street", 1.0, true) + if err != nil { + t.Fatal(err) + } + misterTermSearcher3, err := NewTermSearcher(twoDocIndexReader, "mister", "title", 5.0, true) + if err != nil { + t.Fatal(err) + } + couchbaseAndMisterSearcher2, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{couchbaseTermSearcher2, misterTermSearcher3}, true) + if err != nil { + t.Fatal(err) + } + beerAndCouchbaseAndMisterSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{beerTermSearcher5, couchbaseAndMisterSearcher2}, true) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + results []*search.DocumentMatch + }{ + { + searcher: beerAndMartySearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 2.0097428702814377, + }, + }, + }, + { + searcher: angstAndBeerSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "2", + Score: 1.0807601687084403, + }, + }, + }, + { + searcher: beerAndJackSearcher, + results: []*search.DocumentMatch{}, + }, + { + searcher: beerAndMisterSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "2", + Score: 1.2877980334016337, + }, + &search.DocumentMatch{ + ID: "3", + Score: 1.2877980334016337, + }, + }, + }, + { + searcher: couchbaseAndMisterSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "2", + Score: 1.4436599157093672, + }, + }, + }, + { + searcher: beerAndCouchbaseAndMisterSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "2", + Score: 1.441614953806971, + }, + }, + }, + } + + for testIndex, test := range tests { + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if !scoresCloseEnough(next.Score, test.results[i].Score) { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction.go new file mode 100644 index 00000000..cc8b32a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction.go @@ -0,0 +1,189 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "math" + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers" +) + +type DisjunctionSearcher struct { + initialized bool + indexReader index.IndexReader + searchers OrderedSearcherList + queryNorm float64 + currs []*search.DocumentMatch + currentID string + scorer *scorers.DisjunctionQueryScorer + min float64 +} + +func NewDisjunctionSearcher(indexReader index.IndexReader, qsearchers []search.Searcher, min float64, explain bool) (*DisjunctionSearcher, error) { + // build the downstream searchers + searchers := make(OrderedSearcherList, len(qsearchers)) + for i, searcher := range qsearchers { + searchers[i] = searcher + } + // sort the searchers + sort.Sort(sort.Reverse(searchers)) + // build our searcher + rv := DisjunctionSearcher{ + indexReader: indexReader, + searchers: searchers, + currs: make([]*search.DocumentMatch, len(searchers)), + scorer: scorers.NewDisjunctionQueryScorer(explain), + min: min, + } + rv.computeQueryNorm() + return &rv, nil +} + +func (s *DisjunctionSearcher) computeQueryNorm() { + // first calculate sum of squared weights + sumOfSquaredWeights := 0.0 + for _, termSearcher := range s.searchers { + sumOfSquaredWeights += termSearcher.Weight() + } + // now compute query norm from this + s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights) + // finally tell all the downstream searchers the norm + for _, termSearcher := range s.searchers { + termSearcher.SetQueryNorm(s.queryNorm) + } +} + +func (s *DisjunctionSearcher) initSearchers() error { + var err error + // get all searchers pointing at their first match + for i, termSearcher := range s.searchers { + s.currs[i], err = termSearcher.Next() + if err != nil { + return err + } + } + + s.currentID = s.nextSmallestID() + s.initialized = true + return nil +} + +func (s *DisjunctionSearcher) nextSmallestID() string { + rv := "" + for _, curr := range s.currs { + if curr != nil && (curr.ID < rv || rv == "") { + rv = curr.ID + } + } + return rv +} + +func (s *DisjunctionSearcher) Weight() float64 { + var rv float64 + for _, searcher := range s.searchers { + rv += searcher.Weight() + } + return rv +} + +func (s *DisjunctionSearcher) SetQueryNorm(qnorm float64) { + for _, searcher := range s.searchers { + searcher.SetQueryNorm(qnorm) + } +} + +func (s *DisjunctionSearcher) Next() (*search.DocumentMatch, error) { + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + var err error + var rv *search.DocumentMatch + matching := make([]*search.DocumentMatch, 0, len(s.searchers)) + + found := false + for !found && s.currentID != "" { + for _, curr := range s.currs { + if curr != nil && curr.ID == s.currentID { + matching = append(matching, curr) + } + } + + if len(matching) >= int(s.min) { + found = true + // score this match + rv = s.scorer.Score(matching, len(matching), len(s.searchers)) + } + + // reset matching + matching = make([]*search.DocumentMatch, 0) + // invoke next on all the matching searchers + for i, curr := range s.currs { + if curr != nil && curr.ID == s.currentID { + searcher := s.searchers[i] + s.currs[i], err = searcher.Next() + if err != nil { + return nil, err + } + } + } + s.currentID = s.nextSmallestID() + } + return rv, nil +} + +func (s *DisjunctionSearcher) Advance(ID string) (*search.DocumentMatch, error) { + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + // get all searchers pointing at their first match + var err error + for i, termSearcher := range s.searchers { + s.currs[i], err = termSearcher.Advance(ID) + if err != nil { + return nil, err + } + } + + s.currentID = s.nextSmallestID() + + return s.Next() +} + +func (s *DisjunctionSearcher) Count() uint64 { + // for now return a worst case + var sum uint64 + for _, searcher := range s.searchers { + sum += searcher.Count() + } + return sum +} + +func (s *DisjunctionSearcher) Close() error { + for _, searcher := range s.searchers { + err := searcher.Close() + if err != nil { + return err + } + } + return nil +} + +func (s *DisjunctionSearcher) Min() int { + return int(s.min) // FIXME just make this an int +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction_test.go new file mode 100644 index 00000000..273ffe40 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_disjunction_test.go @@ -0,0 +1,168 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestDisjunctionSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + martyTermSearcher, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + martyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, true) + if err != nil { + t.Fatal(err) + } + + martyTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher2, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + martyOrDustinSearcher2, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher2, dustinTermSearcher2}, 0, true) + if err != nil { + t.Fatal(err) + } + + raviTermSearcher, err := NewTermSearcher(twoDocIndexReader, "ravi", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + nestedRaviOrMartyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{raviTermSearcher, martyOrDustinSearcher2}, 0, true) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + results []*search.DocumentMatch + }{ + { + searcher: martyOrDustinSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 0.6775110856165737, + }, + &search.DocumentMatch{ + ID: "3", + Score: 0.6775110856165737, + }, + }, + }, + // test a nested disjunction + { + searcher: nestedRaviOrMartyOrDustinSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 0.2765927424732821, + }, + &search.DocumentMatch{ + ID: "3", + Score: 0.2765927424732821, + }, + &search.DocumentMatch{ + ID: "4", + Score: 0.5531854849465642, + }, + }, + }, + } + + for testIndex, test := range tests { + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if !scoresCloseEnough(next.Score, test.results[i].Score) { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} + +func TestDisjunctionAdvance(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + martyTermSearcher, err := NewTermSearcher(twoDocIndexReader, "marty", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + dustinTermSearcher, err := NewTermSearcher(twoDocIndexReader, "dustin", "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + martyOrDustinSearcher, err := NewDisjunctionSearcher(twoDocIndexReader, []search.Searcher{martyTermSearcher, dustinTermSearcher}, 0, true) + if err != nil { + t.Fatal(err) + } + + match, err := martyOrDustinSearcher.Advance("3") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if match == nil { + t.Errorf("expected 3, got nil") + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_fuzzy.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_fuzzy.go new file mode 100644 index 00000000..4f5e3003 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_fuzzy.go @@ -0,0 +1,112 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type FuzzySearcher struct { + indexReader index.IndexReader + term string + prefix int + fuzziness int + field string + explain bool + searcher *DisjunctionSearcher +} + +func NewFuzzySearcher(indexReader index.IndexReader, term string, prefix, fuzziness int, field string, boost float64, explain bool) (*FuzzySearcher, error) { + prefixTerm := "" + for i, r := range term { + if i < prefix { + prefixTerm += string(r) + } + } + + // find the terms with this prefix + var fieldDict index.FieldDict + var err error + if len(prefixTerm) > 0 { + fieldDict, err = indexReader.FieldDictPrefix(field, []byte(prefixTerm)) + } else { + fieldDict, err = indexReader.FieldDict(field) + } + + // enumerate terms and check levenshtein distance + candidateTerms := make([]string, 0) + tfd, err := fieldDict.Next() + for err == nil && tfd != nil { + ld, exceeded := search.LevenshteinDistanceMax(&term, &tfd.Term, fuzziness) + if !exceeded && ld <= fuzziness { + candidateTerms = append(candidateTerms, tfd.Term) + } + tfd, err = fieldDict.Next() + } + if err != nil { + return nil, err + } + + // enumerate all the terms in the range + qsearchers := make([]search.Searcher, 0, 25) + + for _, cterm := range candidateTerms { + qsearcher, err := NewTermSearcher(indexReader, cterm, field, 1.0, explain) + if err != nil { + return nil, err + } + qsearchers = append(qsearchers, qsearcher) + } + + // build disjunction searcher of these ranges + searcher, err := NewDisjunctionSearcher(indexReader, qsearchers, 0, explain) + if err != nil { + return nil, err + } + + return &FuzzySearcher{ + indexReader: indexReader, + term: term, + prefix: prefix, + fuzziness: fuzziness, + field: field, + explain: explain, + searcher: searcher, + }, nil +} +func (s *FuzzySearcher) Count() uint64 { + return s.searcher.Count() +} + +func (s *FuzzySearcher) Weight() float64 { + return s.searcher.Weight() +} + +func (s *FuzzySearcher) SetQueryNorm(qnorm float64) { + s.searcher.SetQueryNorm(qnorm) +} + +func (s *FuzzySearcher) Next() (*search.DocumentMatch, error) { + return s.searcher.Next() + +} + +func (s *FuzzySearcher) Advance(ID string) (*search.DocumentMatch, error) { + return s.searcher.Next() +} + +func (s *FuzzySearcher) Close() error { + return s.searcher.Close() +} + +func (s *FuzzySearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all.go new file mode 100644 index 00000000..8ce5740f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all.go @@ -0,0 +1,89 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers" +) + +type MatchAllSearcher struct { + indexReader index.IndexReader + reader index.DocIDReader + scorer *scorers.ConstantScorer +} + +func NewMatchAllSearcher(indexReader index.IndexReader, boost float64, explain bool) (*MatchAllSearcher, error) { + reader, err := indexReader.DocIDReader("", "") + if err != nil { + return nil, err + } + scorer := scorers.NewConstantScorer(1.0, boost, explain) + return &MatchAllSearcher{ + indexReader: indexReader, + reader: reader, + scorer: scorer, + }, nil +} + +func (s *MatchAllSearcher) Count() uint64 { + return s.indexReader.DocCount() +} + +func (s *MatchAllSearcher) Weight() float64 { + return s.scorer.Weight() +} + +func (s *MatchAllSearcher) SetQueryNorm(qnorm float64) { + s.scorer.SetQueryNorm(qnorm) +} + +func (s *MatchAllSearcher) Next() (*search.DocumentMatch, error) { + id, err := s.reader.Next() + if err != nil { + return nil, err + } + + if id == "" { + return nil, nil + } + + // score match + docMatch := s.scorer.Score(id) + // return doc match + return docMatch, nil + +} + +func (s *MatchAllSearcher) Advance(ID string) (*search.DocumentMatch, error) { + id, err := s.reader.Advance(ID) + if err != nil { + return nil, err + } + + if id == "" { + return nil, nil + } + + // score match + docMatch := s.scorer.Score(id) + + // return doc match + return docMatch, nil +} + +func (s *MatchAllSearcher) Close() error { + return s.reader.Close() +} + +func (s *MatchAllSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all_test.go new file mode 100644 index 00000000..3bb6e149 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_all_test.go @@ -0,0 +1,134 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestMatchAllSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + allSearcher, err := NewMatchAllSearcher(twoDocIndexReader, 1.0, true) + if err != nil { + t.Fatal(err) + } + + allSearcher2, err := NewMatchAllSearcher(twoDocIndexReader, 1.2, true) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + queryNorm float64 + results []*search.DocumentMatch + }{ + { + searcher: allSearcher, + queryNorm: 1.0, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "2", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "3", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "4", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "5", + Score: 1.0, + }, + }, + }, + { + searcher: allSearcher2, + queryNorm: 0.8333333, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "2", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "3", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "4", + Score: 1.0, + }, + &search.DocumentMatch{ + ID: "5", + Score: 1.0, + }, + }, + }, + } + + for testIndex, test := range tests { + + if test.queryNorm != 1.0 { + test.searcher.SetQueryNorm(test.queryNorm) + } + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if !scoresCloseEnough(next.Score, test.results[i].Score) { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none.go new file mode 100644 index 00000000..f7c5940f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none.go @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type MatchNoneSearcher struct { + indexReader index.IndexReader +} + +func NewMatchNoneSearcher(indexReader index.IndexReader) (*MatchNoneSearcher, error) { + return &MatchNoneSearcher{ + indexReader: indexReader, + }, nil +} + +func (s *MatchNoneSearcher) Count() uint64 { + return uint64(0) +} + +func (s *MatchNoneSearcher) Weight() float64 { + return 0.0 +} + +func (s *MatchNoneSearcher) SetQueryNorm(qnorm float64) { + +} + +func (s *MatchNoneSearcher) Next() (*search.DocumentMatch, error) { + return nil, nil +} + +func (s *MatchNoneSearcher) Advance(ID string) (*search.DocumentMatch, error) { + return nil, nil +} + +func (s *MatchNoneSearcher) Close() error { + return nil +} + +func (s *MatchNoneSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none_test.go new file mode 100644 index 00000000..ce7dee86 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_match_none_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestMatchNoneSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + noneSearcher, err := NewMatchNoneSearcher(twoDocIndexReader) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + results []*search.DocumentMatch + }{ + { + searcher: noneSearcher, + results: []*search.DocumentMatch{}, + }, + } + + for testIndex, test := range tests { + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if !scoresCloseEnough(next.Score, test.results[i].Score) { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range.go new file mode 100644 index 00000000..a5a02690 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range.go @@ -0,0 +1,214 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "bytes" + "math" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type NumericRangeSearcher struct { + indexReader index.IndexReader + min *float64 + max *float64 + field string + explain bool + searcher *DisjunctionSearcher +} + +func NewNumericRangeSearcher(indexReader index.IndexReader, min *float64, max *float64, inclusiveMin, inclusiveMax *bool, field string, boost float64, explain bool) (*NumericRangeSearcher, error) { + // account for unbounded edges + if min == nil { + negInf := math.Inf(-1) + min = &negInf + } + if max == nil { + Inf := math.Inf(1) + max = &Inf + } + if inclusiveMin == nil { + defaultInclusiveMin := true + inclusiveMin = &defaultInclusiveMin + } + if inclusiveMax == nil { + defaultInclusiveMax := false + inclusiveMax = &defaultInclusiveMax + } + // find all the ranges + minInt64 := numeric_util.Float64ToInt64(*min) + if !*inclusiveMin && minInt64 != math.MaxInt64 { + minInt64++ + } + maxInt64 := numeric_util.Float64ToInt64(*max) + if !*inclusiveMax && maxInt64 != math.MinInt64 { + maxInt64-- + } + // FIXME hard-coded precision, should match field declaration + termRanges := splitInt64Range(minInt64, maxInt64, 4) + terms := termRanges.Enumerate() + // enumerate all the terms in the range + qsearchers := make([]search.Searcher, len(terms)) + for i, term := range terms { + var err error + qsearchers[i], err = NewTermSearcher(indexReader, string(term), field, 1.0, explain) + if err != nil { + return nil, err + } + } + // build disjunction searcher of these ranges + searcher, err := NewDisjunctionSearcher(indexReader, qsearchers, 0, explain) + if err != nil { + return nil, err + } + return &NumericRangeSearcher{ + indexReader: indexReader, + min: min, + max: max, + field: field, + explain: explain, + searcher: searcher, + }, nil +} + +func (s *NumericRangeSearcher) Count() uint64 { + return s.searcher.Count() +} + +func (s *NumericRangeSearcher) Weight() float64 { + return s.searcher.Weight() +} + +func (s *NumericRangeSearcher) SetQueryNorm(qnorm float64) { + s.searcher.SetQueryNorm(qnorm) +} + +func (s *NumericRangeSearcher) Next() (*search.DocumentMatch, error) { + return s.searcher.Next() +} + +func (s *NumericRangeSearcher) Advance(ID string) (*search.DocumentMatch, error) { + return s.searcher.Advance(ID) +} + +func (s *NumericRangeSearcher) Close() error { + return s.searcher.Close() +} + +type termRange struct { + startTerm []byte + endTerm []byte +} + +func (t *termRange) Enumerate() [][]byte { + rv := make([][]byte, 0) + next := t.startTerm + for bytes.Compare(next, t.endTerm) <= 0 { + rv = append(rv, next) + next = incrementBytes(next) + } + return rv +} + +func incrementBytes(in []byte) []byte { + rv := make([]byte, len(in)) + copy(rv, in) + for i := len(rv) - 1; i >= 0; i-- { + rv[i] = rv[i] + 1 + if rv[i] != 0 { + // didnt' overflow, so stop + break + } + } + return rv +} + +type termRanges []*termRange + +func (tr termRanges) Enumerate() [][]byte { + rv := make([][]byte, 0) + for _, tri := range tr { + trie := tri.Enumerate() + rv = append(rv, trie...) + } + return rv +} + +func splitInt64Range(minBound, maxBound int64, precisionStep uint) termRanges { + rv := make(termRanges, 0) + if minBound > maxBound { + return rv + } + + for shift := uint(0); ; shift += precisionStep { + + diff := int64(1) << (shift + precisionStep) + mask := ((int64(1) << precisionStep) - int64(1)) << shift + hasLower := (minBound & mask) != int64(0) + hasUpper := (maxBound & mask) != mask + + var nextMinBound int64 + if hasLower { + nextMinBound = (minBound + diff) &^ mask + } else { + nextMinBound = minBound &^ mask + } + var nextMaxBound int64 + if hasUpper { + nextMaxBound = (maxBound - diff) &^ mask + } else { + nextMaxBound = maxBound &^ mask + } + + lowerWrapped := nextMinBound < minBound + upperWrapped := nextMaxBound > maxBound + + if shift+precisionStep >= 64 || nextMinBound > nextMaxBound || lowerWrapped || upperWrapped { + // We are in the lowest precision or the next precision is not available. + rv = append(rv, newRange(minBound, maxBound, shift)) + // exit the split recursion loop + break + } + + if hasLower { + rv = append(rv, newRange(minBound, minBound|mask, shift)) + } + if hasUpper { + rv = append(rv, newRange(maxBound&^mask, maxBound, shift)) + } + + // recurse to next precision + minBound = nextMinBound + maxBound = nextMaxBound + } + + return rv +} + +func newRange(minBound, maxBound int64, shift uint) *termRange { + maxBound |= (int64(1) << shift) - int64(1) + minBytes := numeric_util.MustNewPrefixCodedInt64(minBound, shift) + maxBytes := numeric_util.MustNewPrefixCodedInt64(maxBound, shift) + return newRangeBytes(minBytes, maxBytes) +} + +func newRangeBytes(minBytes, maxBytes []byte) *termRange { + return &termRange{ + startTerm: minBytes, + endTerm: maxBytes, + } +} + +func (s *NumericRangeSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range_test.go new file mode 100644 index 00000000..a7599e8b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_numeric_range_test.go @@ -0,0 +1,55 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "reflect" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/numeric_util" +) + +func TestSplitRange(t *testing.T) { + min := numeric_util.Float64ToInt64(1.0) + max := numeric_util.Float64ToInt64(5.0) + ranges := splitInt64Range(min, max, 4) + enumerated := ranges.Enumerate() + if len(enumerated) != 135 { + t.Errorf("expected 135 terms, got %d", len(enumerated)) + } + +} + +func TestIncrementBytes(t *testing.T) { + tests := []struct { + in []byte + out []byte + }{ + { + in: []byte{0}, + out: []byte{1}, + }, + { + in: []byte{0, 0}, + out: []byte{0, 1}, + }, + { + in: []byte{0, 255}, + out: []byte{1, 0}, + }, + } + + for _, test := range tests { + actual := incrementBytes(test.in) + if !reflect.DeepEqual(actual, test.out) { + t.Errorf("expected %#v, got %#v", test.out, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase.go new file mode 100644 index 00000000..3f8f5342 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase.go @@ -0,0 +1,197 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "math" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type PhraseSearcher struct { + initialized bool + indexReader index.IndexReader + mustSearcher *ConjunctionSearcher + queryNorm float64 + currMust *search.DocumentMatch + slop int + terms []string +} + +func NewPhraseSearcher(indexReader index.IndexReader, mustSearcher *ConjunctionSearcher, terms []string) (*PhraseSearcher, error) { + // build our searcher + rv := PhraseSearcher{ + indexReader: indexReader, + mustSearcher: mustSearcher, + terms: terms, + } + rv.computeQueryNorm() + return &rv, nil +} + +func (s *PhraseSearcher) computeQueryNorm() { + // first calculate sum of squared weights + sumOfSquaredWeights := 0.0 + if s.mustSearcher != nil { + sumOfSquaredWeights += s.mustSearcher.Weight() + } + + // now compute query norm from this + s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights) + // finally tell all the downstream searchers the norm + if s.mustSearcher != nil { + s.mustSearcher.SetQueryNorm(s.queryNorm) + } +} + +func (s *PhraseSearcher) initSearchers() error { + var err error + // get all searchers pointing at their first match + if s.mustSearcher != nil { + s.currMust, err = s.mustSearcher.Next() + if err != nil { + return err + } + } + + s.initialized = true + return nil +} + +func (s *PhraseSearcher) advanceNextMust() error { + var err error + + if s.mustSearcher != nil { + s.currMust, err = s.mustSearcher.Next() + if err != nil { + return err + } + } + + return nil +} + +func (s *PhraseSearcher) Weight() float64 { + var rv float64 + rv += s.mustSearcher.Weight() + + return rv +} + +func (s *PhraseSearcher) SetQueryNorm(qnorm float64) { + s.mustSearcher.SetQueryNorm(qnorm) +} + +func (s *PhraseSearcher) Next() (*search.DocumentMatch, error) { + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + + var rv *search.DocumentMatch + for s.currMust != nil { + rvftlm := make(search.FieldTermLocationMap, 0) + freq := 0 + firstTerm := s.terms[0] + for field, termLocMap := range s.currMust.Locations { + rvtlm := make(search.TermLocationMap, 0) + locations, ok := termLocMap[firstTerm] + if ok { + OUTER: + for _, location := range locations { + crvtlm := make(search.TermLocationMap, 0) + INNER: + for i := 0; i < len(s.terms); i++ { + nextTerm := s.terms[i] + if nextTerm != "" { + // look through all these term locations + // to try and find the correct offsets + nextLocations, ok := termLocMap[nextTerm] + if ok { + for _, nextLocation := range nextLocations { + if nextLocation.Pos == location.Pos+float64(i) { + // found a location match for this term + crvtlm.AddLocation(nextTerm, nextLocation) + continue INNER + } + } + // if we got here we didn't find a location match for this term + continue OUTER + } else { + continue OUTER + } + } + } + // if we got here all the terms matched + freq++ + search.MergeTermLocationMaps(rvtlm, crvtlm) + rvftlm[field] = rvtlm + } + } + } + + if freq > 0 { + // return match + rv = s.currMust + rv.Locations = rvftlm + err := s.advanceNextMust() + if err != nil { + return nil, err + } + return rv, nil + } + + err := s.advanceNextMust() + if err != nil { + return nil, err + } + } + + return nil, nil +} + +func (s *PhraseSearcher) Advance(ID string) (*search.DocumentMatch, error) { + if !s.initialized { + err := s.initSearchers() + if err != nil { + return nil, err + } + } + var err error + s.currMust, err = s.mustSearcher.Advance(ID) + if err != nil { + return nil, err + } + return s.Next() +} + +func (s *PhraseSearcher) Count() uint64 { + // for now return a worst case + var sum uint64 + sum += s.mustSearcher.Count() + return sum +} + +func (s *PhraseSearcher) Close() error { + if s.mustSearcher != nil { + err := s.mustSearcher.Close() + if err != nil { + return err + } + } + return nil +} + +func (s *PhraseSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase_test.go new file mode 100644 index 00000000..9deaeefd --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_phrase_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestPhraseSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + angstTermSearcher, err := NewTermSearcher(twoDocIndexReader, "angst", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + mustSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{angstTermSearcher, beerTermSearcher}, true) + if err != nil { + t.Fatal(err) + } + phraseSearcher, err := NewPhraseSearcher(twoDocIndexReader, mustSearcher, []string{"angst", "beer"}) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + results []*search.DocumentMatch + }{ + { + searcher: phraseSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "2", + Score: 1.0807601687084403, + }, + }, + }, + } + + for testIndex, test := range tests { + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if next.Score != test.results[i].Score { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp.go new file mode 100644 index 00000000..7a5905b9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp.go @@ -0,0 +1,108 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "regexp" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type RegexpSearcher struct { + indexReader index.IndexReader + pattern *regexp.Regexp + field string + explain bool + searcher *DisjunctionSearcher +} + +func NewRegexpSearcher(indexReader index.IndexReader, pattern *regexp.Regexp, field string, boost float64, explain bool) (*RegexpSearcher, error) { + + prefixTerm, complete := pattern.LiteralPrefix() + candidateTerms := make([]string, 0) + if complete { + // there is no pattern + candidateTerms = append(candidateTerms, prefixTerm) + } else { + var fieldDict index.FieldDict + var err error + if len(prefixTerm) > 0 { + fieldDict, err = indexReader.FieldDictPrefix(field, []byte(prefixTerm)) + } else { + fieldDict, err = indexReader.FieldDict(field) + } + + // enumerate the terms and check against regexp + tfd, err := fieldDict.Next() + for err == nil && tfd != nil { + if pattern.MatchString(tfd.Term) { + candidateTerms = append(candidateTerms, tfd.Term) + } + tfd, err = fieldDict.Next() + } + if err != nil { + return nil, err + } + } + + // enumerate all the terms in the range + qsearchers := make([]search.Searcher, 0, 25) + + for _, cterm := range candidateTerms { + qsearcher, err := NewTermSearcher(indexReader, cterm, field, 1.0, explain) + if err != nil { + return nil, err + } + qsearchers = append(qsearchers, qsearcher) + } + + // build disjunction searcher of these ranges + searcher, err := NewDisjunctionSearcher(indexReader, qsearchers, 0, explain) + if err != nil { + return nil, err + } + + return &RegexpSearcher{ + indexReader: indexReader, + pattern: pattern, + field: field, + explain: explain, + searcher: searcher, + }, nil +} +func (s *RegexpSearcher) Count() uint64 { + return s.searcher.Count() +} + +func (s *RegexpSearcher) Weight() float64 { + return s.searcher.Weight() +} + +func (s *RegexpSearcher) SetQueryNorm(qnorm float64) { + s.searcher.SetQueryNorm(qnorm) +} + +func (s *RegexpSearcher) Next() (*search.DocumentMatch, error) { + return s.searcher.Next() + +} + +func (s *RegexpSearcher) Advance(ID string) (*search.DocumentMatch, error) { + return s.searcher.Next() +} + +func (s *RegexpSearcher) Close() error { + return s.searcher.Close() +} + +func (s *RegexpSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp_test.go new file mode 100644 index 00000000..87e7bf8b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_regexp_test.go @@ -0,0 +1,110 @@ +// Copyright (c) 2015 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "regexp" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestRegexpSearch(t *testing.T) { + + twoDocIndexReader, err := twoDocIndex.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := twoDocIndexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + pattern, err := regexp.Compile("ma.*") + if err != nil { + t.Fatal(err) + } + + regexpSearcher, err := NewRegexpSearcher(twoDocIndexReader, pattern, "name", 1.0, true) + if err != nil { + t.Fatal(err) + } + + patternCo, err := regexp.Compile("co.*") + if err != nil { + t.Fatal(err) + } + + regexpSearcherCo, err := NewRegexpSearcher(twoDocIndexReader, patternCo, "desc", 1.0, true) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + searcher search.Searcher + results []*search.DocumentMatch + }{ + { + searcher: regexpSearcher, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "1", + Score: 1.916290731874155, + }, + }, + }, + { + searcher: regexpSearcherCo, + results: []*search.DocumentMatch{ + &search.DocumentMatch{ + ID: "2", + Score: 0.33875554280828685, + }, + &search.DocumentMatch{ + ID: "3", + Score: 0.33875554280828685, + }, + }, + }, + } + + for testIndex, test := range tests { + defer func() { + err := test.searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + next, err := test.searcher.Next() + i := 0 + for err == nil && next != nil { + if i < len(test.results) { + if next.ID != test.results[i].ID { + t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].ID, next.ID, testIndex) + } + if next.Score != test.results[i].Score { + t.Errorf("expected result %d to have score %v got %v for test %d", i, test.results[i].Score, next.Score, testIndex) + t.Logf("scoring explanation: %s", next.Expl) + } + } + next, err = test.searcher.Next() + i++ + } + if err != nil { + t.Fatalf("error iterating searcher: %v for test %d", err, testIndex) + } + if len(test.results) != i { + t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term.go new file mode 100644 index 00000000..51b8a944 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term.go @@ -0,0 +1,95 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search/scorers" +) + +type TermSearcher struct { + indexReader index.IndexReader + term string + field string + explain bool + reader index.TermFieldReader + scorer *scorers.TermQueryScorer +} + +func NewTermSearcher(indexReader index.IndexReader, term string, field string, boost float64, explain bool) (*TermSearcher, error) { + reader, err := indexReader.TermFieldReader([]byte(term), field) + if err != nil { + return nil, err + } + scorer := scorers.NewTermQueryScorer(term, field, boost, indexReader.DocCount(), reader.Count(), explain) + return &TermSearcher{ + indexReader: indexReader, + term: term, + field: field, + explain: explain, + reader: reader, + scorer: scorer, + }, nil +} + +func (s *TermSearcher) Count() uint64 { + return s.reader.Count() +} + +func (s *TermSearcher) Weight() float64 { + return s.scorer.Weight() +} + +func (s *TermSearcher) SetQueryNorm(qnorm float64) { + s.scorer.SetQueryNorm(qnorm) +} + +func (s *TermSearcher) Next() (*search.DocumentMatch, error) { + termMatch, err := s.reader.Next() + if err != nil { + return nil, err + } + + if termMatch == nil { + return nil, nil + } + + // score match + docMatch := s.scorer.Score(termMatch) + // return doc match + return docMatch, nil + +} + +func (s *TermSearcher) Advance(ID string) (*search.DocumentMatch, error) { + termMatch, err := s.reader.Advance(ID) + if err != nil { + return nil, err + } + + if termMatch == nil { + return nil, nil + } + + // score match + docMatch := s.scorer.Score(termMatch) + + // return doc match + return docMatch, nil +} + +func (s *TermSearcher) Close() error { + return s.reader.Close() +} + +func (s *TermSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_prefix.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_prefix.go new file mode 100644 index 00000000..3fd88df6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_prefix.go @@ -0,0 +1,81 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +type TermPrefixSearcher struct { + indexReader index.IndexReader + prefix string + field string + explain bool + searcher *DisjunctionSearcher +} + +func NewTermPrefixSearcher(indexReader index.IndexReader, prefix string, field string, boost float64, explain bool) (*TermPrefixSearcher, error) { + // find the terms with this prefix + fieldDict, err := indexReader.FieldDictPrefix(field, []byte(prefix)) + + // enumerate all the terms in the range + qsearchers := make([]search.Searcher, 0, 25) + tfd, err := fieldDict.Next() + for err == nil && tfd != nil { + qsearcher, err := NewTermSearcher(indexReader, string(tfd.Term), field, 1.0, explain) + if err != nil { + return nil, err + } + qsearchers = append(qsearchers, qsearcher) + tfd, err = fieldDict.Next() + } + // build disjunction searcher of these ranges + searcher, err := NewDisjunctionSearcher(indexReader, qsearchers, 0, explain) + if err != nil { + return nil, err + } + + return &TermPrefixSearcher{ + indexReader: indexReader, + prefix: prefix, + field: field, + explain: explain, + searcher: searcher, + }, nil +} +func (s *TermPrefixSearcher) Count() uint64 { + return s.searcher.Count() +} + +func (s *TermPrefixSearcher) Weight() float64 { + return s.searcher.Weight() +} + +func (s *TermPrefixSearcher) SetQueryNorm(qnorm float64) { + s.searcher.SetQueryNorm(qnorm) +} + +func (s *TermPrefixSearcher) Next() (*search.DocumentMatch, error) { + return s.searcher.Next() + +} + +func (s *TermPrefixSearcher) Advance(ID string) (*search.DocumentMatch, error) { + return s.searcher.Next() +} + +func (s *TermPrefixSearcher) Close() error { + return s.searcher.Close() +} + +func (s *TermPrefixSearcher) Min() int { + return 0 +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_test.go new file mode 100644 index 00000000..4f2b52ef --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/searchers/search_term_test.go @@ -0,0 +1,195 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package searchers + +import ( + "math" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/document" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/store/inmem" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down" +) + +func TestTermSearcher(t *testing.T) { + + var queryTerm = "beer" + var queryField = "desc" + var queryBoost = 3.0 + var queryExplain = true + + inMemStore, _ := inmem.New() + analysisQueue := upside_down.NewAnalysisQueue(1) + i := upside_down.NewUpsideDownCouch(inMemStore, analysisQueue) + err := i.Open() + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "a", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "b", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "c", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "d", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "e", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "f", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "g", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "h", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "i", + Fields: []document.Field{ + document.NewTextField("desc", []uint64{}, []byte("beer")), + }, + }) + if err != nil { + t.Fatal(err) + } + err = i.Update(&document.Document{ + ID: "j", + Fields: []document.Field{ + document.NewTextField("title", []uint64{}, []byte("cat")), + }, + }) + if err != nil { + t.Fatal(err) + } + + indexReader, err := i.Reader() + if err != nil { + t.Error(err) + } + defer func() { + err := indexReader.Close() + if err != nil { + t.Fatal(err) + } + }() + + searcher, err := NewTermSearcher(indexReader, queryTerm, queryField, queryBoost, queryExplain) + if err != nil { + t.Fatal(err) + } + defer func() { + err := searcher.Close() + if err != nil { + t.Fatal(err) + } + }() + + searcher.SetQueryNorm(2.0) + docCount, err := i.DocCount() + if err != nil { + t.Fatal(err) + } + idf := 1.0 + math.Log(float64(docCount)/float64(searcher.Count()+1.0)) + expectedQueryWeight := 3 * idf * 3 * idf + if expectedQueryWeight != searcher.Weight() { + t.Errorf("expected weight %v got %v", expectedQueryWeight, searcher.Weight()) + } + + if searcher.Count() != 9 { + t.Errorf("expected count of 9, got %d", searcher.Count()) + } + + docMatch, err := searcher.Next() + if err != nil { + t.Errorf("expected result, got %v", err) + } + if docMatch.ID != "a" { + t.Errorf("expected result ID to be 'a', got '%s", docMatch.ID) + } + docMatch, err = searcher.Advance("c") + if err != nil { + t.Errorf("expected result, got %v", err) + } + if docMatch.ID != "c" { + t.Errorf("expected result ID to be 'c' got '%s'", docMatch.ID) + } + + // try advancing past end + docMatch, err = searcher.Advance("z") + if err != nil { + t.Fatal(err) + } + if docMatch != nil { + t.Errorf("expected nil, got %v", docMatch) + } + + // try pushing next past end + docMatch, err = searcher.Next() + if err != nil { + t.Fatal(err) + } + if docMatch != nil { + t.Errorf("expected nil, got %v", docMatch) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/util.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/util.go new file mode 100644 index 00000000..6867eee7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/util.go @@ -0,0 +1,37 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +func MergeLocations(locations []FieldTermLocationMap) FieldTermLocationMap { + rv := locations[0] + + for i := 1; i < len(locations); i++ { + nextLocations := locations[i] + for field, termLocationMap := range nextLocations { + rvTermLocationMap, rvHasField := rv[field] + if rvHasField { + rv[field] = MergeTermLocationMaps(rvTermLocationMap, termLocationMap) + } else { + rv[field] = termLocationMap + } + } + } + + return rv +} + +func MergeTermLocationMaps(rv, other TermLocationMap) TermLocationMap { + for term, locationMap := range other { + // for a given term/document there cannot be different locations + // if they came back from different clauses, overwrite is ok + rv[term] = locationMap + } + return rv +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search/util_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/util_test.go new file mode 100644 index 00000000..4185646e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search/util_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2013 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package search + +import ( + "reflect" + "testing" +) + +func TestMergeLocations(t *testing.T) { + flm1 := FieldTermLocationMap{ + "marty": TermLocationMap{ + "name": { + &Location{ + Pos: 1, + Start: 0, + End: 5, + }, + }, + }, + } + + flm2 := FieldTermLocationMap{ + "marty": TermLocationMap{ + "description": { + &Location{ + Pos: 5, + Start: 20, + End: 25, + }, + }, + }, + } + + flm3 := FieldTermLocationMap{ + "josh": TermLocationMap{ + "description": { + &Location{ + Pos: 5, + Start: 20, + End: 25, + }, + }, + }, + } + + expectedMerge := FieldTermLocationMap{ + "marty": TermLocationMap{ + "description": { + &Location{ + Pos: 5, + Start: 20, + End: 25, + }, + }, + "name": { + &Location{ + Pos: 1, + Start: 0, + End: 5, + }, + }, + }, + "josh": TermLocationMap{ + "description": { + &Location{ + Pos: 5, + Start: 20, + End: 25, + }, + }, + }, + } + + mergedLocations := MergeLocations([]FieldTermLocationMap{flm1, flm2, flm3}) + if !reflect.DeepEqual(expectedMerge, mergedLocations) { + t.Errorf("expected %v, got %v", expectedMerge, mergedLocations) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/search_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/search_test.go new file mode 100644 index 00000000..16ffc7b9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/search_test.go @@ -0,0 +1,117 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package bleve + +import ( + "reflect" + "strings" + "testing" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/search" +) + +func TestSearchResultString(t *testing.T) { + + tests := []struct { + result *SearchResult + str string + }{ + { + result: &SearchResult{ + Request: &SearchRequest{ + Size: 10, + }, + Total: 5, + Took: 1 * time.Second, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{}, + &search.DocumentMatch{}, + &search.DocumentMatch{}, + &search.DocumentMatch{}, + &search.DocumentMatch{}, + }, + }, + str: "5 matches, showing 1 through 5, took 1s", + }, + { + result: &SearchResult{ + Request: &SearchRequest{ + Size: 0, + }, + Total: 5, + Hits: search.DocumentMatchCollection{}, + }, + str: "5 matches", + }, + { + result: &SearchResult{ + Request: &SearchRequest{ + Size: 10, + }, + Total: 0, + Hits: search.DocumentMatchCollection{}, + }, + str: "No matches", + }, + } + + for _, test := range tests { + srstring := test.result.String() + if !strings.HasPrefix(srstring, test.str) { + t.Errorf("expected to start %s, got %s", test.str, srstring) + } + } +} + +func TestSearchResultMerge(t *testing.T) { + l := &SearchResult{ + Total: 1, + MaxScore: 1, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 1, + }, + }, + } + + r := &SearchResult{ + Total: 1, + MaxScore: 2, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "b", + Score: 2, + }, + }, + } + + expected := &SearchResult{ + Total: 2, + MaxScore: 2, + Hits: search.DocumentMatchCollection{ + &search.DocumentMatch{ + ID: "a", + Score: 1, + }, + &search.DocumentMatch{ + ID: "b", + Score: 2, + }, + }, + } + + l.Merge(r) + + if !reflect.DeepEqual(l, expected) { + t.Errorf("expected %#v, got %#v", expected, l) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration.go new file mode 100644 index 00000000..45e4cb33 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration.go @@ -0,0 +1,22 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package test + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +type SearchTest struct { + Search *bleve.SearchRequest `json:"search"` + Result *bleve.SearchResult `json:"result"` + Comment string `json:"comment"` +} + +type SearchTests []*SearchTest diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration_test.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration_test.go new file mode 100644 index 00000000..1b424632 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/integration_test.go @@ -0,0 +1,163 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package test + +import ( + "encoding/json" + "flag" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "regexp" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +var dataset = flag.String("dataset", "", "only test datasets matching this regex") +var keepIndex = flag.Bool("keepIndex", false, "keep the index after testing") + +func TestIntegration(t *testing.T) { + + flag.Parse() + + var err error + var datasetRegexp *regexp.Regexp + if *dataset != "" { + datasetRegexp, err = regexp.Compile(*dataset) + if err != nil { + t.Fatal(err) + } + } + + fis, err := ioutil.ReadDir("tests") + if err != nil { + t.Fatal(err) + } + for _, fi := range fis { + if datasetRegexp != nil { + if !datasetRegexp.MatchString(fi.Name()) { + continue + } + } + if fi.IsDir() { + t.Logf("Running test: %s", fi.Name()) + runTestDir(t, "tests"+string(filepath.Separator)+fi.Name()) + } + } +} + +func runTestDir(t *testing.T, dir string) { + // read the mapping + mappingBytes, err := ioutil.ReadFile(dir + string(filepath.Separator) + "mapping.json") + if err != nil { + t.Errorf("error reading mapping: %v", err) + return + } + var mapping bleve.IndexMapping + err = json.Unmarshal(mappingBytes, &mapping) + if err != nil { + t.Errorf("error unmarshalling mapping: %v", err) + return + } + + // open new index + if !*keepIndex { + defer func() { + err := os.RemoveAll("test.bleve") + if err != nil { + t.Fatal(err) + } + }() + } + index, err := bleve.New("test.bleve", &mapping) + if err != nil { + t.Errorf("error creating new index: %v", err) + return + } + defer func() { + err := index.Close() + if err != nil { + t.Fatal(err) + } + }() + + // index data + fis, err := ioutil.ReadDir(dir + string(filepath.Separator) + "data") + if err != nil { + t.Errorf("error reading data dir: %v", err) + return + } + for _, fi := range fis { + fileBytes, err := ioutil.ReadFile(dir + string(filepath.Separator) + "data" + string(filepath.Separator) + fi.Name()) + if err != nil { + t.Errorf("error reading data file: %v", err) + return + } + filename := fi.Name() + ext := filepath.Ext(filename) + id := filename[0 : len(filename)-len(ext)] + err = index.Index(id, fileBytes) + if err != nil { + t.Errorf("error indexing data: %v", err) + return + } + } + + // read the searches + searchBytes, err := ioutil.ReadFile(dir + string(filepath.Separator) + "searches.json") + if err != nil { + t.Errorf("error reading searches: %v", err) + return + } + var searches SearchTests + err = json.Unmarshal(searchBytes, &searches) + if err != nil { + t.Errorf("error unmarshalling searches: %v", err) + return + } + + // run the searches + for testNum, search := range searches { + res, err := index.Search(search.Search) + if err != nil { + t.Errorf("error running search: %v", err) + } + if res.Total != search.Result.Total { + t.Errorf("test %d - expected total: %d got %d", testNum, search.Result.Total, res.Total) + continue + } + if len(res.Hits) != len(search.Result.Hits) { + t.Errorf("test %d - expected hits len: %d got %d", testNum, len(search.Result.Hits), len(res.Hits)) + continue + } + for hi, hit := range search.Result.Hits { + if hit.ID != res.Hits[hi].ID { + t.Errorf("test %d - expected hit %d to have ID %s got %s", testNum, hi, hit.ID, res.Hits[hi].ID) + } + if hit.Fields != nil { + if !reflect.DeepEqual(hit.Fields, res.Hits[hi].Fields) { + t.Errorf("test %d - expected hit %d to have fields %#v got %#v", testNum, hi, hit.Fields, res.Hits[hi].Fields) + } + } + if hit.Fragments != nil { + if !reflect.DeepEqual(hit.Fragments, res.Hits[hi].Fragments) { + t.Errorf("test %d - expected hit %d to have fragments %#v got %#v", testNum, hi, hit.Fragments, res.Hits[hi].Fragments) + } + } + } + if search.Result.Facets != nil { + if !reflect.DeepEqual(search.Result.Facets, res.Facets) { + t.Errorf("test %d - expected facets: %#v got %#v", testNum, search.Result.Facets, res.Facets) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/a.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/a.json new file mode 100644 index 00000000..992bbd99 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/a.json @@ -0,0 +1,7 @@ +{ + "id": "a", + "name": "marty", + "age": 19, + "title": "mista", + "tags": ["gopher", "belieber"] +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/b.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/b.json new file mode 100644 index 00000000..58118a55 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/b.json @@ -0,0 +1,7 @@ +{ + "id": "b", + "name": "steve has a long name", + "age": 27, + "birthday": "2001-09-09T01:46:40Z", + "title": "missess" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/c.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/c.json new file mode 100644 index 00000000..2b5d3088 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/c.json @@ -0,0 +1,7 @@ +{ + "id": "c", + "name": "bob walks home", + "age": 64, + "birthday": "2014-05-13T16:53:20Z", + "title": "masta" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/d.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/d.json new file mode 100644 index 00000000..dbc2f51b --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/data/d.json @@ -0,0 +1,7 @@ +{ + "id": "d", + "name": "bobbleheaded wings top the phone", + "age": 72, + "birthday": "2014-05-13T16:53:20Z", + "title": "mizz" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/mapping.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/mapping.json new file mode 100644 index 00000000..a7a049be --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/mapping.json @@ -0,0 +1,27 @@ +{ + "types": { + "person": { + "properties": { + "name": { + "fields": [ + { + "include_term_vectors": true, + "include_in_all": true, + "index": true, + "store": true, + "analyzer": "en", + "type": "text" + } + ], + "dynamic": true, + "enabled": true + }, + "id": { + "dynamic": false, + "enabled": false + } + } + } + }, + "default_type": "person" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/searches.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/searches.json new file mode 100644 index 00000000..6f61fc1e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/basic/searches.json @@ -0,0 +1,406 @@ +[ + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "term": "marti" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "term": "noone" + } + }, + "result": { + "total_hits": 0, + "hits": [] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "match_phrase": "long name" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "term": "walking" + } + }, + "result": { + "total_hits": 0, + "hits": [] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "fuzziness": 0, + "prefix_length": 0, + "field": "name", + "match": "walking" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "c" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "prefix": "bobble" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "d" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "query": "+name:phone" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "d" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "age", + "max": 30 + } + }, + "result": { + "total_hits": 2, + "hits": [ + { + "id": "b" + }, + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "age", + "max": 30, + "min": 20 + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "conjuncts": [ + { + "boost": 1, + "field": "age", + "min": 20 + }, + { + "boost": 1, + "field": "age", + "max": 30 + } + ] + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "birthday", + "start": "2010-01-01" + } + }, + "result": { + "total_hits": 2, + "hits": [ + { + "id": "d" + }, + { + "id": "c" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "birthday", + "end": "2010-01-01" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "tags", + "term": "gopher" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "tags", + "term": "belieber" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "tags", + "term": "notintagsarray" + } + }, + "result": { + "total_hits": 0, + "hits": [] + } + }, + { + "comment": "with size 0, total should be 1, but hits empty", + "search": { + "from": 0, + "size": 0, + "query": { + "field": "name", + "term": "marti" + } + }, + "result": { + "total_hits": 1, + "hits": [] + } + }, + { + "comment": "a search for doc a that includes tags field, verifies both values come back", + "search": { + "from": 0, + "size": 10, + "fields": ["tags"], + "query": { + "field": "name", + "term": "marti" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a", + "fields": { + "tags": ["gopher", "belieber"] + } + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "term": "msrti", + "fuzziness": 1 + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "comment": "highlight results", + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "match": "long" + }, + "highlight": { + "fields": ["name"] + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b", + "fragments": { + "name": ["steve has a long name"] + } + } + ] + } + }, + { + "comment": "highlight results without specifying fields", + "search": { + "from": 0, + "size": 10, + "query": { + "field": "name", + "match": "long" + }, + "highlight": {} + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b", + "fragments": { + "name": ["steve has a long name"] + } + } + ] + } + }, + { + "comment": "request fields", + "search": { + "from": 0, + "size": 10, + "fields": ["age","birthday"], + "query": { + "field": "name", + "match": "long" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "b", + "fields": { + "age": 27, + "birthday": "2001-09-09T01:46:40Z" + } + } + ] + } + } +] \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/a.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/a.json new file mode 100644 index 00000000..777b21f9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/a.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "book", + "rating": 2, + "updated": "2014-11-25" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/b.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/b.json new file mode 100644 index 00000000..c3c2c696 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/b.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "book", + "rating": 7, + "updated": "2013-07-25" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/c.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/c.json new file mode 100644 index 00000000..da3542cc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/c.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "book", + "rating": 1, + "updated": "2014-03-03" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/d.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/d.json new file mode 100644 index 00000000..20aaef1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/d.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "book", + "rating": 9, + "updated": "2014-09-16" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/e.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/e.json new file mode 100644 index 00000000..8dbd28a8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/e.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "book", + "rating": 5, + "updated": "2014-11-15" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/f.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/f.json new file mode 100644 index 00000000..74e8cd21 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/f.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "movie", + "rating": 3, + "updated": "2017-06-05" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/g.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/g.json new file mode 100644 index 00000000..ea5f29fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/g.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "movie", + "rating": 9, + "updated": "2011-10-03" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/h.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/h.json new file mode 100644 index 00000000..f91c0d78 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/h.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "movie", + "rating": 9, + "updated": "2019-08-26" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/i.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/i.json new file mode 100644 index 00000000..e46e5b70 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/i.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "movie", + "rating": 1, + "updated": "2014-12-14" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/j.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/j.json new file mode 100644 index 00000000..263f07b5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/data/j.json @@ -0,0 +1,6 @@ +{ + "category": "inventory", + "type": "game", + "rating": 9, + "updated": "2013-10-20" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/mapping.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/mapping.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/mapping.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/searches.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/searches.json new file mode 100644 index 00000000..6752282a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/facet/searches.json @@ -0,0 +1,144 @@ +[ + { + "search": { + "from": 0, + "size": 0, + "query": { + "field": "category", + "term": "inventory" + }, + "facets": { + "types": { + "size": 3, + "field": "type" + } + } + }, + "result": { + "total_hits": 10, + "hits": [], + "facets": { + "types": { + "field": "type", + "total": 10, + "missing": 0, + "other": 0, + "terms": [ + { + "term": "book", + "count": 5 + }, + { + "term": "movie", + "count": 4 + }, + { + "term": "game", + "count": 1 + } + ] + } + } + } + }, + { + "search": { + "from": 0, + "size": 0, + "query": { + "field": "category", + "term": "inventory" + }, + "facets": { + "types": { + "size": 3, + "field": "rating", + "numeric_ranges": [ + { + "name": "low", + "max": 5 + }, + { + "name": "high", + "min": 5 + } + ] + } + } + }, + "result": { + "total_hits": 10, + "hits": [], + "facets": { + "types": { + "field": "rating", + "total": 10, + "missing": 0, + "other": 0, + "numeric_ranges": [ + { + "name": "high", + "count": 6, + "min": 5 + }, + { + "name": "low", + "count": 4, + "max": 5 + } + ] + } + } + } + }, + { + "search": { + "from": 0, + "size": 0, + "query": { + "field": "category", + "term": "inventory" + }, + "facets": { + "types": { + "size": 3, + "field": "updated", + "date_ranges": [ + { + "name": "old", + "end": "2012-01-01" + }, + { + "name": "new", + "start": "2012-01-01" + } + ] + } + } + }, + "result": { + "total_hits": 10, + "hits": [], + "facets": { + "types": { + "field": "updated", + "total": 10, + "missing": 0, + "other": 0, + "date_ranges": [ + { + "name": "new", + "count": 9, + "start": "2012-01-01T00:00:00Z" + }, + { + "name": "old", + "count": 1, + "end": "2012-01-01T00:00:00Z" + } + ] + } + } + } + } +] \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3311@FOSDEM15@fosdem.org.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3311@FOSDEM15@fosdem.org.json new file mode 100644 index 00000000..62918db4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3311@FOSDEM15@fosdem.org.json @@ -0,0 +1,4 @@ +{ + "description": "From Prolog to Erlang to Haskell to Lisp to TLC and then back to Prolog I have journeyed, and I'd like to share some of the beautiful", + "category": "Word" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3492@FOSDEM15@fosdem.org.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3492@FOSDEM15@fosdem.org.json new file mode 100644 index 00000000..874f60ec --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3492@FOSDEM15@fosdem.org.json @@ -0,0 +1,4 @@ +{ + "description": "different cats", + "category": "Perl" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3496@FOSDEM15@fosdem.org.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3496@FOSDEM15@fosdem.org.json new file mode 100644 index 00000000..1acdf344 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3496@FOSDEM15@fosdem.org.json @@ -0,0 +1,4 @@ +{ + "description": "many cats", + "category": "Perl" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3505@FOSDEM15@fosdem.org.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3505@FOSDEM15@fosdem.org.json new file mode 100644 index 00000000..fb670aa2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3505@FOSDEM15@fosdem.org.json @@ -0,0 +1,4 @@ +{ + "description": "From Prolog to Erlang to Haskell to Lisp to TLC and then back to Prolog I have journeyed, and I'd like to share some of the beautiful", + "category": "Perl" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3507@FOSDEM15@fosdem.org.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3507@FOSDEM15@fosdem.org.json new file mode 100644 index 00000000..38be8e35 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/data/3507@FOSDEM15@fosdem.org.json @@ -0,0 +1,4 @@ +{ + "description": "From Prolog to Erlang to Haskell to Gel to TLC and then back to Prolog I have journeyed, and I'd like to share some of the beautiful", + "category": "Perl" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/mapping.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/mapping.json new file mode 100644 index 00000000..470b9940 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/mapping.json @@ -0,0 +1,76 @@ +{ + "default_mapping": { + "enabled": true, + "dynamic": true, + "properties": { + "category": { + "enabled": true, + "dynamic": true, + "fields": [ + { + "type": "text", + "analyzer": "keyword", + "store": true, + "index": true, + "include_term_vectors": true, + "include_in_all": true + } + ], + "default_analyzer": "" + }, + "description": { + "enabled": true, + "dynamic": true, + "fields": [ + { + "type": "text", + "analyzer": "en", + "store": true, + "index": true, + "include_term_vectors": true, + "include_in_all": true + } + ], + "default_analyzer": "" + }, + "summary": { + "enabled": true, + "dynamic": true, + "fields": [ + { + "type": "text", + "analyzer": "en", + "store": true, + "index": true, + "include_term_vectors": true, + "include_in_all": true + } + ], + "default_analyzer": "" + }, + "url": { + "enabled": true, + "dynamic": true, + "fields": [ + { + "type": "text", + "analyzer": "keyword", + "store": true, + "index": true, + "include_term_vectors": true, + "include_in_all": true + } + ], + "default_analyzer": "" + } + }, + "default_analyzer": "" + }, + "type_field": "_type", + "default_type": "_default", + "default_analyzer": "en", + "default_datetime_parser": "dateTimeOptional", + "default_field": "_all", + "byte_array_converter": "json", + "analysis": {} +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/searches.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/searches.json new file mode 100644 index 00000000..d7ed9efd --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/fosdem/searches.json @@ -0,0 +1,105 @@ +[ + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "category", + "match_phrase": "Perl" + } + }, + "result": { + "total_hits": 4, + "hits": [ + { + "id": "3507@FOSDEM15@fosdem.org" + }, + { + "id": "3505@FOSDEM15@fosdem.org" + }, + { + "id": "3496@FOSDEM15@fosdem.org" + } + , + { + "id": "3492@FOSDEM15@fosdem.org" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "match": "lisp" + } + }, + "result": { + "total_hits": 2, + "hits": [ + { + "id": "3505@FOSDEM15@fosdem.org" + }, + { + "id": "3311@FOSDEM15@fosdem.org" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": {"boost":1,"query":"+lisp +category:Perl"} + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "3505@FOSDEM15@fosdem.org" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": {"boost":1,"query":"+lisp +category:\"Perl\""} + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "3505@FOSDEM15@fosdem.org" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "must": { + "conjuncts":[ + {"boost":1,"query":"+cats"}, + {"field":"category","match_phrase":"Perl"} + ] + } + } + }, + "result": { + "total_hits": 2, + "hits": [ + { + "id": "3496@FOSDEM15@fosdem.org" + }, + { + "id": "3492@FOSDEM15@fosdem.org" + } + ] + } + } +] \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/data/a.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/data/a.json new file mode 100644 index 00000000..5fe2dd87 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/data/a.json @@ -0,0 +1,3 @@ +{ + "body": "Twenty Thousand Leagues Under The Sea" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/mapping.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/mapping.json new file mode 100644 index 00000000..6629a21c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/mapping.json @@ -0,0 +1,23 @@ +{ + "types": { + "book": { + "properties": { + "body": { + "fields": [ + { + "include_term_vectors": true, + "include_in_all": true, + "index": true, + "store": true, + "analyzer": "en", + "type": "text" + } + ], + "dynamic": true, + "enabled": true + } + } + } + }, + "default_type": "book" +} \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/searches.json b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/searches.json new file mode 100644 index 00000000..76c0d474 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/test/tests/phrase/searches.json @@ -0,0 +1,326 @@ +[ + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Twenty" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Twenty Thousand" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Twenty Thousand Leagues" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Twenty Thousand Leagues Under" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Twenty Thousand Leagues Under the" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Twenty Thousand Leagues Under the Sea" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Thousand" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Thousand Leagues" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Thousand Leagues Under" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Thousand Leagues Under the" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Thousand Leagues Under the Sea" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Leagues" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Leagues Under" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Leagues Under the" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Leagues Under the Sea" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Under the Sea" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "the Sea" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + }, + { + "search": { + "from": 0, + "size": 10, + "query": { + "field": "body", + "match_phrase": "Sea" + } + }, + "result": { + "total_hits": 1, + "hits": [ + { + "id": "a" + } + ] + } + } +] \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_bulkindex/main.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_bulkindex/main.go new file mode 100644 index 00000000..13783107 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_bulkindex/main.go @@ -0,0 +1,104 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package main + +import ( + "bufio" + "flag" + "log" + "math/rand" + "os" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +var indexPath = flag.String("index", "", "index path") +var batchSize = flag.Int("size", 1000, "size of a single batch to index") + +func main() { + + flag.Parse() + + if *indexPath == "" { + log.Fatal("must specify index path") + } + + // open the index + index, err := bleve.Open(*indexPath) + if err != nil { + log.Fatal(err) + } + defer func() { + cerr := index.Close() + if cerr != nil { + log.Fatalf("error closing index: %v", err) + } + }() + + if flag.NArg() < 1 { + log.Fatal("must specify at least one path to index") + } + + i := 0 + batch := index.NewBatch() + + for _, file := range flag.Args() { + + file, err := os.Open(file) + defer func() { + cerr := file.Close() + if cerr != nil { + log.Fatalf("error closing file: %v", cerr) + } + }() + if err != nil { + log.Fatal(err) + } + + log.Printf("Indexing: %s\n", file.Name()) + r := bufio.NewReader(file) + + for { + if i%*batchSize == 0 { + log.Printf("Indexing batch (%d docs)...\n", i) + err := index.Batch(batch) + if err != nil { + log.Fatal(err) + } + batch = index.NewBatch() + } + + b, _ := r.ReadBytes('\n') + if len(b) == 0 { + break + } + docID := randomString(5) + err := batch.Index(docID, b) + if err != nil { + log.Fatal(err) + } + i++ + } + err = index.Batch(batch) + if err != nil { + log.Fatal(err) + } + } +} + +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func randomString(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_create/main.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_create/main.go new file mode 100644 index 00000000..7850e550 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_create/main.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package main + +import ( + "encoding/json" + "flag" + "io/ioutil" + "log" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +var indexPath = flag.String("index", "", "index path") +var mappingFile = flag.String("mapping", "", "mapping file") + +func main() { + + flag.Parse() + + if *indexPath == "" { + log.Fatal("must specify index path") + } + + // create a new default mapping + mapping := bleve.NewIndexMapping() + if *mappingFile != "" { + mappingBytes, err := ioutil.ReadFile(*mappingFile) + if err != nil { + log.Fatal(err) + } + err = json.Unmarshal(mappingBytes, &mapping) + if err != nil { + log.Fatal(err) + } + } + + // create the index + index, err := bleve.New(*indexPath, mapping) + if err != nil { + log.Fatal(err) + } + defer func() { + cerr := index.Close() + if cerr != nil { + log.Fatalf("error closing index: %v", err) + } + }() + + log.Printf("Created bleve index at: %s", *indexPath) +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_dump/main.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_dump/main.go new file mode 100644 index 00000000..6404b593 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_dump/main.go @@ -0,0 +1,73 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package main + +import ( + "encoding/json" + "flag" + "fmt" + "log" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/index/upside_down" +) + +var indexPath = flag.String("index", "", "index path") + +var fieldsOnly = flag.Bool("fields", false, "fields only") +var docID = flag.String("docID", "", "docID to dump") +var mappingOnly = flag.Bool("mapping", false, "print mapping") + +func main() { + flag.Parse() + if *indexPath == "" { + log.Fatal("specify index to dump") + } + + index, err := bleve.Open(*indexPath) + if err != nil { + log.Fatal(err) + } + defer func() { + cerr := index.Close() + if cerr != nil { + log.Fatalf("error closing index: %v", err) + } + }() + + if *mappingOnly { + mapping := index.Mapping() + jsonBytes, err := json.MarshalIndent(mapping, "", " ") + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s\n", jsonBytes) + return + } + + var dumpChan chan interface{} + if *docID != "" { + dumpChan = index.DumpDoc(*docID) + } else if *fieldsOnly { + dumpChan = index.DumpFields() + } else { + dumpChan = index.DumpAll() + } + + for rowOrErr := range dumpChan { + switch rowOrErr := rowOrErr.(type) { + case error: + log.Printf("error dumping: %v", rowOrErr) + case upside_down.UpsideDownCouchRow: + fmt.Printf("%v\n", rowOrErr) + fmt.Printf("Key: % -100x\nValue: % -100x\n\n", rowOrErr.Key(), rowOrErr.Value()) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_index/main.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_index/main.go new file mode 100644 index 00000000..4f5fc708 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_index/main.go @@ -0,0 +1,115 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package main + +import ( + "flag" + "io/ioutil" + "log" + "os" + "path/filepath" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +var indexPath = flag.String("index", "", "index path") +var keepExt = flag.Bool("keepExt", false, "keep extension in doc id") +var keepDir = flag.Bool("keepDir", false, "keep dir in doc id") + +func main() { + + flag.Parse() + + if *indexPath == "" { + log.Fatal("must specify index path") + } + + // open the index + index, err := bleve.Open(*indexPath) + if err != nil { + log.Fatal(err) + } + defer func() { + cerr := index.Close() + if cerr != nil { + log.Fatalf("error closing index: %v", err) + } + }() + + if flag.NArg() < 1 { + log.Fatal("must specify at least one path to index") + } + + for file := range handleArgs(flag.Args()) { + // index the files + docID := file.filename + if !*keepDir { + _, docID = filepath.Split(docID) + } + if !*keepExt { + ext := filepath.Ext(docID) + docID = docID[0 : len(docID)-len(ext)] + } + log.Printf("Indexing: %s", docID) + err = index.Index(docID, file.contents) + if err != nil { + log.Fatal(err) + } + } +} + +type file struct { + filename string + contents []byte +} + +func handleArgs(args []string) chan file { + rv := make(chan file) + + go func() { + for _, arg := range args { + arg = filepath.Clean(arg) + handleArgRecursive(arg, rv) + } + close(rv) + }() + + return rv +} + +func handleArgRecursive(arg string, results chan file) { + stat, err := os.Stat(arg) + if err != nil { + log.Print(err) + return + } + if stat.IsDir() { + // open the directory + dirEntries, err := ioutil.ReadDir(arg) + if err != nil { + log.Fatal(err) + } + + // walk the directory entries + for _, dirEntry := range dirEntries { + handleArgRecursive(arg+string(os.PathSeparator)+dirEntry.Name(), results) + } + } else { + bytes, err := ioutil.ReadFile(arg) + if err != nil { + log.Fatal(err) + } + + results <- file{ + filename: arg, + contents: bytes, + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_query/main.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_query/main.go new file mode 100644 index 00000000..668469ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_query/main.go @@ -0,0 +1,85 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "runtime/pprof" + "strings" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" +) + +var indexPath = flag.String("index", "", "index path") +var limit = flag.Int("limit", 10, "limit to first N results") +var skip = flag.Int("skip", 0, "skip the first N results") +var explain = flag.Bool("explain", false, "explain scores") +var includeHighlights = flag.Bool("highlight", true, "highlight matches") +var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") +var repeat = flag.Int("repeat", 1, "repeat query n times") + +func main() { + + flag.Parse() + + if *cpuprofile != "" { + f, err := os.Create(*cpuprofile) + if err != nil { + log.Fatal(err) + } + err = pprof.StartCPUProfile(f) + if err != nil { + log.Fatal(err) + } + defer pprof.StopCPUProfile() + } + + if *indexPath == "" { + log.Fatal("Specify index to query") + } + + if flag.NArg() < 1 { + log.Fatal("Specify search query") + } + + // open index + index, err := bleve.Open(*indexPath) + if err != nil { + log.Fatal(err) + } + defer func() { + cerr := index.Close() + if cerr != nil { + log.Fatalf("error closing index: %v", err) + } + }() + + for i := 0; i < *repeat; i++ { + // build a search with the provided parameters + queryString := strings.Join(flag.Args(), " ") + query := bleve.NewQueryStringQuery(queryString) + searchRequest := bleve.NewSearchRequestOptions(query, *limit, *skip, *explain) + + // enable highlights if requested + if *includeHighlights { + searchRequest.Highlight = bleve.NewHighlightWithStyle("ansi") + } + + // execute the search + searchResult, err := index.Search(searchRequest) + if err != nil { + log.Fatalf("search error: %v", err) + } + fmt.Println(searchResult) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_registry/main.go b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_registry/main.go new file mode 100644 index 00000000..cfd23a96 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/bleve/utils/bleve_registry/main.go @@ -0,0 +1,82 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package main + +import ( + "fmt" + "sort" + + _ "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve/registry" +) + +func main() { + fmt.Printf("Bleve Registry:\n") + printRegistry() +} + +func printRegistry() { + types, instances := registry.CharFilterTypesAndInstances() + printType("Char Filter", types, instances) + + types, instances = registry.TokenizerTypesAndInstances() + printType("Tokenizer", types, instances) + + types, instances = registry.TokenMapTypesAndInstances() + printType("Token Map", types, instances) + + types, instances = registry.TokenFilterTypesAndInstances() + printType("Token Filter", types, instances) + + types, instances = registry.AnalyzerTypesAndInstances() + printType("Analyzer", types, instances) + + types, instances = registry.DateTimeParserTypesAndInstances() + printType("Date Time Parser", types, instances) + + types, instances = registry.KVStoreTypesAndInstances() + printType("KV Store", types, instances) + + types, instances = registry.ByteArrayConverterTypesAndInstances() + printType("ByteArrayConverter", types, instances) + + types, instances = registry.FragmentFormatterTypesAndInstances() + printType("Fragment Formatter", types, instances) + + types, instances = registry.FragmenterTypesAndInstances() + printType("Fragmenter", types, instances) + + types, instances = registry.HighlighterTypesAndInstances() + printType("Highlighter", types, instances) +} + +func sortStrings(in []string) []string { + sortedStrings := make(sort.StringSlice, 0, len(in)) + for _, str := range in { + sortedStrings = append(sortedStrings, str) + } + sortedStrings.Sort() + return sortedStrings +} + +func printType(label string, types, instances []string) { + sortedTypes := sortStrings(types) + sortedInstances := sortStrings(instances) + fmt.Printf(label + " Types:\n") + for _, name := range sortedTypes { + fmt.Printf("\t%s\n", name) + } + fmt.Println() + fmt.Printf(label + " Instances:\n") + for _, name := range sortedInstances { + fmt.Printf("\t%s\n", name) + } + fmt.Println() +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.gitignore b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.gitignore new file mode 100644 index 00000000..d1ffcc5d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.gitignore @@ -0,0 +1,8 @@ +#* +*.sublime-* +*~ +.#* +.project +.settings +.DS_Store +/testdata diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.travis.yml b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.travis.yml new file mode 100644 index 00000000..d032f234 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - 1.4 + +script: + - go get golang.org/x/tools/cmd/vet + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - go test -v -covermode=count -coverprofile=profile.out + - go vet + - goveralls -service drone.io -coverprofile=profile.out -repotoken $COVERALLS + +notifications: + email: + - marty.schoch@gmail.com diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/LICENSE b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/LICENSE new file mode 100644 index 00000000..8d2999cc --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Charles Iliya Krempeaux :: http://changelog.ca/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/README.md b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/README.md new file mode 100644 index 00000000..d96911ac --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/README.md @@ -0,0 +1,118 @@ +# This fork... + +I'm maintaining this fork because the original author was not replying to issues or pull requests. For now I plan on maintaining this fork as necessary. + +## Status + +[![Build Status](https://travis-ci.org/blevesearch/go-porterstemmer.svg?branch=master)](https://travis-ci.org/blevesearch/go-porterstemmer) + +[![Coverage Status](https://coveralls.io/repos/blevesearch/go-porterstemmer/badge.png?branch=HEAD)](https://coveralls.io/r/blevesearch/go-porterstemmer?branch=HEAD) + +# Go Porter Stemmer + +A native Go clean room implementation of the Porter Stemming Algorithm. + +This algorithm is of interest to people doing Machine Learning or +Natural Language Processing (NLP). + +This is NOT a port. This is a native Go implementation from the human-readable +description of the algorithm. + +I've tried to make it (more) efficient by NOT internally using string's, but +instead internally using []rune's and using the same (array) buffer used by +the []rune slice (and sub-slices) at all steps of the algorithm. + +For Porter Stemmer algorithm, see: + +http://tartarus.org/martin/PorterStemmer/def.txt (URL #1) + +http://tartarus.org/martin/PorterStemmer/ (URL #2) + +# Departures + +Also, since when I initially implemented it, it failed the tests at... + +http://tartarus.org/martin/PorterStemmer/voc.txt (URL #3) + +http://tartarus.org/martin/PorterStemmer/output.txt (URL #4) + +... after reading the human-readble text over and over again to try to figure out +what the error I made was (and doing all sorts of things to debug it) I came to the +conclusion that the some of these tests were wrong according to the human-readable +description of the algorithm. + +This led me to wonder if maybe other people's code that was passing these tests had +rules that were not in the human-readable description. Which led me to look at the source +code here... + +http://tartarus.org/martin/PorterStemmer/c.txt (URL #5) + +... When I looked there I noticed that there are some items marked as a "DEPARTURE", +which differ from the original algorithm. (There are 2 of these.) + +I implemented these departures, and the tests at URL #3 and URL #4 all passed. + +## Usage + +To use this Golang library, use with something like: + + package main + + import ( + "fmt" + "github.com/reiver/go-porterstemmer" + ) + + func main() { + + word := "Waxes" + + stem := porterstemmer.StemString(word) + + fmt.Printf("The word [%s] has the stem [%s].\n", word, stem) + } + +Alternatively, if you want to be a bit more efficient, use []rune slices instead, with code like: + + package main + + import ( + "fmt" + "github.com/reiver/go-porterstemmer" + ) + + func main() { + + word := []rune("Waxes") + + stem := porterstemmer.Stem(word) + + fmt.Printf("The word [%s] has the stem [%s].\n", string(word), string(stem)) + } + +Although NOTE that the above code may modify original slice (named "word" in the example) as a side +effect, for efficiency reasons. And that the slice named "stem" in the example above may be a +sub-slice of the slice named "word". + +Also alternatively, if you already know that your word is already lowercase (and you don't need +this library to lowercase your word for you) you can instead use code like: + + package main + + import ( + "fmt" + "github.com/reiver/go-porterstemmer" + ) + + func main() { + + word := []rune("waxes") + + stem := porterstemmer.StemWithoutLowerCasing(word) + + fmt.Printf("The word [%s] has the stem [%s].\n", string(word), string(stem)) + } + +Again NOTE (like with the previous example) that the above code may modify original slice (named +"word" in the example) as a side effect, for efficiency reasons. And that the slice named "stem" +in the example above may be a sub-slice of the slice named "word". diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer.go new file mode 100644 index 00000000..d1f77e6f --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer.go @@ -0,0 +1,839 @@ +package porterstemmer + +import ( + // "log" + "unicode" +) + +func isConsonant(s []rune, i int) bool { + + //DEBUG + //log.Printf("isConsonant: [%+v]", string(s[i])) + + result := true + + switch s[i] { + case 'a', 'e', 'i', 'o', 'u': + result = false + case 'y': + if 0 == i { + result = true + } else { + result = !isConsonant(s, i-1) + } + default: + result = true + } + + return result +} + +func measure(s []rune) uint { + + // Initialize. + lenS := len(s) + result := uint(0) + i := 0 + + // Short Circuit. + if 0 == lenS { + /////////// RETURN + return result + } + + // Ignore (potential) consonant sequence at the beginning of word. + for isConsonant(s, i) { + + //DEBUG + //log.Printf("[measure([%s])] Eat Consonant [%d] -> [%s]", string(s), i, string(s[i])) + + i++ + if i >= lenS { + /////////////// RETURN + return result + } + } + + // For each pair of a vowel sequence followed by a consonant sequence, increment result. +Outer: + for i < lenS { + + for !isConsonant(s, i) { + + //DEBUG + //log.Printf("[measure([%s])] VOWEL [%d] -> [%s]", string(s), i, string(s[i])) + + i++ + if i >= lenS { + /////////// BREAK + break Outer + } + } + for isConsonant(s, i) { + + //DEBUG + //log.Printf("[measure([%s])] CONSONANT [%d] -> [%s]", string(s), i, string(s[i])) + + i++ + if i >= lenS { + result++ + /////////// BREAK + break Outer + } + } + result++ + } + + // Return + return result +} + +func hasSuffix(s, suffix []rune) bool { + + lenSMinusOne := len(s) - 1 + lenSuffixMinusOne := len(suffix) - 1 + + if lenSMinusOne <= lenSuffixMinusOne { + return false + } else if s[lenSMinusOne] != suffix[lenSuffixMinusOne] { // I suspect checking this first should speed this function up in practice. + /////// RETURN + return false + } else { + + for i := 0; i < lenSuffixMinusOne; i++ { + + if suffix[i] != s[lenSMinusOne-lenSuffixMinusOne+i] { + /////////////// RETURN + return false + } + + } + + } + + return true +} + +func containsVowel(s []rune) bool { + + lenS := len(s) + + for i := 0; i < lenS; i++ { + + if !isConsonant(s, i) { + /////////// RETURN + return true + } + + } + + return false +} + +func hasRepeatDoubleConsonantSuffix(s []rune) bool { + + // Initialize. + lenS := len(s) + + result := false + + // Do it! + if 2 > lenS { + result = false + } else if s[lenS-1] == s[lenS-2] && isConsonant(s, lenS-1) { // Will using isConsonant() cause a problem with "YY"? + result = true + } else { + result = false + } + + // Return, + return result +} + +func hasConsonantVowelConsonantSuffix(s []rune) bool { + + // Initialize. + lenS := len(s) + + result := false + + // Do it! + if 3 > lenS { + result = false + } else if isConsonant(s, lenS-3) && !isConsonant(s, lenS-2) && isConsonant(s, lenS-1) { + result = true + } else { + result = false + } + + // Return + return result +} + +func step1a(s []rune) []rune { + + // Initialize. + var result []rune = s + + lenS := len(s) + + // Do it! + if suffix := []rune("sses"); hasSuffix(s, suffix) { + + lenTrim := 2 + + subSlice := s[:lenS-lenTrim] + + result = subSlice + } else if suffix := []rune("ies"); hasSuffix(s, suffix) { + lenTrim := 2 + + subSlice := s[:lenS-lenTrim] + + result = subSlice + } else if suffix := []rune("ss"); hasSuffix(s, suffix) { + + result = s + } else if suffix := []rune("s"); hasSuffix(s, suffix) { + + lenSuffix := 1 + + subSlice := s[:lenS-lenSuffix] + + result = subSlice + } + + // Return. + return result +} + +func step1b(s []rune) []rune { + + // Initialize. + var result []rune = s + + lenS := len(s) + + // Do it! + if suffix := []rune("eed"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 0 < m { + lenTrim := 1 + + result = s[:lenS-lenTrim] + } + } else if suffix := []rune("ed"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + if containsVowel(subSlice) { + + if suffix2 := []rune("at"); hasSuffix(subSlice, suffix2) { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + } else if suffix2 := []rune("bl"); hasSuffix(subSlice, suffix2) { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + } else if suffix2 := []rune("iz"); hasSuffix(subSlice, suffix2) { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + } else if c := subSlice[len(subSlice)-1]; 'l' != c && 's' != c && 'z' != c && hasRepeatDoubleConsonantSuffix(subSlice) { + lenTrim := 1 + + lenSubSlice := len(subSlice) + + result = subSlice[:lenSubSlice-lenTrim] + } else if c := subSlice[len(subSlice)-1]; 1 == measure(subSlice) && hasConsonantVowelConsonantSuffix(subSlice) && 'w' != c && 'x' != c && 'y' != c { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + + result[len(result)-1] = 'e' + } else { + result = subSlice + } + + } + } else if suffix := []rune("ing"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + if containsVowel(subSlice) { + + if suffix2 := []rune("at"); hasSuffix(subSlice, suffix2) { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + + result[len(result)-1] = 'e' + } else if suffix2 := []rune("bl"); hasSuffix(subSlice, suffix2) { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + + result[len(result)-1] = 'e' + } else if suffix2 := []rune("iz"); hasSuffix(subSlice, suffix2) { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + + result[len(result)-1] = 'e' + } else if c := subSlice[len(subSlice)-1]; 'l' != c && 's' != c && 'z' != c && hasRepeatDoubleConsonantSuffix(subSlice) { + lenTrim := 1 + + lenSubSlice := len(subSlice) + + result = subSlice[:lenSubSlice-lenTrim] + } else if c := subSlice[len(subSlice)-1]; 1 == measure(subSlice) && hasConsonantVowelConsonantSuffix(subSlice) && 'w' != c && 'x' != c && 'y' != c { + lenTrim := -1 + + result = s[:lenS-lenSuffix-lenTrim] + + result[len(result)-1] = 'e' + } else { + result = subSlice + } + + } + } + + // Return. + return result +} + +func step1c(s []rune) []rune { + + // Initialize. + lenS := len(s) + + result := s + + // Do it! + if 2 > lenS { + /////////// RETURN + return result + } + + if 'y' == s[lenS-1] && containsVowel(s[:lenS-1]) { + + result[lenS-1] = 'i' + + } else if 'Y' == s[lenS-1] && containsVowel(s[:lenS-1]) { + + result[lenS-1] = 'I' + + } + + // Return. + return result +} + +func step2(s []rune) []rune { + + // Initialize. + lenS := len(s) + + result := s + + // Do it! + if suffix := []rune("ational"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-5] = 'e' + result = result[:lenS-4] + } + } else if suffix := []rune("tional"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = result[:lenS-2] + } + } else if suffix := []rune("enci"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-1] = 'e' + } + } else if suffix := []rune("anci"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-1] = 'e' + } + } else if suffix := []rune("izer"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-1] + } + } else if suffix := []rune("bli"); hasSuffix(s, suffix) { // --DEPARTURE-- + // } else if suffix := []rune("abli") ; hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-1] = 'e' + } + } else if suffix := []rune("alli"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-2] + } + } else if suffix := []rune("entli"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-2] + } + } else if suffix := []rune("eli"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-2] + } + } else if suffix := []rune("ousli"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-2] + } + } else if suffix := []rune("ization"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-5] = 'e' + + result = s[:lenS-4] + } + } else if suffix := []rune("ation"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-3] = 'e' + + result = s[:lenS-2] + } + } else if suffix := []rune("ator"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-2] = 'e' + + result = s[:lenS-1] + } + } else if suffix := []rune("alism"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-3] + } + } else if suffix := []rune("iveness"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-4] + } + } else if suffix := []rune("fulness"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-4] + } + } else if suffix := []rune("ousness"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-4] + } + } else if suffix := []rune("aliti"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result = s[:lenS-3] + } + } else if suffix := []rune("iviti"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-3] = 'e' + + result = result[:lenS-2] + } + } else if suffix := []rune("biliti"); hasSuffix(s, suffix) { + if 0 < measure(s[:lenS-len(suffix)]) { + result[lenS-5] = 'l' + result[lenS-4] = 'e' + + result = result[:lenS-3] + } + } else if suffix := []rune("logi"); hasSuffix(s, suffix) { // --DEPARTURE-- + if 0 < measure(s[:lenS-len(suffix)]) { + lenTrim := 1 + + result = s[:lenS-lenTrim] + } + } + + // Return. + return result +} + +func step3(s []rune) []rune { + + // Initialize. + lenS := len(s) + result := s + + // Do it! + if suffix := []rune("icate"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + if 0 < measure(s[:lenS-lenSuffix]) { + result = result[:lenS-3] + } + } else if suffix := []rune("ative"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 0 < m { + result = subSlice + } + } else if suffix := []rune("alize"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + if 0 < measure(s[:lenS-lenSuffix]) { + result = result[:lenS-3] + } + } else if suffix := []rune("iciti"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + if 0 < measure(s[:lenS-lenSuffix]) { + result = result[:lenS-3] + } + } else if suffix := []rune("ical"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + if 0 < measure(s[:lenS-lenSuffix]) { + result = result[:lenS-2] + } + } else if suffix := []rune("ful"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 0 < m { + result = subSlice + } + } else if suffix := []rune("ness"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 0 < m { + result = subSlice + } + } + + // Return. + return result +} + +func step4(s []rune) []rune { + + // Initialize. + lenS := len(s) + result := s + + // Do it! + if suffix := []rune("al"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = result[:lenS-lenSuffix] + } + } else if suffix := []rune("ance"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = result[:lenS-lenSuffix] + } + } else if suffix := []rune("ence"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = result[:lenS-lenSuffix] + } + } else if suffix := []rune("er"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ic"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("able"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ible"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ant"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ement"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ment"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ent"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ion"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + c := subSlice[len(subSlice)-1] + + if 1 < m && ('s' == c || 't' == c) { + result = subSlice + } + } else if suffix := []rune("ou"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ism"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ate"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("iti"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ous"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ive"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } else if suffix := []rune("ize"); hasSuffix(s, suffix) { + lenSuffix := len(suffix) + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } + + // Return. + return result +} + +func step5a(s []rune) []rune { + + // Initialize. + lenS := len(s) + result := s + + // Do it! + if 'e' == s[lenS-1] { + lenSuffix := 1 + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } else if 1 == m { + if c := subSlice[len(subSlice)-1]; !(hasConsonantVowelConsonantSuffix(subSlice) && 'w' != c && 'x' != c && 'y' != c) { + result = subSlice + } + } + } + + // Return. + return result +} + +func step5b(s []rune) []rune { + + // Initialize. + lenS := len(s) + result := s + + // Do it! + if 2 < lenS && 'l' == s[lenS-2] && 'l' == s[lenS-1] { + + lenSuffix := 1 + + subSlice := s[:lenS-lenSuffix] + + m := measure(subSlice) + + if 1 < m { + result = subSlice + } + } + + // Return. + return result +} + +func StemString(s string) string { + + // Convert string to []rune + runeArr := []rune(s) + + // Stem. + runeArr = Stem(runeArr) + + // Convert []rune to string + str := string(runeArr) + + // Return. + return str +} + +func Stem(s []rune) []rune { + + // Initialize. + lenS := len(s) + + // Short circuit. + if 0 == lenS { + /////////// RETURN + return s + } + + // Make all runes lowercase. + for i := 0; i < lenS; i++ { + s[i] = unicode.ToLower(s[i]) + } + + // Stem + result := StemWithoutLowerCasing(s) + + // Return. + return result +} + +func StemWithoutLowerCasing(s []rune) []rune { + + // Initialize. + lenS := len(s) + + // Words that are of length 2 or less is already stemmed. + // Don't do anything. + if 2 >= lenS { + /////////// RETURN + return s + } + + // Stem + s = step1a(s) + s = step1b(s) + s = step1c(s) + s = step2(s) + s = step3(s) + s = step4(s) + s = step5a(s) + s = step5b(s) + + // Return. + return s +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_contains_vowel_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_contains_vowel_test.go new file mode 100644 index 00000000..3532cb7d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_contains_vowel_test.go @@ -0,0 +1,57 @@ +package porterstemmer + +import ( + "testing" +) + +func TestContainsVowel(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected bool + }, 15) + + tests[i].S = []rune("apple") + tests[i].Expected = true + i++ + + tests[i].S = []rune("f") + tests[i].Expected = false + i++ + + tests[i].S = []rune("a") + tests[i].Expected = true + i++ + + tests[i].S = []rune("e") + tests[i].Expected = true + i++ + + tests[i].S = []rune("i") + tests[i].Expected = true + i++ + + tests[i].S = []rune("o") + tests[i].Expected = true + i++ + + tests[i].S = []rune("u") + tests[i].Expected = true + i++ + + tests[i].S = []rune("y") + tests[i].Expected = false + i++ + + tests[i].S = []rune("cy") + tests[i].Expected = true + i++ + + for _, datum := range tests { + if actual := containsVowel(datum.S); actual != datum.Expected { + t.Errorf("Did NOT get what was expected for calling containsVowel() on [%s]. Expect [%t] but got [%t]", string(datum.S), datum.Expected, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fixes_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fixes_test.go new file mode 100644 index 00000000..a99eda9e --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fixes_test.go @@ -0,0 +1,20 @@ +package porterstemmer + +import ( + "testing" +) + +// Test for issue listed here: +// https://github.com/reiver/go-porterstemmer/issues/1 +// +// StemString("ion") was causing runtime exception +func TestStemStringIon(t *testing.T) { + + expected := "ion" + + s := "ion" + actual := StemString(s) + if expected != actual { + t.Errorf("Input: [%s] -> Actual: [%s]. Expected: [%s]", s, actual, expected) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fuzz_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fuzz_test.go new file mode 100644 index 00000000..af398390 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_fuzz_test.go @@ -0,0 +1,59 @@ +package porterstemmer + +import ( + "bytes" + "testing" +) + +const maxFuzzLen = 6 + +// Test inputs of English characters less than maxFuzzLen +// Added to help diagnose https://github.com/reiver/go-porterstemmer/issues/4 +func TestStemFuzz(t *testing.T) { + + input := []byte{'a'} + for len(input) < maxFuzzLen { + // test input + + panicked := false + func() { + defer func() { panicked = recover() != nil }() + StemString(string(input)) + }() + if panicked { + t.Errorf("StemString panicked for input '%s'", input) + } + + // if all z's extend + if allZs(input) { + input = bytes.Repeat([]byte{'a'}, len(input)+1) + } else { + // increment + input = incrementBytes(input) + } + } +} + +func incrementBytes(in []byte) []byte { + rv := make([]byte, len(in)) + copy(rv, in) + for i := len(rv) - 1; i >= 0; i-- { + if rv[i]+1 == '{' { + rv[i] = 'a' + continue + } + rv[i] = rv[i] + 1 + break + + } + return rv +} + +func allZs(in []byte) bool { + for _, b := range in { + if b != 'z' { + return false + } + } + return true +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_repeat_double_consonant_suffix_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_repeat_double_consonant_suffix_test.go new file mode 100644 index 00000000..420f84a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_repeat_double_consonant_suffix_test.go @@ -0,0 +1,42 @@ +package porterstemmer + +import ( + "testing" +) + +func TestHasDoubleConsonantSuffix(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected bool + }, 12) + + tests[i].S = []rune("apple") + tests[i].Expected = false + i++ + + tests[i].S = []rune("hiss") + tests[i].Expected = true + i++ + + tests[i].S = []rune("fizz") + tests[i].Expected = true + i++ + + tests[i].S = []rune("fill") + tests[i].Expected = true + i++ + + tests[i].S = []rune("ahaa") + tests[i].Expected = false + i++ + + for _, datum := range tests { + + if actual := hasRepeatDoubleConsonantSuffix(datum.S); actual != datum.Expected { + t.Errorf("Did NOT get what was expected for calling hasDoubleConsonantSuffix() on [%s]. Expect [%t] but got [%t]", string(datum.S), datum.Expected, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_suffix_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_suffix_test.go new file mode 100644 index 00000000..47ae81b5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_has_suffix_test.go @@ -0,0 +1,432 @@ +package porterstemmer + +import ( + "testing" +) + +func TestHasSuffix(t *testing.T) { + + tests := make([]struct { + S []rune + Suffix []rune + Expected bool + }, 82) + + i := 0 + + tests[i].S = []rune("ran") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runner") + tests[i].Suffix = []rune("er") + tests[i].Expected = true + i++ + + tests[i].S = []rune("runnar") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runned") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runnre") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + // FIXME marty changed Expected + // to false here because it seems + // the contract does not support + // suffix of same length as input + // as this test implied + tests[i].S = []rune("er") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("re") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("ran") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runner") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runnar") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runned") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("runnre") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("er") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("re") + tests[i].Suffix = []rune("ER") + tests[i].Expected = false + i++ + + tests[i].S = []rune("") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("e") + tests[i].Suffix = []rune("er") + tests[i].Expected = false + i++ + + tests[i].S = []rune("caresses") + tests[i].Suffix = []rune("sses") + tests[i].Expected = true + i++ + + tests[i].S = []rune("ponies") + tests[i].Suffix = []rune("ies") + tests[i].Expected = true + i++ + + tests[i].S = []rune("caress") + tests[i].Suffix = []rune("ss") + tests[i].Expected = true + i++ + + tests[i].S = []rune("cats") + tests[i].Suffix = []rune("s") + tests[i].Expected = true + i++ + + tests[i].S = []rune("feed") + tests[i].Suffix = []rune("eed") + tests[i].Expected = true + i++ + + tests[i].S = []rune("agreed") + tests[i].Suffix = []rune("eed") + tests[i].Expected = true + i++ + + tests[i].S = []rune("plastered") + tests[i].Suffix = []rune("ed") + tests[i].Expected = true + i++ + + tests[i].S = []rune("bled") + tests[i].Suffix = []rune("ed") + tests[i].Expected = true + i++ + + tests[i].S = []rune("motoring") + tests[i].Suffix = []rune("ing") + tests[i].Expected = true + i++ + + tests[i].S = []rune("sing") + tests[i].Suffix = []rune("ing") + tests[i].Expected = true + i++ + + tests[i].S = []rune("conflat") + tests[i].Suffix = []rune("at") + tests[i].Expected = true + i++ + + tests[i].S = []rune("troubl") + tests[i].Suffix = []rune("bl") + tests[i].Expected = true + i++ + + tests[i].S = []rune("siz") + tests[i].Suffix = []rune("iz") + tests[i].Expected = true + i++ + + tests[i].S = []rune("happy") + tests[i].Suffix = []rune("y") + tests[i].Expected = true + i++ + + tests[i].S = []rune("sky") + tests[i].Suffix = []rune("y") + tests[i].Expected = true + i++ + + tests[i].S = []rune("relational") + tests[i].Suffix = []rune("ational") + tests[i].Expected = true + i++ + + tests[i].S = []rune("conditional") + tests[i].Suffix = []rune("tional") + tests[i].Expected = true + i++ + + tests[i].S = []rune("rational") + tests[i].Suffix = []rune("tional") + tests[i].Expected = true + i++ + + tests[i].S = []rune("valenci") + tests[i].Suffix = []rune("enci") + tests[i].Expected = true + i++ + + tests[i].S = []rune("hesitanci") + tests[i].Suffix = []rune("anci") + tests[i].Expected = true + i++ + + tests[i].S = []rune("digitizer") + tests[i].Suffix = []rune("izer") + tests[i].Expected = true + i++ + + tests[i].S = []rune("conformabli") + tests[i].Suffix = []rune("abli") + tests[i].Expected = true + i++ + + tests[i].S = []rune("radicalli") + tests[i].Suffix = []rune("alli") + tests[i].Expected = true + i++ + + tests[i].S = []rune("differentli") + tests[i].Suffix = []rune("entli") + tests[i].Expected = true + i++ + + tests[i].S = []rune("vileli") + tests[i].Suffix = []rune("eli") + tests[i].Expected = true + i++ + + tests[i].S = []rune("analogousli") + tests[i].Suffix = []rune("ousli") + tests[i].Expected = true + i++ + + tests[i].S = []rune("vietnamization") + tests[i].Suffix = []rune("ization") + tests[i].Expected = true + i++ + + tests[i].S = []rune("predication") + tests[i].Suffix = []rune("ation") + tests[i].Expected = true + i++ + + tests[i].S = []rune("operator") + tests[i].Suffix = []rune("ator") + tests[i].Expected = true + i++ + + tests[i].S = []rune("feudalism") + tests[i].Suffix = []rune("alism") + tests[i].Expected = true + i++ + + tests[i].S = []rune("decisiveness") + tests[i].Suffix = []rune("iveness") + tests[i].Expected = true + i++ + + tests[i].S = []rune("hopefulness") + tests[i].Suffix = []rune("fulness") + tests[i].Expected = true + i++ + + tests[i].S = []rune("callousness") + tests[i].Suffix = []rune("ousness") + tests[i].Expected = true + i++ + + tests[i].S = []rune("formaliti") + tests[i].Suffix = []rune("aliti") + tests[i].Expected = true + i++ + + tests[i].S = []rune("sensitiviti") + tests[i].Suffix = []rune("iviti") + tests[i].Expected = true + i++ + + tests[i].S = []rune("sensibiliti") + tests[i].Suffix = []rune("biliti") + tests[i].Expected = true + i++ + + tests[i].S = []rune("triplicate") + tests[i].Suffix = []rune("icate") + tests[i].Expected = true + i++ + + tests[i].S = []rune("formative") + tests[i].Suffix = []rune("ative") + tests[i].Expected = true + i++ + + tests[i].S = []rune("formalize") + tests[i].Suffix = []rune("alize") + tests[i].Expected = true + i++ + + tests[i].S = []rune("electriciti") + tests[i].Suffix = []rune("iciti") + tests[i].Expected = true + i++ + + tests[i].S = []rune("electrical") + tests[i].Suffix = []rune("ical") + tests[i].Expected = true + i++ + + tests[i].S = []rune("hopeful") + tests[i].Suffix = []rune("ful") + tests[i].Expected = true + i++ + + tests[i].S = []rune("goodness") + tests[i].Suffix = []rune("ness") + tests[i].Expected = true + i++ + + tests[i].S = []rune("revival") + tests[i].Suffix = []rune("al") + tests[i].Expected = true + i++ + + tests[i].S = []rune("allowance") + tests[i].Suffix = []rune("ance") + tests[i].Expected = true + i++ + + tests[i].S = []rune("inference") + tests[i].Suffix = []rune("ence") + tests[i].Expected = true + i++ + + tests[i].S = []rune("airliner") + tests[i].Suffix = []rune("er") + tests[i].Expected = true + i++ + + tests[i].S = []rune("gyroscopic") + tests[i].Suffix = []rune("ic") + tests[i].Expected = true + i++ + + tests[i].S = []rune("adjustable") + tests[i].Suffix = []rune("able") + tests[i].Expected = true + i++ + + tests[i].S = []rune("defensible") + tests[i].Suffix = []rune("ible") + tests[i].Expected = true + i++ + + tests[i].S = []rune("irritant") + tests[i].Suffix = []rune("ant") + tests[i].Expected = true + i++ + + tests[i].S = []rune("replacement") + tests[i].Suffix = []rune("ement") + tests[i].Expected = true + i++ + + tests[i].S = []rune("adjustment") + tests[i].Suffix = []rune("ment") + tests[i].Expected = true + i++ + + tests[i].S = []rune("dependent") + tests[i].Suffix = []rune("ent") + tests[i].Expected = true + i++ + + tests[i].S = []rune("adoption") + tests[i].Suffix = []rune("ion") + tests[i].Expected = true + i++ + + tests[i].S = []rune("homologou") + tests[i].Suffix = []rune("ou") + tests[i].Expected = true + i++ + + tests[i].S = []rune("communism") + tests[i].Suffix = []rune("ism") + tests[i].Expected = true + i++ + + tests[i].S = []rune("activate") + tests[i].Suffix = []rune("ate") + tests[i].Expected = true + i++ + + tests[i].S = []rune("angulariti") + tests[i].Suffix = []rune("iti") + tests[i].Expected = true + i++ + + tests[i].S = []rune("homologous") + tests[i].Suffix = []rune("ous") + tests[i].Expected = true + i++ + + tests[i].S = []rune("effective") + tests[i].Suffix = []rune("ive") + tests[i].Expected = true + i++ + + tests[i].S = []rune("bowdlerize") + tests[i].Suffix = []rune("ize") + tests[i].Expected = true + i++ + + tests[i].S = []rune("probate") + tests[i].Suffix = []rune("e") + tests[i].Expected = true + i++ + + tests[i].S = []rune("rate") + tests[i].Suffix = []rune("e") + tests[i].Expected = true + i++ + + tests[i].S = []rune("cease") + tests[i].Suffix = []rune("e") + tests[i].Expected = true + i++ + + for _, datum := range tests { + if actual := hasSuffix(datum.S, datum.Suffix); actual != datum.Expected { + t.Errorf("Did NOT get what was expected for calling hasSuffix() on [%s] with suffix [%s]. Expect [%t] but got [%t]", string(datum.S), string(datum.Suffix), datum.Expected, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_is_consontant_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_is_consontant_test.go new file mode 100644 index 00000000..dc665654 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_is_consontant_test.go @@ -0,0 +1,74 @@ +package porterstemmer + +import ( + "testing" +) + +func TestIsConsontant(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []bool + }, 12) + + tests[i].S = []rune("apple") + tests[i].Expected = []bool{false, true, true, true, false} + i++ + + tests[i].S = []rune("cyan") + tests[i].Expected = []bool{true, false, false, true} + i++ + + tests[i].S = []rune("connects") + tests[i].Expected = []bool{true, false, true, true, false, true, true, true} + i++ + + tests[i].S = []rune("yellow") + tests[i].Expected = []bool{true, false, true, true, false, true} + i++ + + tests[i].S = []rune("excellent") + tests[i].Expected = []bool{false, true, true, false, true, true, false, true, true} + i++ + + tests[i].S = []rune("yuk") + tests[i].Expected = []bool{true, false, true} + i++ + + tests[i].S = []rune("syzygy") + tests[i].Expected = []bool{true, false, true, false, true, false} + i++ + + tests[i].S = []rune("school") + tests[i].Expected = []bool{true, true, true, false, false, true} + i++ + + tests[i].S = []rune("pay") + tests[i].Expected = []bool{true, false, true} + i++ + + tests[i].S = []rune("golang") + tests[i].Expected = []bool{true, false, true, false, true, true} + i++ + + // NOTE: The Porter Stemmer technical should make a mistake on the second "y". + // Really, both the 1st and 2nd "y" are consontants. But + tests[i].S = []rune("sayyid") + tests[i].Expected = []bool{true, false, true, false, false, true} + i++ + + tests[i].S = []rune("ya") + tests[i].Expected = []bool{true, false} + i++ + + for _, datum := range tests { + for i = 0; i < len(datum.S); i++ { + + if actual := isConsonant(datum.S, i); actual != datum.Expected[i] { + t.Errorf("Did NOT get what was expected for calling isConsonant() on [%s] at [%d] (i.e., [%s]). Expect [%t] but got [%t]", string(datum.S), i, string(datum.S[i]), datum.Expected[i], actual) + } + } // for + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_measure_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_measure_test.go new file mode 100644 index 00000000..d53024b9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_measure_test.go @@ -0,0 +1,99 @@ +package porterstemmer + +import ( + "testing" +) + +func TestMeasure(t *testing.T) { + + tests := make([]struct { + S []rune + Expected uint + }, 27) + + tests[0].S = []rune("ya") + tests[0].Expected = 0 + + tests[1].S = []rune("cyan") + tests[1].Expected = 1 + + tests[2].S = []rune("connects") + tests[2].Expected = 2 + + tests[3].S = []rune("yellow") + tests[3].Expected = 2 + + tests[4].S = []rune("excellent") + tests[4].Expected = 3 + + tests[5].S = []rune("yuk") + tests[5].Expected = 1 + + tests[6].S = []rune("syzygy") + tests[6].Expected = 2 + + tests[7].S = []rune("school") + tests[7].Expected = 1 + + tests[8].S = []rune("pay") + tests[8].Expected = 1 + + tests[9].S = []rune("golang") + tests[9].Expected = 2 + + // NOTE: The Porter Stemmer technical should make a mistake on the second "y". + // Really, both the 1st and 2nd "y" are consontants. But + tests[10].S = []rune("sayyid") + tests[10].Expected = 2 + + tests[11].S = []rune("ya") + tests[11].Expected = 0 + + tests[12].S = []rune("") + tests[12].Expected = 0 + + tests[13].S = []rune("tr") + tests[13].Expected = 0 + + tests[14].S = []rune("ee") + tests[14].Expected = 0 + + tests[15].S = []rune("tree") + tests[15].Expected = 0 + + tests[16].S = []rune("t") + tests[16].Expected = 0 + + tests[18].S = []rune("by") + tests[18].Expected = 0 + + tests[19].S = []rune("trouble") + tests[19].Expected = 1 + + tests[20].S = []rune("oats") + tests[20].Expected = 1 + + tests[21].S = []rune("trees") + tests[21].Expected = 1 + + tests[22].S = []rune("ivy") + tests[22].Expected = 1 + + tests[23].S = []rune("troubles") + tests[23].Expected = 2 + + tests[24].S = []rune("private") + tests[24].Expected = 2 + + tests[25].S = []rune("oaten") + tests[25].Expected = 2 + + tests[26].S = []rune("orrery") + tests[26].Expected = 2 + + for _, datum := range tests { + if actual := measure(datum.S); actual != datum.Expected { + t.Errorf("Did NOT get what was expected for calling measure() on [%s]. Expect [%d] but got [%d]", string(datum.S), datum.Expected, actual) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_string_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_string_test.go new file mode 100644 index 00000000..f93258d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_string_test.go @@ -0,0 +1,118 @@ +package porterstemmer + +import ( + "bufio" + "io/ioutil" + "net/http" + "os" + "strings" + "testing" +) + +func TestStemString(t *testing.T) { + + testDataDirName := "testdata" + + _, err := os.Stat(testDataDirName) + if nil != err { + _ = os.Mkdir(testDataDirName, 0755) + } + _, err = os.Stat(testDataDirName) + if nil != err { + t.Errorf("The test data folder ([%s]) does not exists (and could not create it). Received error: [%v]", testDataDirName, err) + /////// RETURN + return + } + + vocFileName := testDataDirName + "/voc.txt" + _, err = os.Stat(vocFileName) + if nil != err { + + vocHref := "http://tartarus.org/martin/PorterStemmer/voc.txt" + + resp, err := http.Get(vocHref) + if nil != err { + t.Errorf("Could not download test file (from web) from URL: [%s]. Received error: [%v]", vocHref, err) + /////////// RETURN + return + } + + respBody, err := ioutil.ReadAll(resp.Body) + if nil != err { + t.Errorf("Error loading the contents of from URL: [%s]. Received error: [%v].", vocHref, err) + /////////// RETURN + return + } + + _ = ioutil.WriteFile(vocFileName, respBody, 0644) + + } + vocFd, err := os.Open(vocFileName) + if nil != err { + t.Errorf("Could NOT open testdata file: [%s]. Received error: [%v]", vocFileName, err) + /////// RETURN + return + } + defer vocFd.Close() + + voc := bufio.NewReaderSize(vocFd, 1024) + + outFileName := testDataDirName + "/output.txt" + _, err = os.Stat(outFileName) + if nil != err { + + outHref := "http://tartarus.org/martin/PorterStemmer/output.txt" + + resp, err := http.Get(outHref) + if nil != err { + t.Errorf("Could not download test file (from web) from URL: [%s]. Received error: [%v]", outHref, err) + /////////// RETURN + return + } + + respBody, err := ioutil.ReadAll(resp.Body) + if nil != err { + t.Errorf("Error loading the contents of from URL: [%s]. Received error: [%v].", outHref, err) + /////////// RETURN + return + } + + _ = ioutil.WriteFile(outFileName, respBody, 0644) + + } + outFd, err := os.Open(outFileName) + if nil != err { + t.Errorf("Could NOT open testdata file: [%s]. Received error: [%v]", outFileName, err) + /////// RETURN + return + } + defer outFd.Close() + + out := bufio.NewReaderSize(outFd, 1024) + + for { + + vocS, err := voc.ReadString('\n') + if nil != err { + /////// BREAK + break + } + + vocS = strings.Trim(vocS, "\n\r\t ") + + expected, err := out.ReadString('\n') + if nil != err { + t.Errorf("Received unexpected error when trying to read a line from [%s]. Received error: [%v]", outFileName, err) + /////// BREAK + break + + } + + expected = strings.Trim(expected, "\n\r\t ") + + actual := StemString(vocS) + if expected != actual { + t.Errorf("Input: [%s] -> Actual: [%s]. Expected: [%s]", vocS, actual, expected) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_without_lower_casing_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_without_lower_casing_test.go new file mode 100644 index 00000000..b8b7035d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_stem_without_lower_casing_test.go @@ -0,0 +1,56 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStemWithoutLowerCasing(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 3) + + tests[i].S = []rune("controll") + tests[i].Expected = []rune("control") + i++ + + tests[i].S = []rune("roll") + tests[i].Expected = []rune("roll") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = StemWithoutLowerCasing(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling StemWithoutLowerCasing() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1a_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1a_test.go new file mode 100644 index 00000000..6fa8445d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1a_test.go @@ -0,0 +1,70 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep1a(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 12) + + tests[i].S = []rune("caresses") + tests[i].Expected = []rune("caress") + i++ + + tests[i].S = []rune("ponies") + tests[i].Expected = []rune("poni") + i++ + + tests[i].S = []rune("ties") + tests[i].Expected = []rune("ti") + i++ + + tests[i].S = []rune("caress") + tests[i].Expected = []rune("caress") + i++ + + tests[i].S = []rune("cats") + tests[i].Expected = []rune("cat") + i++ + + for _, datum := range tests { + for i = 0; i < len(datum.S); i++ { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step1a(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step1a() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } // for + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1b_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1b_test.go new file mode 100644 index 00000000..31b4c08d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1b_test.go @@ -0,0 +1,112 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep1b(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 17) + + tests[i].S = []rune("feed") + tests[i].Expected = []rune("feed") + i++ + + tests[i].S = []rune("agreed") + tests[i].Expected = []rune("agree") + i++ + + tests[i].S = []rune("plastered") + tests[i].Expected = []rune("plaster") + i++ + + tests[i].S = []rune("bled") + tests[i].Expected = []rune("bled") + i++ + + tests[i].S = []rune("motoring") + tests[i].Expected = []rune("motor") + i++ + + tests[i].S = []rune("sing") + tests[i].Expected = []rune("sing") + i++ + + tests[i].S = []rune("conflated") + tests[i].Expected = []rune("conflate") + i++ + + tests[i].S = []rune("troubled") + tests[i].Expected = []rune("trouble") + i++ + + tests[i].S = []rune("sized") + tests[i].Expected = []rune("size") + i++ + + tests[i].S = []rune("hopping") + tests[i].Expected = []rune("hop") + i++ + + tests[i].S = []rune("tanned") + tests[i].Expected = []rune("tan") + i++ + + tests[i].S = []rune("falling") + tests[i].Expected = []rune("fall") + i++ + + tests[i].S = []rune("hissing") + tests[i].Expected = []rune("hiss") + i++ + + tests[i].S = []rune("fizzed") + tests[i].Expected = []rune("fizz") + i++ + + tests[i].S = []rune("failing") + tests[i].Expected = []rune("fail") + i++ + + tests[i].S = []rune("filing") + tests[i].Expected = []rune("file") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step1b(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step1b() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1c_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1c_test.go new file mode 100644 index 00000000..7dc864ad --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step1c_test.go @@ -0,0 +1,60 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep1c(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 17) + + tests[i].S = []rune("happy") + tests[i].Expected = []rune("happi") + i++ + + tests[i].S = []rune("sky") + tests[i].Expected = []rune("sky") + i++ + + tests[i].S = []rune("apology") + tests[i].Expected = []rune("apologi") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step1c(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step1c() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step2_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step2_test.go new file mode 100644 index 00000000..f8258f65 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step2_test.go @@ -0,0 +1,132 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep2(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 22) + + tests[i].S = []rune("relational") + tests[i].Expected = []rune("relate") + i++ + + tests[i].S = []rune("conditional") + tests[i].Expected = []rune("condition") + i++ + + tests[i].S = []rune("rational") + tests[i].Expected = []rune("rational") + i++ + + tests[i].S = []rune("valenci") + tests[i].Expected = []rune("valence") + i++ + + tests[i].S = []rune("hesitanci") + tests[i].Expected = []rune("hesitance") + i++ + + tests[i].S = []rune("digitizer") + tests[i].Expected = []rune("digitize") + i++ + + tests[i].S = []rune("conformabli") + tests[i].Expected = []rune("conformable") + i++ + + tests[i].S = []rune("radicalli") + tests[i].Expected = []rune("radical") + i++ + + tests[i].S = []rune("differentli") + tests[i].Expected = []rune("different") + i++ + + tests[i].S = []rune("vileli") + tests[i].Expected = []rune("vile") + i++ + + tests[i].S = []rune("analogousli") + tests[i].Expected = []rune("analogous") + i++ + + tests[i].S = []rune("vietnamization") + tests[i].Expected = []rune("vietnamize") + i++ + + tests[i].S = []rune("predication") + tests[i].Expected = []rune("predicate") + i++ + + tests[i].S = []rune("operator") + tests[i].Expected = []rune("operate") + i++ + + tests[i].S = []rune("feudalism") + tests[i].Expected = []rune("feudal") + i++ + + tests[i].S = []rune("decisiveness") + tests[i].Expected = []rune("decisive") + i++ + + tests[i].S = []rune("hopefulness") + tests[i].Expected = []rune("hopeful") + i++ + + tests[i].S = []rune("callousness") + tests[i].Expected = []rune("callous") + i++ + + tests[i].S = []rune("formaliti") + tests[i].Expected = []rune("formal") + i++ + + tests[i].S = []rune("sensitiviti") + tests[i].Expected = []rune("sensitive") + i++ + + tests[i].S = []rune("sensibiliti") + tests[i].Expected = []rune("sensible") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step2(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step2() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step3_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step3_test.go new file mode 100644 index 00000000..d2a5e9aa --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step3_test.go @@ -0,0 +1,76 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep3(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 22) + + tests[i].S = []rune("triplicate") + tests[i].Expected = []rune("triplic") + i++ + + tests[i].S = []rune("formative") + tests[i].Expected = []rune("form") + i++ + + tests[i].S = []rune("formalize") + tests[i].Expected = []rune("formal") + i++ + + tests[i].S = []rune("electriciti") + tests[i].Expected = []rune("electric") + i++ + + tests[i].S = []rune("electrical") + tests[i].Expected = []rune("electric") + i++ + + tests[i].S = []rune("hopeful") + tests[i].Expected = []rune("hope") + i++ + + tests[i].S = []rune("goodness") + tests[i].Expected = []rune("good") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step3(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step3() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step4_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step4_test.go new file mode 100644 index 00000000..9154490c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step4_test.go @@ -0,0 +1,124 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep4(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 20) + + tests[i].S = []rune("revival") + tests[i].Expected = []rune("reviv") + i++ + + tests[i].S = []rune("allowance") + tests[i].Expected = []rune("allow") + i++ + + tests[i].S = []rune("inference") + tests[i].Expected = []rune("infer") + i++ + + tests[i].S = []rune("airliner") + tests[i].Expected = []rune("airlin") + i++ + + tests[i].S = []rune("gyroscopic") + tests[i].Expected = []rune("gyroscop") + i++ + + tests[i].S = []rune("adjustable") + tests[i].Expected = []rune("adjust") + i++ + + tests[i].S = []rune("defensible") + tests[i].Expected = []rune("defens") + i++ + + tests[i].S = []rune("irritant") + tests[i].Expected = []rune("irrit") + i++ + + tests[i].S = []rune("replacement") + tests[i].Expected = []rune("replac") + i++ + + tests[i].S = []rune("adjustment") + tests[i].Expected = []rune("adjust") + i++ + + tests[i].S = []rune("dependent") + tests[i].Expected = []rune("depend") + i++ + + tests[i].S = []rune("adoption") + tests[i].Expected = []rune("adopt") + i++ + + tests[i].S = []rune("homologou") + tests[i].Expected = []rune("homolog") + i++ + + tests[i].S = []rune("communism") + tests[i].Expected = []rune("commun") + i++ + + tests[i].S = []rune("activate") + tests[i].Expected = []rune("activ") + i++ + + tests[i].S = []rune("angulariti") + tests[i].Expected = []rune("angular") + i++ + + tests[i].S = []rune("homologous") + tests[i].Expected = []rune("homolog") + i++ + + tests[i].S = []rune("effective") + tests[i].Expected = []rune("effect") + i++ + + tests[i].S = []rune("bowdlerize") + tests[i].Expected = []rune("bowdler") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step4(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step4() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5a_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5a_test.go new file mode 100644 index 00000000..65245277 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5a_test.go @@ -0,0 +1,60 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep5a(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 3) + + tests[i].S = []rune("probate") + tests[i].Expected = []rune("probat") + i++ + + tests[i].S = []rune("rate") + tests[i].Expected = []rune("rate") + i++ + + tests[i].S = []rune("cease") + tests[i].Expected = []rune("ceas") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step5a(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step5a() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5b_test.go b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5b_test.go new file mode 100644 index 00000000..233c37e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/go-porterstemmer/porterstemmer_step5b_test.go @@ -0,0 +1,56 @@ +package porterstemmer + +import ( + "testing" +) + +func TestStep5b(t *testing.T) { + + i := 0 + + tests := make([]struct { + S []rune + Expected []rune + }, 3) + + tests[i].S = []rune("controll") + tests[i].Expected = []rune("control") + i++ + + tests[i].S = []rune("roll") + tests[i].Expected = []rune("roll") + i++ + + for _, datum := range tests { + + actual := make([]rune, len(datum.S)) + copy(actual, datum.S) + + actual = step5b(actual) + + lenActual := len(actual) + lenExpected := len(datum.Expected) + + equal := true + if 0 == lenActual && 0 == lenExpected { + equal = true + } else if lenActual != lenExpected { + equal = false + } else if actual[0] != datum.Expected[0] { + equal = false + } else if actual[lenActual-1] != datum.Expected[lenExpected-1] { + equal = false + } else { + for j := 0; j < lenActual; j++ { + + if actual[j] != datum.Expected[j] { + equal = false + } + } + } + + if !equal { + t.Errorf("Did NOT get what was expected for calling step5b() on [%s]. Expect [%s] but got [%s]", string(datum.S), string(datum.Expected), string(actual)) + } + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/.gitignore b/Godeps/_workspace/src/github.com/blevesearch/segment/.gitignore new file mode 100644 index 00000000..33474427 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/.gitignore @@ -0,0 +1,9 @@ +#* +*.sublime-* +*~ +.#* +.project +.settings +.DS_Store +/maketables +/maketesttables diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/.travis.yml b/Godeps/_workspace/src/github.com/blevesearch/segment/.travis.yml new file mode 100644 index 00000000..d032f234 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - 1.4 + +script: + - go get golang.org/x/tools/cmd/vet + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - go test -v -covermode=count -coverprofile=profile.out + - go vet + - goveralls -service drone.io -coverprofile=profile.out -repotoken $COVERALLS + +notifications: + email: + - marty.schoch@gmail.com diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/LICENSE b/Godeps/_workspace/src/github.com/blevesearch/segment/LICENSE new file mode 100644 index 00000000..7a4a3ea2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/Makefile b/Godeps/_workspace/src/github.com/blevesearch/segment/Makefile new file mode 100644 index 00000000..547d389c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/Makefile @@ -0,0 +1,9 @@ +maketables: maketables.go maketesttables.go + go build maketables.go + go build maketesttables.go + +tables: maketables + ./maketables > tables.go + gofmt -w tables.go + ./maketesttables > tables_test.go + gofmt -w tables_test.go diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/README.md b/Godeps/_workspace/src/github.com/blevesearch/segment/README.md new file mode 100644 index 00000000..52dbde82 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/README.md @@ -0,0 +1,61 @@ +# segment + +A Go library for performing Unicode Text Segmentation +as described in [Unicode Standard Annex #29](http://www.unicode.org/reports/tr29/) + +## Features + +* Currently only segmentation at Word Boundaries is supported. + +## License + +Apache License Version 2.0 + +## Usage + +The functionality is exposed in two ways: + +1. You can use a bufio.Scanner with the SplitWords implementation of SplitFunc. +The SplitWords function will identify the appropriate word boundaries in the input +text and the Scanner will return tokens at the appropriate place. + + scanner := bufio.NewScanner(...) + scanner.Split(segment.SplitWords) + for scanner.Scan() { + tokenBytes := scanner.Bytes() + } + if err := scanner.Err(); err != nil { + t.Fatal(err) + } + +2. Sometimes you would also like information returned about the type of token. +To do this we have introduce a new type named Segmenter. It works just like Scanner +but additionally a token type is returned. + + segmenter := segment.NewWordSegmenter(...) + for segmenter.Segment() { + tokenBytes := segmenter.Bytes()) + tokenType := segmenter.Type() + } + if err := segmenter.Err(); err != nil { + t.Fatal(err) + } + +## Generating Tables + +The tables.go file is generated from the data in the Unicode Text Segmentation property data files. Also the tables_test.go file is generated from the data in the Unicode Text Segmentation test data files. + +To regenerate the files run: + + go generate + + The data generated will be based on the Unicode version set by the unicode package value ```unicode.Version```. + +## Status + + +[![Build Status](https://travis-ci.org/blevesearch/segment.svg?branch=master)](https://travis-ci.org/blevesearch/segment) + +[![Coverage Status](https://img.shields.io/coveralls/blevesearch/segment.svg)](https://coveralls.io/r/blevesearch/segment?branch=master) + +[![GoDoc](https://godoc.org/github.com/blevesearch/segment?status.svg)](https://godoc.org/github.com/blevesearch/segment) \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/doc.go b/Godeps/_workspace/src/github.com/blevesearch/segment/doc.go new file mode 100644 index 00000000..6eed3e3a --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/doc.go @@ -0,0 +1,45 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +/* +Package segment is a library for performing Unicode Text Segmentation +as described in Unicode Standard Annex #29 http://www.unicode.org/reports/tr29/ + +Currently only segmentation at Word Boundaries is supported. + +The functionality is exposed in two ways: + +1. You can use a bufio.Scanner with the SplitWords implementation of SplitFunc. +The SplitWords function will identify the appropriate word boundaries in the input +text and the Scanner will return tokens at the appropriate place. + + scanner := bufio.NewScanner(...) + scanner.Split(segment.SplitWords) + for scanner.Scan() { + tokenBytes := scanner.Bytes() + } + if err := scanner.Err(); err != nil { + t.Fatal(err) + } + +2. Sometimes you would also like information returned about the type of token. +To do this we have introduce a new type named Segmenter. It works just like Scanner +but additionally a token type is returned. + + segmenter := segment.NewWordSegmenter(...) + for segmenter.Segment() { + tokenBytes := segmenter.Bytes()) + tokenType := segmenter.Type() + } + if err := segmenter.Err(); err != nil { + t.Fatal(err) + } + +*/ +package segment diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/export_test.go b/Godeps/_workspace/src/github.com/blevesearch/segment/export_test.go new file mode 100644 index 00000000..ae8bddba --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/export_test.go @@ -0,0 +1,20 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package segment + +// Exported for testing only. +import ( + "unicode/utf8" +) + +func (s *Segmenter) MaxTokenSize(n int) { + if n < utf8.UTFMax || n > 1e9 { + panic("bad max token size") + } + if n < len(s.buf) { + s.buf = make([]byte, n) + } + s.maxTokenSize = n +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/maketables.go b/Godeps/_workspace/src/github.com/blevesearch/segment/maketables.go new file mode 100644 index 00000000..e97ea8e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/maketables.go @@ -0,0 +1,279 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build ignore + +package main + +import ( + "bufio" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "os/exec" + "strconv" + "strings" + "unicode" +) + +var url = flag.String("url", + "http://www.unicode.org/Public/"+unicode.Version+"/ucd/auxiliary/", + "URL of Unicode database directory") +var verbose = flag.Bool("verbose", + false, + "write data to stdout as it is parsed") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") +var outputFile = flag.String("output", + "", + "output file for generated tables; default stdout") + +var output *bufio.Writer + +func main() { + flag.Parse() + setupOutput() + + graphemePropertyRanges := make(map[string]*unicode.RangeTable) + loadUnicodeData("GraphemeBreakProperty.txt", graphemePropertyRanges) + wordPropertyRanges := make(map[string]*unicode.RangeTable) + loadUnicodeData("WordBreakProperty.txt", wordPropertyRanges) + sentencePropertyRanges := make(map[string]*unicode.RangeTable) + loadUnicodeData("SentenceBreakProperty.txt", sentencePropertyRanges) + + fmt.Fprintf(output, fileHeader, *url) + generateTables("Grapheme", graphemePropertyRanges) + generateTables("Word", wordPropertyRanges) + generateTables("Sentence", sentencePropertyRanges) + + flushOutput() +} + +// WordBreakProperty.txt has the form: +// 05F0..05F2 ; Hebrew_Letter # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD +// FB1D ; Hebrew_Letter # Lo HEBREW LETTER YOD WITH HIRIQ +func openReader(file string) (input io.ReadCloser) { + if *localFiles { + f, err := os.Open(file) + if err != nil { + log.Fatal(err) + } + input = f + } else { + path := *url + file + resp, err := http.Get(path) + if err != nil { + log.Fatal(err) + } + if resp.StatusCode != 200 { + log.Fatal("bad GET status for "+file, resp.Status) + } + input = resp.Body + } + return +} + +func loadUnicodeData(filename string, propertyRanges map[string]*unicode.RangeTable) { + f := openReader(filename) + defer f.Close() + bufioReader := bufio.NewReader(f) + line, err := bufioReader.ReadString('\n') + for err == nil { + parseLine(line, propertyRanges) + line, err = bufioReader.ReadString('\n') + } + // if the err was EOF still need to process last value + if err == io.EOF { + parseLine(line, propertyRanges) + } +} + +const comment = "#" +const sep = ";" +const rnge = ".." + +func parseLine(line string, propertyRanges map[string]*unicode.RangeTable) { + if strings.HasPrefix(line, comment) { + return + } + line = strings.TrimSpace(line) + if len(line) == 0 { + return + } + commentStart := strings.Index(line, comment) + if commentStart > 0 { + line = line[0:commentStart] + } + pieces := strings.Split(line, sep) + if len(pieces) != 2 { + log.Printf("unexpected %d pieces in %s", len(pieces), line) + return + } + + propertyName := strings.TrimSpace(pieces[1]) + + rangeTable, ok := propertyRanges[propertyName] + if !ok { + rangeTable = &unicode.RangeTable{ + LatinOffset: 0, + } + propertyRanges[propertyName] = rangeTable + } + + codepointRange := strings.TrimSpace(pieces[0]) + rngeIndex := strings.Index(codepointRange, rnge) + + if rngeIndex < 0 { + // single codepoint, not range + codepointInt, err := strconv.ParseUint(codepointRange, 16, 64) + if err != nil { + log.Printf("error parsing int: %v", err) + return + } + if codepointInt < 0x10000 { + r16 := unicode.Range16{ + Lo: uint16(codepointInt), + Hi: uint16(codepointInt), + Stride: 1, + } + addR16ToTable(rangeTable, r16) + } else { + r32 := unicode.Range32{ + Lo: uint32(codepointInt), + Hi: uint32(codepointInt), + Stride: 1, + } + addR32ToTable(rangeTable, r32) + } + } else { + rngeStart := codepointRange[0:rngeIndex] + rngeEnd := codepointRange[rngeIndex+2:] + rngeStartInt, err := strconv.ParseUint(rngeStart, 16, 64) + if err != nil { + log.Printf("error parsing int: %v", err) + return + } + rngeEndInt, err := strconv.ParseUint(rngeEnd, 16, 64) + if err != nil { + log.Printf("error parsing int: %v", err) + return + } + if rngeStartInt < 0x10000 && rngeEndInt < 0x10000 { + r16 := unicode.Range16{ + Lo: uint16(rngeStartInt), + Hi: uint16(rngeEndInt), + Stride: 1, + } + addR16ToTable(rangeTable, r16) + } else if rngeStartInt >= 0x10000 && rngeEndInt >= 0x10000 { + r32 := unicode.Range32{ + Lo: uint32(rngeStartInt), + Hi: uint32(rngeEndInt), + Stride: 1, + } + addR32ToTable(rangeTable, r32) + } else { + log.Printf("unexpected range") + } + } +} + +func addR16ToTable(r *unicode.RangeTable, r16 unicode.Range16) { + if r.R16 == nil { + r.R16 = make([]unicode.Range16, 0, 1) + } + r.R16 = append(r.R16, r16) + if r16.Hi <= unicode.MaxLatin1 { + r.LatinOffset++ + } +} + +func addR32ToTable(r *unicode.RangeTable, r32 unicode.Range32) { + if r.R32 == nil { + r.R32 = make([]unicode.Range32, 0, 1) + } + r.R32 = append(r.R32, r32) +} + +func generateTables(prefix string, propertyRanges map[string]*unicode.RangeTable) { + for key, rt := range propertyRanges { + fmt.Fprintf(output, "var _%s%s = %s\n", prefix, key, generateRangeTable(rt)) + } +} + +func generateRangeTable(rt *unicode.RangeTable) string { + rv := "&unicode.RangeTable{\n" + if rt.R16 != nil { + rv += "\tR16: []unicode.Range16{\n" + for _, r16 := range rt.R16 { + rv += fmt.Sprintf("\t\t%#v,\n", r16) + } + rv += "\t},\n" + } + if rt.R32 != nil { + rv += "\tR32: []unicode.Range32{\n" + for _, r32 := range rt.R32 { + rv += fmt.Sprintf("\t\t%#v,\n", r32) + } + rv += "\t},\n" + } + rv += fmt.Sprintf("\t\tLatinOffset: %d,\n", rt.LatinOffset) + rv += "}\n" + return rv +} + +const fileHeader = `// Generated by running +// maketables --url=%s +// DO NOT EDIT + +package segment + +import( + "unicode" +) +` + +func setupOutput() { + output = bufio.NewWriter(startGofmt()) +} + +// startGofmt connects output to a gofmt process if -output is set. +func startGofmt() io.Writer { + if *outputFile == "" { + return os.Stdout + } + stdout, err := os.Create(*outputFile) + if err != nil { + log.Fatal(err) + } + // Pipe output to gofmt. + gofmt := exec.Command("gofmt") + fd, err := gofmt.StdinPipe() + if err != nil { + log.Fatal(err) + } + gofmt.Stdout = stdout + gofmt.Stderr = os.Stderr + err = gofmt.Start() + if err != nil { + log.Fatal(err) + } + return fd +} + +func flushOutput() { + err := output.Flush() + if err != nil { + log.Fatal(err) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/maketesttables.go b/Godeps/_workspace/src/github.com/blevesearch/segment/maketesttables.go new file mode 100644 index 00000000..53f97764 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/maketesttables.go @@ -0,0 +1,212 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +// +build ignore + +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "os/exec" + "strconv" + "strings" + "unicode" +) + +var url = flag.String("url", + "http://www.unicode.org/Public/"+unicode.Version+"/ucd/auxiliary/", + "URL of Unicode database directory") +var verbose = flag.Bool("verbose", + false, + "write data to stdout as it is parsed") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") + +var outputFile = flag.String("output", + "", + "output file for generated tables; default stdout") + +var output *bufio.Writer + +func main() { + flag.Parse() + setupOutput() + + graphemeTests := make([]test, 0) + graphemeTests = loadUnicodeData("GraphemeBreakTest.txt", graphemeTests) + wordTests := make([]test, 0) + wordTests = loadUnicodeData("WordBreakTest.txt", wordTests) + sentenceTests := make([]test, 0) + sentenceTests = loadUnicodeData("SentenceBreakTest.txt", sentenceTests) + + fmt.Fprintf(output, fileHeader, *url) + generateTestTables("Grapheme", graphemeTests) + generateTestTables("Word", wordTests) + generateTestTables("Sentence", sentenceTests) + + flushOutput() +} + +// WordBreakProperty.txt has the form: +// 05F0..05F2 ; Hebrew_Letter # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD +// FB1D ; Hebrew_Letter # Lo HEBREW LETTER YOD WITH HIRIQ +func openReader(file string) (input io.ReadCloser) { + if *localFiles { + f, err := os.Open(file) + if err != nil { + log.Fatal(err) + } + input = f + } else { + path := *url + file + resp, err := http.Get(path) + if err != nil { + log.Fatal(err) + } + if resp.StatusCode != 200 { + log.Fatal("bad GET status for "+file, resp.Status) + } + input = resp.Body + } + return +} + +func loadUnicodeData(filename string, tests []test) []test { + f := openReader(filename) + defer f.Close() + bufioReader := bufio.NewReader(f) + line, err := bufioReader.ReadString('\n') + for err == nil { + tests = parseLine(line, tests) + line, err = bufioReader.ReadString('\n') + } + // if the err was EOF still need to process last value + if err == io.EOF { + tests = parseLine(line, tests) + } + return tests +} + +const comment = "#" +const brk = "÷" +const nbrk = "×" + +type test [][]byte + +func parseLine(line string, tests []test) []test { + if strings.HasPrefix(line, comment) { + return tests + } + line = strings.TrimSpace(line) + if len(line) == 0 { + return tests + } + commentStart := strings.Index(line, comment) + if commentStart > 0 { + line = line[0:commentStart] + } + pieces := strings.Split(line, brk) + t := make(test, 0) + for _, piece := range pieces { + piece = strings.TrimSpace(piece) + if len(piece) > 0 { + codePoints := strings.Split(piece, nbrk) + word := "" + for _, codePoint := range codePoints { + codePoint = strings.TrimSpace(codePoint) + r, err := strconv.ParseInt(codePoint, 16, 64) + if err != nil { + log.Printf("err: %v for '%s'", err, string(r)) + return tests + } + + word += string(r) + } + t = append(t, []byte(word)) + } + } + tests = append(tests, t) + return tests +} + +func generateTestTables(prefix string, tests []test) { + fmt.Fprintf(output, testHeader, prefix) + for _, t := range tests { + fmt.Fprintf(output, "\t\t{\n") + fmt.Fprintf(output, "\t\t\tinput: %#v,\n", bytes.Join(t, []byte{})) + fmt.Fprintf(output, "\t\t\toutput: %s,\n", generateTest(t)) + fmt.Fprintf(output, "\t\t},\n") + } + fmt.Fprintf(output, "}\n") +} + +func generateTest(t test) string { + rv := "[][]byte{" + for _, te := range t { + rv += fmt.Sprintf("%#v,", te) + } + rv += "}" + return rv +} + +const fileHeader = `// Generated by running +// maketesttables --url=%s +// DO NOT EDIT + +package segment +` + +const testHeader = `var unicode%sTests = []struct { + input []byte + output [][]byte + }{ +` + +func setupOutput() { + output = bufio.NewWriter(startGofmt()) +} + +// startGofmt connects output to a gofmt process if -output is set. +func startGofmt() io.Writer { + if *outputFile == "" { + return os.Stdout + } + stdout, err := os.Create(*outputFile) + if err != nil { + log.Fatal(err) + } + // Pipe output to gofmt. + gofmt := exec.Command("gofmt") + fd, err := gofmt.StdinPipe() + if err != nil { + log.Fatal(err) + } + gofmt.Stdout = stdout + gofmt.Stderr = os.Stderr + err = gofmt.Start() + if err != nil { + log.Fatal(err) + } + return fd +} + +func flushOutput() { + err := output.Flush() + if err != nil { + log.Fatal(err) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/segment.go b/Godeps/_workspace/src/github.com/blevesearch/segment/segment.go new file mode 100644 index 00000000..4fb6e208 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/segment.go @@ -0,0 +1,244 @@ +// Substantially copied from: +// go/src/pkg/bufio/scan.go +// +// Original Copyright: +// +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run maketables.go -output tables.go +//go:generate go run maketesttables.go -output tables_test.go + +package segment + +import ( + "errors" + "io" +) + +const maxConsecutiveEmptyReads = 100 + +// NewSegmenter returns a new Segmenter to read from r. +// Defaults to segment using SegmentWords +func NewSegmenter(r io.Reader) *Segmenter { + return &Segmenter{ + r: r, + segment: SegmentWords, + maxTokenSize: MaxScanTokenSize, + buf: make([]byte, 4096), // Plausible starting size; needn't be large. + } +} + +// NewSegmenterDirect returns a new Segmenter to work directly with buf. +// Defaults to segment using SegmentWords +func NewSegmenterDirect(buf []byte) *Segmenter { + return &Segmenter{ + segment: SegmentWords, + maxTokenSize: MaxScanTokenSize, + buf: buf, + start: 0, + end: len(buf), + err: io.EOF, + } +} + +// Segmenter provides a convenient interface for reading data such as +// a file of newline-delimited lines of text. Successive calls to +// the Segment method will step through the 'tokens' of a file, skipping +// the bytes between the tokens. The specification of a token is +// defined by a split function of type SplitFunc; the default split +// function breaks the input into lines with line termination stripped. Split +// functions are defined in this package for scanning a file into +// lines, bytes, UTF-8-encoded runes, and space-delimited words. The +// client may instead provide a custom split function. +// +// Segmenting stops unrecoverably at EOF, the first I/O error, or a token too +// large to fit in the buffer. When a scan stops, the reader may have +// advanced arbitrarily far past the last token. Programs that need more +// control over error handling or large tokens, or must run sequential scans +// on a reader, should use bufio.Reader instead. +// +type Segmenter struct { + r io.Reader // The reader provided by the client. + segment SegmentFunc // The function to split the tokens. + maxTokenSize int // Maximum size of a token; modified by tests. + token []byte // Last token returned by split. + buf []byte // Buffer used as argument to split. + start int // First non-processed byte in buf. + end int // End of data in buf. + typ int // The token type + err error // Sticky error. +} + +// SegmentFunc is the signature of the segmenting function used to tokenize the +// input. The arguments are an initial substring of the remaining unprocessed +// data and a flag, atEOF, that reports whether the Reader has no more data +// to give. The return values are the number of bytes to advance the input +// and the next token to return to the user, plus an error, if any. If the +// data does not yet hold a complete token, for instance if it has no newline +// while scanning lines, SegmentFunc can return (0, nil, nil) to signal the +// Segmenter to read more data into the slice and try again with a longer slice +// starting at the same point in the input. +// +// If the returned error is non-nil, segmenting stops and the error +// is returned to the client. +// +// The function is never called with an empty data slice unless atEOF +// is true. If atEOF is true, however, data may be non-empty and, +// as always, holds unprocessed text. +type SegmentFunc func(data []byte, atEOF bool) (advance int, token []byte, segmentType int, err error) + +// Errors returned by Segmenter. +var ( + ErrTooLong = errors.New("bufio.Segmenter: token too long") + ErrNegativeAdvance = errors.New("bufio.Segmenter: SplitFunc returns negative advance count") + ErrAdvanceTooFar = errors.New("bufio.Segmenter: SplitFunc returns advance count beyond input") +) + +const ( + // Maximum size used to buffer a token. The actual maximum token size + // may be smaller as the buffer may need to include, for instance, a newline. + MaxScanTokenSize = 64 * 1024 +) + +// Err returns the first non-EOF error that was encountered by the Segmenter. +func (s *Segmenter) Err() error { + if s.err == io.EOF { + return nil + } + return s.err +} + +func (s *Segmenter) Type() int { + return s.typ +} + +// Bytes returns the most recent token generated by a call to Segment. +// The underlying array may point to data that will be overwritten +// by a subsequent call to Segment. It does no allocation. +func (s *Segmenter) Bytes() []byte { + return s.token +} + +// Text returns the most recent token generated by a call to Segment +// as a newly allocated string holding its bytes. +func (s *Segmenter) Text() string { + return string(s.token) +} + +// Segment advances the Segmenter to the next token, which will then be +// available through the Bytes or Text method. It returns false when the +// scan stops, either by reaching the end of the input or an error. +// After Segment returns false, the Err method will return any error that +// occurred during scanning, except that if it was io.EOF, Err +// will return nil. +func (s *Segmenter) Segment() bool { + // Loop until we have a token. + for { + // See if we can get a token with what we already have. + if s.end > s.start { + advance, token, typ, err := s.segment(s.buf[s.start:s.end], s.err != nil) + if err != nil { + s.setErr(err) + return false + } + s.typ = typ + if !s.advance(advance) { + return false + } + s.token = token + if token != nil { + return true + } + } + // We cannot generate a token with what we are holding. + // If we've already hit EOF or an I/O error, we are done. + if s.err != nil { + // Shut it down. + s.start = 0 + s.end = 0 + return false + } + // Must read more data. + // First, shift data to beginning of buffer if there's lots of empty space + // or space is needed. + if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) { + copy(s.buf, s.buf[s.start:s.end]) + s.end -= s.start + s.start = 0 + } + // Is the buffer full? If so, resize. + if s.end == len(s.buf) { + if len(s.buf) >= s.maxTokenSize { + s.setErr(ErrTooLong) + return false + } + newSize := len(s.buf) * 2 + if newSize > s.maxTokenSize { + newSize = s.maxTokenSize + } + newBuf := make([]byte, newSize) + copy(newBuf, s.buf[s.start:s.end]) + s.buf = newBuf + s.end -= s.start + s.start = 0 + continue + } + // Finally we can read some input. Make sure we don't get stuck with + // a misbehaving Reader. Officially we don't need to do this, but let's + // be extra careful: Segmenter is for safe, simple jobs. + for loop := 0; ; { + n, err := s.r.Read(s.buf[s.end:len(s.buf)]) + s.end += n + if err != nil { + s.setErr(err) + break + } + if n > 0 { + break + } + loop++ + if loop > maxConsecutiveEmptyReads { + s.setErr(io.ErrNoProgress) + break + } + } + } +} + +// advance consumes n bytes of the buffer. It reports whether the advance was legal. +func (s *Segmenter) advance(n int) bool { + if n < 0 { + s.setErr(ErrNegativeAdvance) + return false + } + if n > s.end-s.start { + s.setErr(ErrAdvanceTooFar) + return false + } + s.start += n + return true +} + +// setErr records the first error encountered. +func (s *Segmenter) setErr(err error) { + if s.err == nil || s.err == io.EOF { + s.err = err + } +} + +// SetSegmenter sets the segment function for the Segmenter. If called, it must be +// called before Segment. +func (s *Segmenter) SetSegmenter(segmenter SegmentFunc) { + s.segment = segmenter +} + +func in(actualTokenType int, possibleTokenTypes ...int) bool { + for _, pt := range possibleTokenTypes { + if pt == actualTokenType { + return true + } + } + return false +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/segment_test.go b/Godeps/_workspace/src/github.com/blevesearch/segment/segment_test.go new file mode 100644 index 00000000..b799ef6c --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/segment_test.go @@ -0,0 +1,241 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package segment + +import ( + "bufio" + "bytes" + "errors" + "io" + "strings" + "testing" +) + +// Tests borrowed from Scanner to test Segmenter + +// slowReader is a reader that returns only a few bytes at a time, to test the incremental +// reads in Scanner.Scan. +type slowReader struct { + max int + buf io.Reader +} + +func (sr *slowReader) Read(p []byte) (n int, err error) { + if len(p) > sr.max { + p = p[0:sr.max] + } + return sr.buf.Read(p) +} + +// genLine writes to buf a predictable but non-trivial line of text of length +// n, including the terminal newline and an occasional carriage return. +// If addNewline is false, the \r and \n are not emitted. +func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) { + buf.Reset() + doCR := lineNum%5 == 0 + if doCR { + n-- + } + for i := 0; i < n-1; i++ { // Stop early for \n. + c := 'a' + byte(lineNum+i) + if c == '\n' || c == '\r' { // Don't confuse us. + c = 'N' + } + buf.WriteByte(c) + } + if addNewline { + if doCR { + buf.WriteByte('\r') + } + buf.WriteByte('\n') + } + return +} + +func wrapSplitFuncAsSegmentFuncForTesting(splitFunc bufio.SplitFunc) SegmentFunc { + return func(data []byte, atEOF bool) (advance int, token []byte, typ int, err error) { + typ = 0 + advance, token, err = splitFunc(data, atEOF) + return + } +} + +// Test that the line segmenter errors out on a long line. +func TestSegmentTooLong(t *testing.T) { + const smallMaxTokenSize = 256 // Much smaller for more efficient testing. + // Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize. + tmp := new(bytes.Buffer) + buf := new(bytes.Buffer) + lineNum := 0 + j := 0 + for i := 0; i < 2*smallMaxTokenSize; i++ { + genLine(tmp, lineNum, j, true) + j++ + buf.Write(tmp.Bytes()) + lineNum++ + } + s := NewSegmenter(&slowReader{3, buf}) + // change to line segmenter for testing + s.SetSegmenter(wrapSplitFuncAsSegmentFuncForTesting(bufio.ScanLines)) + s.MaxTokenSize(smallMaxTokenSize) + j = 0 + for lineNum := 0; s.Segment(); lineNum++ { + genLine(tmp, lineNum, j, false) + if j < smallMaxTokenSize { + j++ + } else { + j-- + } + line := tmp.Bytes() + if !bytes.Equal(s.Bytes(), line) { + t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line) + } + } + err := s.Err() + if err != ErrTooLong { + t.Fatalf("expected ErrTooLong; got %s", err) + } +} + +var testError = errors.New("testError") + +// Test the correct error is returned when the split function errors out. +func TestSegmentError(t *testing.T) { + // Create a split function that delivers a little data, then a predictable error. + numSplits := 0 + const okCount = 7 + errorSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF { + panic("didn't get enough data") + } + if numSplits >= okCount { + return 0, nil, testError + } + numSplits++ + return 1, data[0:1], nil + } + // Read the data. + const text = "abcdefghijklmnopqrstuvwxyz" + buf := strings.NewReader(text) + s := NewSegmenter(&slowReader{1, buf}) + // change to line segmenter for testing + s.SetSegmenter(wrapSplitFuncAsSegmentFuncForTesting(errorSplit)) + var i int + for i = 0; s.Segment(); i++ { + if len(s.Bytes()) != 1 || text[i] != s.Bytes()[0] { + t.Errorf("#%d: expected %q got %q", i, text[i], s.Bytes()[0]) + } + } + // Check correct termination location and error. + if i != okCount { + t.Errorf("unexpected termination; expected %d tokens got %d", okCount, i) + } + err := s.Err() + if err != testError { + t.Fatalf("expected %q got %v", testError, err) + } +} + +// Test that Scan finishes if we have endless empty reads. +type endlessZeros struct{} + +func (endlessZeros) Read(p []byte) (int, error) { + return 0, nil +} + +func TestBadReader(t *testing.T) { + scanner := NewSegmenter(endlessZeros{}) + for scanner.Segment() { + t.Fatal("read should fail") + } + err := scanner.Err() + if err != io.ErrNoProgress { + t.Errorf("unexpected error: %v", err) + } +} + +func TestSegmentAdvanceNegativeError(t *testing.T) { + errorSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF { + panic("didn't get enough data") + } + return -1, data[0:1], nil + } + // Read the data. + const text = "abcdefghijklmnopqrstuvwxyz" + buf := strings.NewReader(text) + s := NewSegmenter(&slowReader{1, buf}) + // change to line segmenter for testing + s.SetSegmenter(wrapSplitFuncAsSegmentFuncForTesting(errorSplit)) + s.Segment() + err := s.Err() + if err != ErrNegativeAdvance { + t.Fatalf("expected %q got %v", testError, err) + } +} + +func TestSegmentAdvanceTooFarError(t *testing.T) { + errorSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF { + panic("didn't get enough data") + } + return len(data) + 10, data[0:1], nil + } + // Read the data. + const text = "abcdefghijklmnopqrstuvwxyz" + buf := strings.NewReader(text) + s := NewSegmenter(&slowReader{1, buf}) + // change to line segmenter for testing + s.SetSegmenter(wrapSplitFuncAsSegmentFuncForTesting(errorSplit)) + s.Segment() + err := s.Err() + if err != ErrAdvanceTooFar { + t.Fatalf("expected %q got %v", testError, err) + } +} + +func TestSegmentLongTokens(t *testing.T) { + // Read the data. + text := bytes.Repeat([]byte("abcdefghijklmnop"), 257) + buf := strings.NewReader(string(text)) + s := NewSegmenter(&slowReader{1, buf}) + // change to line segmenter for testing + s.SetSegmenter(wrapSplitFuncAsSegmentFuncForTesting(bufio.ScanLines)) + for s.Segment() { + line := s.Bytes() + if !bytes.Equal(text, line) { + t.Errorf("expected %s, got %s", text, line) + } + } + err := s.Err() + if err != nil { + t.Fatalf("unexpected error; got %s", err) + } +} + +func TestSegmentLongTokensDontDouble(t *testing.T) { + // Read the data. + text := bytes.Repeat([]byte("abcdefghijklmnop"), 257) + buf := strings.NewReader(string(text)) + s := NewSegmenter(&slowReader{1, buf}) + // change to line segmenter for testing + s.SetSegmenter(wrapSplitFuncAsSegmentFuncForTesting(bufio.ScanLines)) + s.MaxTokenSize(6144) + for s.Segment() { + line := s.Bytes() + if !bytes.Equal(text, line) { + t.Errorf("expected %s, got %s", text, line) + } + } + err := s.Err() + if err != nil { + t.Fatalf("unexpected error; got %s", err) + } +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/segment_words.go b/Godeps/_workspace/src/github.com/blevesearch/segment/segment_words.go new file mode 100644 index 00000000..e01f51ce --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/segment_words.go @@ -0,0 +1,326 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package segment + +import ( + "io" + "unicode" + "unicode/utf8" +) + +// NewWordSegmenter returns a new Segmenter to read from r. +func NewWordSegmenter(r io.Reader) *Segmenter { + return NewSegmenter(r) +} + +// NewWordSegmenterDirect returns a new Segmenter to work directly with buf. +func NewWordSegmenterDirect(buf []byte) *Segmenter { + return NewSegmenterDirect(buf) +} + +const ( + wordCR = iota + wordLF + wordNewline + wordExtend + wordRegional_Indicator + wordFormat + wordKatakana + wordHebrew_Letter + wordALetter + wordSingle_Quote + wordDouble_Quote + wordMidNumLet + wordMidLetter + wordMidNum + wordNumeric + wordExtendNumLet + wordOther +) + +// Word Types +const ( + None = iota + Number + Letter + Kana + Ideo +) + +func SplitWords(data []byte, atEOF bool) (int, []byte, error) { + advance, token, _, err := SegmentWords(data, atEOF) + return advance, token, err +} + +func SegmentWords(data []byte, atEOF bool) (advance int, token []byte, typ int, err error) { + prevType := -1 + prevPrevType := -1 + nextType := -1 + immediateNextType := -1 + start := 0 + wordType := None + currType := -1 + for width := 0; start < len(data); start += width { + width = 1 + r := rune(data[start]) + if r >= utf8.RuneSelf { + r, width = utf8.DecodeRune(data[start:]) + } + + if immediateNextType > 0 { + currType = immediateNextType + } else { + currType = wordSegmentProperty(r) + } + + hasNext := false + next := start + width + nextToken := utf8.RuneError + for next < len(data) { + nextWidth := 1 + nextToken = rune(data[next]) + if nextToken >= utf8.RuneSelf { + nextToken, nextWidth = utf8.DecodeRune(data[next:]) + } + nextType = wordSegmentProperty(nextToken) + if !hasNext { + immediateNextType = nextType + } + hasNext = true + if nextType != wordExtend && nextType != wordFormat { + break + } + next = next + nextWidth + } + + if start != 0 && in(currType, wordExtend, wordFormat) { + // wb4 + // dont set prevType, prevPrevType + // we ignore that these extended are here + // so types should be whatever we saw before them + continue + } else if in(currType, wordALetter, wordHebrew_Letter) && + in(prevType, wordALetter, wordHebrew_Letter) { + // wb5 + wordType = updateWordType(wordType, lookupWordType(currType)) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordMidLetter, wordMidNumLet, wordSingle_Quote) && + in(prevType, wordALetter, wordHebrew_Letter) && + hasNext && in(nextType, wordALetter, wordHebrew_Letter) { + // wb6 + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordMidLetter, wordMidNumLet, wordSingle_Quote) && + in(prevType, wordALetter, wordHebrew_Letter) && + !hasNext && !atEOF { + // possibly wb6, need more data to know + return 0, nil, 0, nil + } else if in(currType, wordALetter, wordHebrew_Letter) && + in(prevType, wordMidLetter, wordMidNumLet, wordSingle_Quote) && + in(prevPrevType, wordALetter, wordHebrew_Letter) { + // wb7 + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordSingle_Quote) && + in(prevType, wordHebrew_Letter) { + // wb7a + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordDouble_Quote) && + in(prevType, wordHebrew_Letter) && + hasNext && in(nextType, wordHebrew_Letter) { + // wb7b + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordDouble_Quote) && + in(prevType, wordHebrew_Letter) && + !hasNext && !atEOF { + // possibly wb7b, need more data + return 0, nil, 0, nil + } else if in(currType, wordHebrew_Letter) && + in(prevType, wordDouble_Quote) && in(prevPrevType, wordHebrew_Letter) { + // wb7c + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordNumeric) && + in(prevType, wordNumeric) { + // wb8 + wordType = updateWordType(wordType, Number) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordNumeric) && + in(prevType, wordALetter, wordHebrew_Letter) { + // wb9 + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordALetter, wordHebrew_Letter) && + in(prevType, wordNumeric) { + // wb10 + wordType = updateWordType(wordType, Letter) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordNumeric) && + in(prevType, wordMidNum, wordMidNumLet, wordSingle_Quote) && + in(prevPrevType, wordNumeric) { + // wb11 + wordType = updateWordType(wordType, Number) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordMidNum, wordMidNumLet, wordSingle_Quote) && + in(prevType, wordNumeric) && + hasNext && in(nextType, wordNumeric) { + // wb12 + wordType = updateWordType(wordType, Number) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordMidNum, wordMidNumLet, wordSingle_Quote) && + in(prevType, wordNumeric) && + !hasNext && !atEOF { + // possibly wb12, need more data + return 0, nil, 0, nil + } else if in(currType, wordKatakana) && + in(prevType, wordKatakana) { + // wb13 + wordType = updateWordType(wordType, Ideo) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordExtendNumLet) && + in(prevType, wordALetter, wordHebrew_Letter, wordNumeric, wordKatakana, wordExtendNumLet) { + // wb13a + wordType = updateWordType(wordType, lookupWordType(currType)) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordALetter, wordHebrew_Letter, wordNumeric, wordKatakana) && + in(prevType, wordExtendNumLet) { + // wb13b + wordType = updateWordType(wordType, lookupWordType(currType)) + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordRegional_Indicator) && + in(prevType, wordRegional_Indicator) { + // wb13c + prevPrevType = prevType + prevType = currType + continue + } else if start == 0 && in(currType, wordCR) && + hasNext && in(immediateNextType, wordLF) { + prevPrevType = prevType + prevType = currType + continue + } else if start == 0 && !in(currType, wordCR, wordLF, wordNewline) { + // only first char, keep goin + wordType = lookupWordType(currType) + if wordType == None { + if unicode.In(r, unicode.Katakana, unicode.Hiragana, unicode.Ideographic) { + wordType = Ideo + } + } + prevPrevType = prevType + prevType = currType + continue + } else if in(currType, wordLF) && in(prevType, wordCR) { + start += width + break + } else { + // wb14 + if start == 0 { + start = width + } + break + } + } + if start > 0 && atEOF { + return start, data[:start], wordType, nil + } + + // Request more data + return 0, nil, 0, nil + +} + +func wordSegmentProperty(r rune) int { + if unicode.Is(_WordALetter, r) { + return wordALetter + } else if unicode.Is(_WordCR, r) { + return wordCR + } else if unicode.Is(_WordLF, r) { + return wordLF + } else if unicode.Is(_WordNewline, r) { + return wordNewline + } else if unicode.Is(_WordExtend, r) { + return wordExtend + } else if unicode.Is(_WordRegional_Indicator, r) { + return wordRegional_Indicator + } else if unicode.Is(_WordFormat, r) { + return wordFormat + } else if unicode.Is(_WordKatakana, r) { + return wordKatakana + } else if unicode.Is(_WordHebrew_Letter, r) { + return wordHebrew_Letter + } else if unicode.Is(_WordSingle_Quote, r) { + return wordSingle_Quote + } else if unicode.Is(_WordDouble_Quote, r) { + return wordDouble_Quote + } else if unicode.Is(_WordMidNumLet, r) { + return wordMidNumLet + } else if unicode.Is(_WordMidLetter, r) { + return wordMidLetter + } else if unicode.Is(_WordMidNum, r) { + return wordMidNum + } else if unicode.Is(_WordNumeric, r) { + return wordNumeric + } else if unicode.Is(_WordExtendNumLet, r) { + return wordExtendNumLet + } else { + return wordOther + } +} + +func lookupWordType(tokenType int) int { + if tokenType == wordNumeric { + return Number + } else if tokenType == wordALetter { + return Letter + } else if tokenType == wordHebrew_Letter { + return Letter + } else if tokenType == wordKatakana { + return Ideo + } + + return None +} + +func updateWordType(currentWordType, newWordType int) int { + if newWordType > currentWordType { + return newWordType + } + return currentWordType +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/segment_words_test.go b/Godeps/_workspace/src/github.com/blevesearch/segment/segment_words_test.go new file mode 100644 index 00000000..7e56eac3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/segment_words_test.go @@ -0,0 +1,360 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +package segment + +import ( + "bufio" + "bytes" + "reflect" + "strings" + "testing" +) + +func TestAdhocSegmentsWithType(t *testing.T) { + + tests := []struct { + input []byte + output [][]byte + outputStrings []string + outputTypes []int + }{ + { + input: []byte("Now is the.\n End."), + output: [][]byte{ + []byte("Now"), + []byte(" "), + []byte("is"), + []byte(" "), + []byte("the"), + []byte("."), + []byte("\n"), + []byte(" "), + []byte("End"), + []byte("."), + }, + outputStrings: []string{ + "Now", + " ", + "is", + " ", + "the", + ".", + "\n", + " ", + "End", + ".", + }, + outputTypes: []int{ + Letter, + None, + Letter, + None, + Letter, + None, + None, + None, + Letter, + None, + }, + }, + { + input: []byte("3.5"), + output: [][]byte{ + []byte("3.5"), + }, + outputStrings: []string{ + "3.5", + }, + outputTypes: []int{ + Number, + }, + }, + { + input: []byte("cat3.5"), + output: [][]byte{ + []byte("cat3.5"), + }, + outputStrings: []string{ + "cat3.5", + }, + outputTypes: []int{ + Letter, + }, + }, + { + input: []byte("c"), + output: [][]byte{ + []byte("c"), + }, + outputStrings: []string{ + "c", + }, + outputTypes: []int{ + Letter, + }, + }, + { + input: []byte("こんにちは世界"), + output: [][]byte{ + []byte("こ"), + []byte("ん"), + []byte("に"), + []byte("ち"), + []byte("は"), + []byte("世"), + []byte("界"), + }, + outputStrings: []string{ + "こ", + "ん", + "に", + "ち", + "は", + "世", + "界", + }, + outputTypes: []int{ + Ideo, + Ideo, + Ideo, + Ideo, + Ideo, + Ideo, + Ideo, + }, + }, + { + input: []byte("你好世界"), + output: [][]byte{ + []byte("你"), + []byte("好"), + []byte("世"), + []byte("界"), + }, + outputStrings: []string{ + "你", + "好", + "世", + "界", + }, + outputTypes: []int{ + Ideo, + Ideo, + Ideo, + Ideo, + }, + }, + { + input: []byte("サッカ"), + output: [][]byte{ + []byte("サッカ"), + }, + outputStrings: []string{ + "サッカ", + }, + outputTypes: []int{ + Ideo, + }, + }, + // test for wb7b/wb7c + { + input: []byte(`א"א`), + output: [][]byte{ + []byte(`א"א`), + }, + outputStrings: []string{ + `א"א`, + }, + outputTypes: []int{ + Letter, + }, + }, + } + + for _, test := range tests { + rv := make([][]byte, 0) + rvstrings := make([]string, 0) + rvtypes := make([]int, 0) + segmenter := NewWordSegmenter(bytes.NewReader(test.input)) + // Set the split function for the scanning operation. + for segmenter.Segment() { + rv = append(rv, segmenter.Bytes()) + rvstrings = append(rvstrings, segmenter.Text()) + rvtypes = append(rvtypes, segmenter.Type()) + } + if err := segmenter.Err(); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(rv, test.output) { + t.Fatalf("expected:\n%#v\ngot:\n%#v\nfor: '%s'", test.output, rv, test.input) + } + if !reflect.DeepEqual(rvstrings, test.outputStrings) { + t.Fatalf("expected:\n%#v\ngot:\n%#v\nfor: '%s'", test.outputStrings, rvstrings, test.input) + } + if !reflect.DeepEqual(rvtypes, test.outputTypes) { + t.Fatalf("expeced:\n%#v\ngot:\n%#v\nfor: '%s'", test.outputTypes, rvtypes, test.input) + } + } + +} + +func TestUnicodeSegments(t *testing.T) { + + for _, test := range unicodeWordTests { + rv := make([][]byte, 0) + scanner := bufio.NewScanner(bytes.NewReader(test.input)) + // Set the split function for the scanning operation. + scanner.Split(SplitWords) + for scanner.Scan() { + rv = append(rv, scanner.Bytes()) + } + if err := scanner.Err(); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(rv, test.output) { + t.Fatalf("expected:\n%#v\ngot:\n%#v\nfor: '%s'", test.output, rv, test.input) + } + } +} + +func TestUnicodeSegmentsSlowReader(t *testing.T) { + + for _, test := range unicodeWordTests { + rv := make([][]byte, 0) + segmenter := NewWordSegmenter(&slowReader{1, bytes.NewReader(test.input)}) + for segmenter.Segment() { + rv = append(rv, segmenter.Bytes()) + } + if err := segmenter.Err(); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(rv, test.output) { + t.Fatalf("expected:\n%#v\ngot:\n%#v\nfor: '%s'", test.output, rv, test.input) + } + } +} + +func TestWordSegmentLongInputSlowReader(t *testing.T) { + // Read the data. + text := bytes.Repeat([]byte("abcdefghijklmnop"), 26) + buf := strings.NewReader(string(text) + " cat") + s := NewSegmenter(&slowReader{1, buf}) + s.MaxTokenSize(6144) + for s.Segment() { + } + err := s.Err() + if err != nil { + t.Fatalf("unexpected error; got '%s'", err) + } + finalWord := s.Text() + if s.Text() != "cat" { + t.Errorf("expected 'cat' got '%s'", finalWord) + } +} + +func BenchmarkWordSegmenter(b *testing.B) { + + for i := 0; i < b.N; i++ { + segmenter := NewWordSegmenter(bytes.NewReader(bleveWikiArticle)) + for segmenter.Segment() { + } + if err := segmenter.Err(); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkWordSegmenterDirect(b *testing.B) { + + for i := 0; i < b.N; i++ { + segmenter := NewWordSegmenterDirect(bleveWikiArticle) + for segmenter.Segment() { + } + if err := segmenter.Err(); err != nil { + b.Fatal(err) + } + } +} + +var bleveWikiArticle = []byte(`Boiling liquid expanding vapor explosion +From Wikipedia, the free encyclopedia +See also: Boiler explosion and Steam explosion + +Flames subsequent to a flammable liquid BLEVE from a tanker. BLEVEs do not necessarily involve fire. + +This article's tone or style may not reflect the encyclopedic tone used on Wikipedia. See Wikipedia's guide to writing better articles for suggestions. (July 2013) +A boiling liquid expanding vapor explosion (BLEVE, /ˈblɛviː/ blev-ee) is an explosion caused by the rupture of a vessel containing a pressurized liquid above its boiling point.[1] +Contents [hide] +1 Mechanism +1.1 Water example +1.2 BLEVEs without chemical reactions +2 Fires +3 Incidents +4 Safety measures +5 See also +6 References +7 External links +Mechanism[edit] + +This section needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed. (July 2013) +There are three characteristics of liquids which are relevant to the discussion of a BLEVE: +If a liquid in a sealed container is boiled, the pressure inside the container increases. As the liquid changes to a gas it expands - this expansion in a vented container would cause the gas and liquid to take up more space. In a sealed container the gas and liquid are not able to take up more space and so the pressure rises. Pressurized vessels containing liquids can reach an equilibrium where the liquid stops boiling and the pressure stops rising. This occurs when no more heat is being added to the system (either because it has reached ambient temperature or has had a heat source removed). +The boiling temperature of a liquid is dependent on pressure - high pressures will yield high boiling temperatures, and low pressures will yield low boiling temperatures. A common simple experiment is to place a cup of water in a vacuum chamber, and then reduce the pressure in the chamber until the water boils. By reducing the pressure the water will boil even at room temperature. This works both ways - if the pressure is increased beyond normal atmospheric pressures, the boiling of hot water could be suppressed far beyond normal temperatures. The cooling system of a modern internal combustion engine is a real-world example. +When a liquid boils it turns into a gas. The resulting gas takes up far more space than the liquid did. +Typically, a BLEVE starts with a container of liquid which is held above its normal, atmospheric-pressure boiling temperature. Many substances normally stored as liquids, such as CO2, propane, and other similar industrial gases have boiling temperatures, at atmospheric pressure, far below room temperature. In the case of water, a BLEVE could occur if a pressurized chamber of water is heated far beyond the standard 100 °C (212 °F). That container, because the boiling water pressurizes it, is capable of holding liquid water at very high temperatures. +If the pressurized vessel, containing liquid at high temperature (which may be room temperature, depending on the substance) ruptures, the pressure which prevents the liquid from boiling is lost. If the rupture is catastrophic, where the vessel is immediately incapable of holding any pressure at all, then there suddenly exists a large mass of liquid which is at very high temperature and very low pressure. This causes the entire volume of liquid to instantaneously boil, which in turn causes an extremely rapid expansion. Depending on temperatures, pressures and the substance involved, that expansion may be so rapid that it can be classified as an explosion, fully capable of inflicting severe damage on its surroundings. +Water example[edit] +Imagine, for example, a tank of pressurized liquid water held at 204.4 °C (400 °F). This tank would normally be pressurized to 1.7 MPa (250 psi) above atmospheric ("gauge") pressure. If the tank containing the water were to rupture, there would for a slight moment exist a volume of liquid water which would be +at atmospheric pressure, and +204.4 °C (400 °F). +At atmospheric pressure the boiling point of water is 100 °C (212 °F) - liquid water at atmospheric pressure cannot exist at temperatures higher than 100 °C (212 °F). At that moment, the water would boil and turn to vapour explosively, and the 204.4 °C (400 °F) liquid water turned to gas would take up a lot more volume than it did as liquid, causing a vapour explosion. Such explosions can happen when the superheated water of a steam engine escapes through a crack in a boiler, causing a boiler explosion. +BLEVEs without chemical reactions[edit] +It is important to note that a BLEVE need not be a chemical explosion—nor does there need to be a fire—however if a flammable substance is subject to a BLEVE it may also be subject to intense heating, either from an external source of heat which may have caused the vessel to rupture in the first place or from an internal source of localized heating such as skin friction. This heating can cause a flammable substance to ignite, adding a secondary explosion caused by the primary BLEVE. While blast effects of any BLEVE can be devastating, a flammable substance such as propane can add significantly to the danger. +Bleve explosion.svg +While the term BLEVE is most often used to describe the results of a container of flammable liquid rupturing due to fire, a BLEVE can occur even with a non-flammable substance such as water,[2] liquid nitrogen,[3] liquid helium or other refrigerants or cryogens, and therefore is not usually considered a type of chemical explosion. +Fires[edit] +BLEVEs can be caused by an external fire near the storage vessel causing heating of the contents and pressure build-up. While tanks are often designed to withstand great pressure, constant heating can cause the metal to weaken and eventually fail. If the tank is being heated in an area where there is no liquid, it may rupture faster without the liquid to absorb the heat. Gas containers are usually equipped with relief valves that vent off excess pressure, but the tank can still fail if the pressure is not released quickly enough.[1] Relief valves are sized to release pressure fast enough to prevent the pressure from increasing beyond the strength of the vessel, but not so fast as to be the cause of an explosion. An appropriately sized relief valve will allow the liquid inside to boil slowly, maintaining a constant pressure in the vessel until all the liquid has boiled and the vessel empties. +If the substance involved is flammable, it is likely that the resulting cloud of the substance will ignite after the BLEVE has occurred, forming a fireball and possibly a fuel-air explosion, also termed a vapor cloud explosion (VCE). If the materials are toxic, a large area will be contaminated.[4] +Incidents[edit] +The term "BLEVE" was coined by three researchers at Factory Mutual, in the analysis of an accident there in 1957 involving a chemical reactor vessel.[5] +In August 1959 the Kansas City Fire Department suffered its largest ever loss of life in the line of duty, when a 25,000 gallon (95,000 litre) gas tank exploded during a fire on Southwest Boulevard killing five firefighters. This was the first time BLEVE was used to describe a burning fuel tank.[citation needed] +Later incidents included the Cheapside Street Whisky Bond Fire in Glasgow, Scotland in 1960; Feyzin, France in 1966; Crescent City, Illinois in 1970; Kingman, Arizona in 1973; a liquid nitrogen tank rupture[6] at Air Products and Chemicals and Mobay Chemical Company at New Martinsville, West Virginia on January 31, 1978 [1];Texas City, Texas in 1978; Murdock, Illinois in 1983; San Juan Ixhuatepec, Mexico City in 1984; and Toronto, Ontario in 2008. +Safety measures[edit] +[icon] This section requires expansion. (July 2013) +Some fire mitigation measures are listed under liquefied petroleum gas. +See also[edit] +Boiler explosion +Expansion ratio +Explosive boiling or phase explosion +Rapid phase transition +Viareggio train derailment +2008 Toronto explosions +Gas carriers +Los Alfaques Disaster +Lac-Mégantic derailment +References[edit] +^ Jump up to: a b Kletz, Trevor (March 1990). Critical Aspects of Safety and Loss Prevention. London: Butterworth–Heinemann. pp. 43–45. ISBN 0-408-04429-2. +Jump up ^ "Temperature Pressure Relief Valves on Water Heaters: test, inspect, replace, repair guide". Inspect-ny.com. Retrieved 2011-07-12. +Jump up ^ Liquid nitrogen BLEVE demo +Jump up ^ "Chemical Process Safety" (PDF). Retrieved 2011-07-12. +Jump up ^ David F. Peterson, BLEVE: Facts, Risk Factors, and Fallacies, Fire Engineering magazine (2002). +Jump up ^ "STATE EX REL. VAPOR CORP. v. NARICK". Supreme Court of Appeals of West Virginia. 1984-07-12. Retrieved 2014-03-16. +External links[edit] + Look up boiling liquid expanding vapor explosion in Wiktionary, the free dictionary. + Wikimedia Commons has media related to BLEVE. +BLEVE Demo on YouTube — video of a controlled BLEVE demo +huge explosions on YouTube — video of propane and isobutane BLEVEs from a train derailment at Murdock, Illinois (3 September 1983) +Propane BLEVE on YouTube — video of BLEVE from the Toronto propane depot fire +Moscow Ring Road Accident on YouTube - Dozens of LPG tank BLEVEs after a road accident in Moscow +Kingman, AZ BLEVE — An account of the 5 July 1973 explosion in Kingman, with photographs +Propane Tank Explosions — Description of circumstances required to cause a propane tank BLEVE. +Analysis of BLEVE Events at DOE Sites - Details physics and mathematics of BLEVEs. +HID - SAFETY REPORT ASSESSMENT GUIDE: Whisky Maturation Warehouses - The liquor is aged in wooden barrels that can suffer BLEVE. +Categories: ExplosivesFirefightingFireTypes of fireGas technologiesIndustrial fires and explosions`) diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/tables.go b/Godeps/_workspace/src/github.com/blevesearch/segment/tables.go new file mode 100644 index 00000000..76ec7b8d --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/tables.go @@ -0,0 +1,5093 @@ +// Generated by running +// maketables --url=http://www.unicode.org/Public/7.0.0/ucd/auxiliary/ +// DO NOT EDIT + +package segment + +import ( + "unicode" +) + +var _GraphemeSpacingMark = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x903, Hi: 0x903, Stride: 0x1}, + unicode.Range16{Lo: 0x93b, Hi: 0x93b, Stride: 0x1}, + unicode.Range16{Lo: 0x93e, Hi: 0x940, Stride: 0x1}, + unicode.Range16{Lo: 0x949, Hi: 0x94c, Stride: 0x1}, + unicode.Range16{Lo: 0x94e, Hi: 0x94f, Stride: 0x1}, + unicode.Range16{Lo: 0x982, Hi: 0x983, Stride: 0x1}, + unicode.Range16{Lo: 0x9bf, Hi: 0x9c0, Stride: 0x1}, + unicode.Range16{Lo: 0x9c7, Hi: 0x9c8, Stride: 0x1}, + unicode.Range16{Lo: 0x9cb, Hi: 0x9cc, Stride: 0x1}, + unicode.Range16{Lo: 0xa03, Hi: 0xa03, Stride: 0x1}, + unicode.Range16{Lo: 0xa3e, Hi: 0xa40, Stride: 0x1}, + unicode.Range16{Lo: 0xa83, Hi: 0xa83, Stride: 0x1}, + unicode.Range16{Lo: 0xabe, Hi: 0xac0, Stride: 0x1}, + unicode.Range16{Lo: 0xac9, Hi: 0xac9, Stride: 0x1}, + unicode.Range16{Lo: 0xacb, Hi: 0xacc, Stride: 0x1}, + unicode.Range16{Lo: 0xb02, Hi: 0xb03, Stride: 0x1}, + unicode.Range16{Lo: 0xb40, Hi: 0xb40, Stride: 0x1}, + unicode.Range16{Lo: 0xb47, Hi: 0xb48, Stride: 0x1}, + unicode.Range16{Lo: 0xb4b, Hi: 0xb4c, Stride: 0x1}, + unicode.Range16{Lo: 0xbbf, Hi: 0xbbf, Stride: 0x1}, + unicode.Range16{Lo: 0xbc1, Hi: 0xbc2, Stride: 0x1}, + unicode.Range16{Lo: 0xbc6, Hi: 0xbc8, Stride: 0x1}, + unicode.Range16{Lo: 0xbca, Hi: 0xbcc, Stride: 0x1}, + unicode.Range16{Lo: 0xc01, Hi: 0xc03, Stride: 0x1}, + unicode.Range16{Lo: 0xc41, Hi: 0xc44, Stride: 0x1}, + unicode.Range16{Lo: 0xc82, Hi: 0xc83, Stride: 0x1}, + unicode.Range16{Lo: 0xcbe, Hi: 0xcbe, Stride: 0x1}, + unicode.Range16{Lo: 0xcc0, Hi: 0xcc1, Stride: 0x1}, + unicode.Range16{Lo: 0xcc3, Hi: 0xcc4, Stride: 0x1}, + unicode.Range16{Lo: 0xcc7, Hi: 0xcc8, Stride: 0x1}, + unicode.Range16{Lo: 0xcca, Hi: 0xccb, Stride: 0x1}, + unicode.Range16{Lo: 0xd02, Hi: 0xd03, Stride: 0x1}, + unicode.Range16{Lo: 0xd3f, Hi: 0xd40, Stride: 0x1}, + unicode.Range16{Lo: 0xd46, Hi: 0xd48, Stride: 0x1}, + unicode.Range16{Lo: 0xd4a, Hi: 0xd4c, Stride: 0x1}, + unicode.Range16{Lo: 0xd82, Hi: 0xd83, Stride: 0x1}, + unicode.Range16{Lo: 0xdd0, Hi: 0xdd1, Stride: 0x1}, + unicode.Range16{Lo: 0xdd8, Hi: 0xdde, Stride: 0x1}, + unicode.Range16{Lo: 0xdf2, Hi: 0xdf3, Stride: 0x1}, + unicode.Range16{Lo: 0xe33, Hi: 0xe33, Stride: 0x1}, + unicode.Range16{Lo: 0xeb3, Hi: 0xeb3, Stride: 0x1}, + unicode.Range16{Lo: 0xf3e, Hi: 0xf3f, Stride: 0x1}, + unicode.Range16{Lo: 0xf7f, Hi: 0xf7f, Stride: 0x1}, + unicode.Range16{Lo: 0x1031, Hi: 0x1031, Stride: 0x1}, + unicode.Range16{Lo: 0x103b, Hi: 0x103c, Stride: 0x1}, + unicode.Range16{Lo: 0x1056, Hi: 0x1057, Stride: 0x1}, + unicode.Range16{Lo: 0x1084, Hi: 0x1084, Stride: 0x1}, + unicode.Range16{Lo: 0x17b6, Hi: 0x17b6, Stride: 0x1}, + unicode.Range16{Lo: 0x17be, Hi: 0x17c5, Stride: 0x1}, + unicode.Range16{Lo: 0x17c7, Hi: 0x17c8, Stride: 0x1}, + unicode.Range16{Lo: 0x1923, Hi: 0x1926, Stride: 0x1}, + unicode.Range16{Lo: 0x1929, Hi: 0x192b, Stride: 0x1}, + unicode.Range16{Lo: 0x1930, Hi: 0x1931, Stride: 0x1}, + unicode.Range16{Lo: 0x1933, Hi: 0x1938, Stride: 0x1}, + unicode.Range16{Lo: 0x19b5, Hi: 0x19b7, Stride: 0x1}, + unicode.Range16{Lo: 0x19ba, Hi: 0x19ba, Stride: 0x1}, + unicode.Range16{Lo: 0x1a19, Hi: 0x1a1a, Stride: 0x1}, + unicode.Range16{Lo: 0x1a55, Hi: 0x1a55, Stride: 0x1}, + unicode.Range16{Lo: 0x1a57, Hi: 0x1a57, Stride: 0x1}, + unicode.Range16{Lo: 0x1a6d, Hi: 0x1a72, Stride: 0x1}, + unicode.Range16{Lo: 0x1b04, Hi: 0x1b04, Stride: 0x1}, + unicode.Range16{Lo: 0x1b35, Hi: 0x1b35, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3b, Hi: 0x1b3b, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3d, Hi: 0x1b41, Stride: 0x1}, + unicode.Range16{Lo: 0x1b43, Hi: 0x1b44, Stride: 0x1}, + unicode.Range16{Lo: 0x1b82, Hi: 0x1b82, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba1, Hi: 0x1ba1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba6, Hi: 0x1ba7, Stride: 0x1}, + unicode.Range16{Lo: 0x1baa, Hi: 0x1baa, Stride: 0x1}, + unicode.Range16{Lo: 0x1be7, Hi: 0x1be7, Stride: 0x1}, + unicode.Range16{Lo: 0x1bea, Hi: 0x1bec, Stride: 0x1}, + unicode.Range16{Lo: 0x1bee, Hi: 0x1bee, Stride: 0x1}, + unicode.Range16{Lo: 0x1bf2, Hi: 0x1bf3, Stride: 0x1}, + unicode.Range16{Lo: 0x1c24, Hi: 0x1c2b, Stride: 0x1}, + unicode.Range16{Lo: 0x1c34, Hi: 0x1c35, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce1, Hi: 0x1ce1, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf2, Hi: 0x1cf3, Stride: 0x1}, + unicode.Range16{Lo: 0xa823, Hi: 0xa824, Stride: 0x1}, + unicode.Range16{Lo: 0xa827, Hi: 0xa827, Stride: 0x1}, + unicode.Range16{Lo: 0xa880, Hi: 0xa881, Stride: 0x1}, + unicode.Range16{Lo: 0xa8b4, Hi: 0xa8c3, Stride: 0x1}, + unicode.Range16{Lo: 0xa952, Hi: 0xa953, Stride: 0x1}, + unicode.Range16{Lo: 0xa983, Hi: 0xa983, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b4, Hi: 0xa9b5, Stride: 0x1}, + unicode.Range16{Lo: 0xa9ba, Hi: 0xa9bb, Stride: 0x1}, + unicode.Range16{Lo: 0xa9bd, Hi: 0xa9c0, Stride: 0x1}, + unicode.Range16{Lo: 0xaa2f, Hi: 0xaa30, Stride: 0x1}, + unicode.Range16{Lo: 0xaa33, Hi: 0xaa34, Stride: 0x1}, + unicode.Range16{Lo: 0xaa4d, Hi: 0xaa4d, Stride: 0x1}, + unicode.Range16{Lo: 0xaaeb, Hi: 0xaaeb, Stride: 0x1}, + unicode.Range16{Lo: 0xaaee, Hi: 0xaaef, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf5, Hi: 0xaaf5, Stride: 0x1}, + unicode.Range16{Lo: 0xabe3, Hi: 0xabe4, Stride: 0x1}, + unicode.Range16{Lo: 0xabe6, Hi: 0xabe7, Stride: 0x1}, + unicode.Range16{Lo: 0xabe9, Hi: 0xabea, Stride: 0x1}, + unicode.Range16{Lo: 0xabec, Hi: 0xabec, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x11000, Hi: 0x11000, Stride: 0x1}, + unicode.Range32{Lo: 0x11002, Hi: 0x11002, Stride: 0x1}, + unicode.Range32{Lo: 0x11082, Hi: 0x11082, Stride: 0x1}, + unicode.Range32{Lo: 0x110b0, Hi: 0x110b2, Stride: 0x1}, + unicode.Range32{Lo: 0x110b7, Hi: 0x110b8, Stride: 0x1}, + unicode.Range32{Lo: 0x1112c, Hi: 0x1112c, Stride: 0x1}, + unicode.Range32{Lo: 0x11182, Hi: 0x11182, Stride: 0x1}, + unicode.Range32{Lo: 0x111b3, Hi: 0x111b5, Stride: 0x1}, + unicode.Range32{Lo: 0x111bf, Hi: 0x111c0, Stride: 0x1}, + unicode.Range32{Lo: 0x1122c, Hi: 0x1122e, Stride: 0x1}, + unicode.Range32{Lo: 0x11232, Hi: 0x11233, Stride: 0x1}, + unicode.Range32{Lo: 0x11235, Hi: 0x11235, Stride: 0x1}, + unicode.Range32{Lo: 0x112e0, Hi: 0x112e2, Stride: 0x1}, + unicode.Range32{Lo: 0x11302, Hi: 0x11303, Stride: 0x1}, + unicode.Range32{Lo: 0x1133f, Hi: 0x1133f, Stride: 0x1}, + unicode.Range32{Lo: 0x11341, Hi: 0x11344, Stride: 0x1}, + unicode.Range32{Lo: 0x11347, Hi: 0x11348, Stride: 0x1}, + unicode.Range32{Lo: 0x1134b, Hi: 0x1134d, Stride: 0x1}, + unicode.Range32{Lo: 0x11362, Hi: 0x11363, Stride: 0x1}, + unicode.Range32{Lo: 0x114b1, Hi: 0x114b2, Stride: 0x1}, + unicode.Range32{Lo: 0x114b9, Hi: 0x114b9, Stride: 0x1}, + unicode.Range32{Lo: 0x114bb, Hi: 0x114bc, Stride: 0x1}, + unicode.Range32{Lo: 0x114be, Hi: 0x114be, Stride: 0x1}, + unicode.Range32{Lo: 0x114c1, Hi: 0x114c1, Stride: 0x1}, + unicode.Range32{Lo: 0x115b0, Hi: 0x115b1, Stride: 0x1}, + unicode.Range32{Lo: 0x115b8, Hi: 0x115bb, Stride: 0x1}, + unicode.Range32{Lo: 0x115be, Hi: 0x115be, Stride: 0x1}, + unicode.Range32{Lo: 0x11630, Hi: 0x11632, Stride: 0x1}, + unicode.Range32{Lo: 0x1163b, Hi: 0x1163c, Stride: 0x1}, + unicode.Range32{Lo: 0x1163e, Hi: 0x1163e, Stride: 0x1}, + unicode.Range32{Lo: 0x116ac, Hi: 0x116ac, Stride: 0x1}, + unicode.Range32{Lo: 0x116ae, Hi: 0x116af, Stride: 0x1}, + unicode.Range32{Lo: 0x116b6, Hi: 0x116b6, Stride: 0x1}, + unicode.Range32{Lo: 0x16f51, Hi: 0x16f7e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d166, Hi: 0x1d166, Stride: 0x1}, + unicode.Range32{Lo: 0x1d16d, Hi: 0x1d16d, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeL = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x1100, Hi: 0x115f, Stride: 0x1}, + unicode.Range16{Lo: 0xa960, Hi: 0xa97c, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeLVT = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xac01, Hi: 0xac1b, Stride: 0x1}, + unicode.Range16{Lo: 0xac1d, Hi: 0xac37, Stride: 0x1}, + unicode.Range16{Lo: 0xac39, Hi: 0xac53, Stride: 0x1}, + unicode.Range16{Lo: 0xac55, Hi: 0xac6f, Stride: 0x1}, + unicode.Range16{Lo: 0xac71, Hi: 0xac8b, Stride: 0x1}, + unicode.Range16{Lo: 0xac8d, Hi: 0xaca7, Stride: 0x1}, + unicode.Range16{Lo: 0xaca9, Hi: 0xacc3, Stride: 0x1}, + unicode.Range16{Lo: 0xacc5, Hi: 0xacdf, Stride: 0x1}, + unicode.Range16{Lo: 0xace1, Hi: 0xacfb, Stride: 0x1}, + unicode.Range16{Lo: 0xacfd, Hi: 0xad17, Stride: 0x1}, + unicode.Range16{Lo: 0xad19, Hi: 0xad33, Stride: 0x1}, + unicode.Range16{Lo: 0xad35, Hi: 0xad4f, Stride: 0x1}, + unicode.Range16{Lo: 0xad51, Hi: 0xad6b, Stride: 0x1}, + unicode.Range16{Lo: 0xad6d, Hi: 0xad87, Stride: 0x1}, + unicode.Range16{Lo: 0xad89, Hi: 0xada3, Stride: 0x1}, + unicode.Range16{Lo: 0xada5, Hi: 0xadbf, Stride: 0x1}, + unicode.Range16{Lo: 0xadc1, Hi: 0xaddb, Stride: 0x1}, + unicode.Range16{Lo: 0xaddd, Hi: 0xadf7, Stride: 0x1}, + unicode.Range16{Lo: 0xadf9, Hi: 0xae13, Stride: 0x1}, + unicode.Range16{Lo: 0xae15, Hi: 0xae2f, Stride: 0x1}, + unicode.Range16{Lo: 0xae31, Hi: 0xae4b, Stride: 0x1}, + unicode.Range16{Lo: 0xae4d, Hi: 0xae67, Stride: 0x1}, + unicode.Range16{Lo: 0xae69, Hi: 0xae83, Stride: 0x1}, + unicode.Range16{Lo: 0xae85, Hi: 0xae9f, Stride: 0x1}, + unicode.Range16{Lo: 0xaea1, Hi: 0xaebb, Stride: 0x1}, + unicode.Range16{Lo: 0xaebd, Hi: 0xaed7, Stride: 0x1}, + unicode.Range16{Lo: 0xaed9, Hi: 0xaef3, Stride: 0x1}, + unicode.Range16{Lo: 0xaef5, Hi: 0xaf0f, Stride: 0x1}, + unicode.Range16{Lo: 0xaf11, Hi: 0xaf2b, Stride: 0x1}, + unicode.Range16{Lo: 0xaf2d, Hi: 0xaf47, Stride: 0x1}, + unicode.Range16{Lo: 0xaf49, Hi: 0xaf63, Stride: 0x1}, + unicode.Range16{Lo: 0xaf65, Hi: 0xaf7f, Stride: 0x1}, + unicode.Range16{Lo: 0xaf81, Hi: 0xaf9b, Stride: 0x1}, + unicode.Range16{Lo: 0xaf9d, Hi: 0xafb7, Stride: 0x1}, + unicode.Range16{Lo: 0xafb9, Hi: 0xafd3, Stride: 0x1}, + unicode.Range16{Lo: 0xafd5, Hi: 0xafef, Stride: 0x1}, + unicode.Range16{Lo: 0xaff1, Hi: 0xb00b, Stride: 0x1}, + unicode.Range16{Lo: 0xb00d, Hi: 0xb027, Stride: 0x1}, + unicode.Range16{Lo: 0xb029, Hi: 0xb043, Stride: 0x1}, + unicode.Range16{Lo: 0xb045, Hi: 0xb05f, Stride: 0x1}, + unicode.Range16{Lo: 0xb061, Hi: 0xb07b, Stride: 0x1}, + unicode.Range16{Lo: 0xb07d, Hi: 0xb097, Stride: 0x1}, + unicode.Range16{Lo: 0xb099, Hi: 0xb0b3, Stride: 0x1}, + unicode.Range16{Lo: 0xb0b5, Hi: 0xb0cf, Stride: 0x1}, + unicode.Range16{Lo: 0xb0d1, Hi: 0xb0eb, Stride: 0x1}, + unicode.Range16{Lo: 0xb0ed, Hi: 0xb107, Stride: 0x1}, + unicode.Range16{Lo: 0xb109, Hi: 0xb123, Stride: 0x1}, + unicode.Range16{Lo: 0xb125, Hi: 0xb13f, Stride: 0x1}, + unicode.Range16{Lo: 0xb141, Hi: 0xb15b, Stride: 0x1}, + unicode.Range16{Lo: 0xb15d, Hi: 0xb177, Stride: 0x1}, + unicode.Range16{Lo: 0xb179, Hi: 0xb193, Stride: 0x1}, + unicode.Range16{Lo: 0xb195, Hi: 0xb1af, Stride: 0x1}, + unicode.Range16{Lo: 0xb1b1, Hi: 0xb1cb, Stride: 0x1}, + unicode.Range16{Lo: 0xb1cd, Hi: 0xb1e7, Stride: 0x1}, + unicode.Range16{Lo: 0xb1e9, Hi: 0xb203, Stride: 0x1}, + unicode.Range16{Lo: 0xb205, Hi: 0xb21f, Stride: 0x1}, + unicode.Range16{Lo: 0xb221, Hi: 0xb23b, Stride: 0x1}, + unicode.Range16{Lo: 0xb23d, Hi: 0xb257, Stride: 0x1}, + unicode.Range16{Lo: 0xb259, Hi: 0xb273, Stride: 0x1}, + unicode.Range16{Lo: 0xb275, Hi: 0xb28f, Stride: 0x1}, + unicode.Range16{Lo: 0xb291, Hi: 0xb2ab, Stride: 0x1}, + unicode.Range16{Lo: 0xb2ad, Hi: 0xb2c7, Stride: 0x1}, + unicode.Range16{Lo: 0xb2c9, Hi: 0xb2e3, Stride: 0x1}, + unicode.Range16{Lo: 0xb2e5, Hi: 0xb2ff, Stride: 0x1}, + unicode.Range16{Lo: 0xb301, Hi: 0xb31b, Stride: 0x1}, + unicode.Range16{Lo: 0xb31d, Hi: 0xb337, Stride: 0x1}, + unicode.Range16{Lo: 0xb339, Hi: 0xb353, Stride: 0x1}, + unicode.Range16{Lo: 0xb355, Hi: 0xb36f, Stride: 0x1}, + unicode.Range16{Lo: 0xb371, Hi: 0xb38b, Stride: 0x1}, + unicode.Range16{Lo: 0xb38d, Hi: 0xb3a7, Stride: 0x1}, + unicode.Range16{Lo: 0xb3a9, Hi: 0xb3c3, Stride: 0x1}, + unicode.Range16{Lo: 0xb3c5, Hi: 0xb3df, Stride: 0x1}, + unicode.Range16{Lo: 0xb3e1, Hi: 0xb3fb, Stride: 0x1}, + unicode.Range16{Lo: 0xb3fd, Hi: 0xb417, Stride: 0x1}, + unicode.Range16{Lo: 0xb419, Hi: 0xb433, Stride: 0x1}, + unicode.Range16{Lo: 0xb435, Hi: 0xb44f, Stride: 0x1}, + unicode.Range16{Lo: 0xb451, Hi: 0xb46b, Stride: 0x1}, + unicode.Range16{Lo: 0xb46d, Hi: 0xb487, Stride: 0x1}, + unicode.Range16{Lo: 0xb489, Hi: 0xb4a3, Stride: 0x1}, + unicode.Range16{Lo: 0xb4a5, Hi: 0xb4bf, Stride: 0x1}, + unicode.Range16{Lo: 0xb4c1, Hi: 0xb4db, Stride: 0x1}, + unicode.Range16{Lo: 0xb4dd, Hi: 0xb4f7, Stride: 0x1}, + unicode.Range16{Lo: 0xb4f9, Hi: 0xb513, Stride: 0x1}, + unicode.Range16{Lo: 0xb515, Hi: 0xb52f, Stride: 0x1}, + unicode.Range16{Lo: 0xb531, Hi: 0xb54b, Stride: 0x1}, + unicode.Range16{Lo: 0xb54d, Hi: 0xb567, Stride: 0x1}, + unicode.Range16{Lo: 0xb569, Hi: 0xb583, Stride: 0x1}, + unicode.Range16{Lo: 0xb585, Hi: 0xb59f, Stride: 0x1}, + unicode.Range16{Lo: 0xb5a1, Hi: 0xb5bb, Stride: 0x1}, + unicode.Range16{Lo: 0xb5bd, Hi: 0xb5d7, Stride: 0x1}, + unicode.Range16{Lo: 0xb5d9, Hi: 0xb5f3, Stride: 0x1}, + unicode.Range16{Lo: 0xb5f5, Hi: 0xb60f, Stride: 0x1}, + unicode.Range16{Lo: 0xb611, Hi: 0xb62b, Stride: 0x1}, + unicode.Range16{Lo: 0xb62d, Hi: 0xb647, Stride: 0x1}, + unicode.Range16{Lo: 0xb649, Hi: 0xb663, Stride: 0x1}, + unicode.Range16{Lo: 0xb665, Hi: 0xb67f, Stride: 0x1}, + unicode.Range16{Lo: 0xb681, Hi: 0xb69b, Stride: 0x1}, + unicode.Range16{Lo: 0xb69d, Hi: 0xb6b7, Stride: 0x1}, + unicode.Range16{Lo: 0xb6b9, Hi: 0xb6d3, Stride: 0x1}, + unicode.Range16{Lo: 0xb6d5, Hi: 0xb6ef, Stride: 0x1}, + unicode.Range16{Lo: 0xb6f1, Hi: 0xb70b, Stride: 0x1}, + unicode.Range16{Lo: 0xb70d, Hi: 0xb727, Stride: 0x1}, + unicode.Range16{Lo: 0xb729, Hi: 0xb743, Stride: 0x1}, + unicode.Range16{Lo: 0xb745, Hi: 0xb75f, Stride: 0x1}, + unicode.Range16{Lo: 0xb761, Hi: 0xb77b, Stride: 0x1}, + unicode.Range16{Lo: 0xb77d, Hi: 0xb797, Stride: 0x1}, + unicode.Range16{Lo: 0xb799, Hi: 0xb7b3, Stride: 0x1}, + unicode.Range16{Lo: 0xb7b5, Hi: 0xb7cf, Stride: 0x1}, + unicode.Range16{Lo: 0xb7d1, Hi: 0xb7eb, Stride: 0x1}, + unicode.Range16{Lo: 0xb7ed, Hi: 0xb807, Stride: 0x1}, + unicode.Range16{Lo: 0xb809, Hi: 0xb823, Stride: 0x1}, + unicode.Range16{Lo: 0xb825, Hi: 0xb83f, Stride: 0x1}, + unicode.Range16{Lo: 0xb841, Hi: 0xb85b, Stride: 0x1}, + unicode.Range16{Lo: 0xb85d, Hi: 0xb877, Stride: 0x1}, + unicode.Range16{Lo: 0xb879, Hi: 0xb893, Stride: 0x1}, + unicode.Range16{Lo: 0xb895, Hi: 0xb8af, Stride: 0x1}, + unicode.Range16{Lo: 0xb8b1, Hi: 0xb8cb, Stride: 0x1}, + unicode.Range16{Lo: 0xb8cd, Hi: 0xb8e7, Stride: 0x1}, + unicode.Range16{Lo: 0xb8e9, Hi: 0xb903, Stride: 0x1}, + unicode.Range16{Lo: 0xb905, Hi: 0xb91f, Stride: 0x1}, + unicode.Range16{Lo: 0xb921, Hi: 0xb93b, Stride: 0x1}, + unicode.Range16{Lo: 0xb93d, Hi: 0xb957, Stride: 0x1}, + unicode.Range16{Lo: 0xb959, Hi: 0xb973, Stride: 0x1}, + unicode.Range16{Lo: 0xb975, Hi: 0xb98f, Stride: 0x1}, + unicode.Range16{Lo: 0xb991, Hi: 0xb9ab, Stride: 0x1}, + unicode.Range16{Lo: 0xb9ad, Hi: 0xb9c7, Stride: 0x1}, + unicode.Range16{Lo: 0xb9c9, Hi: 0xb9e3, Stride: 0x1}, + unicode.Range16{Lo: 0xb9e5, Hi: 0xb9ff, Stride: 0x1}, + unicode.Range16{Lo: 0xba01, Hi: 0xba1b, Stride: 0x1}, + unicode.Range16{Lo: 0xba1d, Hi: 0xba37, Stride: 0x1}, + unicode.Range16{Lo: 0xba39, Hi: 0xba53, Stride: 0x1}, + unicode.Range16{Lo: 0xba55, Hi: 0xba6f, Stride: 0x1}, + unicode.Range16{Lo: 0xba71, Hi: 0xba8b, Stride: 0x1}, + unicode.Range16{Lo: 0xba8d, Hi: 0xbaa7, Stride: 0x1}, + unicode.Range16{Lo: 0xbaa9, Hi: 0xbac3, Stride: 0x1}, + unicode.Range16{Lo: 0xbac5, Hi: 0xbadf, Stride: 0x1}, + unicode.Range16{Lo: 0xbae1, Hi: 0xbafb, Stride: 0x1}, + unicode.Range16{Lo: 0xbafd, Hi: 0xbb17, Stride: 0x1}, + unicode.Range16{Lo: 0xbb19, Hi: 0xbb33, Stride: 0x1}, + unicode.Range16{Lo: 0xbb35, Hi: 0xbb4f, Stride: 0x1}, + unicode.Range16{Lo: 0xbb51, Hi: 0xbb6b, Stride: 0x1}, + unicode.Range16{Lo: 0xbb6d, Hi: 0xbb87, Stride: 0x1}, + unicode.Range16{Lo: 0xbb89, Hi: 0xbba3, Stride: 0x1}, + unicode.Range16{Lo: 0xbba5, Hi: 0xbbbf, Stride: 0x1}, + unicode.Range16{Lo: 0xbbc1, Hi: 0xbbdb, Stride: 0x1}, + unicode.Range16{Lo: 0xbbdd, Hi: 0xbbf7, Stride: 0x1}, + unicode.Range16{Lo: 0xbbf9, Hi: 0xbc13, Stride: 0x1}, + unicode.Range16{Lo: 0xbc15, Hi: 0xbc2f, Stride: 0x1}, + unicode.Range16{Lo: 0xbc31, Hi: 0xbc4b, Stride: 0x1}, + unicode.Range16{Lo: 0xbc4d, Hi: 0xbc67, Stride: 0x1}, + unicode.Range16{Lo: 0xbc69, Hi: 0xbc83, Stride: 0x1}, + unicode.Range16{Lo: 0xbc85, Hi: 0xbc9f, Stride: 0x1}, + unicode.Range16{Lo: 0xbca1, Hi: 0xbcbb, Stride: 0x1}, + unicode.Range16{Lo: 0xbcbd, Hi: 0xbcd7, Stride: 0x1}, + unicode.Range16{Lo: 0xbcd9, Hi: 0xbcf3, Stride: 0x1}, + unicode.Range16{Lo: 0xbcf5, Hi: 0xbd0f, Stride: 0x1}, + unicode.Range16{Lo: 0xbd11, Hi: 0xbd2b, Stride: 0x1}, + unicode.Range16{Lo: 0xbd2d, Hi: 0xbd47, Stride: 0x1}, + unicode.Range16{Lo: 0xbd49, Hi: 0xbd63, Stride: 0x1}, + unicode.Range16{Lo: 0xbd65, Hi: 0xbd7f, Stride: 0x1}, + unicode.Range16{Lo: 0xbd81, Hi: 0xbd9b, Stride: 0x1}, + unicode.Range16{Lo: 0xbd9d, Hi: 0xbdb7, Stride: 0x1}, + unicode.Range16{Lo: 0xbdb9, Hi: 0xbdd3, Stride: 0x1}, + unicode.Range16{Lo: 0xbdd5, Hi: 0xbdef, Stride: 0x1}, + unicode.Range16{Lo: 0xbdf1, Hi: 0xbe0b, Stride: 0x1}, + unicode.Range16{Lo: 0xbe0d, Hi: 0xbe27, Stride: 0x1}, + unicode.Range16{Lo: 0xbe29, Hi: 0xbe43, Stride: 0x1}, + unicode.Range16{Lo: 0xbe45, Hi: 0xbe5f, Stride: 0x1}, + unicode.Range16{Lo: 0xbe61, Hi: 0xbe7b, Stride: 0x1}, + unicode.Range16{Lo: 0xbe7d, Hi: 0xbe97, Stride: 0x1}, + unicode.Range16{Lo: 0xbe99, Hi: 0xbeb3, Stride: 0x1}, + unicode.Range16{Lo: 0xbeb5, Hi: 0xbecf, Stride: 0x1}, + unicode.Range16{Lo: 0xbed1, Hi: 0xbeeb, Stride: 0x1}, + unicode.Range16{Lo: 0xbeed, Hi: 0xbf07, Stride: 0x1}, + unicode.Range16{Lo: 0xbf09, Hi: 0xbf23, Stride: 0x1}, + unicode.Range16{Lo: 0xbf25, Hi: 0xbf3f, Stride: 0x1}, + unicode.Range16{Lo: 0xbf41, Hi: 0xbf5b, Stride: 0x1}, + unicode.Range16{Lo: 0xbf5d, Hi: 0xbf77, Stride: 0x1}, + unicode.Range16{Lo: 0xbf79, Hi: 0xbf93, Stride: 0x1}, + unicode.Range16{Lo: 0xbf95, Hi: 0xbfaf, Stride: 0x1}, + unicode.Range16{Lo: 0xbfb1, Hi: 0xbfcb, Stride: 0x1}, + unicode.Range16{Lo: 0xbfcd, Hi: 0xbfe7, Stride: 0x1}, + unicode.Range16{Lo: 0xbfe9, Hi: 0xc003, Stride: 0x1}, + unicode.Range16{Lo: 0xc005, Hi: 0xc01f, Stride: 0x1}, + unicode.Range16{Lo: 0xc021, Hi: 0xc03b, Stride: 0x1}, + unicode.Range16{Lo: 0xc03d, Hi: 0xc057, Stride: 0x1}, + unicode.Range16{Lo: 0xc059, Hi: 0xc073, Stride: 0x1}, + unicode.Range16{Lo: 0xc075, Hi: 0xc08f, Stride: 0x1}, + unicode.Range16{Lo: 0xc091, Hi: 0xc0ab, Stride: 0x1}, + unicode.Range16{Lo: 0xc0ad, Hi: 0xc0c7, Stride: 0x1}, + unicode.Range16{Lo: 0xc0c9, Hi: 0xc0e3, Stride: 0x1}, + unicode.Range16{Lo: 0xc0e5, Hi: 0xc0ff, Stride: 0x1}, + unicode.Range16{Lo: 0xc101, Hi: 0xc11b, Stride: 0x1}, + unicode.Range16{Lo: 0xc11d, Hi: 0xc137, Stride: 0x1}, + unicode.Range16{Lo: 0xc139, Hi: 0xc153, Stride: 0x1}, + unicode.Range16{Lo: 0xc155, Hi: 0xc16f, Stride: 0x1}, + unicode.Range16{Lo: 0xc171, Hi: 0xc18b, Stride: 0x1}, + unicode.Range16{Lo: 0xc18d, Hi: 0xc1a7, Stride: 0x1}, + unicode.Range16{Lo: 0xc1a9, Hi: 0xc1c3, Stride: 0x1}, + unicode.Range16{Lo: 0xc1c5, Hi: 0xc1df, Stride: 0x1}, + unicode.Range16{Lo: 0xc1e1, Hi: 0xc1fb, Stride: 0x1}, + unicode.Range16{Lo: 0xc1fd, Hi: 0xc217, Stride: 0x1}, + unicode.Range16{Lo: 0xc219, Hi: 0xc233, Stride: 0x1}, + unicode.Range16{Lo: 0xc235, Hi: 0xc24f, Stride: 0x1}, + unicode.Range16{Lo: 0xc251, Hi: 0xc26b, Stride: 0x1}, + unicode.Range16{Lo: 0xc26d, Hi: 0xc287, Stride: 0x1}, + unicode.Range16{Lo: 0xc289, Hi: 0xc2a3, Stride: 0x1}, + unicode.Range16{Lo: 0xc2a5, Hi: 0xc2bf, Stride: 0x1}, + unicode.Range16{Lo: 0xc2c1, Hi: 0xc2db, Stride: 0x1}, + unicode.Range16{Lo: 0xc2dd, Hi: 0xc2f7, Stride: 0x1}, + unicode.Range16{Lo: 0xc2f9, Hi: 0xc313, Stride: 0x1}, + unicode.Range16{Lo: 0xc315, Hi: 0xc32f, Stride: 0x1}, + unicode.Range16{Lo: 0xc331, Hi: 0xc34b, Stride: 0x1}, + unicode.Range16{Lo: 0xc34d, Hi: 0xc367, Stride: 0x1}, + unicode.Range16{Lo: 0xc369, Hi: 0xc383, Stride: 0x1}, + unicode.Range16{Lo: 0xc385, Hi: 0xc39f, Stride: 0x1}, + unicode.Range16{Lo: 0xc3a1, Hi: 0xc3bb, Stride: 0x1}, + unicode.Range16{Lo: 0xc3bd, Hi: 0xc3d7, Stride: 0x1}, + unicode.Range16{Lo: 0xc3d9, Hi: 0xc3f3, Stride: 0x1}, + unicode.Range16{Lo: 0xc3f5, Hi: 0xc40f, Stride: 0x1}, + unicode.Range16{Lo: 0xc411, Hi: 0xc42b, Stride: 0x1}, + unicode.Range16{Lo: 0xc42d, Hi: 0xc447, Stride: 0x1}, + unicode.Range16{Lo: 0xc449, Hi: 0xc463, Stride: 0x1}, + unicode.Range16{Lo: 0xc465, Hi: 0xc47f, Stride: 0x1}, + unicode.Range16{Lo: 0xc481, Hi: 0xc49b, Stride: 0x1}, + unicode.Range16{Lo: 0xc49d, Hi: 0xc4b7, Stride: 0x1}, + unicode.Range16{Lo: 0xc4b9, Hi: 0xc4d3, Stride: 0x1}, + unicode.Range16{Lo: 0xc4d5, Hi: 0xc4ef, Stride: 0x1}, + unicode.Range16{Lo: 0xc4f1, Hi: 0xc50b, Stride: 0x1}, + unicode.Range16{Lo: 0xc50d, Hi: 0xc527, Stride: 0x1}, + unicode.Range16{Lo: 0xc529, Hi: 0xc543, Stride: 0x1}, + unicode.Range16{Lo: 0xc545, Hi: 0xc55f, Stride: 0x1}, + unicode.Range16{Lo: 0xc561, Hi: 0xc57b, Stride: 0x1}, + unicode.Range16{Lo: 0xc57d, Hi: 0xc597, Stride: 0x1}, + unicode.Range16{Lo: 0xc599, Hi: 0xc5b3, Stride: 0x1}, + unicode.Range16{Lo: 0xc5b5, Hi: 0xc5cf, Stride: 0x1}, + unicode.Range16{Lo: 0xc5d1, Hi: 0xc5eb, Stride: 0x1}, + unicode.Range16{Lo: 0xc5ed, Hi: 0xc607, Stride: 0x1}, + unicode.Range16{Lo: 0xc609, Hi: 0xc623, Stride: 0x1}, + unicode.Range16{Lo: 0xc625, Hi: 0xc63f, Stride: 0x1}, + unicode.Range16{Lo: 0xc641, Hi: 0xc65b, Stride: 0x1}, + unicode.Range16{Lo: 0xc65d, Hi: 0xc677, Stride: 0x1}, + unicode.Range16{Lo: 0xc679, Hi: 0xc693, Stride: 0x1}, + unicode.Range16{Lo: 0xc695, Hi: 0xc6af, Stride: 0x1}, + unicode.Range16{Lo: 0xc6b1, Hi: 0xc6cb, Stride: 0x1}, + unicode.Range16{Lo: 0xc6cd, Hi: 0xc6e7, Stride: 0x1}, + unicode.Range16{Lo: 0xc6e9, Hi: 0xc703, Stride: 0x1}, + unicode.Range16{Lo: 0xc705, Hi: 0xc71f, Stride: 0x1}, + unicode.Range16{Lo: 0xc721, Hi: 0xc73b, Stride: 0x1}, + unicode.Range16{Lo: 0xc73d, Hi: 0xc757, Stride: 0x1}, + unicode.Range16{Lo: 0xc759, Hi: 0xc773, Stride: 0x1}, + unicode.Range16{Lo: 0xc775, Hi: 0xc78f, Stride: 0x1}, + unicode.Range16{Lo: 0xc791, Hi: 0xc7ab, Stride: 0x1}, + unicode.Range16{Lo: 0xc7ad, Hi: 0xc7c7, Stride: 0x1}, + unicode.Range16{Lo: 0xc7c9, Hi: 0xc7e3, Stride: 0x1}, + unicode.Range16{Lo: 0xc7e5, Hi: 0xc7ff, Stride: 0x1}, + unicode.Range16{Lo: 0xc801, Hi: 0xc81b, Stride: 0x1}, + unicode.Range16{Lo: 0xc81d, Hi: 0xc837, Stride: 0x1}, + unicode.Range16{Lo: 0xc839, Hi: 0xc853, Stride: 0x1}, + unicode.Range16{Lo: 0xc855, Hi: 0xc86f, Stride: 0x1}, + unicode.Range16{Lo: 0xc871, Hi: 0xc88b, Stride: 0x1}, + unicode.Range16{Lo: 0xc88d, Hi: 0xc8a7, Stride: 0x1}, + unicode.Range16{Lo: 0xc8a9, Hi: 0xc8c3, Stride: 0x1}, + unicode.Range16{Lo: 0xc8c5, Hi: 0xc8df, Stride: 0x1}, + unicode.Range16{Lo: 0xc8e1, Hi: 0xc8fb, Stride: 0x1}, + unicode.Range16{Lo: 0xc8fd, Hi: 0xc917, Stride: 0x1}, + unicode.Range16{Lo: 0xc919, Hi: 0xc933, Stride: 0x1}, + unicode.Range16{Lo: 0xc935, Hi: 0xc94f, Stride: 0x1}, + unicode.Range16{Lo: 0xc951, Hi: 0xc96b, Stride: 0x1}, + unicode.Range16{Lo: 0xc96d, Hi: 0xc987, Stride: 0x1}, + unicode.Range16{Lo: 0xc989, Hi: 0xc9a3, Stride: 0x1}, + unicode.Range16{Lo: 0xc9a5, Hi: 0xc9bf, Stride: 0x1}, + unicode.Range16{Lo: 0xc9c1, Hi: 0xc9db, Stride: 0x1}, + unicode.Range16{Lo: 0xc9dd, Hi: 0xc9f7, Stride: 0x1}, + unicode.Range16{Lo: 0xc9f9, Hi: 0xca13, Stride: 0x1}, + unicode.Range16{Lo: 0xca15, Hi: 0xca2f, Stride: 0x1}, + unicode.Range16{Lo: 0xca31, Hi: 0xca4b, Stride: 0x1}, + unicode.Range16{Lo: 0xca4d, Hi: 0xca67, Stride: 0x1}, + unicode.Range16{Lo: 0xca69, Hi: 0xca83, Stride: 0x1}, + unicode.Range16{Lo: 0xca85, Hi: 0xca9f, Stride: 0x1}, + unicode.Range16{Lo: 0xcaa1, Hi: 0xcabb, Stride: 0x1}, + unicode.Range16{Lo: 0xcabd, Hi: 0xcad7, Stride: 0x1}, + unicode.Range16{Lo: 0xcad9, Hi: 0xcaf3, Stride: 0x1}, + unicode.Range16{Lo: 0xcaf5, Hi: 0xcb0f, Stride: 0x1}, + unicode.Range16{Lo: 0xcb11, Hi: 0xcb2b, Stride: 0x1}, + unicode.Range16{Lo: 0xcb2d, Hi: 0xcb47, Stride: 0x1}, + unicode.Range16{Lo: 0xcb49, Hi: 0xcb63, Stride: 0x1}, + unicode.Range16{Lo: 0xcb65, Hi: 0xcb7f, Stride: 0x1}, + unicode.Range16{Lo: 0xcb81, Hi: 0xcb9b, Stride: 0x1}, + unicode.Range16{Lo: 0xcb9d, Hi: 0xcbb7, Stride: 0x1}, + unicode.Range16{Lo: 0xcbb9, Hi: 0xcbd3, Stride: 0x1}, + unicode.Range16{Lo: 0xcbd5, Hi: 0xcbef, Stride: 0x1}, + unicode.Range16{Lo: 0xcbf1, Hi: 0xcc0b, Stride: 0x1}, + unicode.Range16{Lo: 0xcc0d, Hi: 0xcc27, Stride: 0x1}, + unicode.Range16{Lo: 0xcc29, Hi: 0xcc43, Stride: 0x1}, + unicode.Range16{Lo: 0xcc45, Hi: 0xcc5f, Stride: 0x1}, + unicode.Range16{Lo: 0xcc61, Hi: 0xcc7b, Stride: 0x1}, + unicode.Range16{Lo: 0xcc7d, Hi: 0xcc97, Stride: 0x1}, + unicode.Range16{Lo: 0xcc99, Hi: 0xccb3, Stride: 0x1}, + unicode.Range16{Lo: 0xccb5, Hi: 0xcccf, Stride: 0x1}, + unicode.Range16{Lo: 0xccd1, Hi: 0xcceb, Stride: 0x1}, + unicode.Range16{Lo: 0xcced, Hi: 0xcd07, Stride: 0x1}, + unicode.Range16{Lo: 0xcd09, Hi: 0xcd23, Stride: 0x1}, + unicode.Range16{Lo: 0xcd25, Hi: 0xcd3f, Stride: 0x1}, + unicode.Range16{Lo: 0xcd41, Hi: 0xcd5b, Stride: 0x1}, + unicode.Range16{Lo: 0xcd5d, Hi: 0xcd77, Stride: 0x1}, + unicode.Range16{Lo: 0xcd79, Hi: 0xcd93, Stride: 0x1}, + unicode.Range16{Lo: 0xcd95, Hi: 0xcdaf, Stride: 0x1}, + unicode.Range16{Lo: 0xcdb1, Hi: 0xcdcb, Stride: 0x1}, + unicode.Range16{Lo: 0xcdcd, Hi: 0xcde7, Stride: 0x1}, + unicode.Range16{Lo: 0xcde9, Hi: 0xce03, Stride: 0x1}, + unicode.Range16{Lo: 0xce05, Hi: 0xce1f, Stride: 0x1}, + unicode.Range16{Lo: 0xce21, Hi: 0xce3b, Stride: 0x1}, + unicode.Range16{Lo: 0xce3d, Hi: 0xce57, Stride: 0x1}, + unicode.Range16{Lo: 0xce59, Hi: 0xce73, Stride: 0x1}, + unicode.Range16{Lo: 0xce75, Hi: 0xce8f, Stride: 0x1}, + unicode.Range16{Lo: 0xce91, Hi: 0xceab, Stride: 0x1}, + unicode.Range16{Lo: 0xcead, Hi: 0xcec7, Stride: 0x1}, + unicode.Range16{Lo: 0xcec9, Hi: 0xcee3, Stride: 0x1}, + unicode.Range16{Lo: 0xcee5, Hi: 0xceff, Stride: 0x1}, + unicode.Range16{Lo: 0xcf01, Hi: 0xcf1b, Stride: 0x1}, + unicode.Range16{Lo: 0xcf1d, Hi: 0xcf37, Stride: 0x1}, + unicode.Range16{Lo: 0xcf39, Hi: 0xcf53, Stride: 0x1}, + unicode.Range16{Lo: 0xcf55, Hi: 0xcf6f, Stride: 0x1}, + unicode.Range16{Lo: 0xcf71, Hi: 0xcf8b, Stride: 0x1}, + unicode.Range16{Lo: 0xcf8d, Hi: 0xcfa7, Stride: 0x1}, + unicode.Range16{Lo: 0xcfa9, Hi: 0xcfc3, Stride: 0x1}, + unicode.Range16{Lo: 0xcfc5, Hi: 0xcfdf, Stride: 0x1}, + unicode.Range16{Lo: 0xcfe1, Hi: 0xcffb, Stride: 0x1}, + unicode.Range16{Lo: 0xcffd, Hi: 0xd017, Stride: 0x1}, + unicode.Range16{Lo: 0xd019, Hi: 0xd033, Stride: 0x1}, + unicode.Range16{Lo: 0xd035, Hi: 0xd04f, Stride: 0x1}, + unicode.Range16{Lo: 0xd051, Hi: 0xd06b, Stride: 0x1}, + unicode.Range16{Lo: 0xd06d, Hi: 0xd087, Stride: 0x1}, + unicode.Range16{Lo: 0xd089, Hi: 0xd0a3, Stride: 0x1}, + unicode.Range16{Lo: 0xd0a5, Hi: 0xd0bf, Stride: 0x1}, + unicode.Range16{Lo: 0xd0c1, Hi: 0xd0db, Stride: 0x1}, + unicode.Range16{Lo: 0xd0dd, Hi: 0xd0f7, Stride: 0x1}, + unicode.Range16{Lo: 0xd0f9, Hi: 0xd113, Stride: 0x1}, + unicode.Range16{Lo: 0xd115, Hi: 0xd12f, Stride: 0x1}, + unicode.Range16{Lo: 0xd131, Hi: 0xd14b, Stride: 0x1}, + unicode.Range16{Lo: 0xd14d, Hi: 0xd167, Stride: 0x1}, + unicode.Range16{Lo: 0xd169, Hi: 0xd183, Stride: 0x1}, + unicode.Range16{Lo: 0xd185, Hi: 0xd19f, Stride: 0x1}, + unicode.Range16{Lo: 0xd1a1, Hi: 0xd1bb, Stride: 0x1}, + unicode.Range16{Lo: 0xd1bd, Hi: 0xd1d7, Stride: 0x1}, + unicode.Range16{Lo: 0xd1d9, Hi: 0xd1f3, Stride: 0x1}, + unicode.Range16{Lo: 0xd1f5, Hi: 0xd20f, Stride: 0x1}, + unicode.Range16{Lo: 0xd211, Hi: 0xd22b, Stride: 0x1}, + unicode.Range16{Lo: 0xd22d, Hi: 0xd247, Stride: 0x1}, + unicode.Range16{Lo: 0xd249, Hi: 0xd263, Stride: 0x1}, + unicode.Range16{Lo: 0xd265, Hi: 0xd27f, Stride: 0x1}, + unicode.Range16{Lo: 0xd281, Hi: 0xd29b, Stride: 0x1}, + unicode.Range16{Lo: 0xd29d, Hi: 0xd2b7, Stride: 0x1}, + unicode.Range16{Lo: 0xd2b9, Hi: 0xd2d3, Stride: 0x1}, + unicode.Range16{Lo: 0xd2d5, Hi: 0xd2ef, Stride: 0x1}, + unicode.Range16{Lo: 0xd2f1, Hi: 0xd30b, Stride: 0x1}, + unicode.Range16{Lo: 0xd30d, Hi: 0xd327, Stride: 0x1}, + unicode.Range16{Lo: 0xd329, Hi: 0xd343, Stride: 0x1}, + unicode.Range16{Lo: 0xd345, Hi: 0xd35f, Stride: 0x1}, + unicode.Range16{Lo: 0xd361, Hi: 0xd37b, Stride: 0x1}, + unicode.Range16{Lo: 0xd37d, Hi: 0xd397, Stride: 0x1}, + unicode.Range16{Lo: 0xd399, Hi: 0xd3b3, Stride: 0x1}, + unicode.Range16{Lo: 0xd3b5, Hi: 0xd3cf, Stride: 0x1}, + unicode.Range16{Lo: 0xd3d1, Hi: 0xd3eb, Stride: 0x1}, + unicode.Range16{Lo: 0xd3ed, Hi: 0xd407, Stride: 0x1}, + unicode.Range16{Lo: 0xd409, Hi: 0xd423, Stride: 0x1}, + unicode.Range16{Lo: 0xd425, Hi: 0xd43f, Stride: 0x1}, + unicode.Range16{Lo: 0xd441, Hi: 0xd45b, Stride: 0x1}, + unicode.Range16{Lo: 0xd45d, Hi: 0xd477, Stride: 0x1}, + unicode.Range16{Lo: 0xd479, Hi: 0xd493, Stride: 0x1}, + unicode.Range16{Lo: 0xd495, Hi: 0xd4af, Stride: 0x1}, + unicode.Range16{Lo: 0xd4b1, Hi: 0xd4cb, Stride: 0x1}, + unicode.Range16{Lo: 0xd4cd, Hi: 0xd4e7, Stride: 0x1}, + unicode.Range16{Lo: 0xd4e9, Hi: 0xd503, Stride: 0x1}, + unicode.Range16{Lo: 0xd505, Hi: 0xd51f, Stride: 0x1}, + unicode.Range16{Lo: 0xd521, Hi: 0xd53b, Stride: 0x1}, + unicode.Range16{Lo: 0xd53d, Hi: 0xd557, Stride: 0x1}, + unicode.Range16{Lo: 0xd559, Hi: 0xd573, Stride: 0x1}, + unicode.Range16{Lo: 0xd575, Hi: 0xd58f, Stride: 0x1}, + unicode.Range16{Lo: 0xd591, Hi: 0xd5ab, Stride: 0x1}, + unicode.Range16{Lo: 0xd5ad, Hi: 0xd5c7, Stride: 0x1}, + unicode.Range16{Lo: 0xd5c9, Hi: 0xd5e3, Stride: 0x1}, + unicode.Range16{Lo: 0xd5e5, Hi: 0xd5ff, Stride: 0x1}, + unicode.Range16{Lo: 0xd601, Hi: 0xd61b, Stride: 0x1}, + unicode.Range16{Lo: 0xd61d, Hi: 0xd637, Stride: 0x1}, + unicode.Range16{Lo: 0xd639, Hi: 0xd653, Stride: 0x1}, + unicode.Range16{Lo: 0xd655, Hi: 0xd66f, Stride: 0x1}, + unicode.Range16{Lo: 0xd671, Hi: 0xd68b, Stride: 0x1}, + unicode.Range16{Lo: 0xd68d, Hi: 0xd6a7, Stride: 0x1}, + unicode.Range16{Lo: 0xd6a9, Hi: 0xd6c3, Stride: 0x1}, + unicode.Range16{Lo: 0xd6c5, Hi: 0xd6df, Stride: 0x1}, + unicode.Range16{Lo: 0xd6e1, Hi: 0xd6fb, Stride: 0x1}, + unicode.Range16{Lo: 0xd6fd, Hi: 0xd717, Stride: 0x1}, + unicode.Range16{Lo: 0xd719, Hi: 0xd733, Stride: 0x1}, + unicode.Range16{Lo: 0xd735, Hi: 0xd74f, Stride: 0x1}, + unicode.Range16{Lo: 0xd751, Hi: 0xd76b, Stride: 0x1}, + unicode.Range16{Lo: 0xd76d, Hi: 0xd787, Stride: 0x1}, + unicode.Range16{Lo: 0xd789, Hi: 0xd7a3, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeLF = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xa, Hi: 0xa, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _GraphemeExtend = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x300, Hi: 0x36f, Stride: 0x1}, + unicode.Range16{Lo: 0x483, Hi: 0x487, Stride: 0x1}, + unicode.Range16{Lo: 0x488, Hi: 0x489, Stride: 0x1}, + unicode.Range16{Lo: 0x591, Hi: 0x5bd, Stride: 0x1}, + unicode.Range16{Lo: 0x5bf, Hi: 0x5bf, Stride: 0x1}, + unicode.Range16{Lo: 0x5c1, Hi: 0x5c2, Stride: 0x1}, + unicode.Range16{Lo: 0x5c4, Hi: 0x5c5, Stride: 0x1}, + unicode.Range16{Lo: 0x5c7, Hi: 0x5c7, Stride: 0x1}, + unicode.Range16{Lo: 0x610, Hi: 0x61a, Stride: 0x1}, + unicode.Range16{Lo: 0x64b, Hi: 0x65f, Stride: 0x1}, + unicode.Range16{Lo: 0x670, Hi: 0x670, Stride: 0x1}, + unicode.Range16{Lo: 0x6d6, Hi: 0x6dc, Stride: 0x1}, + unicode.Range16{Lo: 0x6df, Hi: 0x6e4, Stride: 0x1}, + unicode.Range16{Lo: 0x6e7, Hi: 0x6e8, Stride: 0x1}, + unicode.Range16{Lo: 0x6ea, Hi: 0x6ed, Stride: 0x1}, + unicode.Range16{Lo: 0x711, Hi: 0x711, Stride: 0x1}, + unicode.Range16{Lo: 0x730, Hi: 0x74a, Stride: 0x1}, + unicode.Range16{Lo: 0x7a6, Hi: 0x7b0, Stride: 0x1}, + unicode.Range16{Lo: 0x7eb, Hi: 0x7f3, Stride: 0x1}, + unicode.Range16{Lo: 0x816, Hi: 0x819, Stride: 0x1}, + unicode.Range16{Lo: 0x81b, Hi: 0x823, Stride: 0x1}, + unicode.Range16{Lo: 0x825, Hi: 0x827, Stride: 0x1}, + unicode.Range16{Lo: 0x829, Hi: 0x82d, Stride: 0x1}, + unicode.Range16{Lo: 0x859, Hi: 0x85b, Stride: 0x1}, + unicode.Range16{Lo: 0x8e4, Hi: 0x902, Stride: 0x1}, + unicode.Range16{Lo: 0x93a, Hi: 0x93a, Stride: 0x1}, + unicode.Range16{Lo: 0x93c, Hi: 0x93c, Stride: 0x1}, + unicode.Range16{Lo: 0x941, Hi: 0x948, Stride: 0x1}, + unicode.Range16{Lo: 0x94d, Hi: 0x94d, Stride: 0x1}, + unicode.Range16{Lo: 0x951, Hi: 0x957, Stride: 0x1}, + unicode.Range16{Lo: 0x962, Hi: 0x963, Stride: 0x1}, + unicode.Range16{Lo: 0x981, Hi: 0x981, Stride: 0x1}, + unicode.Range16{Lo: 0x9bc, Hi: 0x9bc, Stride: 0x1}, + unicode.Range16{Lo: 0x9be, Hi: 0x9be, Stride: 0x1}, + unicode.Range16{Lo: 0x9c1, Hi: 0x9c4, Stride: 0x1}, + unicode.Range16{Lo: 0x9cd, Hi: 0x9cd, Stride: 0x1}, + unicode.Range16{Lo: 0x9d7, Hi: 0x9d7, Stride: 0x1}, + unicode.Range16{Lo: 0x9e2, Hi: 0x9e3, Stride: 0x1}, + unicode.Range16{Lo: 0xa01, Hi: 0xa02, Stride: 0x1}, + unicode.Range16{Lo: 0xa3c, Hi: 0xa3c, Stride: 0x1}, + unicode.Range16{Lo: 0xa41, Hi: 0xa42, Stride: 0x1}, + unicode.Range16{Lo: 0xa47, Hi: 0xa48, Stride: 0x1}, + unicode.Range16{Lo: 0xa4b, Hi: 0xa4d, Stride: 0x1}, + unicode.Range16{Lo: 0xa51, Hi: 0xa51, Stride: 0x1}, + unicode.Range16{Lo: 0xa70, Hi: 0xa71, Stride: 0x1}, + unicode.Range16{Lo: 0xa75, Hi: 0xa75, Stride: 0x1}, + unicode.Range16{Lo: 0xa81, Hi: 0xa82, Stride: 0x1}, + unicode.Range16{Lo: 0xabc, Hi: 0xabc, Stride: 0x1}, + unicode.Range16{Lo: 0xac1, Hi: 0xac5, Stride: 0x1}, + unicode.Range16{Lo: 0xac7, Hi: 0xac8, Stride: 0x1}, + unicode.Range16{Lo: 0xacd, Hi: 0xacd, Stride: 0x1}, + unicode.Range16{Lo: 0xae2, Hi: 0xae3, Stride: 0x1}, + unicode.Range16{Lo: 0xb01, Hi: 0xb01, Stride: 0x1}, + unicode.Range16{Lo: 0xb3c, Hi: 0xb3c, Stride: 0x1}, + unicode.Range16{Lo: 0xb3e, Hi: 0xb3e, Stride: 0x1}, + unicode.Range16{Lo: 0xb3f, Hi: 0xb3f, Stride: 0x1}, + unicode.Range16{Lo: 0xb41, Hi: 0xb44, Stride: 0x1}, + unicode.Range16{Lo: 0xb4d, Hi: 0xb4d, Stride: 0x1}, + unicode.Range16{Lo: 0xb56, Hi: 0xb56, Stride: 0x1}, + unicode.Range16{Lo: 0xb57, Hi: 0xb57, Stride: 0x1}, + unicode.Range16{Lo: 0xb62, Hi: 0xb63, Stride: 0x1}, + unicode.Range16{Lo: 0xb82, Hi: 0xb82, Stride: 0x1}, + unicode.Range16{Lo: 0xbbe, Hi: 0xbbe, Stride: 0x1}, + unicode.Range16{Lo: 0xbc0, Hi: 0xbc0, Stride: 0x1}, + unicode.Range16{Lo: 0xbcd, Hi: 0xbcd, Stride: 0x1}, + unicode.Range16{Lo: 0xbd7, Hi: 0xbd7, Stride: 0x1}, + unicode.Range16{Lo: 0xc00, Hi: 0xc00, Stride: 0x1}, + unicode.Range16{Lo: 0xc3e, Hi: 0xc40, Stride: 0x1}, + unicode.Range16{Lo: 0xc46, Hi: 0xc48, Stride: 0x1}, + unicode.Range16{Lo: 0xc4a, Hi: 0xc4d, Stride: 0x1}, + unicode.Range16{Lo: 0xc55, Hi: 0xc56, Stride: 0x1}, + unicode.Range16{Lo: 0xc62, Hi: 0xc63, Stride: 0x1}, + unicode.Range16{Lo: 0xc81, Hi: 0xc81, Stride: 0x1}, + unicode.Range16{Lo: 0xcbc, Hi: 0xcbc, Stride: 0x1}, + unicode.Range16{Lo: 0xcbf, Hi: 0xcbf, Stride: 0x1}, + unicode.Range16{Lo: 0xcc2, Hi: 0xcc2, Stride: 0x1}, + unicode.Range16{Lo: 0xcc6, Hi: 0xcc6, Stride: 0x1}, + unicode.Range16{Lo: 0xccc, Hi: 0xccd, Stride: 0x1}, + unicode.Range16{Lo: 0xcd5, Hi: 0xcd6, Stride: 0x1}, + unicode.Range16{Lo: 0xce2, Hi: 0xce3, Stride: 0x1}, + unicode.Range16{Lo: 0xd01, Hi: 0xd01, Stride: 0x1}, + unicode.Range16{Lo: 0xd3e, Hi: 0xd3e, Stride: 0x1}, + unicode.Range16{Lo: 0xd41, Hi: 0xd44, Stride: 0x1}, + unicode.Range16{Lo: 0xd4d, Hi: 0xd4d, Stride: 0x1}, + unicode.Range16{Lo: 0xd57, Hi: 0xd57, Stride: 0x1}, + unicode.Range16{Lo: 0xd62, Hi: 0xd63, Stride: 0x1}, + unicode.Range16{Lo: 0xdca, Hi: 0xdca, Stride: 0x1}, + unicode.Range16{Lo: 0xdcf, Hi: 0xdcf, Stride: 0x1}, + unicode.Range16{Lo: 0xdd2, Hi: 0xdd4, Stride: 0x1}, + unicode.Range16{Lo: 0xdd6, Hi: 0xdd6, Stride: 0x1}, + unicode.Range16{Lo: 0xddf, Hi: 0xddf, Stride: 0x1}, + unicode.Range16{Lo: 0xe31, Hi: 0xe31, Stride: 0x1}, + unicode.Range16{Lo: 0xe34, Hi: 0xe3a, Stride: 0x1}, + unicode.Range16{Lo: 0xe47, Hi: 0xe4e, Stride: 0x1}, + unicode.Range16{Lo: 0xeb1, Hi: 0xeb1, Stride: 0x1}, + unicode.Range16{Lo: 0xeb4, Hi: 0xeb9, Stride: 0x1}, + unicode.Range16{Lo: 0xebb, Hi: 0xebc, Stride: 0x1}, + unicode.Range16{Lo: 0xec8, Hi: 0xecd, Stride: 0x1}, + unicode.Range16{Lo: 0xf18, Hi: 0xf19, Stride: 0x1}, + unicode.Range16{Lo: 0xf35, Hi: 0xf35, Stride: 0x1}, + unicode.Range16{Lo: 0xf37, Hi: 0xf37, Stride: 0x1}, + unicode.Range16{Lo: 0xf39, Hi: 0xf39, Stride: 0x1}, + unicode.Range16{Lo: 0xf71, Hi: 0xf7e, Stride: 0x1}, + unicode.Range16{Lo: 0xf80, Hi: 0xf84, Stride: 0x1}, + unicode.Range16{Lo: 0xf86, Hi: 0xf87, Stride: 0x1}, + unicode.Range16{Lo: 0xf8d, Hi: 0xf97, Stride: 0x1}, + unicode.Range16{Lo: 0xf99, Hi: 0xfbc, Stride: 0x1}, + unicode.Range16{Lo: 0xfc6, Hi: 0xfc6, Stride: 0x1}, + unicode.Range16{Lo: 0x102d, Hi: 0x1030, Stride: 0x1}, + unicode.Range16{Lo: 0x1032, Hi: 0x1037, Stride: 0x1}, + unicode.Range16{Lo: 0x1039, Hi: 0x103a, Stride: 0x1}, + unicode.Range16{Lo: 0x103d, Hi: 0x103e, Stride: 0x1}, + unicode.Range16{Lo: 0x1058, Hi: 0x1059, Stride: 0x1}, + unicode.Range16{Lo: 0x105e, Hi: 0x1060, Stride: 0x1}, + unicode.Range16{Lo: 0x1071, Hi: 0x1074, Stride: 0x1}, + unicode.Range16{Lo: 0x1082, Hi: 0x1082, Stride: 0x1}, + unicode.Range16{Lo: 0x1085, Hi: 0x1086, Stride: 0x1}, + unicode.Range16{Lo: 0x108d, Hi: 0x108d, Stride: 0x1}, + unicode.Range16{Lo: 0x109d, Hi: 0x109d, Stride: 0x1}, + unicode.Range16{Lo: 0x135d, Hi: 0x135f, Stride: 0x1}, + unicode.Range16{Lo: 0x1712, Hi: 0x1714, Stride: 0x1}, + unicode.Range16{Lo: 0x1732, Hi: 0x1734, Stride: 0x1}, + unicode.Range16{Lo: 0x1752, Hi: 0x1753, Stride: 0x1}, + unicode.Range16{Lo: 0x1772, Hi: 0x1773, Stride: 0x1}, + unicode.Range16{Lo: 0x17b4, Hi: 0x17b5, Stride: 0x1}, + unicode.Range16{Lo: 0x17b7, Hi: 0x17bd, Stride: 0x1}, + unicode.Range16{Lo: 0x17c6, Hi: 0x17c6, Stride: 0x1}, + unicode.Range16{Lo: 0x17c9, Hi: 0x17d3, Stride: 0x1}, + unicode.Range16{Lo: 0x17dd, Hi: 0x17dd, Stride: 0x1}, + unicode.Range16{Lo: 0x180b, Hi: 0x180d, Stride: 0x1}, + unicode.Range16{Lo: 0x18a9, Hi: 0x18a9, Stride: 0x1}, + unicode.Range16{Lo: 0x1920, Hi: 0x1922, Stride: 0x1}, + unicode.Range16{Lo: 0x1927, Hi: 0x1928, Stride: 0x1}, + unicode.Range16{Lo: 0x1932, Hi: 0x1932, Stride: 0x1}, + unicode.Range16{Lo: 0x1939, Hi: 0x193b, Stride: 0x1}, + unicode.Range16{Lo: 0x1a17, Hi: 0x1a18, Stride: 0x1}, + unicode.Range16{Lo: 0x1a1b, Hi: 0x1a1b, Stride: 0x1}, + unicode.Range16{Lo: 0x1a56, Hi: 0x1a56, Stride: 0x1}, + unicode.Range16{Lo: 0x1a58, Hi: 0x1a5e, Stride: 0x1}, + unicode.Range16{Lo: 0x1a60, Hi: 0x1a60, Stride: 0x1}, + unicode.Range16{Lo: 0x1a62, Hi: 0x1a62, Stride: 0x1}, + unicode.Range16{Lo: 0x1a65, Hi: 0x1a6c, Stride: 0x1}, + unicode.Range16{Lo: 0x1a73, Hi: 0x1a7c, Stride: 0x1}, + unicode.Range16{Lo: 0x1a7f, Hi: 0x1a7f, Stride: 0x1}, + unicode.Range16{Lo: 0x1ab0, Hi: 0x1abd, Stride: 0x1}, + unicode.Range16{Lo: 0x1abe, Hi: 0x1abe, Stride: 0x1}, + unicode.Range16{Lo: 0x1b00, Hi: 0x1b03, Stride: 0x1}, + unicode.Range16{Lo: 0x1b34, Hi: 0x1b34, Stride: 0x1}, + unicode.Range16{Lo: 0x1b36, Hi: 0x1b3a, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3c, Hi: 0x1b3c, Stride: 0x1}, + unicode.Range16{Lo: 0x1b42, Hi: 0x1b42, Stride: 0x1}, + unicode.Range16{Lo: 0x1b6b, Hi: 0x1b73, Stride: 0x1}, + unicode.Range16{Lo: 0x1b80, Hi: 0x1b81, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba2, Hi: 0x1ba5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba8, Hi: 0x1ba9, Stride: 0x1}, + unicode.Range16{Lo: 0x1bab, Hi: 0x1bad, Stride: 0x1}, + unicode.Range16{Lo: 0x1be6, Hi: 0x1be6, Stride: 0x1}, + unicode.Range16{Lo: 0x1be8, Hi: 0x1be9, Stride: 0x1}, + unicode.Range16{Lo: 0x1bed, Hi: 0x1bed, Stride: 0x1}, + unicode.Range16{Lo: 0x1bef, Hi: 0x1bf1, Stride: 0x1}, + unicode.Range16{Lo: 0x1c2c, Hi: 0x1c33, Stride: 0x1}, + unicode.Range16{Lo: 0x1c36, Hi: 0x1c37, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd0, Hi: 0x1cd2, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd4, Hi: 0x1ce0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce2, Hi: 0x1ce8, Stride: 0x1}, + unicode.Range16{Lo: 0x1ced, Hi: 0x1ced, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf4, Hi: 0x1cf4, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf8, Hi: 0x1cf9, Stride: 0x1}, + unicode.Range16{Lo: 0x1dc0, Hi: 0x1df5, Stride: 0x1}, + unicode.Range16{Lo: 0x1dfc, Hi: 0x1dff, Stride: 0x1}, + unicode.Range16{Lo: 0x200c, Hi: 0x200d, Stride: 0x1}, + unicode.Range16{Lo: 0x20d0, Hi: 0x20dc, Stride: 0x1}, + unicode.Range16{Lo: 0x20dd, Hi: 0x20e0, Stride: 0x1}, + unicode.Range16{Lo: 0x20e1, Hi: 0x20e1, Stride: 0x1}, + unicode.Range16{Lo: 0x20e2, Hi: 0x20e4, Stride: 0x1}, + unicode.Range16{Lo: 0x20e5, Hi: 0x20f0, Stride: 0x1}, + unicode.Range16{Lo: 0x2cef, Hi: 0x2cf1, Stride: 0x1}, + unicode.Range16{Lo: 0x2d7f, Hi: 0x2d7f, Stride: 0x1}, + unicode.Range16{Lo: 0x2de0, Hi: 0x2dff, Stride: 0x1}, + unicode.Range16{Lo: 0x302a, Hi: 0x302d, Stride: 0x1}, + unicode.Range16{Lo: 0x302e, Hi: 0x302f, Stride: 0x1}, + unicode.Range16{Lo: 0x3099, Hi: 0x309a, Stride: 0x1}, + unicode.Range16{Lo: 0xa66f, Hi: 0xa66f, Stride: 0x1}, + unicode.Range16{Lo: 0xa670, Hi: 0xa672, Stride: 0x1}, + unicode.Range16{Lo: 0xa674, Hi: 0xa67d, Stride: 0x1}, + unicode.Range16{Lo: 0xa69f, Hi: 0xa69f, Stride: 0x1}, + unicode.Range16{Lo: 0xa6f0, Hi: 0xa6f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa802, Hi: 0xa802, Stride: 0x1}, + unicode.Range16{Lo: 0xa806, Hi: 0xa806, Stride: 0x1}, + unicode.Range16{Lo: 0xa80b, Hi: 0xa80b, Stride: 0x1}, + unicode.Range16{Lo: 0xa825, Hi: 0xa826, Stride: 0x1}, + unicode.Range16{Lo: 0xa8c4, Hi: 0xa8c4, Stride: 0x1}, + unicode.Range16{Lo: 0xa8e0, Hi: 0xa8f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa926, Hi: 0xa92d, Stride: 0x1}, + unicode.Range16{Lo: 0xa947, Hi: 0xa951, Stride: 0x1}, + unicode.Range16{Lo: 0xa980, Hi: 0xa982, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b3, Hi: 0xa9b3, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b6, Hi: 0xa9b9, Stride: 0x1}, + unicode.Range16{Lo: 0xa9bc, Hi: 0xa9bc, Stride: 0x1}, + unicode.Range16{Lo: 0xa9e5, Hi: 0xa9e5, Stride: 0x1}, + unicode.Range16{Lo: 0xaa29, Hi: 0xaa2e, Stride: 0x1}, + unicode.Range16{Lo: 0xaa31, Hi: 0xaa32, Stride: 0x1}, + unicode.Range16{Lo: 0xaa35, Hi: 0xaa36, Stride: 0x1}, + unicode.Range16{Lo: 0xaa43, Hi: 0xaa43, Stride: 0x1}, + unicode.Range16{Lo: 0xaa4c, Hi: 0xaa4c, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7c, Hi: 0xaa7c, Stride: 0x1}, + unicode.Range16{Lo: 0xaab0, Hi: 0xaab0, Stride: 0x1}, + unicode.Range16{Lo: 0xaab2, Hi: 0xaab4, Stride: 0x1}, + unicode.Range16{Lo: 0xaab7, Hi: 0xaab8, Stride: 0x1}, + unicode.Range16{Lo: 0xaabe, Hi: 0xaabf, Stride: 0x1}, + unicode.Range16{Lo: 0xaac1, Hi: 0xaac1, Stride: 0x1}, + unicode.Range16{Lo: 0xaaec, Hi: 0xaaed, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf6, Hi: 0xaaf6, Stride: 0x1}, + unicode.Range16{Lo: 0xabe5, Hi: 0xabe5, Stride: 0x1}, + unicode.Range16{Lo: 0xabe8, Hi: 0xabe8, Stride: 0x1}, + unicode.Range16{Lo: 0xabed, Hi: 0xabed, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1e, Hi: 0xfb1e, Stride: 0x1}, + unicode.Range16{Lo: 0xfe00, Hi: 0xfe0f, Stride: 0x1}, + unicode.Range16{Lo: 0xfe20, Hi: 0xfe2d, Stride: 0x1}, + unicode.Range16{Lo: 0xff9e, Hi: 0xff9f, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x101fd, Hi: 0x101fd, Stride: 0x1}, + unicode.Range32{Lo: 0x102e0, Hi: 0x102e0, Stride: 0x1}, + unicode.Range32{Lo: 0x10376, Hi: 0x1037a, Stride: 0x1}, + unicode.Range32{Lo: 0x10a01, Hi: 0x10a03, Stride: 0x1}, + unicode.Range32{Lo: 0x10a05, Hi: 0x10a06, Stride: 0x1}, + unicode.Range32{Lo: 0x10a0c, Hi: 0x10a0f, Stride: 0x1}, + unicode.Range32{Lo: 0x10a38, Hi: 0x10a3a, Stride: 0x1}, + unicode.Range32{Lo: 0x10a3f, Hi: 0x10a3f, Stride: 0x1}, + unicode.Range32{Lo: 0x10ae5, Hi: 0x10ae6, Stride: 0x1}, + unicode.Range32{Lo: 0x11001, Hi: 0x11001, Stride: 0x1}, + unicode.Range32{Lo: 0x11038, Hi: 0x11046, Stride: 0x1}, + unicode.Range32{Lo: 0x1107f, Hi: 0x11081, Stride: 0x1}, + unicode.Range32{Lo: 0x110b3, Hi: 0x110b6, Stride: 0x1}, + unicode.Range32{Lo: 0x110b9, Hi: 0x110ba, Stride: 0x1}, + unicode.Range32{Lo: 0x11100, Hi: 0x11102, Stride: 0x1}, + unicode.Range32{Lo: 0x11127, Hi: 0x1112b, Stride: 0x1}, + unicode.Range32{Lo: 0x1112d, Hi: 0x11134, Stride: 0x1}, + unicode.Range32{Lo: 0x11173, Hi: 0x11173, Stride: 0x1}, + unicode.Range32{Lo: 0x11180, Hi: 0x11181, Stride: 0x1}, + unicode.Range32{Lo: 0x111b6, Hi: 0x111be, Stride: 0x1}, + unicode.Range32{Lo: 0x1122f, Hi: 0x11231, Stride: 0x1}, + unicode.Range32{Lo: 0x11234, Hi: 0x11234, Stride: 0x1}, + unicode.Range32{Lo: 0x11236, Hi: 0x11237, Stride: 0x1}, + unicode.Range32{Lo: 0x112df, Hi: 0x112df, Stride: 0x1}, + unicode.Range32{Lo: 0x112e3, Hi: 0x112ea, Stride: 0x1}, + unicode.Range32{Lo: 0x11301, Hi: 0x11301, Stride: 0x1}, + unicode.Range32{Lo: 0x1133c, Hi: 0x1133c, Stride: 0x1}, + unicode.Range32{Lo: 0x1133e, Hi: 0x1133e, Stride: 0x1}, + unicode.Range32{Lo: 0x11340, Hi: 0x11340, Stride: 0x1}, + unicode.Range32{Lo: 0x11357, Hi: 0x11357, Stride: 0x1}, + unicode.Range32{Lo: 0x11366, Hi: 0x1136c, Stride: 0x1}, + unicode.Range32{Lo: 0x11370, Hi: 0x11374, Stride: 0x1}, + unicode.Range32{Lo: 0x114b0, Hi: 0x114b0, Stride: 0x1}, + unicode.Range32{Lo: 0x114b3, Hi: 0x114b8, Stride: 0x1}, + unicode.Range32{Lo: 0x114ba, Hi: 0x114ba, Stride: 0x1}, + unicode.Range32{Lo: 0x114bd, Hi: 0x114bd, Stride: 0x1}, + unicode.Range32{Lo: 0x114bf, Hi: 0x114c0, Stride: 0x1}, + unicode.Range32{Lo: 0x114c2, Hi: 0x114c3, Stride: 0x1}, + unicode.Range32{Lo: 0x115af, Hi: 0x115af, Stride: 0x1}, + unicode.Range32{Lo: 0x115b2, Hi: 0x115b5, Stride: 0x1}, + unicode.Range32{Lo: 0x115bc, Hi: 0x115bd, Stride: 0x1}, + unicode.Range32{Lo: 0x115bf, Hi: 0x115c0, Stride: 0x1}, + unicode.Range32{Lo: 0x11633, Hi: 0x1163a, Stride: 0x1}, + unicode.Range32{Lo: 0x1163d, Hi: 0x1163d, Stride: 0x1}, + unicode.Range32{Lo: 0x1163f, Hi: 0x11640, Stride: 0x1}, + unicode.Range32{Lo: 0x116ab, Hi: 0x116ab, Stride: 0x1}, + unicode.Range32{Lo: 0x116ad, Hi: 0x116ad, Stride: 0x1}, + unicode.Range32{Lo: 0x116b0, Hi: 0x116b5, Stride: 0x1}, + unicode.Range32{Lo: 0x116b7, Hi: 0x116b7, Stride: 0x1}, + unicode.Range32{Lo: 0x16af0, Hi: 0x16af4, Stride: 0x1}, + unicode.Range32{Lo: 0x16b30, Hi: 0x16b36, Stride: 0x1}, + unicode.Range32{Lo: 0x16f8f, Hi: 0x16f92, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc9d, Hi: 0x1bc9e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d165, Hi: 0x1d165, Stride: 0x1}, + unicode.Range32{Lo: 0x1d167, Hi: 0x1d169, Stride: 0x1}, + unicode.Range32{Lo: 0x1d16e, Hi: 0x1d172, Stride: 0x1}, + unicode.Range32{Lo: 0x1d17b, Hi: 0x1d182, Stride: 0x1}, + unicode.Range32{Lo: 0x1d185, Hi: 0x1d18b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d1aa, Hi: 0x1d1ad, Stride: 0x1}, + unicode.Range32{Lo: 0x1d242, Hi: 0x1d244, Stride: 0x1}, + unicode.Range32{Lo: 0x1e8d0, Hi: 0x1e8d6, Stride: 0x1}, + unicode.Range32{Lo: 0xe0100, Hi: 0xe01ef, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeRegional_Indicator = &unicode.RangeTable{ + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x1f1e6, Hi: 0x1f1ff, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeT = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x11a8, Hi: 0x11ff, Stride: 0x1}, + unicode.Range16{Lo: 0xd7cb, Hi: 0xd7fb, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeLV = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xac00, Hi: 0xac00, Stride: 0x1}, + unicode.Range16{Lo: 0xac1c, Hi: 0xac1c, Stride: 0x1}, + unicode.Range16{Lo: 0xac38, Hi: 0xac38, Stride: 0x1}, + unicode.Range16{Lo: 0xac54, Hi: 0xac54, Stride: 0x1}, + unicode.Range16{Lo: 0xac70, Hi: 0xac70, Stride: 0x1}, + unicode.Range16{Lo: 0xac8c, Hi: 0xac8c, Stride: 0x1}, + unicode.Range16{Lo: 0xaca8, Hi: 0xaca8, Stride: 0x1}, + unicode.Range16{Lo: 0xacc4, Hi: 0xacc4, Stride: 0x1}, + unicode.Range16{Lo: 0xace0, Hi: 0xace0, Stride: 0x1}, + unicode.Range16{Lo: 0xacfc, Hi: 0xacfc, Stride: 0x1}, + unicode.Range16{Lo: 0xad18, Hi: 0xad18, Stride: 0x1}, + unicode.Range16{Lo: 0xad34, Hi: 0xad34, Stride: 0x1}, + unicode.Range16{Lo: 0xad50, Hi: 0xad50, Stride: 0x1}, + unicode.Range16{Lo: 0xad6c, Hi: 0xad6c, Stride: 0x1}, + unicode.Range16{Lo: 0xad88, Hi: 0xad88, Stride: 0x1}, + unicode.Range16{Lo: 0xada4, Hi: 0xada4, Stride: 0x1}, + unicode.Range16{Lo: 0xadc0, Hi: 0xadc0, Stride: 0x1}, + unicode.Range16{Lo: 0xaddc, Hi: 0xaddc, Stride: 0x1}, + unicode.Range16{Lo: 0xadf8, Hi: 0xadf8, Stride: 0x1}, + unicode.Range16{Lo: 0xae14, Hi: 0xae14, Stride: 0x1}, + unicode.Range16{Lo: 0xae30, Hi: 0xae30, Stride: 0x1}, + unicode.Range16{Lo: 0xae4c, Hi: 0xae4c, Stride: 0x1}, + unicode.Range16{Lo: 0xae68, Hi: 0xae68, Stride: 0x1}, + unicode.Range16{Lo: 0xae84, Hi: 0xae84, Stride: 0x1}, + unicode.Range16{Lo: 0xaea0, Hi: 0xaea0, Stride: 0x1}, + unicode.Range16{Lo: 0xaebc, Hi: 0xaebc, Stride: 0x1}, + unicode.Range16{Lo: 0xaed8, Hi: 0xaed8, Stride: 0x1}, + unicode.Range16{Lo: 0xaef4, Hi: 0xaef4, Stride: 0x1}, + unicode.Range16{Lo: 0xaf10, Hi: 0xaf10, Stride: 0x1}, + unicode.Range16{Lo: 0xaf2c, Hi: 0xaf2c, Stride: 0x1}, + unicode.Range16{Lo: 0xaf48, Hi: 0xaf48, Stride: 0x1}, + unicode.Range16{Lo: 0xaf64, Hi: 0xaf64, Stride: 0x1}, + unicode.Range16{Lo: 0xaf80, Hi: 0xaf80, Stride: 0x1}, + unicode.Range16{Lo: 0xaf9c, Hi: 0xaf9c, Stride: 0x1}, + unicode.Range16{Lo: 0xafb8, Hi: 0xafb8, Stride: 0x1}, + unicode.Range16{Lo: 0xafd4, Hi: 0xafd4, Stride: 0x1}, + unicode.Range16{Lo: 0xaff0, Hi: 0xaff0, Stride: 0x1}, + unicode.Range16{Lo: 0xb00c, Hi: 0xb00c, Stride: 0x1}, + unicode.Range16{Lo: 0xb028, Hi: 0xb028, Stride: 0x1}, + unicode.Range16{Lo: 0xb044, Hi: 0xb044, Stride: 0x1}, + unicode.Range16{Lo: 0xb060, Hi: 0xb060, Stride: 0x1}, + unicode.Range16{Lo: 0xb07c, Hi: 0xb07c, Stride: 0x1}, + unicode.Range16{Lo: 0xb098, Hi: 0xb098, Stride: 0x1}, + unicode.Range16{Lo: 0xb0b4, Hi: 0xb0b4, Stride: 0x1}, + unicode.Range16{Lo: 0xb0d0, Hi: 0xb0d0, Stride: 0x1}, + unicode.Range16{Lo: 0xb0ec, Hi: 0xb0ec, Stride: 0x1}, + unicode.Range16{Lo: 0xb108, Hi: 0xb108, Stride: 0x1}, + unicode.Range16{Lo: 0xb124, Hi: 0xb124, Stride: 0x1}, + unicode.Range16{Lo: 0xb140, Hi: 0xb140, Stride: 0x1}, + unicode.Range16{Lo: 0xb15c, Hi: 0xb15c, Stride: 0x1}, + unicode.Range16{Lo: 0xb178, Hi: 0xb178, Stride: 0x1}, + unicode.Range16{Lo: 0xb194, Hi: 0xb194, Stride: 0x1}, + unicode.Range16{Lo: 0xb1b0, Hi: 0xb1b0, Stride: 0x1}, + unicode.Range16{Lo: 0xb1cc, Hi: 0xb1cc, Stride: 0x1}, + unicode.Range16{Lo: 0xb1e8, Hi: 0xb1e8, Stride: 0x1}, + unicode.Range16{Lo: 0xb204, Hi: 0xb204, Stride: 0x1}, + unicode.Range16{Lo: 0xb220, Hi: 0xb220, Stride: 0x1}, + unicode.Range16{Lo: 0xb23c, Hi: 0xb23c, Stride: 0x1}, + unicode.Range16{Lo: 0xb258, Hi: 0xb258, Stride: 0x1}, + unicode.Range16{Lo: 0xb274, Hi: 0xb274, Stride: 0x1}, + unicode.Range16{Lo: 0xb290, Hi: 0xb290, Stride: 0x1}, + unicode.Range16{Lo: 0xb2ac, Hi: 0xb2ac, Stride: 0x1}, + unicode.Range16{Lo: 0xb2c8, Hi: 0xb2c8, Stride: 0x1}, + unicode.Range16{Lo: 0xb2e4, Hi: 0xb2e4, Stride: 0x1}, + unicode.Range16{Lo: 0xb300, Hi: 0xb300, Stride: 0x1}, + unicode.Range16{Lo: 0xb31c, Hi: 0xb31c, Stride: 0x1}, + unicode.Range16{Lo: 0xb338, Hi: 0xb338, Stride: 0x1}, + unicode.Range16{Lo: 0xb354, Hi: 0xb354, Stride: 0x1}, + unicode.Range16{Lo: 0xb370, Hi: 0xb370, Stride: 0x1}, + unicode.Range16{Lo: 0xb38c, Hi: 0xb38c, Stride: 0x1}, + unicode.Range16{Lo: 0xb3a8, Hi: 0xb3a8, Stride: 0x1}, + unicode.Range16{Lo: 0xb3c4, Hi: 0xb3c4, Stride: 0x1}, + unicode.Range16{Lo: 0xb3e0, Hi: 0xb3e0, Stride: 0x1}, + unicode.Range16{Lo: 0xb3fc, Hi: 0xb3fc, Stride: 0x1}, + unicode.Range16{Lo: 0xb418, Hi: 0xb418, Stride: 0x1}, + unicode.Range16{Lo: 0xb434, Hi: 0xb434, Stride: 0x1}, + unicode.Range16{Lo: 0xb450, Hi: 0xb450, Stride: 0x1}, + unicode.Range16{Lo: 0xb46c, Hi: 0xb46c, Stride: 0x1}, + unicode.Range16{Lo: 0xb488, Hi: 0xb488, Stride: 0x1}, + unicode.Range16{Lo: 0xb4a4, Hi: 0xb4a4, Stride: 0x1}, + unicode.Range16{Lo: 0xb4c0, Hi: 0xb4c0, Stride: 0x1}, + unicode.Range16{Lo: 0xb4dc, Hi: 0xb4dc, Stride: 0x1}, + unicode.Range16{Lo: 0xb4f8, Hi: 0xb4f8, Stride: 0x1}, + unicode.Range16{Lo: 0xb514, Hi: 0xb514, Stride: 0x1}, + unicode.Range16{Lo: 0xb530, Hi: 0xb530, Stride: 0x1}, + unicode.Range16{Lo: 0xb54c, Hi: 0xb54c, Stride: 0x1}, + unicode.Range16{Lo: 0xb568, Hi: 0xb568, Stride: 0x1}, + unicode.Range16{Lo: 0xb584, Hi: 0xb584, Stride: 0x1}, + unicode.Range16{Lo: 0xb5a0, Hi: 0xb5a0, Stride: 0x1}, + unicode.Range16{Lo: 0xb5bc, Hi: 0xb5bc, Stride: 0x1}, + unicode.Range16{Lo: 0xb5d8, Hi: 0xb5d8, Stride: 0x1}, + unicode.Range16{Lo: 0xb5f4, Hi: 0xb5f4, Stride: 0x1}, + unicode.Range16{Lo: 0xb610, Hi: 0xb610, Stride: 0x1}, + unicode.Range16{Lo: 0xb62c, Hi: 0xb62c, Stride: 0x1}, + unicode.Range16{Lo: 0xb648, Hi: 0xb648, Stride: 0x1}, + unicode.Range16{Lo: 0xb664, Hi: 0xb664, Stride: 0x1}, + unicode.Range16{Lo: 0xb680, Hi: 0xb680, Stride: 0x1}, + unicode.Range16{Lo: 0xb69c, Hi: 0xb69c, Stride: 0x1}, + unicode.Range16{Lo: 0xb6b8, Hi: 0xb6b8, Stride: 0x1}, + unicode.Range16{Lo: 0xb6d4, Hi: 0xb6d4, Stride: 0x1}, + unicode.Range16{Lo: 0xb6f0, Hi: 0xb6f0, Stride: 0x1}, + unicode.Range16{Lo: 0xb70c, Hi: 0xb70c, Stride: 0x1}, + unicode.Range16{Lo: 0xb728, Hi: 0xb728, Stride: 0x1}, + unicode.Range16{Lo: 0xb744, Hi: 0xb744, Stride: 0x1}, + unicode.Range16{Lo: 0xb760, Hi: 0xb760, Stride: 0x1}, + unicode.Range16{Lo: 0xb77c, Hi: 0xb77c, Stride: 0x1}, + unicode.Range16{Lo: 0xb798, Hi: 0xb798, Stride: 0x1}, + unicode.Range16{Lo: 0xb7b4, Hi: 0xb7b4, Stride: 0x1}, + unicode.Range16{Lo: 0xb7d0, Hi: 0xb7d0, Stride: 0x1}, + unicode.Range16{Lo: 0xb7ec, Hi: 0xb7ec, Stride: 0x1}, + unicode.Range16{Lo: 0xb808, Hi: 0xb808, Stride: 0x1}, + unicode.Range16{Lo: 0xb824, Hi: 0xb824, Stride: 0x1}, + unicode.Range16{Lo: 0xb840, Hi: 0xb840, Stride: 0x1}, + unicode.Range16{Lo: 0xb85c, Hi: 0xb85c, Stride: 0x1}, + unicode.Range16{Lo: 0xb878, Hi: 0xb878, Stride: 0x1}, + unicode.Range16{Lo: 0xb894, Hi: 0xb894, Stride: 0x1}, + unicode.Range16{Lo: 0xb8b0, Hi: 0xb8b0, Stride: 0x1}, + unicode.Range16{Lo: 0xb8cc, Hi: 0xb8cc, Stride: 0x1}, + unicode.Range16{Lo: 0xb8e8, Hi: 0xb8e8, Stride: 0x1}, + unicode.Range16{Lo: 0xb904, Hi: 0xb904, Stride: 0x1}, + unicode.Range16{Lo: 0xb920, Hi: 0xb920, Stride: 0x1}, + unicode.Range16{Lo: 0xb93c, Hi: 0xb93c, Stride: 0x1}, + unicode.Range16{Lo: 0xb958, Hi: 0xb958, Stride: 0x1}, + unicode.Range16{Lo: 0xb974, Hi: 0xb974, Stride: 0x1}, + unicode.Range16{Lo: 0xb990, Hi: 0xb990, Stride: 0x1}, + unicode.Range16{Lo: 0xb9ac, Hi: 0xb9ac, Stride: 0x1}, + unicode.Range16{Lo: 0xb9c8, Hi: 0xb9c8, Stride: 0x1}, + unicode.Range16{Lo: 0xb9e4, Hi: 0xb9e4, Stride: 0x1}, + unicode.Range16{Lo: 0xba00, Hi: 0xba00, Stride: 0x1}, + unicode.Range16{Lo: 0xba1c, Hi: 0xba1c, Stride: 0x1}, + unicode.Range16{Lo: 0xba38, Hi: 0xba38, Stride: 0x1}, + unicode.Range16{Lo: 0xba54, Hi: 0xba54, Stride: 0x1}, + unicode.Range16{Lo: 0xba70, Hi: 0xba70, Stride: 0x1}, + unicode.Range16{Lo: 0xba8c, Hi: 0xba8c, Stride: 0x1}, + unicode.Range16{Lo: 0xbaa8, Hi: 0xbaa8, Stride: 0x1}, + unicode.Range16{Lo: 0xbac4, Hi: 0xbac4, Stride: 0x1}, + unicode.Range16{Lo: 0xbae0, Hi: 0xbae0, Stride: 0x1}, + unicode.Range16{Lo: 0xbafc, Hi: 0xbafc, Stride: 0x1}, + unicode.Range16{Lo: 0xbb18, Hi: 0xbb18, Stride: 0x1}, + unicode.Range16{Lo: 0xbb34, Hi: 0xbb34, Stride: 0x1}, + unicode.Range16{Lo: 0xbb50, Hi: 0xbb50, Stride: 0x1}, + unicode.Range16{Lo: 0xbb6c, Hi: 0xbb6c, Stride: 0x1}, + unicode.Range16{Lo: 0xbb88, Hi: 0xbb88, Stride: 0x1}, + unicode.Range16{Lo: 0xbba4, Hi: 0xbba4, Stride: 0x1}, + unicode.Range16{Lo: 0xbbc0, Hi: 0xbbc0, Stride: 0x1}, + unicode.Range16{Lo: 0xbbdc, Hi: 0xbbdc, Stride: 0x1}, + unicode.Range16{Lo: 0xbbf8, Hi: 0xbbf8, Stride: 0x1}, + unicode.Range16{Lo: 0xbc14, Hi: 0xbc14, Stride: 0x1}, + unicode.Range16{Lo: 0xbc30, Hi: 0xbc30, Stride: 0x1}, + unicode.Range16{Lo: 0xbc4c, Hi: 0xbc4c, Stride: 0x1}, + unicode.Range16{Lo: 0xbc68, Hi: 0xbc68, Stride: 0x1}, + unicode.Range16{Lo: 0xbc84, Hi: 0xbc84, Stride: 0x1}, + unicode.Range16{Lo: 0xbca0, Hi: 0xbca0, Stride: 0x1}, + unicode.Range16{Lo: 0xbcbc, Hi: 0xbcbc, Stride: 0x1}, + unicode.Range16{Lo: 0xbcd8, Hi: 0xbcd8, Stride: 0x1}, + unicode.Range16{Lo: 0xbcf4, Hi: 0xbcf4, Stride: 0x1}, + unicode.Range16{Lo: 0xbd10, Hi: 0xbd10, Stride: 0x1}, + unicode.Range16{Lo: 0xbd2c, Hi: 0xbd2c, Stride: 0x1}, + unicode.Range16{Lo: 0xbd48, Hi: 0xbd48, Stride: 0x1}, + unicode.Range16{Lo: 0xbd64, Hi: 0xbd64, Stride: 0x1}, + unicode.Range16{Lo: 0xbd80, Hi: 0xbd80, Stride: 0x1}, + unicode.Range16{Lo: 0xbd9c, Hi: 0xbd9c, Stride: 0x1}, + unicode.Range16{Lo: 0xbdb8, Hi: 0xbdb8, Stride: 0x1}, + unicode.Range16{Lo: 0xbdd4, Hi: 0xbdd4, Stride: 0x1}, + unicode.Range16{Lo: 0xbdf0, Hi: 0xbdf0, Stride: 0x1}, + unicode.Range16{Lo: 0xbe0c, Hi: 0xbe0c, Stride: 0x1}, + unicode.Range16{Lo: 0xbe28, Hi: 0xbe28, Stride: 0x1}, + unicode.Range16{Lo: 0xbe44, Hi: 0xbe44, Stride: 0x1}, + unicode.Range16{Lo: 0xbe60, Hi: 0xbe60, Stride: 0x1}, + unicode.Range16{Lo: 0xbe7c, Hi: 0xbe7c, Stride: 0x1}, + unicode.Range16{Lo: 0xbe98, Hi: 0xbe98, Stride: 0x1}, + unicode.Range16{Lo: 0xbeb4, Hi: 0xbeb4, Stride: 0x1}, + unicode.Range16{Lo: 0xbed0, Hi: 0xbed0, Stride: 0x1}, + unicode.Range16{Lo: 0xbeec, Hi: 0xbeec, Stride: 0x1}, + unicode.Range16{Lo: 0xbf08, Hi: 0xbf08, Stride: 0x1}, + unicode.Range16{Lo: 0xbf24, Hi: 0xbf24, Stride: 0x1}, + unicode.Range16{Lo: 0xbf40, Hi: 0xbf40, Stride: 0x1}, + unicode.Range16{Lo: 0xbf5c, Hi: 0xbf5c, Stride: 0x1}, + unicode.Range16{Lo: 0xbf78, Hi: 0xbf78, Stride: 0x1}, + unicode.Range16{Lo: 0xbf94, Hi: 0xbf94, Stride: 0x1}, + unicode.Range16{Lo: 0xbfb0, Hi: 0xbfb0, Stride: 0x1}, + unicode.Range16{Lo: 0xbfcc, Hi: 0xbfcc, Stride: 0x1}, + unicode.Range16{Lo: 0xbfe8, Hi: 0xbfe8, Stride: 0x1}, + unicode.Range16{Lo: 0xc004, Hi: 0xc004, Stride: 0x1}, + unicode.Range16{Lo: 0xc020, Hi: 0xc020, Stride: 0x1}, + unicode.Range16{Lo: 0xc03c, Hi: 0xc03c, Stride: 0x1}, + unicode.Range16{Lo: 0xc058, Hi: 0xc058, Stride: 0x1}, + unicode.Range16{Lo: 0xc074, Hi: 0xc074, Stride: 0x1}, + unicode.Range16{Lo: 0xc090, Hi: 0xc090, Stride: 0x1}, + unicode.Range16{Lo: 0xc0ac, Hi: 0xc0ac, Stride: 0x1}, + unicode.Range16{Lo: 0xc0c8, Hi: 0xc0c8, Stride: 0x1}, + unicode.Range16{Lo: 0xc0e4, Hi: 0xc0e4, Stride: 0x1}, + unicode.Range16{Lo: 0xc100, Hi: 0xc100, Stride: 0x1}, + unicode.Range16{Lo: 0xc11c, Hi: 0xc11c, Stride: 0x1}, + unicode.Range16{Lo: 0xc138, Hi: 0xc138, Stride: 0x1}, + unicode.Range16{Lo: 0xc154, Hi: 0xc154, Stride: 0x1}, + unicode.Range16{Lo: 0xc170, Hi: 0xc170, Stride: 0x1}, + unicode.Range16{Lo: 0xc18c, Hi: 0xc18c, Stride: 0x1}, + unicode.Range16{Lo: 0xc1a8, Hi: 0xc1a8, Stride: 0x1}, + unicode.Range16{Lo: 0xc1c4, Hi: 0xc1c4, Stride: 0x1}, + unicode.Range16{Lo: 0xc1e0, Hi: 0xc1e0, Stride: 0x1}, + unicode.Range16{Lo: 0xc1fc, Hi: 0xc1fc, Stride: 0x1}, + unicode.Range16{Lo: 0xc218, Hi: 0xc218, Stride: 0x1}, + unicode.Range16{Lo: 0xc234, Hi: 0xc234, Stride: 0x1}, + unicode.Range16{Lo: 0xc250, Hi: 0xc250, Stride: 0x1}, + unicode.Range16{Lo: 0xc26c, Hi: 0xc26c, Stride: 0x1}, + unicode.Range16{Lo: 0xc288, Hi: 0xc288, Stride: 0x1}, + unicode.Range16{Lo: 0xc2a4, Hi: 0xc2a4, Stride: 0x1}, + unicode.Range16{Lo: 0xc2c0, Hi: 0xc2c0, Stride: 0x1}, + unicode.Range16{Lo: 0xc2dc, Hi: 0xc2dc, Stride: 0x1}, + unicode.Range16{Lo: 0xc2f8, Hi: 0xc2f8, Stride: 0x1}, + unicode.Range16{Lo: 0xc314, Hi: 0xc314, Stride: 0x1}, + unicode.Range16{Lo: 0xc330, Hi: 0xc330, Stride: 0x1}, + unicode.Range16{Lo: 0xc34c, Hi: 0xc34c, Stride: 0x1}, + unicode.Range16{Lo: 0xc368, Hi: 0xc368, Stride: 0x1}, + unicode.Range16{Lo: 0xc384, Hi: 0xc384, Stride: 0x1}, + unicode.Range16{Lo: 0xc3a0, Hi: 0xc3a0, Stride: 0x1}, + unicode.Range16{Lo: 0xc3bc, Hi: 0xc3bc, Stride: 0x1}, + unicode.Range16{Lo: 0xc3d8, Hi: 0xc3d8, Stride: 0x1}, + unicode.Range16{Lo: 0xc3f4, Hi: 0xc3f4, Stride: 0x1}, + unicode.Range16{Lo: 0xc410, Hi: 0xc410, Stride: 0x1}, + unicode.Range16{Lo: 0xc42c, Hi: 0xc42c, Stride: 0x1}, + unicode.Range16{Lo: 0xc448, Hi: 0xc448, Stride: 0x1}, + unicode.Range16{Lo: 0xc464, Hi: 0xc464, Stride: 0x1}, + unicode.Range16{Lo: 0xc480, Hi: 0xc480, Stride: 0x1}, + unicode.Range16{Lo: 0xc49c, Hi: 0xc49c, Stride: 0x1}, + unicode.Range16{Lo: 0xc4b8, Hi: 0xc4b8, Stride: 0x1}, + unicode.Range16{Lo: 0xc4d4, Hi: 0xc4d4, Stride: 0x1}, + unicode.Range16{Lo: 0xc4f0, Hi: 0xc4f0, Stride: 0x1}, + unicode.Range16{Lo: 0xc50c, Hi: 0xc50c, Stride: 0x1}, + unicode.Range16{Lo: 0xc528, Hi: 0xc528, Stride: 0x1}, + unicode.Range16{Lo: 0xc544, Hi: 0xc544, Stride: 0x1}, + unicode.Range16{Lo: 0xc560, Hi: 0xc560, Stride: 0x1}, + unicode.Range16{Lo: 0xc57c, Hi: 0xc57c, Stride: 0x1}, + unicode.Range16{Lo: 0xc598, Hi: 0xc598, Stride: 0x1}, + unicode.Range16{Lo: 0xc5b4, Hi: 0xc5b4, Stride: 0x1}, + unicode.Range16{Lo: 0xc5d0, Hi: 0xc5d0, Stride: 0x1}, + unicode.Range16{Lo: 0xc5ec, Hi: 0xc5ec, Stride: 0x1}, + unicode.Range16{Lo: 0xc608, Hi: 0xc608, Stride: 0x1}, + unicode.Range16{Lo: 0xc624, Hi: 0xc624, Stride: 0x1}, + unicode.Range16{Lo: 0xc640, Hi: 0xc640, Stride: 0x1}, + unicode.Range16{Lo: 0xc65c, Hi: 0xc65c, Stride: 0x1}, + unicode.Range16{Lo: 0xc678, Hi: 0xc678, Stride: 0x1}, + unicode.Range16{Lo: 0xc694, Hi: 0xc694, Stride: 0x1}, + unicode.Range16{Lo: 0xc6b0, Hi: 0xc6b0, Stride: 0x1}, + unicode.Range16{Lo: 0xc6cc, Hi: 0xc6cc, Stride: 0x1}, + unicode.Range16{Lo: 0xc6e8, Hi: 0xc6e8, Stride: 0x1}, + unicode.Range16{Lo: 0xc704, Hi: 0xc704, Stride: 0x1}, + unicode.Range16{Lo: 0xc720, Hi: 0xc720, Stride: 0x1}, + unicode.Range16{Lo: 0xc73c, Hi: 0xc73c, Stride: 0x1}, + unicode.Range16{Lo: 0xc758, Hi: 0xc758, Stride: 0x1}, + unicode.Range16{Lo: 0xc774, Hi: 0xc774, Stride: 0x1}, + unicode.Range16{Lo: 0xc790, Hi: 0xc790, Stride: 0x1}, + unicode.Range16{Lo: 0xc7ac, Hi: 0xc7ac, Stride: 0x1}, + unicode.Range16{Lo: 0xc7c8, Hi: 0xc7c8, Stride: 0x1}, + unicode.Range16{Lo: 0xc7e4, Hi: 0xc7e4, Stride: 0x1}, + unicode.Range16{Lo: 0xc800, Hi: 0xc800, Stride: 0x1}, + unicode.Range16{Lo: 0xc81c, Hi: 0xc81c, Stride: 0x1}, + unicode.Range16{Lo: 0xc838, Hi: 0xc838, Stride: 0x1}, + unicode.Range16{Lo: 0xc854, Hi: 0xc854, Stride: 0x1}, + unicode.Range16{Lo: 0xc870, Hi: 0xc870, Stride: 0x1}, + unicode.Range16{Lo: 0xc88c, Hi: 0xc88c, Stride: 0x1}, + unicode.Range16{Lo: 0xc8a8, Hi: 0xc8a8, Stride: 0x1}, + unicode.Range16{Lo: 0xc8c4, Hi: 0xc8c4, Stride: 0x1}, + unicode.Range16{Lo: 0xc8e0, Hi: 0xc8e0, Stride: 0x1}, + unicode.Range16{Lo: 0xc8fc, Hi: 0xc8fc, Stride: 0x1}, + unicode.Range16{Lo: 0xc918, Hi: 0xc918, Stride: 0x1}, + unicode.Range16{Lo: 0xc934, Hi: 0xc934, Stride: 0x1}, + unicode.Range16{Lo: 0xc950, Hi: 0xc950, Stride: 0x1}, + unicode.Range16{Lo: 0xc96c, Hi: 0xc96c, Stride: 0x1}, + unicode.Range16{Lo: 0xc988, Hi: 0xc988, Stride: 0x1}, + unicode.Range16{Lo: 0xc9a4, Hi: 0xc9a4, Stride: 0x1}, + unicode.Range16{Lo: 0xc9c0, Hi: 0xc9c0, Stride: 0x1}, + unicode.Range16{Lo: 0xc9dc, Hi: 0xc9dc, Stride: 0x1}, + unicode.Range16{Lo: 0xc9f8, Hi: 0xc9f8, Stride: 0x1}, + unicode.Range16{Lo: 0xca14, Hi: 0xca14, Stride: 0x1}, + unicode.Range16{Lo: 0xca30, Hi: 0xca30, Stride: 0x1}, + unicode.Range16{Lo: 0xca4c, Hi: 0xca4c, Stride: 0x1}, + unicode.Range16{Lo: 0xca68, Hi: 0xca68, Stride: 0x1}, + unicode.Range16{Lo: 0xca84, Hi: 0xca84, Stride: 0x1}, + unicode.Range16{Lo: 0xcaa0, Hi: 0xcaa0, Stride: 0x1}, + unicode.Range16{Lo: 0xcabc, Hi: 0xcabc, Stride: 0x1}, + unicode.Range16{Lo: 0xcad8, Hi: 0xcad8, Stride: 0x1}, + unicode.Range16{Lo: 0xcaf4, Hi: 0xcaf4, Stride: 0x1}, + unicode.Range16{Lo: 0xcb10, Hi: 0xcb10, Stride: 0x1}, + unicode.Range16{Lo: 0xcb2c, Hi: 0xcb2c, Stride: 0x1}, + unicode.Range16{Lo: 0xcb48, Hi: 0xcb48, Stride: 0x1}, + unicode.Range16{Lo: 0xcb64, Hi: 0xcb64, Stride: 0x1}, + unicode.Range16{Lo: 0xcb80, Hi: 0xcb80, Stride: 0x1}, + unicode.Range16{Lo: 0xcb9c, Hi: 0xcb9c, Stride: 0x1}, + unicode.Range16{Lo: 0xcbb8, Hi: 0xcbb8, Stride: 0x1}, + unicode.Range16{Lo: 0xcbd4, Hi: 0xcbd4, Stride: 0x1}, + unicode.Range16{Lo: 0xcbf0, Hi: 0xcbf0, Stride: 0x1}, + unicode.Range16{Lo: 0xcc0c, Hi: 0xcc0c, Stride: 0x1}, + unicode.Range16{Lo: 0xcc28, Hi: 0xcc28, Stride: 0x1}, + unicode.Range16{Lo: 0xcc44, Hi: 0xcc44, Stride: 0x1}, + unicode.Range16{Lo: 0xcc60, Hi: 0xcc60, Stride: 0x1}, + unicode.Range16{Lo: 0xcc7c, Hi: 0xcc7c, Stride: 0x1}, + unicode.Range16{Lo: 0xcc98, Hi: 0xcc98, Stride: 0x1}, + unicode.Range16{Lo: 0xccb4, Hi: 0xccb4, Stride: 0x1}, + unicode.Range16{Lo: 0xccd0, Hi: 0xccd0, Stride: 0x1}, + unicode.Range16{Lo: 0xccec, Hi: 0xccec, Stride: 0x1}, + unicode.Range16{Lo: 0xcd08, Hi: 0xcd08, Stride: 0x1}, + unicode.Range16{Lo: 0xcd24, Hi: 0xcd24, Stride: 0x1}, + unicode.Range16{Lo: 0xcd40, Hi: 0xcd40, Stride: 0x1}, + unicode.Range16{Lo: 0xcd5c, Hi: 0xcd5c, Stride: 0x1}, + unicode.Range16{Lo: 0xcd78, Hi: 0xcd78, Stride: 0x1}, + unicode.Range16{Lo: 0xcd94, Hi: 0xcd94, Stride: 0x1}, + unicode.Range16{Lo: 0xcdb0, Hi: 0xcdb0, Stride: 0x1}, + unicode.Range16{Lo: 0xcdcc, Hi: 0xcdcc, Stride: 0x1}, + unicode.Range16{Lo: 0xcde8, Hi: 0xcde8, Stride: 0x1}, + unicode.Range16{Lo: 0xce04, Hi: 0xce04, Stride: 0x1}, + unicode.Range16{Lo: 0xce20, Hi: 0xce20, Stride: 0x1}, + unicode.Range16{Lo: 0xce3c, Hi: 0xce3c, Stride: 0x1}, + unicode.Range16{Lo: 0xce58, Hi: 0xce58, Stride: 0x1}, + unicode.Range16{Lo: 0xce74, Hi: 0xce74, Stride: 0x1}, + unicode.Range16{Lo: 0xce90, Hi: 0xce90, Stride: 0x1}, + unicode.Range16{Lo: 0xceac, Hi: 0xceac, Stride: 0x1}, + unicode.Range16{Lo: 0xcec8, Hi: 0xcec8, Stride: 0x1}, + unicode.Range16{Lo: 0xcee4, Hi: 0xcee4, Stride: 0x1}, + unicode.Range16{Lo: 0xcf00, Hi: 0xcf00, Stride: 0x1}, + unicode.Range16{Lo: 0xcf1c, Hi: 0xcf1c, Stride: 0x1}, + unicode.Range16{Lo: 0xcf38, Hi: 0xcf38, Stride: 0x1}, + unicode.Range16{Lo: 0xcf54, Hi: 0xcf54, Stride: 0x1}, + unicode.Range16{Lo: 0xcf70, Hi: 0xcf70, Stride: 0x1}, + unicode.Range16{Lo: 0xcf8c, Hi: 0xcf8c, Stride: 0x1}, + unicode.Range16{Lo: 0xcfa8, Hi: 0xcfa8, Stride: 0x1}, + unicode.Range16{Lo: 0xcfc4, Hi: 0xcfc4, Stride: 0x1}, + unicode.Range16{Lo: 0xcfe0, Hi: 0xcfe0, Stride: 0x1}, + unicode.Range16{Lo: 0xcffc, Hi: 0xcffc, Stride: 0x1}, + unicode.Range16{Lo: 0xd018, Hi: 0xd018, Stride: 0x1}, + unicode.Range16{Lo: 0xd034, Hi: 0xd034, Stride: 0x1}, + unicode.Range16{Lo: 0xd050, Hi: 0xd050, Stride: 0x1}, + unicode.Range16{Lo: 0xd06c, Hi: 0xd06c, Stride: 0x1}, + unicode.Range16{Lo: 0xd088, Hi: 0xd088, Stride: 0x1}, + unicode.Range16{Lo: 0xd0a4, Hi: 0xd0a4, Stride: 0x1}, + unicode.Range16{Lo: 0xd0c0, Hi: 0xd0c0, Stride: 0x1}, + unicode.Range16{Lo: 0xd0dc, Hi: 0xd0dc, Stride: 0x1}, + unicode.Range16{Lo: 0xd0f8, Hi: 0xd0f8, Stride: 0x1}, + unicode.Range16{Lo: 0xd114, Hi: 0xd114, Stride: 0x1}, + unicode.Range16{Lo: 0xd130, Hi: 0xd130, Stride: 0x1}, + unicode.Range16{Lo: 0xd14c, Hi: 0xd14c, Stride: 0x1}, + unicode.Range16{Lo: 0xd168, Hi: 0xd168, Stride: 0x1}, + unicode.Range16{Lo: 0xd184, Hi: 0xd184, Stride: 0x1}, + unicode.Range16{Lo: 0xd1a0, Hi: 0xd1a0, Stride: 0x1}, + unicode.Range16{Lo: 0xd1bc, Hi: 0xd1bc, Stride: 0x1}, + unicode.Range16{Lo: 0xd1d8, Hi: 0xd1d8, Stride: 0x1}, + unicode.Range16{Lo: 0xd1f4, Hi: 0xd1f4, Stride: 0x1}, + unicode.Range16{Lo: 0xd210, Hi: 0xd210, Stride: 0x1}, + unicode.Range16{Lo: 0xd22c, Hi: 0xd22c, Stride: 0x1}, + unicode.Range16{Lo: 0xd248, Hi: 0xd248, Stride: 0x1}, + unicode.Range16{Lo: 0xd264, Hi: 0xd264, Stride: 0x1}, + unicode.Range16{Lo: 0xd280, Hi: 0xd280, Stride: 0x1}, + unicode.Range16{Lo: 0xd29c, Hi: 0xd29c, Stride: 0x1}, + unicode.Range16{Lo: 0xd2b8, Hi: 0xd2b8, Stride: 0x1}, + unicode.Range16{Lo: 0xd2d4, Hi: 0xd2d4, Stride: 0x1}, + unicode.Range16{Lo: 0xd2f0, Hi: 0xd2f0, Stride: 0x1}, + unicode.Range16{Lo: 0xd30c, Hi: 0xd30c, Stride: 0x1}, + unicode.Range16{Lo: 0xd328, Hi: 0xd328, Stride: 0x1}, + unicode.Range16{Lo: 0xd344, Hi: 0xd344, Stride: 0x1}, + unicode.Range16{Lo: 0xd360, Hi: 0xd360, Stride: 0x1}, + unicode.Range16{Lo: 0xd37c, Hi: 0xd37c, Stride: 0x1}, + unicode.Range16{Lo: 0xd398, Hi: 0xd398, Stride: 0x1}, + unicode.Range16{Lo: 0xd3b4, Hi: 0xd3b4, Stride: 0x1}, + unicode.Range16{Lo: 0xd3d0, Hi: 0xd3d0, Stride: 0x1}, + unicode.Range16{Lo: 0xd3ec, Hi: 0xd3ec, Stride: 0x1}, + unicode.Range16{Lo: 0xd408, Hi: 0xd408, Stride: 0x1}, + unicode.Range16{Lo: 0xd424, Hi: 0xd424, Stride: 0x1}, + unicode.Range16{Lo: 0xd440, Hi: 0xd440, Stride: 0x1}, + unicode.Range16{Lo: 0xd45c, Hi: 0xd45c, Stride: 0x1}, + unicode.Range16{Lo: 0xd478, Hi: 0xd478, Stride: 0x1}, + unicode.Range16{Lo: 0xd494, Hi: 0xd494, Stride: 0x1}, + unicode.Range16{Lo: 0xd4b0, Hi: 0xd4b0, Stride: 0x1}, + unicode.Range16{Lo: 0xd4cc, Hi: 0xd4cc, Stride: 0x1}, + unicode.Range16{Lo: 0xd4e8, Hi: 0xd4e8, Stride: 0x1}, + unicode.Range16{Lo: 0xd504, Hi: 0xd504, Stride: 0x1}, + unicode.Range16{Lo: 0xd520, Hi: 0xd520, Stride: 0x1}, + unicode.Range16{Lo: 0xd53c, Hi: 0xd53c, Stride: 0x1}, + unicode.Range16{Lo: 0xd558, Hi: 0xd558, Stride: 0x1}, + unicode.Range16{Lo: 0xd574, Hi: 0xd574, Stride: 0x1}, + unicode.Range16{Lo: 0xd590, Hi: 0xd590, Stride: 0x1}, + unicode.Range16{Lo: 0xd5ac, Hi: 0xd5ac, Stride: 0x1}, + unicode.Range16{Lo: 0xd5c8, Hi: 0xd5c8, Stride: 0x1}, + unicode.Range16{Lo: 0xd5e4, Hi: 0xd5e4, Stride: 0x1}, + unicode.Range16{Lo: 0xd600, Hi: 0xd600, Stride: 0x1}, + unicode.Range16{Lo: 0xd61c, Hi: 0xd61c, Stride: 0x1}, + unicode.Range16{Lo: 0xd638, Hi: 0xd638, Stride: 0x1}, + unicode.Range16{Lo: 0xd654, Hi: 0xd654, Stride: 0x1}, + unicode.Range16{Lo: 0xd670, Hi: 0xd670, Stride: 0x1}, + unicode.Range16{Lo: 0xd68c, Hi: 0xd68c, Stride: 0x1}, + unicode.Range16{Lo: 0xd6a8, Hi: 0xd6a8, Stride: 0x1}, + unicode.Range16{Lo: 0xd6c4, Hi: 0xd6c4, Stride: 0x1}, + unicode.Range16{Lo: 0xd6e0, Hi: 0xd6e0, Stride: 0x1}, + unicode.Range16{Lo: 0xd6fc, Hi: 0xd6fc, Stride: 0x1}, + unicode.Range16{Lo: 0xd718, Hi: 0xd718, Stride: 0x1}, + unicode.Range16{Lo: 0xd734, Hi: 0xd734, Stride: 0x1}, + unicode.Range16{Lo: 0xd750, Hi: 0xd750, Stride: 0x1}, + unicode.Range16{Lo: 0xd76c, Hi: 0xd76c, Stride: 0x1}, + unicode.Range16{Lo: 0xd788, Hi: 0xd788, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _GraphemeCR = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xd, Hi: 0xd, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _GraphemeControl = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x0, Hi: 0x9, Stride: 0x1}, + unicode.Range16{Lo: 0xb, Hi: 0xc, Stride: 0x1}, + unicode.Range16{Lo: 0xe, Hi: 0x1f, Stride: 0x1}, + unicode.Range16{Lo: 0x7f, Hi: 0x9f, Stride: 0x1}, + unicode.Range16{Lo: 0xad, Hi: 0xad, Stride: 0x1}, + unicode.Range16{Lo: 0x600, Hi: 0x605, Stride: 0x1}, + unicode.Range16{Lo: 0x61c, Hi: 0x61c, Stride: 0x1}, + unicode.Range16{Lo: 0x6dd, Hi: 0x6dd, Stride: 0x1}, + unicode.Range16{Lo: 0x70f, Hi: 0x70f, Stride: 0x1}, + unicode.Range16{Lo: 0x180e, Hi: 0x180e, Stride: 0x1}, + unicode.Range16{Lo: 0x200b, Hi: 0x200b, Stride: 0x1}, + unicode.Range16{Lo: 0x200e, Hi: 0x200f, Stride: 0x1}, + unicode.Range16{Lo: 0x2028, Hi: 0x2028, Stride: 0x1}, + unicode.Range16{Lo: 0x2029, Hi: 0x2029, Stride: 0x1}, + unicode.Range16{Lo: 0x202a, Hi: 0x202e, Stride: 0x1}, + unicode.Range16{Lo: 0x2060, Hi: 0x2064, Stride: 0x1}, + unicode.Range16{Lo: 0x2065, Hi: 0x2065, Stride: 0x1}, + unicode.Range16{Lo: 0x2066, Hi: 0x206f, Stride: 0x1}, + unicode.Range16{Lo: 0xd800, Hi: 0xdfff, Stride: 0x1}, + unicode.Range16{Lo: 0xfeff, Hi: 0xfeff, Stride: 0x1}, + unicode.Range16{Lo: 0xfff0, Hi: 0xfff8, Stride: 0x1}, + unicode.Range16{Lo: 0xfff9, Hi: 0xfffb, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x110bd, Hi: 0x110bd, Stride: 0x1}, + unicode.Range32{Lo: 0x1bca0, Hi: 0x1bca3, Stride: 0x1}, + unicode.Range32{Lo: 0x1d173, Hi: 0x1d17a, Stride: 0x1}, + unicode.Range32{Lo: 0xe0000, Hi: 0xe0000, Stride: 0x1}, + unicode.Range32{Lo: 0xe0001, Hi: 0xe0001, Stride: 0x1}, + unicode.Range32{Lo: 0xe0002, Hi: 0xe001f, Stride: 0x1}, + unicode.Range32{Lo: 0xe0020, Hi: 0xe007f, Stride: 0x1}, + unicode.Range32{Lo: 0xe0080, Hi: 0xe00ff, Stride: 0x1}, + unicode.Range32{Lo: 0xe01f0, Hi: 0xe0fff, Stride: 0x1}, + }, + LatinOffset: 5, +} + +var _GraphemeV = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x1160, Hi: 0x11a7, Stride: 0x1}, + unicode.Range16{Lo: 0xd7b0, Hi: 0xd7c6, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _WordLF = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xa, Hi: 0xa, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordALetter = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x41, Hi: 0x5a, Stride: 0x1}, + unicode.Range16{Lo: 0x61, Hi: 0x7a, Stride: 0x1}, + unicode.Range16{Lo: 0xaa, Hi: 0xaa, Stride: 0x1}, + unicode.Range16{Lo: 0xb5, Hi: 0xb5, Stride: 0x1}, + unicode.Range16{Lo: 0xba, Hi: 0xba, Stride: 0x1}, + unicode.Range16{Lo: 0xc0, Hi: 0xd6, Stride: 0x1}, + unicode.Range16{Lo: 0xd8, Hi: 0xf6, Stride: 0x1}, + unicode.Range16{Lo: 0xf8, Hi: 0x1ba, Stride: 0x1}, + unicode.Range16{Lo: 0x1bb, Hi: 0x1bb, Stride: 0x1}, + unicode.Range16{Lo: 0x1bc, Hi: 0x1bf, Stride: 0x1}, + unicode.Range16{Lo: 0x1c0, Hi: 0x1c3, Stride: 0x1}, + unicode.Range16{Lo: 0x1c4, Hi: 0x293, Stride: 0x1}, + unicode.Range16{Lo: 0x294, Hi: 0x294, Stride: 0x1}, + unicode.Range16{Lo: 0x295, Hi: 0x2af, Stride: 0x1}, + unicode.Range16{Lo: 0x2b0, Hi: 0x2c1, Stride: 0x1}, + unicode.Range16{Lo: 0x2c6, Hi: 0x2d1, Stride: 0x1}, + unicode.Range16{Lo: 0x2e0, Hi: 0x2e4, Stride: 0x1}, + unicode.Range16{Lo: 0x2ec, Hi: 0x2ec, Stride: 0x1}, + unicode.Range16{Lo: 0x2ee, Hi: 0x2ee, Stride: 0x1}, + unicode.Range16{Lo: 0x370, Hi: 0x373, Stride: 0x1}, + unicode.Range16{Lo: 0x374, Hi: 0x374, Stride: 0x1}, + unicode.Range16{Lo: 0x376, Hi: 0x377, Stride: 0x1}, + unicode.Range16{Lo: 0x37a, Hi: 0x37a, Stride: 0x1}, + unicode.Range16{Lo: 0x37b, Hi: 0x37d, Stride: 0x1}, + unicode.Range16{Lo: 0x37f, Hi: 0x37f, Stride: 0x1}, + unicode.Range16{Lo: 0x386, Hi: 0x386, Stride: 0x1}, + unicode.Range16{Lo: 0x388, Hi: 0x38a, Stride: 0x1}, + unicode.Range16{Lo: 0x38c, Hi: 0x38c, Stride: 0x1}, + unicode.Range16{Lo: 0x38e, Hi: 0x3a1, Stride: 0x1}, + unicode.Range16{Lo: 0x3a3, Hi: 0x3f5, Stride: 0x1}, + unicode.Range16{Lo: 0x3f7, Hi: 0x481, Stride: 0x1}, + unicode.Range16{Lo: 0x48a, Hi: 0x52f, Stride: 0x1}, + unicode.Range16{Lo: 0x531, Hi: 0x556, Stride: 0x1}, + unicode.Range16{Lo: 0x559, Hi: 0x559, Stride: 0x1}, + unicode.Range16{Lo: 0x561, Hi: 0x587, Stride: 0x1}, + unicode.Range16{Lo: 0x5f3, Hi: 0x5f3, Stride: 0x1}, + unicode.Range16{Lo: 0x620, Hi: 0x63f, Stride: 0x1}, + unicode.Range16{Lo: 0x640, Hi: 0x640, Stride: 0x1}, + unicode.Range16{Lo: 0x641, Hi: 0x64a, Stride: 0x1}, + unicode.Range16{Lo: 0x66e, Hi: 0x66f, Stride: 0x1}, + unicode.Range16{Lo: 0x671, Hi: 0x6d3, Stride: 0x1}, + unicode.Range16{Lo: 0x6d5, Hi: 0x6d5, Stride: 0x1}, + unicode.Range16{Lo: 0x6e5, Hi: 0x6e6, Stride: 0x1}, + unicode.Range16{Lo: 0x6ee, Hi: 0x6ef, Stride: 0x1}, + unicode.Range16{Lo: 0x6fa, Hi: 0x6fc, Stride: 0x1}, + unicode.Range16{Lo: 0x6ff, Hi: 0x6ff, Stride: 0x1}, + unicode.Range16{Lo: 0x710, Hi: 0x710, Stride: 0x1}, + unicode.Range16{Lo: 0x712, Hi: 0x72f, Stride: 0x1}, + unicode.Range16{Lo: 0x74d, Hi: 0x7a5, Stride: 0x1}, + unicode.Range16{Lo: 0x7b1, Hi: 0x7b1, Stride: 0x1}, + unicode.Range16{Lo: 0x7ca, Hi: 0x7ea, Stride: 0x1}, + unicode.Range16{Lo: 0x7f4, Hi: 0x7f5, Stride: 0x1}, + unicode.Range16{Lo: 0x7fa, Hi: 0x7fa, Stride: 0x1}, + unicode.Range16{Lo: 0x800, Hi: 0x815, Stride: 0x1}, + unicode.Range16{Lo: 0x81a, Hi: 0x81a, Stride: 0x1}, + unicode.Range16{Lo: 0x824, Hi: 0x824, Stride: 0x1}, + unicode.Range16{Lo: 0x828, Hi: 0x828, Stride: 0x1}, + unicode.Range16{Lo: 0x840, Hi: 0x858, Stride: 0x1}, + unicode.Range16{Lo: 0x8a0, Hi: 0x8b2, Stride: 0x1}, + unicode.Range16{Lo: 0x904, Hi: 0x939, Stride: 0x1}, + unicode.Range16{Lo: 0x93d, Hi: 0x93d, Stride: 0x1}, + unicode.Range16{Lo: 0x950, Hi: 0x950, Stride: 0x1}, + unicode.Range16{Lo: 0x958, Hi: 0x961, Stride: 0x1}, + unicode.Range16{Lo: 0x971, Hi: 0x971, Stride: 0x1}, + unicode.Range16{Lo: 0x972, Hi: 0x980, Stride: 0x1}, + unicode.Range16{Lo: 0x985, Hi: 0x98c, Stride: 0x1}, + unicode.Range16{Lo: 0x98f, Hi: 0x990, Stride: 0x1}, + unicode.Range16{Lo: 0x993, Hi: 0x9a8, Stride: 0x1}, + unicode.Range16{Lo: 0x9aa, Hi: 0x9b0, Stride: 0x1}, + unicode.Range16{Lo: 0x9b2, Hi: 0x9b2, Stride: 0x1}, + unicode.Range16{Lo: 0x9b6, Hi: 0x9b9, Stride: 0x1}, + unicode.Range16{Lo: 0x9bd, Hi: 0x9bd, Stride: 0x1}, + unicode.Range16{Lo: 0x9ce, Hi: 0x9ce, Stride: 0x1}, + unicode.Range16{Lo: 0x9dc, Hi: 0x9dd, Stride: 0x1}, + unicode.Range16{Lo: 0x9df, Hi: 0x9e1, Stride: 0x1}, + unicode.Range16{Lo: 0x9f0, Hi: 0x9f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa05, Hi: 0xa0a, Stride: 0x1}, + unicode.Range16{Lo: 0xa0f, Hi: 0xa10, Stride: 0x1}, + unicode.Range16{Lo: 0xa13, Hi: 0xa28, Stride: 0x1}, + unicode.Range16{Lo: 0xa2a, Hi: 0xa30, Stride: 0x1}, + unicode.Range16{Lo: 0xa32, Hi: 0xa33, Stride: 0x1}, + unicode.Range16{Lo: 0xa35, Hi: 0xa36, Stride: 0x1}, + unicode.Range16{Lo: 0xa38, Hi: 0xa39, Stride: 0x1}, + unicode.Range16{Lo: 0xa59, Hi: 0xa5c, Stride: 0x1}, + unicode.Range16{Lo: 0xa5e, Hi: 0xa5e, Stride: 0x1}, + unicode.Range16{Lo: 0xa72, Hi: 0xa74, Stride: 0x1}, + unicode.Range16{Lo: 0xa85, Hi: 0xa8d, Stride: 0x1}, + unicode.Range16{Lo: 0xa8f, Hi: 0xa91, Stride: 0x1}, + unicode.Range16{Lo: 0xa93, Hi: 0xaa8, Stride: 0x1}, + unicode.Range16{Lo: 0xaaa, Hi: 0xab0, Stride: 0x1}, + unicode.Range16{Lo: 0xab2, Hi: 0xab3, Stride: 0x1}, + unicode.Range16{Lo: 0xab5, Hi: 0xab9, Stride: 0x1}, + unicode.Range16{Lo: 0xabd, Hi: 0xabd, Stride: 0x1}, + unicode.Range16{Lo: 0xad0, Hi: 0xad0, Stride: 0x1}, + unicode.Range16{Lo: 0xae0, Hi: 0xae1, Stride: 0x1}, + unicode.Range16{Lo: 0xb05, Hi: 0xb0c, Stride: 0x1}, + unicode.Range16{Lo: 0xb0f, Hi: 0xb10, Stride: 0x1}, + unicode.Range16{Lo: 0xb13, Hi: 0xb28, Stride: 0x1}, + unicode.Range16{Lo: 0xb2a, Hi: 0xb30, Stride: 0x1}, + unicode.Range16{Lo: 0xb32, Hi: 0xb33, Stride: 0x1}, + unicode.Range16{Lo: 0xb35, Hi: 0xb39, Stride: 0x1}, + unicode.Range16{Lo: 0xb3d, Hi: 0xb3d, Stride: 0x1}, + unicode.Range16{Lo: 0xb5c, Hi: 0xb5d, Stride: 0x1}, + unicode.Range16{Lo: 0xb5f, Hi: 0xb61, Stride: 0x1}, + unicode.Range16{Lo: 0xb71, Hi: 0xb71, Stride: 0x1}, + unicode.Range16{Lo: 0xb83, Hi: 0xb83, Stride: 0x1}, + unicode.Range16{Lo: 0xb85, Hi: 0xb8a, Stride: 0x1}, + unicode.Range16{Lo: 0xb8e, Hi: 0xb90, Stride: 0x1}, + unicode.Range16{Lo: 0xb92, Hi: 0xb95, Stride: 0x1}, + unicode.Range16{Lo: 0xb99, Hi: 0xb9a, Stride: 0x1}, + unicode.Range16{Lo: 0xb9c, Hi: 0xb9c, Stride: 0x1}, + unicode.Range16{Lo: 0xb9e, Hi: 0xb9f, Stride: 0x1}, + unicode.Range16{Lo: 0xba3, Hi: 0xba4, Stride: 0x1}, + unicode.Range16{Lo: 0xba8, Hi: 0xbaa, Stride: 0x1}, + unicode.Range16{Lo: 0xbae, Hi: 0xbb9, Stride: 0x1}, + unicode.Range16{Lo: 0xbd0, Hi: 0xbd0, Stride: 0x1}, + unicode.Range16{Lo: 0xc05, Hi: 0xc0c, Stride: 0x1}, + unicode.Range16{Lo: 0xc0e, Hi: 0xc10, Stride: 0x1}, + unicode.Range16{Lo: 0xc12, Hi: 0xc28, Stride: 0x1}, + unicode.Range16{Lo: 0xc2a, Hi: 0xc39, Stride: 0x1}, + unicode.Range16{Lo: 0xc3d, Hi: 0xc3d, Stride: 0x1}, + unicode.Range16{Lo: 0xc58, Hi: 0xc59, Stride: 0x1}, + unicode.Range16{Lo: 0xc60, Hi: 0xc61, Stride: 0x1}, + unicode.Range16{Lo: 0xc85, Hi: 0xc8c, Stride: 0x1}, + unicode.Range16{Lo: 0xc8e, Hi: 0xc90, Stride: 0x1}, + unicode.Range16{Lo: 0xc92, Hi: 0xca8, Stride: 0x1}, + unicode.Range16{Lo: 0xcaa, Hi: 0xcb3, Stride: 0x1}, + unicode.Range16{Lo: 0xcb5, Hi: 0xcb9, Stride: 0x1}, + unicode.Range16{Lo: 0xcbd, Hi: 0xcbd, Stride: 0x1}, + unicode.Range16{Lo: 0xcde, Hi: 0xcde, Stride: 0x1}, + unicode.Range16{Lo: 0xce0, Hi: 0xce1, Stride: 0x1}, + unicode.Range16{Lo: 0xcf1, Hi: 0xcf2, Stride: 0x1}, + unicode.Range16{Lo: 0xd05, Hi: 0xd0c, Stride: 0x1}, + unicode.Range16{Lo: 0xd0e, Hi: 0xd10, Stride: 0x1}, + unicode.Range16{Lo: 0xd12, Hi: 0xd3a, Stride: 0x1}, + unicode.Range16{Lo: 0xd3d, Hi: 0xd3d, Stride: 0x1}, + unicode.Range16{Lo: 0xd4e, Hi: 0xd4e, Stride: 0x1}, + unicode.Range16{Lo: 0xd60, Hi: 0xd61, Stride: 0x1}, + unicode.Range16{Lo: 0xd7a, Hi: 0xd7f, Stride: 0x1}, + unicode.Range16{Lo: 0xd85, Hi: 0xd96, Stride: 0x1}, + unicode.Range16{Lo: 0xd9a, Hi: 0xdb1, Stride: 0x1}, + unicode.Range16{Lo: 0xdb3, Hi: 0xdbb, Stride: 0x1}, + unicode.Range16{Lo: 0xdbd, Hi: 0xdbd, Stride: 0x1}, + unicode.Range16{Lo: 0xdc0, Hi: 0xdc6, Stride: 0x1}, + unicode.Range16{Lo: 0xf00, Hi: 0xf00, Stride: 0x1}, + unicode.Range16{Lo: 0xf40, Hi: 0xf47, Stride: 0x1}, + unicode.Range16{Lo: 0xf49, Hi: 0xf6c, Stride: 0x1}, + unicode.Range16{Lo: 0xf88, Hi: 0xf8c, Stride: 0x1}, + unicode.Range16{Lo: 0x10a0, Hi: 0x10c5, Stride: 0x1}, + unicode.Range16{Lo: 0x10c7, Hi: 0x10c7, Stride: 0x1}, + unicode.Range16{Lo: 0x10cd, Hi: 0x10cd, Stride: 0x1}, + unicode.Range16{Lo: 0x10d0, Hi: 0x10fa, Stride: 0x1}, + unicode.Range16{Lo: 0x10fc, Hi: 0x10fc, Stride: 0x1}, + unicode.Range16{Lo: 0x10fd, Hi: 0x1248, Stride: 0x1}, + unicode.Range16{Lo: 0x124a, Hi: 0x124d, Stride: 0x1}, + unicode.Range16{Lo: 0x1250, Hi: 0x1256, Stride: 0x1}, + unicode.Range16{Lo: 0x1258, Hi: 0x1258, Stride: 0x1}, + unicode.Range16{Lo: 0x125a, Hi: 0x125d, Stride: 0x1}, + unicode.Range16{Lo: 0x1260, Hi: 0x1288, Stride: 0x1}, + unicode.Range16{Lo: 0x128a, Hi: 0x128d, Stride: 0x1}, + unicode.Range16{Lo: 0x1290, Hi: 0x12b0, Stride: 0x1}, + unicode.Range16{Lo: 0x12b2, Hi: 0x12b5, Stride: 0x1}, + unicode.Range16{Lo: 0x12b8, Hi: 0x12be, Stride: 0x1}, + unicode.Range16{Lo: 0x12c0, Hi: 0x12c0, Stride: 0x1}, + unicode.Range16{Lo: 0x12c2, Hi: 0x12c5, Stride: 0x1}, + unicode.Range16{Lo: 0x12c8, Hi: 0x12d6, Stride: 0x1}, + unicode.Range16{Lo: 0x12d8, Hi: 0x1310, Stride: 0x1}, + unicode.Range16{Lo: 0x1312, Hi: 0x1315, Stride: 0x1}, + unicode.Range16{Lo: 0x1318, Hi: 0x135a, Stride: 0x1}, + unicode.Range16{Lo: 0x1380, Hi: 0x138f, Stride: 0x1}, + unicode.Range16{Lo: 0x13a0, Hi: 0x13f4, Stride: 0x1}, + unicode.Range16{Lo: 0x1401, Hi: 0x166c, Stride: 0x1}, + unicode.Range16{Lo: 0x166f, Hi: 0x167f, Stride: 0x1}, + unicode.Range16{Lo: 0x1681, Hi: 0x169a, Stride: 0x1}, + unicode.Range16{Lo: 0x16a0, Hi: 0x16ea, Stride: 0x1}, + unicode.Range16{Lo: 0x16ee, Hi: 0x16f0, Stride: 0x1}, + unicode.Range16{Lo: 0x16f1, Hi: 0x16f8, Stride: 0x1}, + unicode.Range16{Lo: 0x1700, Hi: 0x170c, Stride: 0x1}, + unicode.Range16{Lo: 0x170e, Hi: 0x1711, Stride: 0x1}, + unicode.Range16{Lo: 0x1720, Hi: 0x1731, Stride: 0x1}, + unicode.Range16{Lo: 0x1740, Hi: 0x1751, Stride: 0x1}, + unicode.Range16{Lo: 0x1760, Hi: 0x176c, Stride: 0x1}, + unicode.Range16{Lo: 0x176e, Hi: 0x1770, Stride: 0x1}, + unicode.Range16{Lo: 0x1820, Hi: 0x1842, Stride: 0x1}, + unicode.Range16{Lo: 0x1843, Hi: 0x1843, Stride: 0x1}, + unicode.Range16{Lo: 0x1844, Hi: 0x1877, Stride: 0x1}, + unicode.Range16{Lo: 0x1880, Hi: 0x18a8, Stride: 0x1}, + unicode.Range16{Lo: 0x18aa, Hi: 0x18aa, Stride: 0x1}, + unicode.Range16{Lo: 0x18b0, Hi: 0x18f5, Stride: 0x1}, + unicode.Range16{Lo: 0x1900, Hi: 0x191e, Stride: 0x1}, + unicode.Range16{Lo: 0x1a00, Hi: 0x1a16, Stride: 0x1}, + unicode.Range16{Lo: 0x1b05, Hi: 0x1b33, Stride: 0x1}, + unicode.Range16{Lo: 0x1b45, Hi: 0x1b4b, Stride: 0x1}, + unicode.Range16{Lo: 0x1b83, Hi: 0x1ba0, Stride: 0x1}, + unicode.Range16{Lo: 0x1bae, Hi: 0x1baf, Stride: 0x1}, + unicode.Range16{Lo: 0x1bba, Hi: 0x1be5, Stride: 0x1}, + unicode.Range16{Lo: 0x1c00, Hi: 0x1c23, Stride: 0x1}, + unicode.Range16{Lo: 0x1c4d, Hi: 0x1c4f, Stride: 0x1}, + unicode.Range16{Lo: 0x1c5a, Hi: 0x1c77, Stride: 0x1}, + unicode.Range16{Lo: 0x1c78, Hi: 0x1c7d, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce9, Hi: 0x1cec, Stride: 0x1}, + unicode.Range16{Lo: 0x1cee, Hi: 0x1cf1, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf5, Hi: 0x1cf6, Stride: 0x1}, + unicode.Range16{Lo: 0x1d00, Hi: 0x1d2b, Stride: 0x1}, + unicode.Range16{Lo: 0x1d2c, Hi: 0x1d6a, Stride: 0x1}, + unicode.Range16{Lo: 0x1d6b, Hi: 0x1d77, Stride: 0x1}, + unicode.Range16{Lo: 0x1d78, Hi: 0x1d78, Stride: 0x1}, + unicode.Range16{Lo: 0x1d79, Hi: 0x1d9a, Stride: 0x1}, + unicode.Range16{Lo: 0x1d9b, Hi: 0x1dbf, Stride: 0x1}, + unicode.Range16{Lo: 0x1e00, Hi: 0x1f15, Stride: 0x1}, + unicode.Range16{Lo: 0x1f18, Hi: 0x1f1d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f20, Hi: 0x1f45, Stride: 0x1}, + unicode.Range16{Lo: 0x1f48, Hi: 0x1f4d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f50, Hi: 0x1f57, Stride: 0x1}, + unicode.Range16{Lo: 0x1f59, Hi: 0x1f59, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5b, Hi: 0x1f5b, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5d, Hi: 0x1f5d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5f, Hi: 0x1f7d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f80, Hi: 0x1fb4, Stride: 0x1}, + unicode.Range16{Lo: 0x1fb6, Hi: 0x1fbc, Stride: 0x1}, + unicode.Range16{Lo: 0x1fbe, Hi: 0x1fbe, Stride: 0x1}, + unicode.Range16{Lo: 0x1fc2, Hi: 0x1fc4, Stride: 0x1}, + unicode.Range16{Lo: 0x1fc6, Hi: 0x1fcc, Stride: 0x1}, + unicode.Range16{Lo: 0x1fd0, Hi: 0x1fd3, Stride: 0x1}, + unicode.Range16{Lo: 0x1fd6, Hi: 0x1fdb, Stride: 0x1}, + unicode.Range16{Lo: 0x1fe0, Hi: 0x1fec, Stride: 0x1}, + unicode.Range16{Lo: 0x1ff2, Hi: 0x1ff4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ff6, Hi: 0x1ffc, Stride: 0x1}, + unicode.Range16{Lo: 0x2071, Hi: 0x2071, Stride: 0x1}, + unicode.Range16{Lo: 0x207f, Hi: 0x207f, Stride: 0x1}, + unicode.Range16{Lo: 0x2090, Hi: 0x209c, Stride: 0x1}, + unicode.Range16{Lo: 0x2102, Hi: 0x2102, Stride: 0x1}, + unicode.Range16{Lo: 0x2107, Hi: 0x2107, Stride: 0x1}, + unicode.Range16{Lo: 0x210a, Hi: 0x2113, Stride: 0x1}, + unicode.Range16{Lo: 0x2115, Hi: 0x2115, Stride: 0x1}, + unicode.Range16{Lo: 0x2119, Hi: 0x211d, Stride: 0x1}, + unicode.Range16{Lo: 0x2124, Hi: 0x2124, Stride: 0x1}, + unicode.Range16{Lo: 0x2126, Hi: 0x2126, Stride: 0x1}, + unicode.Range16{Lo: 0x2128, Hi: 0x2128, Stride: 0x1}, + unicode.Range16{Lo: 0x212a, Hi: 0x212d, Stride: 0x1}, + unicode.Range16{Lo: 0x212f, Hi: 0x2134, Stride: 0x1}, + unicode.Range16{Lo: 0x2135, Hi: 0x2138, Stride: 0x1}, + unicode.Range16{Lo: 0x2139, Hi: 0x2139, Stride: 0x1}, + unicode.Range16{Lo: 0x213c, Hi: 0x213f, Stride: 0x1}, + unicode.Range16{Lo: 0x2145, Hi: 0x2149, Stride: 0x1}, + unicode.Range16{Lo: 0x214e, Hi: 0x214e, Stride: 0x1}, + unicode.Range16{Lo: 0x2160, Hi: 0x2182, Stride: 0x1}, + unicode.Range16{Lo: 0x2183, Hi: 0x2184, Stride: 0x1}, + unicode.Range16{Lo: 0x2185, Hi: 0x2188, Stride: 0x1}, + unicode.Range16{Lo: 0x24b6, Hi: 0x24e9, Stride: 0x1}, + unicode.Range16{Lo: 0x2c00, Hi: 0x2c2e, Stride: 0x1}, + unicode.Range16{Lo: 0x2c30, Hi: 0x2c5e, Stride: 0x1}, + unicode.Range16{Lo: 0x2c60, Hi: 0x2c7b, Stride: 0x1}, + unicode.Range16{Lo: 0x2c7c, Hi: 0x2c7d, Stride: 0x1}, + unicode.Range16{Lo: 0x2c7e, Hi: 0x2ce4, Stride: 0x1}, + unicode.Range16{Lo: 0x2ceb, Hi: 0x2cee, Stride: 0x1}, + unicode.Range16{Lo: 0x2cf2, Hi: 0x2cf3, Stride: 0x1}, + unicode.Range16{Lo: 0x2d00, Hi: 0x2d25, Stride: 0x1}, + unicode.Range16{Lo: 0x2d27, Hi: 0x2d27, Stride: 0x1}, + unicode.Range16{Lo: 0x2d2d, Hi: 0x2d2d, Stride: 0x1}, + unicode.Range16{Lo: 0x2d30, Hi: 0x2d67, Stride: 0x1}, + unicode.Range16{Lo: 0x2d6f, Hi: 0x2d6f, Stride: 0x1}, + unicode.Range16{Lo: 0x2d80, Hi: 0x2d96, Stride: 0x1}, + unicode.Range16{Lo: 0x2da0, Hi: 0x2da6, Stride: 0x1}, + unicode.Range16{Lo: 0x2da8, Hi: 0x2dae, Stride: 0x1}, + unicode.Range16{Lo: 0x2db0, Hi: 0x2db6, Stride: 0x1}, + unicode.Range16{Lo: 0x2db8, Hi: 0x2dbe, Stride: 0x1}, + unicode.Range16{Lo: 0x2dc0, Hi: 0x2dc6, Stride: 0x1}, + unicode.Range16{Lo: 0x2dc8, Hi: 0x2dce, Stride: 0x1}, + unicode.Range16{Lo: 0x2dd0, Hi: 0x2dd6, Stride: 0x1}, + unicode.Range16{Lo: 0x2dd8, Hi: 0x2dde, Stride: 0x1}, + unicode.Range16{Lo: 0x2e2f, Hi: 0x2e2f, Stride: 0x1}, + unicode.Range16{Lo: 0x3005, Hi: 0x3005, Stride: 0x1}, + unicode.Range16{Lo: 0x303b, Hi: 0x303b, Stride: 0x1}, + unicode.Range16{Lo: 0x303c, Hi: 0x303c, Stride: 0x1}, + unicode.Range16{Lo: 0x3105, Hi: 0x312d, Stride: 0x1}, + unicode.Range16{Lo: 0x3131, Hi: 0x318e, Stride: 0x1}, + unicode.Range16{Lo: 0x31a0, Hi: 0x31ba, Stride: 0x1}, + unicode.Range16{Lo: 0xa000, Hi: 0xa014, Stride: 0x1}, + unicode.Range16{Lo: 0xa015, Hi: 0xa015, Stride: 0x1}, + unicode.Range16{Lo: 0xa016, Hi: 0xa48c, Stride: 0x1}, + unicode.Range16{Lo: 0xa4d0, Hi: 0xa4f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa4f8, Hi: 0xa4fd, Stride: 0x1}, + unicode.Range16{Lo: 0xa500, Hi: 0xa60b, Stride: 0x1}, + unicode.Range16{Lo: 0xa60c, Hi: 0xa60c, Stride: 0x1}, + unicode.Range16{Lo: 0xa610, Hi: 0xa61f, Stride: 0x1}, + unicode.Range16{Lo: 0xa62a, Hi: 0xa62b, Stride: 0x1}, + unicode.Range16{Lo: 0xa640, Hi: 0xa66d, Stride: 0x1}, + unicode.Range16{Lo: 0xa66e, Hi: 0xa66e, Stride: 0x1}, + unicode.Range16{Lo: 0xa67f, Hi: 0xa67f, Stride: 0x1}, + unicode.Range16{Lo: 0xa680, Hi: 0xa69b, Stride: 0x1}, + unicode.Range16{Lo: 0xa69c, Hi: 0xa69d, Stride: 0x1}, + unicode.Range16{Lo: 0xa6a0, Hi: 0xa6e5, Stride: 0x1}, + unicode.Range16{Lo: 0xa6e6, Hi: 0xa6ef, Stride: 0x1}, + unicode.Range16{Lo: 0xa717, Hi: 0xa71f, Stride: 0x1}, + unicode.Range16{Lo: 0xa722, Hi: 0xa76f, Stride: 0x1}, + unicode.Range16{Lo: 0xa770, Hi: 0xa770, Stride: 0x1}, + unicode.Range16{Lo: 0xa771, Hi: 0xa787, Stride: 0x1}, + unicode.Range16{Lo: 0xa788, Hi: 0xa788, Stride: 0x1}, + unicode.Range16{Lo: 0xa78b, Hi: 0xa78e, Stride: 0x1}, + unicode.Range16{Lo: 0xa790, Hi: 0xa7ad, Stride: 0x1}, + unicode.Range16{Lo: 0xa7b0, Hi: 0xa7b1, Stride: 0x1}, + unicode.Range16{Lo: 0xa7f7, Hi: 0xa7f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa7f8, Hi: 0xa7f9, Stride: 0x1}, + unicode.Range16{Lo: 0xa7fa, Hi: 0xa7fa, Stride: 0x1}, + unicode.Range16{Lo: 0xa7fb, Hi: 0xa801, Stride: 0x1}, + unicode.Range16{Lo: 0xa803, Hi: 0xa805, Stride: 0x1}, + unicode.Range16{Lo: 0xa807, Hi: 0xa80a, Stride: 0x1}, + unicode.Range16{Lo: 0xa80c, Hi: 0xa822, Stride: 0x1}, + unicode.Range16{Lo: 0xa840, Hi: 0xa873, Stride: 0x1}, + unicode.Range16{Lo: 0xa882, Hi: 0xa8b3, Stride: 0x1}, + unicode.Range16{Lo: 0xa8f2, Hi: 0xa8f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa8fb, Hi: 0xa8fb, Stride: 0x1}, + unicode.Range16{Lo: 0xa90a, Hi: 0xa925, Stride: 0x1}, + unicode.Range16{Lo: 0xa930, Hi: 0xa946, Stride: 0x1}, + unicode.Range16{Lo: 0xa960, Hi: 0xa97c, Stride: 0x1}, + unicode.Range16{Lo: 0xa984, Hi: 0xa9b2, Stride: 0x1}, + unicode.Range16{Lo: 0xa9cf, Hi: 0xa9cf, Stride: 0x1}, + unicode.Range16{Lo: 0xaa00, Hi: 0xaa28, Stride: 0x1}, + unicode.Range16{Lo: 0xaa40, Hi: 0xaa42, Stride: 0x1}, + unicode.Range16{Lo: 0xaa44, Hi: 0xaa4b, Stride: 0x1}, + unicode.Range16{Lo: 0xaae0, Hi: 0xaaea, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf2, Hi: 0xaaf2, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf3, Hi: 0xaaf4, Stride: 0x1}, + unicode.Range16{Lo: 0xab01, Hi: 0xab06, Stride: 0x1}, + unicode.Range16{Lo: 0xab09, Hi: 0xab0e, Stride: 0x1}, + unicode.Range16{Lo: 0xab11, Hi: 0xab16, Stride: 0x1}, + unicode.Range16{Lo: 0xab20, Hi: 0xab26, Stride: 0x1}, + unicode.Range16{Lo: 0xab28, Hi: 0xab2e, Stride: 0x1}, + unicode.Range16{Lo: 0xab30, Hi: 0xab5a, Stride: 0x1}, + unicode.Range16{Lo: 0xab5c, Hi: 0xab5f, Stride: 0x1}, + unicode.Range16{Lo: 0xab64, Hi: 0xab65, Stride: 0x1}, + unicode.Range16{Lo: 0xabc0, Hi: 0xabe2, Stride: 0x1}, + unicode.Range16{Lo: 0xac00, Hi: 0xd7a3, Stride: 0x1}, + unicode.Range16{Lo: 0xd7b0, Hi: 0xd7c6, Stride: 0x1}, + unicode.Range16{Lo: 0xd7cb, Hi: 0xd7fb, Stride: 0x1}, + unicode.Range16{Lo: 0xfb00, Hi: 0xfb06, Stride: 0x1}, + unicode.Range16{Lo: 0xfb13, Hi: 0xfb17, Stride: 0x1}, + unicode.Range16{Lo: 0xfb50, Hi: 0xfbb1, Stride: 0x1}, + unicode.Range16{Lo: 0xfbd3, Hi: 0xfd3d, Stride: 0x1}, + unicode.Range16{Lo: 0xfd50, Hi: 0xfd8f, Stride: 0x1}, + unicode.Range16{Lo: 0xfd92, Hi: 0xfdc7, Stride: 0x1}, + unicode.Range16{Lo: 0xfdf0, Hi: 0xfdfb, Stride: 0x1}, + unicode.Range16{Lo: 0xfe70, Hi: 0xfe74, Stride: 0x1}, + unicode.Range16{Lo: 0xfe76, Hi: 0xfefc, Stride: 0x1}, + unicode.Range16{Lo: 0xff21, Hi: 0xff3a, Stride: 0x1}, + unicode.Range16{Lo: 0xff41, Hi: 0xff5a, Stride: 0x1}, + unicode.Range16{Lo: 0xffa0, Hi: 0xffbe, Stride: 0x1}, + unicode.Range16{Lo: 0xffc2, Hi: 0xffc7, Stride: 0x1}, + unicode.Range16{Lo: 0xffca, Hi: 0xffcf, Stride: 0x1}, + unicode.Range16{Lo: 0xffd2, Hi: 0xffd7, Stride: 0x1}, + unicode.Range16{Lo: 0xffda, Hi: 0xffdc, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x10000, Hi: 0x1000b, Stride: 0x1}, + unicode.Range32{Lo: 0x1000d, Hi: 0x10026, Stride: 0x1}, + unicode.Range32{Lo: 0x10028, Hi: 0x1003a, Stride: 0x1}, + unicode.Range32{Lo: 0x1003c, Hi: 0x1003d, Stride: 0x1}, + unicode.Range32{Lo: 0x1003f, Hi: 0x1004d, Stride: 0x1}, + unicode.Range32{Lo: 0x10050, Hi: 0x1005d, Stride: 0x1}, + unicode.Range32{Lo: 0x10080, Hi: 0x100fa, Stride: 0x1}, + unicode.Range32{Lo: 0x10140, Hi: 0x10174, Stride: 0x1}, + unicode.Range32{Lo: 0x10280, Hi: 0x1029c, Stride: 0x1}, + unicode.Range32{Lo: 0x102a0, Hi: 0x102d0, Stride: 0x1}, + unicode.Range32{Lo: 0x10300, Hi: 0x1031f, Stride: 0x1}, + unicode.Range32{Lo: 0x10330, Hi: 0x10340, Stride: 0x1}, + unicode.Range32{Lo: 0x10341, Hi: 0x10341, Stride: 0x1}, + unicode.Range32{Lo: 0x10342, Hi: 0x10349, Stride: 0x1}, + unicode.Range32{Lo: 0x1034a, Hi: 0x1034a, Stride: 0x1}, + unicode.Range32{Lo: 0x10350, Hi: 0x10375, Stride: 0x1}, + unicode.Range32{Lo: 0x10380, Hi: 0x1039d, Stride: 0x1}, + unicode.Range32{Lo: 0x103a0, Hi: 0x103c3, Stride: 0x1}, + unicode.Range32{Lo: 0x103c8, Hi: 0x103cf, Stride: 0x1}, + unicode.Range32{Lo: 0x103d1, Hi: 0x103d5, Stride: 0x1}, + unicode.Range32{Lo: 0x10400, Hi: 0x1044f, Stride: 0x1}, + unicode.Range32{Lo: 0x10450, Hi: 0x1049d, Stride: 0x1}, + unicode.Range32{Lo: 0x10500, Hi: 0x10527, Stride: 0x1}, + unicode.Range32{Lo: 0x10530, Hi: 0x10563, Stride: 0x1}, + unicode.Range32{Lo: 0x10600, Hi: 0x10736, Stride: 0x1}, + unicode.Range32{Lo: 0x10740, Hi: 0x10755, Stride: 0x1}, + unicode.Range32{Lo: 0x10760, Hi: 0x10767, Stride: 0x1}, + unicode.Range32{Lo: 0x10800, Hi: 0x10805, Stride: 0x1}, + unicode.Range32{Lo: 0x10808, Hi: 0x10808, Stride: 0x1}, + unicode.Range32{Lo: 0x1080a, Hi: 0x10835, Stride: 0x1}, + unicode.Range32{Lo: 0x10837, Hi: 0x10838, Stride: 0x1}, + unicode.Range32{Lo: 0x1083c, Hi: 0x1083c, Stride: 0x1}, + unicode.Range32{Lo: 0x1083f, Hi: 0x10855, Stride: 0x1}, + unicode.Range32{Lo: 0x10860, Hi: 0x10876, Stride: 0x1}, + unicode.Range32{Lo: 0x10880, Hi: 0x1089e, Stride: 0x1}, + unicode.Range32{Lo: 0x10900, Hi: 0x10915, Stride: 0x1}, + unicode.Range32{Lo: 0x10920, Hi: 0x10939, Stride: 0x1}, + unicode.Range32{Lo: 0x10980, Hi: 0x109b7, Stride: 0x1}, + unicode.Range32{Lo: 0x109be, Hi: 0x109bf, Stride: 0x1}, + unicode.Range32{Lo: 0x10a00, Hi: 0x10a00, Stride: 0x1}, + unicode.Range32{Lo: 0x10a10, Hi: 0x10a13, Stride: 0x1}, + unicode.Range32{Lo: 0x10a15, Hi: 0x10a17, Stride: 0x1}, + unicode.Range32{Lo: 0x10a19, Hi: 0x10a33, Stride: 0x1}, + unicode.Range32{Lo: 0x10a60, Hi: 0x10a7c, Stride: 0x1}, + unicode.Range32{Lo: 0x10a80, Hi: 0x10a9c, Stride: 0x1}, + unicode.Range32{Lo: 0x10ac0, Hi: 0x10ac7, Stride: 0x1}, + unicode.Range32{Lo: 0x10ac9, Hi: 0x10ae4, Stride: 0x1}, + unicode.Range32{Lo: 0x10b00, Hi: 0x10b35, Stride: 0x1}, + unicode.Range32{Lo: 0x10b40, Hi: 0x10b55, Stride: 0x1}, + unicode.Range32{Lo: 0x10b60, Hi: 0x10b72, Stride: 0x1}, + unicode.Range32{Lo: 0x10b80, Hi: 0x10b91, Stride: 0x1}, + unicode.Range32{Lo: 0x10c00, Hi: 0x10c48, Stride: 0x1}, + unicode.Range32{Lo: 0x11003, Hi: 0x11037, Stride: 0x1}, + unicode.Range32{Lo: 0x11083, Hi: 0x110af, Stride: 0x1}, + unicode.Range32{Lo: 0x110d0, Hi: 0x110e8, Stride: 0x1}, + unicode.Range32{Lo: 0x11103, Hi: 0x11126, Stride: 0x1}, + unicode.Range32{Lo: 0x11150, Hi: 0x11172, Stride: 0x1}, + unicode.Range32{Lo: 0x11176, Hi: 0x11176, Stride: 0x1}, + unicode.Range32{Lo: 0x11183, Hi: 0x111b2, Stride: 0x1}, + unicode.Range32{Lo: 0x111c1, Hi: 0x111c4, Stride: 0x1}, + unicode.Range32{Lo: 0x111da, Hi: 0x111da, Stride: 0x1}, + unicode.Range32{Lo: 0x11200, Hi: 0x11211, Stride: 0x1}, + unicode.Range32{Lo: 0x11213, Hi: 0x1122b, Stride: 0x1}, + unicode.Range32{Lo: 0x112b0, Hi: 0x112de, Stride: 0x1}, + unicode.Range32{Lo: 0x11305, Hi: 0x1130c, Stride: 0x1}, + unicode.Range32{Lo: 0x1130f, Hi: 0x11310, Stride: 0x1}, + unicode.Range32{Lo: 0x11313, Hi: 0x11328, Stride: 0x1}, + unicode.Range32{Lo: 0x1132a, Hi: 0x11330, Stride: 0x1}, + unicode.Range32{Lo: 0x11332, Hi: 0x11333, Stride: 0x1}, + unicode.Range32{Lo: 0x11335, Hi: 0x11339, Stride: 0x1}, + unicode.Range32{Lo: 0x1133d, Hi: 0x1133d, Stride: 0x1}, + unicode.Range32{Lo: 0x1135d, Hi: 0x11361, Stride: 0x1}, + unicode.Range32{Lo: 0x11480, Hi: 0x114af, Stride: 0x1}, + unicode.Range32{Lo: 0x114c4, Hi: 0x114c5, Stride: 0x1}, + unicode.Range32{Lo: 0x114c7, Hi: 0x114c7, Stride: 0x1}, + unicode.Range32{Lo: 0x11580, Hi: 0x115ae, Stride: 0x1}, + unicode.Range32{Lo: 0x11600, Hi: 0x1162f, Stride: 0x1}, + unicode.Range32{Lo: 0x11644, Hi: 0x11644, Stride: 0x1}, + unicode.Range32{Lo: 0x11680, Hi: 0x116aa, Stride: 0x1}, + unicode.Range32{Lo: 0x118a0, Hi: 0x118df, Stride: 0x1}, + unicode.Range32{Lo: 0x118ff, Hi: 0x118ff, Stride: 0x1}, + unicode.Range32{Lo: 0x11ac0, Hi: 0x11af8, Stride: 0x1}, + unicode.Range32{Lo: 0x12000, Hi: 0x12398, Stride: 0x1}, + unicode.Range32{Lo: 0x12400, Hi: 0x1246e, Stride: 0x1}, + unicode.Range32{Lo: 0x13000, Hi: 0x1342e, Stride: 0x1}, + unicode.Range32{Lo: 0x16800, Hi: 0x16a38, Stride: 0x1}, + unicode.Range32{Lo: 0x16a40, Hi: 0x16a5e, Stride: 0x1}, + unicode.Range32{Lo: 0x16ad0, Hi: 0x16aed, Stride: 0x1}, + unicode.Range32{Lo: 0x16b00, Hi: 0x16b2f, Stride: 0x1}, + unicode.Range32{Lo: 0x16b40, Hi: 0x16b43, Stride: 0x1}, + unicode.Range32{Lo: 0x16b63, Hi: 0x16b77, Stride: 0x1}, + unicode.Range32{Lo: 0x16b7d, Hi: 0x16b8f, Stride: 0x1}, + unicode.Range32{Lo: 0x16f00, Hi: 0x16f44, Stride: 0x1}, + unicode.Range32{Lo: 0x16f50, Hi: 0x16f50, Stride: 0x1}, + unicode.Range32{Lo: 0x16f93, Hi: 0x16f9f, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc00, Hi: 0x1bc6a, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc70, Hi: 0x1bc7c, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc80, Hi: 0x1bc88, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc90, Hi: 0x1bc99, Stride: 0x1}, + unicode.Range32{Lo: 0x1d400, Hi: 0x1d454, Stride: 0x1}, + unicode.Range32{Lo: 0x1d456, Hi: 0x1d49c, Stride: 0x1}, + unicode.Range32{Lo: 0x1d49e, Hi: 0x1d49f, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4a2, Hi: 0x1d4a2, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4a5, Hi: 0x1d4a6, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4a9, Hi: 0x1d4ac, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4ae, Hi: 0x1d4b9, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4bb, Hi: 0x1d4bb, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4bd, Hi: 0x1d4c3, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4c5, Hi: 0x1d505, Stride: 0x1}, + unicode.Range32{Lo: 0x1d507, Hi: 0x1d50a, Stride: 0x1}, + unicode.Range32{Lo: 0x1d50d, Hi: 0x1d514, Stride: 0x1}, + unicode.Range32{Lo: 0x1d516, Hi: 0x1d51c, Stride: 0x1}, + unicode.Range32{Lo: 0x1d51e, Hi: 0x1d539, Stride: 0x1}, + unicode.Range32{Lo: 0x1d53b, Hi: 0x1d53e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d540, Hi: 0x1d544, Stride: 0x1}, + unicode.Range32{Lo: 0x1d546, Hi: 0x1d546, Stride: 0x1}, + unicode.Range32{Lo: 0x1d54a, Hi: 0x1d550, Stride: 0x1}, + unicode.Range32{Lo: 0x1d552, Hi: 0x1d6a5, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6a8, Hi: 0x1d6c0, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6c2, Hi: 0x1d6da, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6dc, Hi: 0x1d6fa, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6fc, Hi: 0x1d714, Stride: 0x1}, + unicode.Range32{Lo: 0x1d716, Hi: 0x1d734, Stride: 0x1}, + unicode.Range32{Lo: 0x1d736, Hi: 0x1d74e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d750, Hi: 0x1d76e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d770, Hi: 0x1d788, Stride: 0x1}, + unicode.Range32{Lo: 0x1d78a, Hi: 0x1d7a8, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7aa, Hi: 0x1d7c2, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7c4, Hi: 0x1d7cb, Stride: 0x1}, + unicode.Range32{Lo: 0x1e800, Hi: 0x1e8c4, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee00, Hi: 0x1ee03, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee05, Hi: 0x1ee1f, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee21, Hi: 0x1ee22, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee24, Hi: 0x1ee24, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee27, Hi: 0x1ee27, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee29, Hi: 0x1ee32, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee34, Hi: 0x1ee37, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee39, Hi: 0x1ee39, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee3b, Hi: 0x1ee3b, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee42, Hi: 0x1ee42, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee47, Hi: 0x1ee47, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee49, Hi: 0x1ee49, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee4b, Hi: 0x1ee4b, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee4d, Hi: 0x1ee4f, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee51, Hi: 0x1ee52, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee54, Hi: 0x1ee54, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee57, Hi: 0x1ee57, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee59, Hi: 0x1ee59, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee5b, Hi: 0x1ee5b, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee5d, Hi: 0x1ee5d, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee5f, Hi: 0x1ee5f, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee61, Hi: 0x1ee62, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee64, Hi: 0x1ee64, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee67, Hi: 0x1ee6a, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee6c, Hi: 0x1ee72, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee74, Hi: 0x1ee77, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee79, Hi: 0x1ee7c, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee7e, Hi: 0x1ee7e, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee80, Hi: 0x1ee89, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee8b, Hi: 0x1ee9b, Stride: 0x1}, + unicode.Range32{Lo: 0x1eea1, Hi: 0x1eea3, Stride: 0x1}, + unicode.Range32{Lo: 0x1eea5, Hi: 0x1eea9, Stride: 0x1}, + unicode.Range32{Lo: 0x1eeab, Hi: 0x1eebb, Stride: 0x1}, + unicode.Range32{Lo: 0x1f130, Hi: 0x1f149, Stride: 0x1}, + unicode.Range32{Lo: 0x1f150, Hi: 0x1f169, Stride: 0x1}, + unicode.Range32{Lo: 0x1f170, Hi: 0x1f189, Stride: 0x1}, + }, + LatinOffset: 7, +} + +var _WordSingle_Quote = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x27, Hi: 0x27, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordRegional_Indicator = &unicode.RangeTable{ + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x1f1e6, Hi: 0x1f1ff, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _WordMidNumLet = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x2e, Hi: 0x2e, Stride: 0x1}, + unicode.Range16{Lo: 0x2018, Hi: 0x2018, Stride: 0x1}, + unicode.Range16{Lo: 0x2019, Hi: 0x2019, Stride: 0x1}, + unicode.Range16{Lo: 0x2024, Hi: 0x2024, Stride: 0x1}, + unicode.Range16{Lo: 0xfe52, Hi: 0xfe52, Stride: 0x1}, + unicode.Range16{Lo: 0xff07, Hi: 0xff07, Stride: 0x1}, + unicode.Range16{Lo: 0xff0e, Hi: 0xff0e, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordMidLetter = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x3a, Hi: 0x3a, Stride: 0x1}, + unicode.Range16{Lo: 0xb7, Hi: 0xb7, Stride: 0x1}, + unicode.Range16{Lo: 0x2d7, Hi: 0x2d7, Stride: 0x1}, + unicode.Range16{Lo: 0x387, Hi: 0x387, Stride: 0x1}, + unicode.Range16{Lo: 0x5f4, Hi: 0x5f4, Stride: 0x1}, + unicode.Range16{Lo: 0x2027, Hi: 0x2027, Stride: 0x1}, + unicode.Range16{Lo: 0xfe13, Hi: 0xfe13, Stride: 0x1}, + unicode.Range16{Lo: 0xfe55, Hi: 0xfe55, Stride: 0x1}, + unicode.Range16{Lo: 0xff1a, Hi: 0xff1a, Stride: 0x1}, + }, + LatinOffset: 2, +} + +var _WordExtendNumLet = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x5f, Hi: 0x5f, Stride: 0x1}, + unicode.Range16{Lo: 0x203f, Hi: 0x2040, Stride: 0x1}, + unicode.Range16{Lo: 0x2054, Hi: 0x2054, Stride: 0x1}, + unicode.Range16{Lo: 0xfe33, Hi: 0xfe34, Stride: 0x1}, + unicode.Range16{Lo: 0xfe4d, Hi: 0xfe4f, Stride: 0x1}, + unicode.Range16{Lo: 0xff3f, Hi: 0xff3f, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordDouble_Quote = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x22, Hi: 0x22, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordHebrew_Letter = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x5d0, Hi: 0x5ea, Stride: 0x1}, + unicode.Range16{Lo: 0x5f0, Hi: 0x5f2, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1d, Hi: 0xfb1d, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1f, Hi: 0xfb28, Stride: 0x1}, + unicode.Range16{Lo: 0xfb2a, Hi: 0xfb36, Stride: 0x1}, + unicode.Range16{Lo: 0xfb38, Hi: 0xfb3c, Stride: 0x1}, + unicode.Range16{Lo: 0xfb3e, Hi: 0xfb3e, Stride: 0x1}, + unicode.Range16{Lo: 0xfb40, Hi: 0xfb41, Stride: 0x1}, + unicode.Range16{Lo: 0xfb43, Hi: 0xfb44, Stride: 0x1}, + unicode.Range16{Lo: 0xfb46, Hi: 0xfb4f, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _WordCR = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xd, Hi: 0xd, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordExtend = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x300, Hi: 0x36f, Stride: 0x1}, + unicode.Range16{Lo: 0x483, Hi: 0x487, Stride: 0x1}, + unicode.Range16{Lo: 0x488, Hi: 0x489, Stride: 0x1}, + unicode.Range16{Lo: 0x591, Hi: 0x5bd, Stride: 0x1}, + unicode.Range16{Lo: 0x5bf, Hi: 0x5bf, Stride: 0x1}, + unicode.Range16{Lo: 0x5c1, Hi: 0x5c2, Stride: 0x1}, + unicode.Range16{Lo: 0x5c4, Hi: 0x5c5, Stride: 0x1}, + unicode.Range16{Lo: 0x5c7, Hi: 0x5c7, Stride: 0x1}, + unicode.Range16{Lo: 0x610, Hi: 0x61a, Stride: 0x1}, + unicode.Range16{Lo: 0x64b, Hi: 0x65f, Stride: 0x1}, + unicode.Range16{Lo: 0x670, Hi: 0x670, Stride: 0x1}, + unicode.Range16{Lo: 0x6d6, Hi: 0x6dc, Stride: 0x1}, + unicode.Range16{Lo: 0x6df, Hi: 0x6e4, Stride: 0x1}, + unicode.Range16{Lo: 0x6e7, Hi: 0x6e8, Stride: 0x1}, + unicode.Range16{Lo: 0x6ea, Hi: 0x6ed, Stride: 0x1}, + unicode.Range16{Lo: 0x711, Hi: 0x711, Stride: 0x1}, + unicode.Range16{Lo: 0x730, Hi: 0x74a, Stride: 0x1}, + unicode.Range16{Lo: 0x7a6, Hi: 0x7b0, Stride: 0x1}, + unicode.Range16{Lo: 0x7eb, Hi: 0x7f3, Stride: 0x1}, + unicode.Range16{Lo: 0x816, Hi: 0x819, Stride: 0x1}, + unicode.Range16{Lo: 0x81b, Hi: 0x823, Stride: 0x1}, + unicode.Range16{Lo: 0x825, Hi: 0x827, Stride: 0x1}, + unicode.Range16{Lo: 0x829, Hi: 0x82d, Stride: 0x1}, + unicode.Range16{Lo: 0x859, Hi: 0x85b, Stride: 0x1}, + unicode.Range16{Lo: 0x8e4, Hi: 0x902, Stride: 0x1}, + unicode.Range16{Lo: 0x903, Hi: 0x903, Stride: 0x1}, + unicode.Range16{Lo: 0x93a, Hi: 0x93a, Stride: 0x1}, + unicode.Range16{Lo: 0x93b, Hi: 0x93b, Stride: 0x1}, + unicode.Range16{Lo: 0x93c, Hi: 0x93c, Stride: 0x1}, + unicode.Range16{Lo: 0x93e, Hi: 0x940, Stride: 0x1}, + unicode.Range16{Lo: 0x941, Hi: 0x948, Stride: 0x1}, + unicode.Range16{Lo: 0x949, Hi: 0x94c, Stride: 0x1}, + unicode.Range16{Lo: 0x94d, Hi: 0x94d, Stride: 0x1}, + unicode.Range16{Lo: 0x94e, Hi: 0x94f, Stride: 0x1}, + unicode.Range16{Lo: 0x951, Hi: 0x957, Stride: 0x1}, + unicode.Range16{Lo: 0x962, Hi: 0x963, Stride: 0x1}, + unicode.Range16{Lo: 0x981, Hi: 0x981, Stride: 0x1}, + unicode.Range16{Lo: 0x982, Hi: 0x983, Stride: 0x1}, + unicode.Range16{Lo: 0x9bc, Hi: 0x9bc, Stride: 0x1}, + unicode.Range16{Lo: 0x9be, Hi: 0x9c0, Stride: 0x1}, + unicode.Range16{Lo: 0x9c1, Hi: 0x9c4, Stride: 0x1}, + unicode.Range16{Lo: 0x9c7, Hi: 0x9c8, Stride: 0x1}, + unicode.Range16{Lo: 0x9cb, Hi: 0x9cc, Stride: 0x1}, + unicode.Range16{Lo: 0x9cd, Hi: 0x9cd, Stride: 0x1}, + unicode.Range16{Lo: 0x9d7, Hi: 0x9d7, Stride: 0x1}, + unicode.Range16{Lo: 0x9e2, Hi: 0x9e3, Stride: 0x1}, + unicode.Range16{Lo: 0xa01, Hi: 0xa02, Stride: 0x1}, + unicode.Range16{Lo: 0xa03, Hi: 0xa03, Stride: 0x1}, + unicode.Range16{Lo: 0xa3c, Hi: 0xa3c, Stride: 0x1}, + unicode.Range16{Lo: 0xa3e, Hi: 0xa40, Stride: 0x1}, + unicode.Range16{Lo: 0xa41, Hi: 0xa42, Stride: 0x1}, + unicode.Range16{Lo: 0xa47, Hi: 0xa48, Stride: 0x1}, + unicode.Range16{Lo: 0xa4b, Hi: 0xa4d, Stride: 0x1}, + unicode.Range16{Lo: 0xa51, Hi: 0xa51, Stride: 0x1}, + unicode.Range16{Lo: 0xa70, Hi: 0xa71, Stride: 0x1}, + unicode.Range16{Lo: 0xa75, Hi: 0xa75, Stride: 0x1}, + unicode.Range16{Lo: 0xa81, Hi: 0xa82, Stride: 0x1}, + unicode.Range16{Lo: 0xa83, Hi: 0xa83, Stride: 0x1}, + unicode.Range16{Lo: 0xabc, Hi: 0xabc, Stride: 0x1}, + unicode.Range16{Lo: 0xabe, Hi: 0xac0, Stride: 0x1}, + unicode.Range16{Lo: 0xac1, Hi: 0xac5, Stride: 0x1}, + unicode.Range16{Lo: 0xac7, Hi: 0xac8, Stride: 0x1}, + unicode.Range16{Lo: 0xac9, Hi: 0xac9, Stride: 0x1}, + unicode.Range16{Lo: 0xacb, Hi: 0xacc, Stride: 0x1}, + unicode.Range16{Lo: 0xacd, Hi: 0xacd, Stride: 0x1}, + unicode.Range16{Lo: 0xae2, Hi: 0xae3, Stride: 0x1}, + unicode.Range16{Lo: 0xb01, Hi: 0xb01, Stride: 0x1}, + unicode.Range16{Lo: 0xb02, Hi: 0xb03, Stride: 0x1}, + unicode.Range16{Lo: 0xb3c, Hi: 0xb3c, Stride: 0x1}, + unicode.Range16{Lo: 0xb3e, Hi: 0xb3e, Stride: 0x1}, + unicode.Range16{Lo: 0xb3f, Hi: 0xb3f, Stride: 0x1}, + unicode.Range16{Lo: 0xb40, Hi: 0xb40, Stride: 0x1}, + unicode.Range16{Lo: 0xb41, Hi: 0xb44, Stride: 0x1}, + unicode.Range16{Lo: 0xb47, Hi: 0xb48, Stride: 0x1}, + unicode.Range16{Lo: 0xb4b, Hi: 0xb4c, Stride: 0x1}, + unicode.Range16{Lo: 0xb4d, Hi: 0xb4d, Stride: 0x1}, + unicode.Range16{Lo: 0xb56, Hi: 0xb56, Stride: 0x1}, + unicode.Range16{Lo: 0xb57, Hi: 0xb57, Stride: 0x1}, + unicode.Range16{Lo: 0xb62, Hi: 0xb63, Stride: 0x1}, + unicode.Range16{Lo: 0xb82, Hi: 0xb82, Stride: 0x1}, + unicode.Range16{Lo: 0xbbe, Hi: 0xbbf, Stride: 0x1}, + unicode.Range16{Lo: 0xbc0, Hi: 0xbc0, Stride: 0x1}, + unicode.Range16{Lo: 0xbc1, Hi: 0xbc2, Stride: 0x1}, + unicode.Range16{Lo: 0xbc6, Hi: 0xbc8, Stride: 0x1}, + unicode.Range16{Lo: 0xbca, Hi: 0xbcc, Stride: 0x1}, + unicode.Range16{Lo: 0xbcd, Hi: 0xbcd, Stride: 0x1}, + unicode.Range16{Lo: 0xbd7, Hi: 0xbd7, Stride: 0x1}, + unicode.Range16{Lo: 0xc00, Hi: 0xc00, Stride: 0x1}, + unicode.Range16{Lo: 0xc01, Hi: 0xc03, Stride: 0x1}, + unicode.Range16{Lo: 0xc3e, Hi: 0xc40, Stride: 0x1}, + unicode.Range16{Lo: 0xc41, Hi: 0xc44, Stride: 0x1}, + unicode.Range16{Lo: 0xc46, Hi: 0xc48, Stride: 0x1}, + unicode.Range16{Lo: 0xc4a, Hi: 0xc4d, Stride: 0x1}, + unicode.Range16{Lo: 0xc55, Hi: 0xc56, Stride: 0x1}, + unicode.Range16{Lo: 0xc62, Hi: 0xc63, Stride: 0x1}, + unicode.Range16{Lo: 0xc81, Hi: 0xc81, Stride: 0x1}, + unicode.Range16{Lo: 0xc82, Hi: 0xc83, Stride: 0x1}, + unicode.Range16{Lo: 0xcbc, Hi: 0xcbc, Stride: 0x1}, + unicode.Range16{Lo: 0xcbe, Hi: 0xcbe, Stride: 0x1}, + unicode.Range16{Lo: 0xcbf, Hi: 0xcbf, Stride: 0x1}, + unicode.Range16{Lo: 0xcc0, Hi: 0xcc4, Stride: 0x1}, + unicode.Range16{Lo: 0xcc6, Hi: 0xcc6, Stride: 0x1}, + unicode.Range16{Lo: 0xcc7, Hi: 0xcc8, Stride: 0x1}, + unicode.Range16{Lo: 0xcca, Hi: 0xccb, Stride: 0x1}, + unicode.Range16{Lo: 0xccc, Hi: 0xccd, Stride: 0x1}, + unicode.Range16{Lo: 0xcd5, Hi: 0xcd6, Stride: 0x1}, + unicode.Range16{Lo: 0xce2, Hi: 0xce3, Stride: 0x1}, + unicode.Range16{Lo: 0xd01, Hi: 0xd01, Stride: 0x1}, + unicode.Range16{Lo: 0xd02, Hi: 0xd03, Stride: 0x1}, + unicode.Range16{Lo: 0xd3e, Hi: 0xd40, Stride: 0x1}, + unicode.Range16{Lo: 0xd41, Hi: 0xd44, Stride: 0x1}, + unicode.Range16{Lo: 0xd46, Hi: 0xd48, Stride: 0x1}, + unicode.Range16{Lo: 0xd4a, Hi: 0xd4c, Stride: 0x1}, + unicode.Range16{Lo: 0xd4d, Hi: 0xd4d, Stride: 0x1}, + unicode.Range16{Lo: 0xd57, Hi: 0xd57, Stride: 0x1}, + unicode.Range16{Lo: 0xd62, Hi: 0xd63, Stride: 0x1}, + unicode.Range16{Lo: 0xd82, Hi: 0xd83, Stride: 0x1}, + unicode.Range16{Lo: 0xdca, Hi: 0xdca, Stride: 0x1}, + unicode.Range16{Lo: 0xdcf, Hi: 0xdd1, Stride: 0x1}, + unicode.Range16{Lo: 0xdd2, Hi: 0xdd4, Stride: 0x1}, + unicode.Range16{Lo: 0xdd6, Hi: 0xdd6, Stride: 0x1}, + unicode.Range16{Lo: 0xdd8, Hi: 0xddf, Stride: 0x1}, + unicode.Range16{Lo: 0xdf2, Hi: 0xdf3, Stride: 0x1}, + unicode.Range16{Lo: 0xe31, Hi: 0xe31, Stride: 0x1}, + unicode.Range16{Lo: 0xe34, Hi: 0xe3a, Stride: 0x1}, + unicode.Range16{Lo: 0xe47, Hi: 0xe4e, Stride: 0x1}, + unicode.Range16{Lo: 0xeb1, Hi: 0xeb1, Stride: 0x1}, + unicode.Range16{Lo: 0xeb4, Hi: 0xeb9, Stride: 0x1}, + unicode.Range16{Lo: 0xebb, Hi: 0xebc, Stride: 0x1}, + unicode.Range16{Lo: 0xec8, Hi: 0xecd, Stride: 0x1}, + unicode.Range16{Lo: 0xf18, Hi: 0xf19, Stride: 0x1}, + unicode.Range16{Lo: 0xf35, Hi: 0xf35, Stride: 0x1}, + unicode.Range16{Lo: 0xf37, Hi: 0xf37, Stride: 0x1}, + unicode.Range16{Lo: 0xf39, Hi: 0xf39, Stride: 0x1}, + unicode.Range16{Lo: 0xf3e, Hi: 0xf3f, Stride: 0x1}, + unicode.Range16{Lo: 0xf71, Hi: 0xf7e, Stride: 0x1}, + unicode.Range16{Lo: 0xf7f, Hi: 0xf7f, Stride: 0x1}, + unicode.Range16{Lo: 0xf80, Hi: 0xf84, Stride: 0x1}, + unicode.Range16{Lo: 0xf86, Hi: 0xf87, Stride: 0x1}, + unicode.Range16{Lo: 0xf8d, Hi: 0xf97, Stride: 0x1}, + unicode.Range16{Lo: 0xf99, Hi: 0xfbc, Stride: 0x1}, + unicode.Range16{Lo: 0xfc6, Hi: 0xfc6, Stride: 0x1}, + unicode.Range16{Lo: 0x102b, Hi: 0x102c, Stride: 0x1}, + unicode.Range16{Lo: 0x102d, Hi: 0x1030, Stride: 0x1}, + unicode.Range16{Lo: 0x1031, Hi: 0x1031, Stride: 0x1}, + unicode.Range16{Lo: 0x1032, Hi: 0x1037, Stride: 0x1}, + unicode.Range16{Lo: 0x1038, Hi: 0x1038, Stride: 0x1}, + unicode.Range16{Lo: 0x1039, Hi: 0x103a, Stride: 0x1}, + unicode.Range16{Lo: 0x103b, Hi: 0x103c, Stride: 0x1}, + unicode.Range16{Lo: 0x103d, Hi: 0x103e, Stride: 0x1}, + unicode.Range16{Lo: 0x1056, Hi: 0x1057, Stride: 0x1}, + unicode.Range16{Lo: 0x1058, Hi: 0x1059, Stride: 0x1}, + unicode.Range16{Lo: 0x105e, Hi: 0x1060, Stride: 0x1}, + unicode.Range16{Lo: 0x1062, Hi: 0x1064, Stride: 0x1}, + unicode.Range16{Lo: 0x1067, Hi: 0x106d, Stride: 0x1}, + unicode.Range16{Lo: 0x1071, Hi: 0x1074, Stride: 0x1}, + unicode.Range16{Lo: 0x1082, Hi: 0x1082, Stride: 0x1}, + unicode.Range16{Lo: 0x1083, Hi: 0x1084, Stride: 0x1}, + unicode.Range16{Lo: 0x1085, Hi: 0x1086, Stride: 0x1}, + unicode.Range16{Lo: 0x1087, Hi: 0x108c, Stride: 0x1}, + unicode.Range16{Lo: 0x108d, Hi: 0x108d, Stride: 0x1}, + unicode.Range16{Lo: 0x108f, Hi: 0x108f, Stride: 0x1}, + unicode.Range16{Lo: 0x109a, Hi: 0x109c, Stride: 0x1}, + unicode.Range16{Lo: 0x109d, Hi: 0x109d, Stride: 0x1}, + unicode.Range16{Lo: 0x135d, Hi: 0x135f, Stride: 0x1}, + unicode.Range16{Lo: 0x1712, Hi: 0x1714, Stride: 0x1}, + unicode.Range16{Lo: 0x1732, Hi: 0x1734, Stride: 0x1}, + unicode.Range16{Lo: 0x1752, Hi: 0x1753, Stride: 0x1}, + unicode.Range16{Lo: 0x1772, Hi: 0x1773, Stride: 0x1}, + unicode.Range16{Lo: 0x17b4, Hi: 0x17b5, Stride: 0x1}, + unicode.Range16{Lo: 0x17b6, Hi: 0x17b6, Stride: 0x1}, + unicode.Range16{Lo: 0x17b7, Hi: 0x17bd, Stride: 0x1}, + unicode.Range16{Lo: 0x17be, Hi: 0x17c5, Stride: 0x1}, + unicode.Range16{Lo: 0x17c6, Hi: 0x17c6, Stride: 0x1}, + unicode.Range16{Lo: 0x17c7, Hi: 0x17c8, Stride: 0x1}, + unicode.Range16{Lo: 0x17c9, Hi: 0x17d3, Stride: 0x1}, + unicode.Range16{Lo: 0x17dd, Hi: 0x17dd, Stride: 0x1}, + unicode.Range16{Lo: 0x180b, Hi: 0x180d, Stride: 0x1}, + unicode.Range16{Lo: 0x18a9, Hi: 0x18a9, Stride: 0x1}, + unicode.Range16{Lo: 0x1920, Hi: 0x1922, Stride: 0x1}, + unicode.Range16{Lo: 0x1923, Hi: 0x1926, Stride: 0x1}, + unicode.Range16{Lo: 0x1927, Hi: 0x1928, Stride: 0x1}, + unicode.Range16{Lo: 0x1929, Hi: 0x192b, Stride: 0x1}, + unicode.Range16{Lo: 0x1930, Hi: 0x1931, Stride: 0x1}, + unicode.Range16{Lo: 0x1932, Hi: 0x1932, Stride: 0x1}, + unicode.Range16{Lo: 0x1933, Hi: 0x1938, Stride: 0x1}, + unicode.Range16{Lo: 0x1939, Hi: 0x193b, Stride: 0x1}, + unicode.Range16{Lo: 0x19b0, Hi: 0x19c0, Stride: 0x1}, + unicode.Range16{Lo: 0x19c8, Hi: 0x19c9, Stride: 0x1}, + unicode.Range16{Lo: 0x1a17, Hi: 0x1a18, Stride: 0x1}, + unicode.Range16{Lo: 0x1a19, Hi: 0x1a1a, Stride: 0x1}, + unicode.Range16{Lo: 0x1a1b, Hi: 0x1a1b, Stride: 0x1}, + unicode.Range16{Lo: 0x1a55, Hi: 0x1a55, Stride: 0x1}, + unicode.Range16{Lo: 0x1a56, Hi: 0x1a56, Stride: 0x1}, + unicode.Range16{Lo: 0x1a57, Hi: 0x1a57, Stride: 0x1}, + unicode.Range16{Lo: 0x1a58, Hi: 0x1a5e, Stride: 0x1}, + unicode.Range16{Lo: 0x1a60, Hi: 0x1a60, Stride: 0x1}, + unicode.Range16{Lo: 0x1a61, Hi: 0x1a61, Stride: 0x1}, + unicode.Range16{Lo: 0x1a62, Hi: 0x1a62, Stride: 0x1}, + unicode.Range16{Lo: 0x1a63, Hi: 0x1a64, Stride: 0x1}, + unicode.Range16{Lo: 0x1a65, Hi: 0x1a6c, Stride: 0x1}, + unicode.Range16{Lo: 0x1a6d, Hi: 0x1a72, Stride: 0x1}, + unicode.Range16{Lo: 0x1a73, Hi: 0x1a7c, Stride: 0x1}, + unicode.Range16{Lo: 0x1a7f, Hi: 0x1a7f, Stride: 0x1}, + unicode.Range16{Lo: 0x1ab0, Hi: 0x1abd, Stride: 0x1}, + unicode.Range16{Lo: 0x1abe, Hi: 0x1abe, Stride: 0x1}, + unicode.Range16{Lo: 0x1b00, Hi: 0x1b03, Stride: 0x1}, + unicode.Range16{Lo: 0x1b04, Hi: 0x1b04, Stride: 0x1}, + unicode.Range16{Lo: 0x1b34, Hi: 0x1b34, Stride: 0x1}, + unicode.Range16{Lo: 0x1b35, Hi: 0x1b35, Stride: 0x1}, + unicode.Range16{Lo: 0x1b36, Hi: 0x1b3a, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3b, Hi: 0x1b3b, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3c, Hi: 0x1b3c, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3d, Hi: 0x1b41, Stride: 0x1}, + unicode.Range16{Lo: 0x1b42, Hi: 0x1b42, Stride: 0x1}, + unicode.Range16{Lo: 0x1b43, Hi: 0x1b44, Stride: 0x1}, + unicode.Range16{Lo: 0x1b6b, Hi: 0x1b73, Stride: 0x1}, + unicode.Range16{Lo: 0x1b80, Hi: 0x1b81, Stride: 0x1}, + unicode.Range16{Lo: 0x1b82, Hi: 0x1b82, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba1, Hi: 0x1ba1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba2, Hi: 0x1ba5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba6, Hi: 0x1ba7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba8, Hi: 0x1ba9, Stride: 0x1}, + unicode.Range16{Lo: 0x1baa, Hi: 0x1baa, Stride: 0x1}, + unicode.Range16{Lo: 0x1bab, Hi: 0x1bad, Stride: 0x1}, + unicode.Range16{Lo: 0x1be6, Hi: 0x1be6, Stride: 0x1}, + unicode.Range16{Lo: 0x1be7, Hi: 0x1be7, Stride: 0x1}, + unicode.Range16{Lo: 0x1be8, Hi: 0x1be9, Stride: 0x1}, + unicode.Range16{Lo: 0x1bea, Hi: 0x1bec, Stride: 0x1}, + unicode.Range16{Lo: 0x1bed, Hi: 0x1bed, Stride: 0x1}, + unicode.Range16{Lo: 0x1bee, Hi: 0x1bee, Stride: 0x1}, + unicode.Range16{Lo: 0x1bef, Hi: 0x1bf1, Stride: 0x1}, + unicode.Range16{Lo: 0x1bf2, Hi: 0x1bf3, Stride: 0x1}, + unicode.Range16{Lo: 0x1c24, Hi: 0x1c2b, Stride: 0x1}, + unicode.Range16{Lo: 0x1c2c, Hi: 0x1c33, Stride: 0x1}, + unicode.Range16{Lo: 0x1c34, Hi: 0x1c35, Stride: 0x1}, + unicode.Range16{Lo: 0x1c36, Hi: 0x1c37, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd0, Hi: 0x1cd2, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd4, Hi: 0x1ce0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce1, Hi: 0x1ce1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce2, Hi: 0x1ce8, Stride: 0x1}, + unicode.Range16{Lo: 0x1ced, Hi: 0x1ced, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf2, Hi: 0x1cf3, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf4, Hi: 0x1cf4, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf8, Hi: 0x1cf9, Stride: 0x1}, + unicode.Range16{Lo: 0x1dc0, Hi: 0x1df5, Stride: 0x1}, + unicode.Range16{Lo: 0x1dfc, Hi: 0x1dff, Stride: 0x1}, + unicode.Range16{Lo: 0x200c, Hi: 0x200d, Stride: 0x1}, + unicode.Range16{Lo: 0x20d0, Hi: 0x20dc, Stride: 0x1}, + unicode.Range16{Lo: 0x20dd, Hi: 0x20e0, Stride: 0x1}, + unicode.Range16{Lo: 0x20e1, Hi: 0x20e1, Stride: 0x1}, + unicode.Range16{Lo: 0x20e2, Hi: 0x20e4, Stride: 0x1}, + unicode.Range16{Lo: 0x20e5, Hi: 0x20f0, Stride: 0x1}, + unicode.Range16{Lo: 0x2cef, Hi: 0x2cf1, Stride: 0x1}, + unicode.Range16{Lo: 0x2d7f, Hi: 0x2d7f, Stride: 0x1}, + unicode.Range16{Lo: 0x2de0, Hi: 0x2dff, Stride: 0x1}, + unicode.Range16{Lo: 0x302a, Hi: 0x302d, Stride: 0x1}, + unicode.Range16{Lo: 0x302e, Hi: 0x302f, Stride: 0x1}, + unicode.Range16{Lo: 0x3099, Hi: 0x309a, Stride: 0x1}, + unicode.Range16{Lo: 0xa66f, Hi: 0xa66f, Stride: 0x1}, + unicode.Range16{Lo: 0xa670, Hi: 0xa672, Stride: 0x1}, + unicode.Range16{Lo: 0xa674, Hi: 0xa67d, Stride: 0x1}, + unicode.Range16{Lo: 0xa69f, Hi: 0xa69f, Stride: 0x1}, + unicode.Range16{Lo: 0xa6f0, Hi: 0xa6f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa802, Hi: 0xa802, Stride: 0x1}, + unicode.Range16{Lo: 0xa806, Hi: 0xa806, Stride: 0x1}, + unicode.Range16{Lo: 0xa80b, Hi: 0xa80b, Stride: 0x1}, + unicode.Range16{Lo: 0xa823, Hi: 0xa824, Stride: 0x1}, + unicode.Range16{Lo: 0xa825, Hi: 0xa826, Stride: 0x1}, + unicode.Range16{Lo: 0xa827, Hi: 0xa827, Stride: 0x1}, + unicode.Range16{Lo: 0xa880, Hi: 0xa881, Stride: 0x1}, + unicode.Range16{Lo: 0xa8b4, Hi: 0xa8c3, Stride: 0x1}, + unicode.Range16{Lo: 0xa8c4, Hi: 0xa8c4, Stride: 0x1}, + unicode.Range16{Lo: 0xa8e0, Hi: 0xa8f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa926, Hi: 0xa92d, Stride: 0x1}, + unicode.Range16{Lo: 0xa947, Hi: 0xa951, Stride: 0x1}, + unicode.Range16{Lo: 0xa952, Hi: 0xa953, Stride: 0x1}, + unicode.Range16{Lo: 0xa980, Hi: 0xa982, Stride: 0x1}, + unicode.Range16{Lo: 0xa983, Hi: 0xa983, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b3, Hi: 0xa9b3, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b4, Hi: 0xa9b5, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b6, Hi: 0xa9b9, Stride: 0x1}, + unicode.Range16{Lo: 0xa9ba, Hi: 0xa9bb, Stride: 0x1}, + unicode.Range16{Lo: 0xa9bc, Hi: 0xa9bc, Stride: 0x1}, + unicode.Range16{Lo: 0xa9bd, Hi: 0xa9c0, Stride: 0x1}, + unicode.Range16{Lo: 0xa9e5, Hi: 0xa9e5, Stride: 0x1}, + unicode.Range16{Lo: 0xaa29, Hi: 0xaa2e, Stride: 0x1}, + unicode.Range16{Lo: 0xaa2f, Hi: 0xaa30, Stride: 0x1}, + unicode.Range16{Lo: 0xaa31, Hi: 0xaa32, Stride: 0x1}, + unicode.Range16{Lo: 0xaa33, Hi: 0xaa34, Stride: 0x1}, + unicode.Range16{Lo: 0xaa35, Hi: 0xaa36, Stride: 0x1}, + unicode.Range16{Lo: 0xaa43, Hi: 0xaa43, Stride: 0x1}, + unicode.Range16{Lo: 0xaa4c, Hi: 0xaa4c, Stride: 0x1}, + unicode.Range16{Lo: 0xaa4d, Hi: 0xaa4d, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7b, Hi: 0xaa7b, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7c, Hi: 0xaa7c, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7d, Hi: 0xaa7d, Stride: 0x1}, + unicode.Range16{Lo: 0xaab0, Hi: 0xaab0, Stride: 0x1}, + unicode.Range16{Lo: 0xaab2, Hi: 0xaab4, Stride: 0x1}, + unicode.Range16{Lo: 0xaab7, Hi: 0xaab8, Stride: 0x1}, + unicode.Range16{Lo: 0xaabe, Hi: 0xaabf, Stride: 0x1}, + unicode.Range16{Lo: 0xaac1, Hi: 0xaac1, Stride: 0x1}, + unicode.Range16{Lo: 0xaaeb, Hi: 0xaaeb, Stride: 0x1}, + unicode.Range16{Lo: 0xaaec, Hi: 0xaaed, Stride: 0x1}, + unicode.Range16{Lo: 0xaaee, Hi: 0xaaef, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf5, Hi: 0xaaf5, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf6, Hi: 0xaaf6, Stride: 0x1}, + unicode.Range16{Lo: 0xabe3, Hi: 0xabe4, Stride: 0x1}, + unicode.Range16{Lo: 0xabe5, Hi: 0xabe5, Stride: 0x1}, + unicode.Range16{Lo: 0xabe6, Hi: 0xabe7, Stride: 0x1}, + unicode.Range16{Lo: 0xabe8, Hi: 0xabe8, Stride: 0x1}, + unicode.Range16{Lo: 0xabe9, Hi: 0xabea, Stride: 0x1}, + unicode.Range16{Lo: 0xabec, Hi: 0xabec, Stride: 0x1}, + unicode.Range16{Lo: 0xabed, Hi: 0xabed, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1e, Hi: 0xfb1e, Stride: 0x1}, + unicode.Range16{Lo: 0xfe00, Hi: 0xfe0f, Stride: 0x1}, + unicode.Range16{Lo: 0xfe20, Hi: 0xfe2d, Stride: 0x1}, + unicode.Range16{Lo: 0xff9e, Hi: 0xff9f, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x101fd, Hi: 0x101fd, Stride: 0x1}, + unicode.Range32{Lo: 0x102e0, Hi: 0x102e0, Stride: 0x1}, + unicode.Range32{Lo: 0x10376, Hi: 0x1037a, Stride: 0x1}, + unicode.Range32{Lo: 0x10a01, Hi: 0x10a03, Stride: 0x1}, + unicode.Range32{Lo: 0x10a05, Hi: 0x10a06, Stride: 0x1}, + unicode.Range32{Lo: 0x10a0c, Hi: 0x10a0f, Stride: 0x1}, + unicode.Range32{Lo: 0x10a38, Hi: 0x10a3a, Stride: 0x1}, + unicode.Range32{Lo: 0x10a3f, Hi: 0x10a3f, Stride: 0x1}, + unicode.Range32{Lo: 0x10ae5, Hi: 0x10ae6, Stride: 0x1}, + unicode.Range32{Lo: 0x11000, Hi: 0x11000, Stride: 0x1}, + unicode.Range32{Lo: 0x11001, Hi: 0x11001, Stride: 0x1}, + unicode.Range32{Lo: 0x11002, Hi: 0x11002, Stride: 0x1}, + unicode.Range32{Lo: 0x11038, Hi: 0x11046, Stride: 0x1}, + unicode.Range32{Lo: 0x1107f, Hi: 0x11081, Stride: 0x1}, + unicode.Range32{Lo: 0x11082, Hi: 0x11082, Stride: 0x1}, + unicode.Range32{Lo: 0x110b0, Hi: 0x110b2, Stride: 0x1}, + unicode.Range32{Lo: 0x110b3, Hi: 0x110b6, Stride: 0x1}, + unicode.Range32{Lo: 0x110b7, Hi: 0x110b8, Stride: 0x1}, + unicode.Range32{Lo: 0x110b9, Hi: 0x110ba, Stride: 0x1}, + unicode.Range32{Lo: 0x11100, Hi: 0x11102, Stride: 0x1}, + unicode.Range32{Lo: 0x11127, Hi: 0x1112b, Stride: 0x1}, + unicode.Range32{Lo: 0x1112c, Hi: 0x1112c, Stride: 0x1}, + unicode.Range32{Lo: 0x1112d, Hi: 0x11134, Stride: 0x1}, + unicode.Range32{Lo: 0x11173, Hi: 0x11173, Stride: 0x1}, + unicode.Range32{Lo: 0x11180, Hi: 0x11181, Stride: 0x1}, + unicode.Range32{Lo: 0x11182, Hi: 0x11182, Stride: 0x1}, + unicode.Range32{Lo: 0x111b3, Hi: 0x111b5, Stride: 0x1}, + unicode.Range32{Lo: 0x111b6, Hi: 0x111be, Stride: 0x1}, + unicode.Range32{Lo: 0x111bf, Hi: 0x111c0, Stride: 0x1}, + unicode.Range32{Lo: 0x1122c, Hi: 0x1122e, Stride: 0x1}, + unicode.Range32{Lo: 0x1122f, Hi: 0x11231, Stride: 0x1}, + unicode.Range32{Lo: 0x11232, Hi: 0x11233, Stride: 0x1}, + unicode.Range32{Lo: 0x11234, Hi: 0x11234, Stride: 0x1}, + unicode.Range32{Lo: 0x11235, Hi: 0x11235, Stride: 0x1}, + unicode.Range32{Lo: 0x11236, Hi: 0x11237, Stride: 0x1}, + unicode.Range32{Lo: 0x112df, Hi: 0x112df, Stride: 0x1}, + unicode.Range32{Lo: 0x112e0, Hi: 0x112e2, Stride: 0x1}, + unicode.Range32{Lo: 0x112e3, Hi: 0x112ea, Stride: 0x1}, + unicode.Range32{Lo: 0x11301, Hi: 0x11301, Stride: 0x1}, + unicode.Range32{Lo: 0x11302, Hi: 0x11303, Stride: 0x1}, + unicode.Range32{Lo: 0x1133c, Hi: 0x1133c, Stride: 0x1}, + unicode.Range32{Lo: 0x1133e, Hi: 0x1133f, Stride: 0x1}, + unicode.Range32{Lo: 0x11340, Hi: 0x11340, Stride: 0x1}, + unicode.Range32{Lo: 0x11341, Hi: 0x11344, Stride: 0x1}, + unicode.Range32{Lo: 0x11347, Hi: 0x11348, Stride: 0x1}, + unicode.Range32{Lo: 0x1134b, Hi: 0x1134d, Stride: 0x1}, + unicode.Range32{Lo: 0x11357, Hi: 0x11357, Stride: 0x1}, + unicode.Range32{Lo: 0x11362, Hi: 0x11363, Stride: 0x1}, + unicode.Range32{Lo: 0x11366, Hi: 0x1136c, Stride: 0x1}, + unicode.Range32{Lo: 0x11370, Hi: 0x11374, Stride: 0x1}, + unicode.Range32{Lo: 0x114b0, Hi: 0x114b2, Stride: 0x1}, + unicode.Range32{Lo: 0x114b3, Hi: 0x114b8, Stride: 0x1}, + unicode.Range32{Lo: 0x114b9, Hi: 0x114b9, Stride: 0x1}, + unicode.Range32{Lo: 0x114ba, Hi: 0x114ba, Stride: 0x1}, + unicode.Range32{Lo: 0x114bb, Hi: 0x114be, Stride: 0x1}, + unicode.Range32{Lo: 0x114bf, Hi: 0x114c0, Stride: 0x1}, + unicode.Range32{Lo: 0x114c1, Hi: 0x114c1, Stride: 0x1}, + unicode.Range32{Lo: 0x114c2, Hi: 0x114c3, Stride: 0x1}, + unicode.Range32{Lo: 0x115af, Hi: 0x115b1, Stride: 0x1}, + unicode.Range32{Lo: 0x115b2, Hi: 0x115b5, Stride: 0x1}, + unicode.Range32{Lo: 0x115b8, Hi: 0x115bb, Stride: 0x1}, + unicode.Range32{Lo: 0x115bc, Hi: 0x115bd, Stride: 0x1}, + unicode.Range32{Lo: 0x115be, Hi: 0x115be, Stride: 0x1}, + unicode.Range32{Lo: 0x115bf, Hi: 0x115c0, Stride: 0x1}, + unicode.Range32{Lo: 0x11630, Hi: 0x11632, Stride: 0x1}, + unicode.Range32{Lo: 0x11633, Hi: 0x1163a, Stride: 0x1}, + unicode.Range32{Lo: 0x1163b, Hi: 0x1163c, Stride: 0x1}, + unicode.Range32{Lo: 0x1163d, Hi: 0x1163d, Stride: 0x1}, + unicode.Range32{Lo: 0x1163e, Hi: 0x1163e, Stride: 0x1}, + unicode.Range32{Lo: 0x1163f, Hi: 0x11640, Stride: 0x1}, + unicode.Range32{Lo: 0x116ab, Hi: 0x116ab, Stride: 0x1}, + unicode.Range32{Lo: 0x116ac, Hi: 0x116ac, Stride: 0x1}, + unicode.Range32{Lo: 0x116ad, Hi: 0x116ad, Stride: 0x1}, + unicode.Range32{Lo: 0x116ae, Hi: 0x116af, Stride: 0x1}, + unicode.Range32{Lo: 0x116b0, Hi: 0x116b5, Stride: 0x1}, + unicode.Range32{Lo: 0x116b6, Hi: 0x116b6, Stride: 0x1}, + unicode.Range32{Lo: 0x116b7, Hi: 0x116b7, Stride: 0x1}, + unicode.Range32{Lo: 0x16af0, Hi: 0x16af4, Stride: 0x1}, + unicode.Range32{Lo: 0x16b30, Hi: 0x16b36, Stride: 0x1}, + unicode.Range32{Lo: 0x16f51, Hi: 0x16f7e, Stride: 0x1}, + unicode.Range32{Lo: 0x16f8f, Hi: 0x16f92, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc9d, Hi: 0x1bc9e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d165, Hi: 0x1d166, Stride: 0x1}, + unicode.Range32{Lo: 0x1d167, Hi: 0x1d169, Stride: 0x1}, + unicode.Range32{Lo: 0x1d16d, Hi: 0x1d172, Stride: 0x1}, + unicode.Range32{Lo: 0x1d17b, Hi: 0x1d182, Stride: 0x1}, + unicode.Range32{Lo: 0x1d185, Hi: 0x1d18b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d1aa, Hi: 0x1d1ad, Stride: 0x1}, + unicode.Range32{Lo: 0x1d242, Hi: 0x1d244, Stride: 0x1}, + unicode.Range32{Lo: 0x1e8d0, Hi: 0x1e8d6, Stride: 0x1}, + unicode.Range32{Lo: 0xe0100, Hi: 0xe01ef, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _WordKatakana = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x3031, Hi: 0x3035, Stride: 0x1}, + unicode.Range16{Lo: 0x309b, Hi: 0x309c, Stride: 0x1}, + unicode.Range16{Lo: 0x30a0, Hi: 0x30a0, Stride: 0x1}, + unicode.Range16{Lo: 0x30a1, Hi: 0x30fa, Stride: 0x1}, + unicode.Range16{Lo: 0x30fc, Hi: 0x30fe, Stride: 0x1}, + unicode.Range16{Lo: 0x30ff, Hi: 0x30ff, Stride: 0x1}, + unicode.Range16{Lo: 0x31f0, Hi: 0x31ff, Stride: 0x1}, + unicode.Range16{Lo: 0x32d0, Hi: 0x32fe, Stride: 0x1}, + unicode.Range16{Lo: 0x3300, Hi: 0x3357, Stride: 0x1}, + unicode.Range16{Lo: 0xff66, Hi: 0xff6f, Stride: 0x1}, + unicode.Range16{Lo: 0xff70, Hi: 0xff70, Stride: 0x1}, + unicode.Range16{Lo: 0xff71, Hi: 0xff9d, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x1b000, Hi: 0x1b000, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _WordNewline = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xb, Hi: 0xc, Stride: 0x1}, + unicode.Range16{Lo: 0x85, Hi: 0x85, Stride: 0x1}, + unicode.Range16{Lo: 0x2028, Hi: 0x2028, Stride: 0x1}, + unicode.Range16{Lo: 0x2029, Hi: 0x2029, Stride: 0x1}, + }, + LatinOffset: 2, +} + +var _WordFormat = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xad, Hi: 0xad, Stride: 0x1}, + unicode.Range16{Lo: 0x600, Hi: 0x605, Stride: 0x1}, + unicode.Range16{Lo: 0x61c, Hi: 0x61c, Stride: 0x1}, + unicode.Range16{Lo: 0x6dd, Hi: 0x6dd, Stride: 0x1}, + unicode.Range16{Lo: 0x70f, Hi: 0x70f, Stride: 0x1}, + unicode.Range16{Lo: 0x180e, Hi: 0x180e, Stride: 0x1}, + unicode.Range16{Lo: 0x200e, Hi: 0x200f, Stride: 0x1}, + unicode.Range16{Lo: 0x202a, Hi: 0x202e, Stride: 0x1}, + unicode.Range16{Lo: 0x2060, Hi: 0x2064, Stride: 0x1}, + unicode.Range16{Lo: 0x2066, Hi: 0x206f, Stride: 0x1}, + unicode.Range16{Lo: 0xfeff, Hi: 0xfeff, Stride: 0x1}, + unicode.Range16{Lo: 0xfff9, Hi: 0xfffb, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x110bd, Hi: 0x110bd, Stride: 0x1}, + unicode.Range32{Lo: 0x1bca0, Hi: 0x1bca3, Stride: 0x1}, + unicode.Range32{Lo: 0x1d173, Hi: 0x1d17a, Stride: 0x1}, + unicode.Range32{Lo: 0xe0001, Hi: 0xe0001, Stride: 0x1}, + unicode.Range32{Lo: 0xe0020, Hi: 0xe007f, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _WordMidNum = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x2c, Hi: 0x2c, Stride: 0x1}, + unicode.Range16{Lo: 0x3b, Hi: 0x3b, Stride: 0x1}, + unicode.Range16{Lo: 0x37e, Hi: 0x37e, Stride: 0x1}, + unicode.Range16{Lo: 0x589, Hi: 0x589, Stride: 0x1}, + unicode.Range16{Lo: 0x60c, Hi: 0x60d, Stride: 0x1}, + unicode.Range16{Lo: 0x66c, Hi: 0x66c, Stride: 0x1}, + unicode.Range16{Lo: 0x7f8, Hi: 0x7f8, Stride: 0x1}, + unicode.Range16{Lo: 0x2044, Hi: 0x2044, Stride: 0x1}, + unicode.Range16{Lo: 0xfe10, Hi: 0xfe10, Stride: 0x1}, + unicode.Range16{Lo: 0xfe14, Hi: 0xfe14, Stride: 0x1}, + unicode.Range16{Lo: 0xfe50, Hi: 0xfe50, Stride: 0x1}, + unicode.Range16{Lo: 0xfe54, Hi: 0xfe54, Stride: 0x1}, + unicode.Range16{Lo: 0xff0c, Hi: 0xff0c, Stride: 0x1}, + unicode.Range16{Lo: 0xff1b, Hi: 0xff1b, Stride: 0x1}, + }, + LatinOffset: 2, +} + +var _WordNumeric = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x30, Hi: 0x39, Stride: 0x1}, + unicode.Range16{Lo: 0x660, Hi: 0x669, Stride: 0x1}, + unicode.Range16{Lo: 0x66b, Hi: 0x66b, Stride: 0x1}, + unicode.Range16{Lo: 0x6f0, Hi: 0x6f9, Stride: 0x1}, + unicode.Range16{Lo: 0x7c0, Hi: 0x7c9, Stride: 0x1}, + unicode.Range16{Lo: 0x966, Hi: 0x96f, Stride: 0x1}, + unicode.Range16{Lo: 0x9e6, Hi: 0x9ef, Stride: 0x1}, + unicode.Range16{Lo: 0xa66, Hi: 0xa6f, Stride: 0x1}, + unicode.Range16{Lo: 0xae6, Hi: 0xaef, Stride: 0x1}, + unicode.Range16{Lo: 0xb66, Hi: 0xb6f, Stride: 0x1}, + unicode.Range16{Lo: 0xbe6, Hi: 0xbef, Stride: 0x1}, + unicode.Range16{Lo: 0xc66, Hi: 0xc6f, Stride: 0x1}, + unicode.Range16{Lo: 0xce6, Hi: 0xcef, Stride: 0x1}, + unicode.Range16{Lo: 0xd66, Hi: 0xd6f, Stride: 0x1}, + unicode.Range16{Lo: 0xde6, Hi: 0xdef, Stride: 0x1}, + unicode.Range16{Lo: 0xe50, Hi: 0xe59, Stride: 0x1}, + unicode.Range16{Lo: 0xed0, Hi: 0xed9, Stride: 0x1}, + unicode.Range16{Lo: 0xf20, Hi: 0xf29, Stride: 0x1}, + unicode.Range16{Lo: 0x1040, Hi: 0x1049, Stride: 0x1}, + unicode.Range16{Lo: 0x1090, Hi: 0x1099, Stride: 0x1}, + unicode.Range16{Lo: 0x17e0, Hi: 0x17e9, Stride: 0x1}, + unicode.Range16{Lo: 0x1810, Hi: 0x1819, Stride: 0x1}, + unicode.Range16{Lo: 0x1946, Hi: 0x194f, Stride: 0x1}, + unicode.Range16{Lo: 0x19d0, Hi: 0x19d9, Stride: 0x1}, + unicode.Range16{Lo: 0x1a80, Hi: 0x1a89, Stride: 0x1}, + unicode.Range16{Lo: 0x1a90, Hi: 0x1a99, Stride: 0x1}, + unicode.Range16{Lo: 0x1b50, Hi: 0x1b59, Stride: 0x1}, + unicode.Range16{Lo: 0x1bb0, Hi: 0x1bb9, Stride: 0x1}, + unicode.Range16{Lo: 0x1c40, Hi: 0x1c49, Stride: 0x1}, + unicode.Range16{Lo: 0x1c50, Hi: 0x1c59, Stride: 0x1}, + unicode.Range16{Lo: 0xa620, Hi: 0xa629, Stride: 0x1}, + unicode.Range16{Lo: 0xa8d0, Hi: 0xa8d9, Stride: 0x1}, + unicode.Range16{Lo: 0xa900, Hi: 0xa909, Stride: 0x1}, + unicode.Range16{Lo: 0xa9d0, Hi: 0xa9d9, Stride: 0x1}, + unicode.Range16{Lo: 0xa9f0, Hi: 0xa9f9, Stride: 0x1}, + unicode.Range16{Lo: 0xaa50, Hi: 0xaa59, Stride: 0x1}, + unicode.Range16{Lo: 0xabf0, Hi: 0xabf9, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x104a0, Hi: 0x104a9, Stride: 0x1}, + unicode.Range32{Lo: 0x11066, Hi: 0x1106f, Stride: 0x1}, + unicode.Range32{Lo: 0x110f0, Hi: 0x110f9, Stride: 0x1}, + unicode.Range32{Lo: 0x11136, Hi: 0x1113f, Stride: 0x1}, + unicode.Range32{Lo: 0x111d0, Hi: 0x111d9, Stride: 0x1}, + unicode.Range32{Lo: 0x112f0, Hi: 0x112f9, Stride: 0x1}, + unicode.Range32{Lo: 0x114d0, Hi: 0x114d9, Stride: 0x1}, + unicode.Range32{Lo: 0x11650, Hi: 0x11659, Stride: 0x1}, + unicode.Range32{Lo: 0x116c0, Hi: 0x116c9, Stride: 0x1}, + unicode.Range32{Lo: 0x118e0, Hi: 0x118e9, Stride: 0x1}, + unicode.Range32{Lo: 0x16a60, Hi: 0x16a69, Stride: 0x1}, + unicode.Range32{Lo: 0x16b50, Hi: 0x16b59, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7ce, Hi: 0x1d7ff, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceUpper = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x41, Hi: 0x5a, Stride: 0x1}, + unicode.Range16{Lo: 0xc0, Hi: 0xd6, Stride: 0x1}, + unicode.Range16{Lo: 0xd8, Hi: 0xde, Stride: 0x1}, + unicode.Range16{Lo: 0x100, Hi: 0x100, Stride: 0x1}, + unicode.Range16{Lo: 0x102, Hi: 0x102, Stride: 0x1}, + unicode.Range16{Lo: 0x104, Hi: 0x104, Stride: 0x1}, + unicode.Range16{Lo: 0x106, Hi: 0x106, Stride: 0x1}, + unicode.Range16{Lo: 0x108, Hi: 0x108, Stride: 0x1}, + unicode.Range16{Lo: 0x10a, Hi: 0x10a, Stride: 0x1}, + unicode.Range16{Lo: 0x10c, Hi: 0x10c, Stride: 0x1}, + unicode.Range16{Lo: 0x10e, Hi: 0x10e, Stride: 0x1}, + unicode.Range16{Lo: 0x110, Hi: 0x110, Stride: 0x1}, + unicode.Range16{Lo: 0x112, Hi: 0x112, Stride: 0x1}, + unicode.Range16{Lo: 0x114, Hi: 0x114, Stride: 0x1}, + unicode.Range16{Lo: 0x116, Hi: 0x116, Stride: 0x1}, + unicode.Range16{Lo: 0x118, Hi: 0x118, Stride: 0x1}, + unicode.Range16{Lo: 0x11a, Hi: 0x11a, Stride: 0x1}, + unicode.Range16{Lo: 0x11c, Hi: 0x11c, Stride: 0x1}, + unicode.Range16{Lo: 0x11e, Hi: 0x11e, Stride: 0x1}, + unicode.Range16{Lo: 0x120, Hi: 0x120, Stride: 0x1}, + unicode.Range16{Lo: 0x122, Hi: 0x122, Stride: 0x1}, + unicode.Range16{Lo: 0x124, Hi: 0x124, Stride: 0x1}, + unicode.Range16{Lo: 0x126, Hi: 0x126, Stride: 0x1}, + unicode.Range16{Lo: 0x128, Hi: 0x128, Stride: 0x1}, + unicode.Range16{Lo: 0x12a, Hi: 0x12a, Stride: 0x1}, + unicode.Range16{Lo: 0x12c, Hi: 0x12c, Stride: 0x1}, + unicode.Range16{Lo: 0x12e, Hi: 0x12e, Stride: 0x1}, + unicode.Range16{Lo: 0x130, Hi: 0x130, Stride: 0x1}, + unicode.Range16{Lo: 0x132, Hi: 0x132, Stride: 0x1}, + unicode.Range16{Lo: 0x134, Hi: 0x134, Stride: 0x1}, + unicode.Range16{Lo: 0x136, Hi: 0x136, Stride: 0x1}, + unicode.Range16{Lo: 0x139, Hi: 0x139, Stride: 0x1}, + unicode.Range16{Lo: 0x13b, Hi: 0x13b, Stride: 0x1}, + unicode.Range16{Lo: 0x13d, Hi: 0x13d, Stride: 0x1}, + unicode.Range16{Lo: 0x13f, Hi: 0x13f, Stride: 0x1}, + unicode.Range16{Lo: 0x141, Hi: 0x141, Stride: 0x1}, + unicode.Range16{Lo: 0x143, Hi: 0x143, Stride: 0x1}, + unicode.Range16{Lo: 0x145, Hi: 0x145, Stride: 0x1}, + unicode.Range16{Lo: 0x147, Hi: 0x147, Stride: 0x1}, + unicode.Range16{Lo: 0x14a, Hi: 0x14a, Stride: 0x1}, + unicode.Range16{Lo: 0x14c, Hi: 0x14c, Stride: 0x1}, + unicode.Range16{Lo: 0x14e, Hi: 0x14e, Stride: 0x1}, + unicode.Range16{Lo: 0x150, Hi: 0x150, Stride: 0x1}, + unicode.Range16{Lo: 0x152, Hi: 0x152, Stride: 0x1}, + unicode.Range16{Lo: 0x154, Hi: 0x154, Stride: 0x1}, + unicode.Range16{Lo: 0x156, Hi: 0x156, Stride: 0x1}, + unicode.Range16{Lo: 0x158, Hi: 0x158, Stride: 0x1}, + unicode.Range16{Lo: 0x15a, Hi: 0x15a, Stride: 0x1}, + unicode.Range16{Lo: 0x15c, Hi: 0x15c, Stride: 0x1}, + unicode.Range16{Lo: 0x15e, Hi: 0x15e, Stride: 0x1}, + unicode.Range16{Lo: 0x160, Hi: 0x160, Stride: 0x1}, + unicode.Range16{Lo: 0x162, Hi: 0x162, Stride: 0x1}, + unicode.Range16{Lo: 0x164, Hi: 0x164, Stride: 0x1}, + unicode.Range16{Lo: 0x166, Hi: 0x166, Stride: 0x1}, + unicode.Range16{Lo: 0x168, Hi: 0x168, Stride: 0x1}, + unicode.Range16{Lo: 0x16a, Hi: 0x16a, Stride: 0x1}, + unicode.Range16{Lo: 0x16c, Hi: 0x16c, Stride: 0x1}, + unicode.Range16{Lo: 0x16e, Hi: 0x16e, Stride: 0x1}, + unicode.Range16{Lo: 0x170, Hi: 0x170, Stride: 0x1}, + unicode.Range16{Lo: 0x172, Hi: 0x172, Stride: 0x1}, + unicode.Range16{Lo: 0x174, Hi: 0x174, Stride: 0x1}, + unicode.Range16{Lo: 0x176, Hi: 0x176, Stride: 0x1}, + unicode.Range16{Lo: 0x178, Hi: 0x179, Stride: 0x1}, + unicode.Range16{Lo: 0x17b, Hi: 0x17b, Stride: 0x1}, + unicode.Range16{Lo: 0x17d, Hi: 0x17d, Stride: 0x1}, + unicode.Range16{Lo: 0x181, Hi: 0x182, Stride: 0x1}, + unicode.Range16{Lo: 0x184, Hi: 0x184, Stride: 0x1}, + unicode.Range16{Lo: 0x186, Hi: 0x187, Stride: 0x1}, + unicode.Range16{Lo: 0x189, Hi: 0x18b, Stride: 0x1}, + unicode.Range16{Lo: 0x18e, Hi: 0x191, Stride: 0x1}, + unicode.Range16{Lo: 0x193, Hi: 0x194, Stride: 0x1}, + unicode.Range16{Lo: 0x196, Hi: 0x198, Stride: 0x1}, + unicode.Range16{Lo: 0x19c, Hi: 0x19d, Stride: 0x1}, + unicode.Range16{Lo: 0x19f, Hi: 0x1a0, Stride: 0x1}, + unicode.Range16{Lo: 0x1a2, Hi: 0x1a2, Stride: 0x1}, + unicode.Range16{Lo: 0x1a4, Hi: 0x1a4, Stride: 0x1}, + unicode.Range16{Lo: 0x1a6, Hi: 0x1a7, Stride: 0x1}, + unicode.Range16{Lo: 0x1a9, Hi: 0x1a9, Stride: 0x1}, + unicode.Range16{Lo: 0x1ac, Hi: 0x1ac, Stride: 0x1}, + unicode.Range16{Lo: 0x1ae, Hi: 0x1af, Stride: 0x1}, + unicode.Range16{Lo: 0x1b1, Hi: 0x1b3, Stride: 0x1}, + unicode.Range16{Lo: 0x1b5, Hi: 0x1b5, Stride: 0x1}, + unicode.Range16{Lo: 0x1b7, Hi: 0x1b8, Stride: 0x1}, + unicode.Range16{Lo: 0x1bc, Hi: 0x1bc, Stride: 0x1}, + unicode.Range16{Lo: 0x1c4, Hi: 0x1c5, Stride: 0x1}, + unicode.Range16{Lo: 0x1c7, Hi: 0x1c8, Stride: 0x1}, + unicode.Range16{Lo: 0x1ca, Hi: 0x1cb, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd, Hi: 0x1cd, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf, Hi: 0x1cf, Stride: 0x1}, + unicode.Range16{Lo: 0x1d1, Hi: 0x1d1, Stride: 0x1}, + unicode.Range16{Lo: 0x1d3, Hi: 0x1d3, Stride: 0x1}, + unicode.Range16{Lo: 0x1d5, Hi: 0x1d5, Stride: 0x1}, + unicode.Range16{Lo: 0x1d7, Hi: 0x1d7, Stride: 0x1}, + unicode.Range16{Lo: 0x1d9, Hi: 0x1d9, Stride: 0x1}, + unicode.Range16{Lo: 0x1db, Hi: 0x1db, Stride: 0x1}, + unicode.Range16{Lo: 0x1de, Hi: 0x1de, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0, Hi: 0x1e0, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2, Hi: 0x1e2, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4, Hi: 0x1e4, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6, Hi: 0x1e6, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8, Hi: 0x1e8, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea, Hi: 0x1ea, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec, Hi: 0x1ec, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee, Hi: 0x1ee, Stride: 0x1}, + unicode.Range16{Lo: 0x1f1, Hi: 0x1f2, Stride: 0x1}, + unicode.Range16{Lo: 0x1f4, Hi: 0x1f4, Stride: 0x1}, + unicode.Range16{Lo: 0x1f6, Hi: 0x1f8, Stride: 0x1}, + unicode.Range16{Lo: 0x1fa, Hi: 0x1fa, Stride: 0x1}, + unicode.Range16{Lo: 0x1fc, Hi: 0x1fc, Stride: 0x1}, + unicode.Range16{Lo: 0x1fe, Hi: 0x1fe, Stride: 0x1}, + unicode.Range16{Lo: 0x200, Hi: 0x200, Stride: 0x1}, + unicode.Range16{Lo: 0x202, Hi: 0x202, Stride: 0x1}, + unicode.Range16{Lo: 0x204, Hi: 0x204, Stride: 0x1}, + unicode.Range16{Lo: 0x206, Hi: 0x206, Stride: 0x1}, + unicode.Range16{Lo: 0x208, Hi: 0x208, Stride: 0x1}, + unicode.Range16{Lo: 0x20a, Hi: 0x20a, Stride: 0x1}, + unicode.Range16{Lo: 0x20c, Hi: 0x20c, Stride: 0x1}, + unicode.Range16{Lo: 0x20e, Hi: 0x20e, Stride: 0x1}, + unicode.Range16{Lo: 0x210, Hi: 0x210, Stride: 0x1}, + unicode.Range16{Lo: 0x212, Hi: 0x212, Stride: 0x1}, + unicode.Range16{Lo: 0x214, Hi: 0x214, Stride: 0x1}, + unicode.Range16{Lo: 0x216, Hi: 0x216, Stride: 0x1}, + unicode.Range16{Lo: 0x218, Hi: 0x218, Stride: 0x1}, + unicode.Range16{Lo: 0x21a, Hi: 0x21a, Stride: 0x1}, + unicode.Range16{Lo: 0x21c, Hi: 0x21c, Stride: 0x1}, + unicode.Range16{Lo: 0x21e, Hi: 0x21e, Stride: 0x1}, + unicode.Range16{Lo: 0x220, Hi: 0x220, Stride: 0x1}, + unicode.Range16{Lo: 0x222, Hi: 0x222, Stride: 0x1}, + unicode.Range16{Lo: 0x224, Hi: 0x224, Stride: 0x1}, + unicode.Range16{Lo: 0x226, Hi: 0x226, Stride: 0x1}, + unicode.Range16{Lo: 0x228, Hi: 0x228, Stride: 0x1}, + unicode.Range16{Lo: 0x22a, Hi: 0x22a, Stride: 0x1}, + unicode.Range16{Lo: 0x22c, Hi: 0x22c, Stride: 0x1}, + unicode.Range16{Lo: 0x22e, Hi: 0x22e, Stride: 0x1}, + unicode.Range16{Lo: 0x230, Hi: 0x230, Stride: 0x1}, + unicode.Range16{Lo: 0x232, Hi: 0x232, Stride: 0x1}, + unicode.Range16{Lo: 0x23a, Hi: 0x23b, Stride: 0x1}, + unicode.Range16{Lo: 0x23d, Hi: 0x23e, Stride: 0x1}, + unicode.Range16{Lo: 0x241, Hi: 0x241, Stride: 0x1}, + unicode.Range16{Lo: 0x243, Hi: 0x246, Stride: 0x1}, + unicode.Range16{Lo: 0x248, Hi: 0x248, Stride: 0x1}, + unicode.Range16{Lo: 0x24a, Hi: 0x24a, Stride: 0x1}, + unicode.Range16{Lo: 0x24c, Hi: 0x24c, Stride: 0x1}, + unicode.Range16{Lo: 0x24e, Hi: 0x24e, Stride: 0x1}, + unicode.Range16{Lo: 0x370, Hi: 0x370, Stride: 0x1}, + unicode.Range16{Lo: 0x372, Hi: 0x372, Stride: 0x1}, + unicode.Range16{Lo: 0x376, Hi: 0x376, Stride: 0x1}, + unicode.Range16{Lo: 0x37f, Hi: 0x37f, Stride: 0x1}, + unicode.Range16{Lo: 0x386, Hi: 0x386, Stride: 0x1}, + unicode.Range16{Lo: 0x388, Hi: 0x38a, Stride: 0x1}, + unicode.Range16{Lo: 0x38c, Hi: 0x38c, Stride: 0x1}, + unicode.Range16{Lo: 0x38e, Hi: 0x38f, Stride: 0x1}, + unicode.Range16{Lo: 0x391, Hi: 0x3a1, Stride: 0x1}, + unicode.Range16{Lo: 0x3a3, Hi: 0x3ab, Stride: 0x1}, + unicode.Range16{Lo: 0x3cf, Hi: 0x3cf, Stride: 0x1}, + unicode.Range16{Lo: 0x3d2, Hi: 0x3d4, Stride: 0x1}, + unicode.Range16{Lo: 0x3d8, Hi: 0x3d8, Stride: 0x1}, + unicode.Range16{Lo: 0x3da, Hi: 0x3da, Stride: 0x1}, + unicode.Range16{Lo: 0x3dc, Hi: 0x3dc, Stride: 0x1}, + unicode.Range16{Lo: 0x3de, Hi: 0x3de, Stride: 0x1}, + unicode.Range16{Lo: 0x3e0, Hi: 0x3e0, Stride: 0x1}, + unicode.Range16{Lo: 0x3e2, Hi: 0x3e2, Stride: 0x1}, + unicode.Range16{Lo: 0x3e4, Hi: 0x3e4, Stride: 0x1}, + unicode.Range16{Lo: 0x3e6, Hi: 0x3e6, Stride: 0x1}, + unicode.Range16{Lo: 0x3e8, Hi: 0x3e8, Stride: 0x1}, + unicode.Range16{Lo: 0x3ea, Hi: 0x3ea, Stride: 0x1}, + unicode.Range16{Lo: 0x3ec, Hi: 0x3ec, Stride: 0x1}, + unicode.Range16{Lo: 0x3ee, Hi: 0x3ee, Stride: 0x1}, + unicode.Range16{Lo: 0x3f4, Hi: 0x3f4, Stride: 0x1}, + unicode.Range16{Lo: 0x3f7, Hi: 0x3f7, Stride: 0x1}, + unicode.Range16{Lo: 0x3f9, Hi: 0x3fa, Stride: 0x1}, + unicode.Range16{Lo: 0x3fd, Hi: 0x42f, Stride: 0x1}, + unicode.Range16{Lo: 0x460, Hi: 0x460, Stride: 0x1}, + unicode.Range16{Lo: 0x462, Hi: 0x462, Stride: 0x1}, + unicode.Range16{Lo: 0x464, Hi: 0x464, Stride: 0x1}, + unicode.Range16{Lo: 0x466, Hi: 0x466, Stride: 0x1}, + unicode.Range16{Lo: 0x468, Hi: 0x468, Stride: 0x1}, + unicode.Range16{Lo: 0x46a, Hi: 0x46a, Stride: 0x1}, + unicode.Range16{Lo: 0x46c, Hi: 0x46c, Stride: 0x1}, + unicode.Range16{Lo: 0x46e, Hi: 0x46e, Stride: 0x1}, + unicode.Range16{Lo: 0x470, Hi: 0x470, Stride: 0x1}, + unicode.Range16{Lo: 0x472, Hi: 0x472, Stride: 0x1}, + unicode.Range16{Lo: 0x474, Hi: 0x474, Stride: 0x1}, + unicode.Range16{Lo: 0x476, Hi: 0x476, Stride: 0x1}, + unicode.Range16{Lo: 0x478, Hi: 0x478, Stride: 0x1}, + unicode.Range16{Lo: 0x47a, Hi: 0x47a, Stride: 0x1}, + unicode.Range16{Lo: 0x47c, Hi: 0x47c, Stride: 0x1}, + unicode.Range16{Lo: 0x47e, Hi: 0x47e, Stride: 0x1}, + unicode.Range16{Lo: 0x480, Hi: 0x480, Stride: 0x1}, + unicode.Range16{Lo: 0x48a, Hi: 0x48a, Stride: 0x1}, + unicode.Range16{Lo: 0x48c, Hi: 0x48c, Stride: 0x1}, + unicode.Range16{Lo: 0x48e, Hi: 0x48e, Stride: 0x1}, + unicode.Range16{Lo: 0x490, Hi: 0x490, Stride: 0x1}, + unicode.Range16{Lo: 0x492, Hi: 0x492, Stride: 0x1}, + unicode.Range16{Lo: 0x494, Hi: 0x494, Stride: 0x1}, + unicode.Range16{Lo: 0x496, Hi: 0x496, Stride: 0x1}, + unicode.Range16{Lo: 0x498, Hi: 0x498, Stride: 0x1}, + unicode.Range16{Lo: 0x49a, Hi: 0x49a, Stride: 0x1}, + unicode.Range16{Lo: 0x49c, Hi: 0x49c, Stride: 0x1}, + unicode.Range16{Lo: 0x49e, Hi: 0x49e, Stride: 0x1}, + unicode.Range16{Lo: 0x4a0, Hi: 0x4a0, Stride: 0x1}, + unicode.Range16{Lo: 0x4a2, Hi: 0x4a2, Stride: 0x1}, + unicode.Range16{Lo: 0x4a4, Hi: 0x4a4, Stride: 0x1}, + unicode.Range16{Lo: 0x4a6, Hi: 0x4a6, Stride: 0x1}, + unicode.Range16{Lo: 0x4a8, Hi: 0x4a8, Stride: 0x1}, + unicode.Range16{Lo: 0x4aa, Hi: 0x4aa, Stride: 0x1}, + unicode.Range16{Lo: 0x4ac, Hi: 0x4ac, Stride: 0x1}, + unicode.Range16{Lo: 0x4ae, Hi: 0x4ae, Stride: 0x1}, + unicode.Range16{Lo: 0x4b0, Hi: 0x4b0, Stride: 0x1}, + unicode.Range16{Lo: 0x4b2, Hi: 0x4b2, Stride: 0x1}, + unicode.Range16{Lo: 0x4b4, Hi: 0x4b4, Stride: 0x1}, + unicode.Range16{Lo: 0x4b6, Hi: 0x4b6, Stride: 0x1}, + unicode.Range16{Lo: 0x4b8, Hi: 0x4b8, Stride: 0x1}, + unicode.Range16{Lo: 0x4ba, Hi: 0x4ba, Stride: 0x1}, + unicode.Range16{Lo: 0x4bc, Hi: 0x4bc, Stride: 0x1}, + unicode.Range16{Lo: 0x4be, Hi: 0x4be, Stride: 0x1}, + unicode.Range16{Lo: 0x4c0, Hi: 0x4c1, Stride: 0x1}, + unicode.Range16{Lo: 0x4c3, Hi: 0x4c3, Stride: 0x1}, + unicode.Range16{Lo: 0x4c5, Hi: 0x4c5, Stride: 0x1}, + unicode.Range16{Lo: 0x4c7, Hi: 0x4c7, Stride: 0x1}, + unicode.Range16{Lo: 0x4c9, Hi: 0x4c9, Stride: 0x1}, + unicode.Range16{Lo: 0x4cb, Hi: 0x4cb, Stride: 0x1}, + unicode.Range16{Lo: 0x4cd, Hi: 0x4cd, Stride: 0x1}, + unicode.Range16{Lo: 0x4d0, Hi: 0x4d0, Stride: 0x1}, + unicode.Range16{Lo: 0x4d2, Hi: 0x4d2, Stride: 0x1}, + unicode.Range16{Lo: 0x4d4, Hi: 0x4d4, Stride: 0x1}, + unicode.Range16{Lo: 0x4d6, Hi: 0x4d6, Stride: 0x1}, + unicode.Range16{Lo: 0x4d8, Hi: 0x4d8, Stride: 0x1}, + unicode.Range16{Lo: 0x4da, Hi: 0x4da, Stride: 0x1}, + unicode.Range16{Lo: 0x4dc, Hi: 0x4dc, Stride: 0x1}, + unicode.Range16{Lo: 0x4de, Hi: 0x4de, Stride: 0x1}, + unicode.Range16{Lo: 0x4e0, Hi: 0x4e0, Stride: 0x1}, + unicode.Range16{Lo: 0x4e2, Hi: 0x4e2, Stride: 0x1}, + unicode.Range16{Lo: 0x4e4, Hi: 0x4e4, Stride: 0x1}, + unicode.Range16{Lo: 0x4e6, Hi: 0x4e6, Stride: 0x1}, + unicode.Range16{Lo: 0x4e8, Hi: 0x4e8, Stride: 0x1}, + unicode.Range16{Lo: 0x4ea, Hi: 0x4ea, Stride: 0x1}, + unicode.Range16{Lo: 0x4ec, Hi: 0x4ec, Stride: 0x1}, + unicode.Range16{Lo: 0x4ee, Hi: 0x4ee, Stride: 0x1}, + unicode.Range16{Lo: 0x4f0, Hi: 0x4f0, Stride: 0x1}, + unicode.Range16{Lo: 0x4f2, Hi: 0x4f2, Stride: 0x1}, + unicode.Range16{Lo: 0x4f4, Hi: 0x4f4, Stride: 0x1}, + unicode.Range16{Lo: 0x4f6, Hi: 0x4f6, Stride: 0x1}, + unicode.Range16{Lo: 0x4f8, Hi: 0x4f8, Stride: 0x1}, + unicode.Range16{Lo: 0x4fa, Hi: 0x4fa, Stride: 0x1}, + unicode.Range16{Lo: 0x4fc, Hi: 0x4fc, Stride: 0x1}, + unicode.Range16{Lo: 0x4fe, Hi: 0x4fe, Stride: 0x1}, + unicode.Range16{Lo: 0x500, Hi: 0x500, Stride: 0x1}, + unicode.Range16{Lo: 0x502, Hi: 0x502, Stride: 0x1}, + unicode.Range16{Lo: 0x504, Hi: 0x504, Stride: 0x1}, + unicode.Range16{Lo: 0x506, Hi: 0x506, Stride: 0x1}, + unicode.Range16{Lo: 0x508, Hi: 0x508, Stride: 0x1}, + unicode.Range16{Lo: 0x50a, Hi: 0x50a, Stride: 0x1}, + unicode.Range16{Lo: 0x50c, Hi: 0x50c, Stride: 0x1}, + unicode.Range16{Lo: 0x50e, Hi: 0x50e, Stride: 0x1}, + unicode.Range16{Lo: 0x510, Hi: 0x510, Stride: 0x1}, + unicode.Range16{Lo: 0x512, Hi: 0x512, Stride: 0x1}, + unicode.Range16{Lo: 0x514, Hi: 0x514, Stride: 0x1}, + unicode.Range16{Lo: 0x516, Hi: 0x516, Stride: 0x1}, + unicode.Range16{Lo: 0x518, Hi: 0x518, Stride: 0x1}, + unicode.Range16{Lo: 0x51a, Hi: 0x51a, Stride: 0x1}, + unicode.Range16{Lo: 0x51c, Hi: 0x51c, Stride: 0x1}, + unicode.Range16{Lo: 0x51e, Hi: 0x51e, Stride: 0x1}, + unicode.Range16{Lo: 0x520, Hi: 0x520, Stride: 0x1}, + unicode.Range16{Lo: 0x522, Hi: 0x522, Stride: 0x1}, + unicode.Range16{Lo: 0x524, Hi: 0x524, Stride: 0x1}, + unicode.Range16{Lo: 0x526, Hi: 0x526, Stride: 0x1}, + unicode.Range16{Lo: 0x528, Hi: 0x528, Stride: 0x1}, + unicode.Range16{Lo: 0x52a, Hi: 0x52a, Stride: 0x1}, + unicode.Range16{Lo: 0x52c, Hi: 0x52c, Stride: 0x1}, + unicode.Range16{Lo: 0x52e, Hi: 0x52e, Stride: 0x1}, + unicode.Range16{Lo: 0x531, Hi: 0x556, Stride: 0x1}, + unicode.Range16{Lo: 0x10a0, Hi: 0x10c5, Stride: 0x1}, + unicode.Range16{Lo: 0x10c7, Hi: 0x10c7, Stride: 0x1}, + unicode.Range16{Lo: 0x10cd, Hi: 0x10cd, Stride: 0x1}, + unicode.Range16{Lo: 0x1e00, Hi: 0x1e00, Stride: 0x1}, + unicode.Range16{Lo: 0x1e02, Hi: 0x1e02, Stride: 0x1}, + unicode.Range16{Lo: 0x1e04, Hi: 0x1e04, Stride: 0x1}, + unicode.Range16{Lo: 0x1e06, Hi: 0x1e06, Stride: 0x1}, + unicode.Range16{Lo: 0x1e08, Hi: 0x1e08, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0a, Hi: 0x1e0a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0c, Hi: 0x1e0c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0e, Hi: 0x1e0e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e10, Hi: 0x1e10, Stride: 0x1}, + unicode.Range16{Lo: 0x1e12, Hi: 0x1e12, Stride: 0x1}, + unicode.Range16{Lo: 0x1e14, Hi: 0x1e14, Stride: 0x1}, + unicode.Range16{Lo: 0x1e16, Hi: 0x1e16, Stride: 0x1}, + unicode.Range16{Lo: 0x1e18, Hi: 0x1e18, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1a, Hi: 0x1e1a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1c, Hi: 0x1e1c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1e, Hi: 0x1e1e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e20, Hi: 0x1e20, Stride: 0x1}, + unicode.Range16{Lo: 0x1e22, Hi: 0x1e22, Stride: 0x1}, + unicode.Range16{Lo: 0x1e24, Hi: 0x1e24, Stride: 0x1}, + unicode.Range16{Lo: 0x1e26, Hi: 0x1e26, Stride: 0x1}, + unicode.Range16{Lo: 0x1e28, Hi: 0x1e28, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2a, Hi: 0x1e2a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2c, Hi: 0x1e2c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2e, Hi: 0x1e2e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e30, Hi: 0x1e30, Stride: 0x1}, + unicode.Range16{Lo: 0x1e32, Hi: 0x1e32, Stride: 0x1}, + unicode.Range16{Lo: 0x1e34, Hi: 0x1e34, Stride: 0x1}, + unicode.Range16{Lo: 0x1e36, Hi: 0x1e36, Stride: 0x1}, + unicode.Range16{Lo: 0x1e38, Hi: 0x1e38, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3a, Hi: 0x1e3a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3c, Hi: 0x1e3c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3e, Hi: 0x1e3e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e40, Hi: 0x1e40, Stride: 0x1}, + unicode.Range16{Lo: 0x1e42, Hi: 0x1e42, Stride: 0x1}, + unicode.Range16{Lo: 0x1e44, Hi: 0x1e44, Stride: 0x1}, + unicode.Range16{Lo: 0x1e46, Hi: 0x1e46, Stride: 0x1}, + unicode.Range16{Lo: 0x1e48, Hi: 0x1e48, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4a, Hi: 0x1e4a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4c, Hi: 0x1e4c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4e, Hi: 0x1e4e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e50, Hi: 0x1e50, Stride: 0x1}, + unicode.Range16{Lo: 0x1e52, Hi: 0x1e52, Stride: 0x1}, + unicode.Range16{Lo: 0x1e54, Hi: 0x1e54, Stride: 0x1}, + unicode.Range16{Lo: 0x1e56, Hi: 0x1e56, Stride: 0x1}, + unicode.Range16{Lo: 0x1e58, Hi: 0x1e58, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5a, Hi: 0x1e5a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5c, Hi: 0x1e5c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5e, Hi: 0x1e5e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e60, Hi: 0x1e60, Stride: 0x1}, + unicode.Range16{Lo: 0x1e62, Hi: 0x1e62, Stride: 0x1}, + unicode.Range16{Lo: 0x1e64, Hi: 0x1e64, Stride: 0x1}, + unicode.Range16{Lo: 0x1e66, Hi: 0x1e66, Stride: 0x1}, + unicode.Range16{Lo: 0x1e68, Hi: 0x1e68, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6a, Hi: 0x1e6a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6c, Hi: 0x1e6c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6e, Hi: 0x1e6e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e70, Hi: 0x1e70, Stride: 0x1}, + unicode.Range16{Lo: 0x1e72, Hi: 0x1e72, Stride: 0x1}, + unicode.Range16{Lo: 0x1e74, Hi: 0x1e74, Stride: 0x1}, + unicode.Range16{Lo: 0x1e76, Hi: 0x1e76, Stride: 0x1}, + unicode.Range16{Lo: 0x1e78, Hi: 0x1e78, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7a, Hi: 0x1e7a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7c, Hi: 0x1e7c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7e, Hi: 0x1e7e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e80, Hi: 0x1e80, Stride: 0x1}, + unicode.Range16{Lo: 0x1e82, Hi: 0x1e82, Stride: 0x1}, + unicode.Range16{Lo: 0x1e84, Hi: 0x1e84, Stride: 0x1}, + unicode.Range16{Lo: 0x1e86, Hi: 0x1e86, Stride: 0x1}, + unicode.Range16{Lo: 0x1e88, Hi: 0x1e88, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8a, Hi: 0x1e8a, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8c, Hi: 0x1e8c, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8e, Hi: 0x1e8e, Stride: 0x1}, + unicode.Range16{Lo: 0x1e90, Hi: 0x1e90, Stride: 0x1}, + unicode.Range16{Lo: 0x1e92, Hi: 0x1e92, Stride: 0x1}, + unicode.Range16{Lo: 0x1e94, Hi: 0x1e94, Stride: 0x1}, + unicode.Range16{Lo: 0x1e9e, Hi: 0x1e9e, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea0, Hi: 0x1ea0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea2, Hi: 0x1ea2, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea4, Hi: 0x1ea4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea6, Hi: 0x1ea6, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea8, Hi: 0x1ea8, Stride: 0x1}, + unicode.Range16{Lo: 0x1eaa, Hi: 0x1eaa, Stride: 0x1}, + unicode.Range16{Lo: 0x1eac, Hi: 0x1eac, Stride: 0x1}, + unicode.Range16{Lo: 0x1eae, Hi: 0x1eae, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb0, Hi: 0x1eb0, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb2, Hi: 0x1eb2, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb4, Hi: 0x1eb4, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb6, Hi: 0x1eb6, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb8, Hi: 0x1eb8, Stride: 0x1}, + unicode.Range16{Lo: 0x1eba, Hi: 0x1eba, Stride: 0x1}, + unicode.Range16{Lo: 0x1ebc, Hi: 0x1ebc, Stride: 0x1}, + unicode.Range16{Lo: 0x1ebe, Hi: 0x1ebe, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec0, Hi: 0x1ec0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec2, Hi: 0x1ec2, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec4, Hi: 0x1ec4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec6, Hi: 0x1ec6, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec8, Hi: 0x1ec8, Stride: 0x1}, + unicode.Range16{Lo: 0x1eca, Hi: 0x1eca, Stride: 0x1}, + unicode.Range16{Lo: 0x1ecc, Hi: 0x1ecc, Stride: 0x1}, + unicode.Range16{Lo: 0x1ece, Hi: 0x1ece, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed0, Hi: 0x1ed0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed2, Hi: 0x1ed2, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed4, Hi: 0x1ed4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed6, Hi: 0x1ed6, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed8, Hi: 0x1ed8, Stride: 0x1}, + unicode.Range16{Lo: 0x1eda, Hi: 0x1eda, Stride: 0x1}, + unicode.Range16{Lo: 0x1edc, Hi: 0x1edc, Stride: 0x1}, + unicode.Range16{Lo: 0x1ede, Hi: 0x1ede, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee0, Hi: 0x1ee0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee2, Hi: 0x1ee2, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee4, Hi: 0x1ee4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee6, Hi: 0x1ee6, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee8, Hi: 0x1ee8, Stride: 0x1}, + unicode.Range16{Lo: 0x1eea, Hi: 0x1eea, Stride: 0x1}, + unicode.Range16{Lo: 0x1eec, Hi: 0x1eec, Stride: 0x1}, + unicode.Range16{Lo: 0x1eee, Hi: 0x1eee, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef0, Hi: 0x1ef0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef2, Hi: 0x1ef2, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef4, Hi: 0x1ef4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef6, Hi: 0x1ef6, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef8, Hi: 0x1ef8, Stride: 0x1}, + unicode.Range16{Lo: 0x1efa, Hi: 0x1efa, Stride: 0x1}, + unicode.Range16{Lo: 0x1efc, Hi: 0x1efc, Stride: 0x1}, + unicode.Range16{Lo: 0x1efe, Hi: 0x1efe, Stride: 0x1}, + unicode.Range16{Lo: 0x1f08, Hi: 0x1f0f, Stride: 0x1}, + unicode.Range16{Lo: 0x1f18, Hi: 0x1f1d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f28, Hi: 0x1f2f, Stride: 0x1}, + unicode.Range16{Lo: 0x1f38, Hi: 0x1f3f, Stride: 0x1}, + unicode.Range16{Lo: 0x1f48, Hi: 0x1f4d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f59, Hi: 0x1f59, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5b, Hi: 0x1f5b, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5d, Hi: 0x1f5d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5f, Hi: 0x1f5f, Stride: 0x1}, + unicode.Range16{Lo: 0x1f68, Hi: 0x1f6f, Stride: 0x1}, + unicode.Range16{Lo: 0x1f88, Hi: 0x1f8f, Stride: 0x1}, + unicode.Range16{Lo: 0x1f98, Hi: 0x1f9f, Stride: 0x1}, + unicode.Range16{Lo: 0x1fa8, Hi: 0x1faf, Stride: 0x1}, + unicode.Range16{Lo: 0x1fb8, Hi: 0x1fbc, Stride: 0x1}, + unicode.Range16{Lo: 0x1fc8, Hi: 0x1fcc, Stride: 0x1}, + unicode.Range16{Lo: 0x1fd8, Hi: 0x1fdb, Stride: 0x1}, + unicode.Range16{Lo: 0x1fe8, Hi: 0x1fec, Stride: 0x1}, + unicode.Range16{Lo: 0x1ff8, Hi: 0x1ffc, Stride: 0x1}, + unicode.Range16{Lo: 0x2102, Hi: 0x2102, Stride: 0x1}, + unicode.Range16{Lo: 0x2107, Hi: 0x2107, Stride: 0x1}, + unicode.Range16{Lo: 0x210b, Hi: 0x210d, Stride: 0x1}, + unicode.Range16{Lo: 0x2110, Hi: 0x2112, Stride: 0x1}, + unicode.Range16{Lo: 0x2115, Hi: 0x2115, Stride: 0x1}, + unicode.Range16{Lo: 0x2119, Hi: 0x211d, Stride: 0x1}, + unicode.Range16{Lo: 0x2124, Hi: 0x2124, Stride: 0x1}, + unicode.Range16{Lo: 0x2126, Hi: 0x2126, Stride: 0x1}, + unicode.Range16{Lo: 0x2128, Hi: 0x2128, Stride: 0x1}, + unicode.Range16{Lo: 0x212a, Hi: 0x212d, Stride: 0x1}, + unicode.Range16{Lo: 0x2130, Hi: 0x2133, Stride: 0x1}, + unicode.Range16{Lo: 0x213e, Hi: 0x213f, Stride: 0x1}, + unicode.Range16{Lo: 0x2145, Hi: 0x2145, Stride: 0x1}, + unicode.Range16{Lo: 0x2160, Hi: 0x216f, Stride: 0x1}, + unicode.Range16{Lo: 0x2183, Hi: 0x2183, Stride: 0x1}, + unicode.Range16{Lo: 0x24b6, Hi: 0x24cf, Stride: 0x1}, + unicode.Range16{Lo: 0x2c00, Hi: 0x2c2e, Stride: 0x1}, + unicode.Range16{Lo: 0x2c60, Hi: 0x2c60, Stride: 0x1}, + unicode.Range16{Lo: 0x2c62, Hi: 0x2c64, Stride: 0x1}, + unicode.Range16{Lo: 0x2c67, Hi: 0x2c67, Stride: 0x1}, + unicode.Range16{Lo: 0x2c69, Hi: 0x2c69, Stride: 0x1}, + unicode.Range16{Lo: 0x2c6b, Hi: 0x2c6b, Stride: 0x1}, + unicode.Range16{Lo: 0x2c6d, Hi: 0x2c70, Stride: 0x1}, + unicode.Range16{Lo: 0x2c72, Hi: 0x2c72, Stride: 0x1}, + unicode.Range16{Lo: 0x2c75, Hi: 0x2c75, Stride: 0x1}, + unicode.Range16{Lo: 0x2c7e, Hi: 0x2c80, Stride: 0x1}, + unicode.Range16{Lo: 0x2c82, Hi: 0x2c82, Stride: 0x1}, + unicode.Range16{Lo: 0x2c84, Hi: 0x2c84, Stride: 0x1}, + unicode.Range16{Lo: 0x2c86, Hi: 0x2c86, Stride: 0x1}, + unicode.Range16{Lo: 0x2c88, Hi: 0x2c88, Stride: 0x1}, + unicode.Range16{Lo: 0x2c8a, Hi: 0x2c8a, Stride: 0x1}, + unicode.Range16{Lo: 0x2c8c, Hi: 0x2c8c, Stride: 0x1}, + unicode.Range16{Lo: 0x2c8e, Hi: 0x2c8e, Stride: 0x1}, + unicode.Range16{Lo: 0x2c90, Hi: 0x2c90, Stride: 0x1}, + unicode.Range16{Lo: 0x2c92, Hi: 0x2c92, Stride: 0x1}, + unicode.Range16{Lo: 0x2c94, Hi: 0x2c94, Stride: 0x1}, + unicode.Range16{Lo: 0x2c96, Hi: 0x2c96, Stride: 0x1}, + unicode.Range16{Lo: 0x2c98, Hi: 0x2c98, Stride: 0x1}, + unicode.Range16{Lo: 0x2c9a, Hi: 0x2c9a, Stride: 0x1}, + unicode.Range16{Lo: 0x2c9c, Hi: 0x2c9c, Stride: 0x1}, + unicode.Range16{Lo: 0x2c9e, Hi: 0x2c9e, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca0, Hi: 0x2ca0, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca2, Hi: 0x2ca2, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca4, Hi: 0x2ca4, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca6, Hi: 0x2ca6, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca8, Hi: 0x2ca8, Stride: 0x1}, + unicode.Range16{Lo: 0x2caa, Hi: 0x2caa, Stride: 0x1}, + unicode.Range16{Lo: 0x2cac, Hi: 0x2cac, Stride: 0x1}, + unicode.Range16{Lo: 0x2cae, Hi: 0x2cae, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb0, Hi: 0x2cb0, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb2, Hi: 0x2cb2, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb4, Hi: 0x2cb4, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb6, Hi: 0x2cb6, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb8, Hi: 0x2cb8, Stride: 0x1}, + unicode.Range16{Lo: 0x2cba, Hi: 0x2cba, Stride: 0x1}, + unicode.Range16{Lo: 0x2cbc, Hi: 0x2cbc, Stride: 0x1}, + unicode.Range16{Lo: 0x2cbe, Hi: 0x2cbe, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc0, Hi: 0x2cc0, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc2, Hi: 0x2cc2, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc4, Hi: 0x2cc4, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc6, Hi: 0x2cc6, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc8, Hi: 0x2cc8, Stride: 0x1}, + unicode.Range16{Lo: 0x2cca, Hi: 0x2cca, Stride: 0x1}, + unicode.Range16{Lo: 0x2ccc, Hi: 0x2ccc, Stride: 0x1}, + unicode.Range16{Lo: 0x2cce, Hi: 0x2cce, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd0, Hi: 0x2cd0, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd2, Hi: 0x2cd2, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd4, Hi: 0x2cd4, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd6, Hi: 0x2cd6, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd8, Hi: 0x2cd8, Stride: 0x1}, + unicode.Range16{Lo: 0x2cda, Hi: 0x2cda, Stride: 0x1}, + unicode.Range16{Lo: 0x2cdc, Hi: 0x2cdc, Stride: 0x1}, + unicode.Range16{Lo: 0x2cde, Hi: 0x2cde, Stride: 0x1}, + unicode.Range16{Lo: 0x2ce0, Hi: 0x2ce0, Stride: 0x1}, + unicode.Range16{Lo: 0x2ce2, Hi: 0x2ce2, Stride: 0x1}, + unicode.Range16{Lo: 0x2ceb, Hi: 0x2ceb, Stride: 0x1}, + unicode.Range16{Lo: 0x2ced, Hi: 0x2ced, Stride: 0x1}, + unicode.Range16{Lo: 0x2cf2, Hi: 0x2cf2, Stride: 0x1}, + unicode.Range16{Lo: 0xa640, Hi: 0xa640, Stride: 0x1}, + unicode.Range16{Lo: 0xa642, Hi: 0xa642, Stride: 0x1}, + unicode.Range16{Lo: 0xa644, Hi: 0xa644, Stride: 0x1}, + unicode.Range16{Lo: 0xa646, Hi: 0xa646, Stride: 0x1}, + unicode.Range16{Lo: 0xa648, Hi: 0xa648, Stride: 0x1}, + unicode.Range16{Lo: 0xa64a, Hi: 0xa64a, Stride: 0x1}, + unicode.Range16{Lo: 0xa64c, Hi: 0xa64c, Stride: 0x1}, + unicode.Range16{Lo: 0xa64e, Hi: 0xa64e, Stride: 0x1}, + unicode.Range16{Lo: 0xa650, Hi: 0xa650, Stride: 0x1}, + unicode.Range16{Lo: 0xa652, Hi: 0xa652, Stride: 0x1}, + unicode.Range16{Lo: 0xa654, Hi: 0xa654, Stride: 0x1}, + unicode.Range16{Lo: 0xa656, Hi: 0xa656, Stride: 0x1}, + unicode.Range16{Lo: 0xa658, Hi: 0xa658, Stride: 0x1}, + unicode.Range16{Lo: 0xa65a, Hi: 0xa65a, Stride: 0x1}, + unicode.Range16{Lo: 0xa65c, Hi: 0xa65c, Stride: 0x1}, + unicode.Range16{Lo: 0xa65e, Hi: 0xa65e, Stride: 0x1}, + unicode.Range16{Lo: 0xa660, Hi: 0xa660, Stride: 0x1}, + unicode.Range16{Lo: 0xa662, Hi: 0xa662, Stride: 0x1}, + unicode.Range16{Lo: 0xa664, Hi: 0xa664, Stride: 0x1}, + unicode.Range16{Lo: 0xa666, Hi: 0xa666, Stride: 0x1}, + unicode.Range16{Lo: 0xa668, Hi: 0xa668, Stride: 0x1}, + unicode.Range16{Lo: 0xa66a, Hi: 0xa66a, Stride: 0x1}, + unicode.Range16{Lo: 0xa66c, Hi: 0xa66c, Stride: 0x1}, + unicode.Range16{Lo: 0xa680, Hi: 0xa680, Stride: 0x1}, + unicode.Range16{Lo: 0xa682, Hi: 0xa682, Stride: 0x1}, + unicode.Range16{Lo: 0xa684, Hi: 0xa684, Stride: 0x1}, + unicode.Range16{Lo: 0xa686, Hi: 0xa686, Stride: 0x1}, + unicode.Range16{Lo: 0xa688, Hi: 0xa688, Stride: 0x1}, + unicode.Range16{Lo: 0xa68a, Hi: 0xa68a, Stride: 0x1}, + unicode.Range16{Lo: 0xa68c, Hi: 0xa68c, Stride: 0x1}, + unicode.Range16{Lo: 0xa68e, Hi: 0xa68e, Stride: 0x1}, + unicode.Range16{Lo: 0xa690, Hi: 0xa690, Stride: 0x1}, + unicode.Range16{Lo: 0xa692, Hi: 0xa692, Stride: 0x1}, + unicode.Range16{Lo: 0xa694, Hi: 0xa694, Stride: 0x1}, + unicode.Range16{Lo: 0xa696, Hi: 0xa696, Stride: 0x1}, + unicode.Range16{Lo: 0xa698, Hi: 0xa698, Stride: 0x1}, + unicode.Range16{Lo: 0xa69a, Hi: 0xa69a, Stride: 0x1}, + unicode.Range16{Lo: 0xa722, Hi: 0xa722, Stride: 0x1}, + unicode.Range16{Lo: 0xa724, Hi: 0xa724, Stride: 0x1}, + unicode.Range16{Lo: 0xa726, Hi: 0xa726, Stride: 0x1}, + unicode.Range16{Lo: 0xa728, Hi: 0xa728, Stride: 0x1}, + unicode.Range16{Lo: 0xa72a, Hi: 0xa72a, Stride: 0x1}, + unicode.Range16{Lo: 0xa72c, Hi: 0xa72c, Stride: 0x1}, + unicode.Range16{Lo: 0xa72e, Hi: 0xa72e, Stride: 0x1}, + unicode.Range16{Lo: 0xa732, Hi: 0xa732, Stride: 0x1}, + unicode.Range16{Lo: 0xa734, Hi: 0xa734, Stride: 0x1}, + unicode.Range16{Lo: 0xa736, Hi: 0xa736, Stride: 0x1}, + unicode.Range16{Lo: 0xa738, Hi: 0xa738, Stride: 0x1}, + unicode.Range16{Lo: 0xa73a, Hi: 0xa73a, Stride: 0x1}, + unicode.Range16{Lo: 0xa73c, Hi: 0xa73c, Stride: 0x1}, + unicode.Range16{Lo: 0xa73e, Hi: 0xa73e, Stride: 0x1}, + unicode.Range16{Lo: 0xa740, Hi: 0xa740, Stride: 0x1}, + unicode.Range16{Lo: 0xa742, Hi: 0xa742, Stride: 0x1}, + unicode.Range16{Lo: 0xa744, Hi: 0xa744, Stride: 0x1}, + unicode.Range16{Lo: 0xa746, Hi: 0xa746, Stride: 0x1}, + unicode.Range16{Lo: 0xa748, Hi: 0xa748, Stride: 0x1}, + unicode.Range16{Lo: 0xa74a, Hi: 0xa74a, Stride: 0x1}, + unicode.Range16{Lo: 0xa74c, Hi: 0xa74c, Stride: 0x1}, + unicode.Range16{Lo: 0xa74e, Hi: 0xa74e, Stride: 0x1}, + unicode.Range16{Lo: 0xa750, Hi: 0xa750, Stride: 0x1}, + unicode.Range16{Lo: 0xa752, Hi: 0xa752, Stride: 0x1}, + unicode.Range16{Lo: 0xa754, Hi: 0xa754, Stride: 0x1}, + unicode.Range16{Lo: 0xa756, Hi: 0xa756, Stride: 0x1}, + unicode.Range16{Lo: 0xa758, Hi: 0xa758, Stride: 0x1}, + unicode.Range16{Lo: 0xa75a, Hi: 0xa75a, Stride: 0x1}, + unicode.Range16{Lo: 0xa75c, Hi: 0xa75c, Stride: 0x1}, + unicode.Range16{Lo: 0xa75e, Hi: 0xa75e, Stride: 0x1}, + unicode.Range16{Lo: 0xa760, Hi: 0xa760, Stride: 0x1}, + unicode.Range16{Lo: 0xa762, Hi: 0xa762, Stride: 0x1}, + unicode.Range16{Lo: 0xa764, Hi: 0xa764, Stride: 0x1}, + unicode.Range16{Lo: 0xa766, Hi: 0xa766, Stride: 0x1}, + unicode.Range16{Lo: 0xa768, Hi: 0xa768, Stride: 0x1}, + unicode.Range16{Lo: 0xa76a, Hi: 0xa76a, Stride: 0x1}, + unicode.Range16{Lo: 0xa76c, Hi: 0xa76c, Stride: 0x1}, + unicode.Range16{Lo: 0xa76e, Hi: 0xa76e, Stride: 0x1}, + unicode.Range16{Lo: 0xa779, Hi: 0xa779, Stride: 0x1}, + unicode.Range16{Lo: 0xa77b, Hi: 0xa77b, Stride: 0x1}, + unicode.Range16{Lo: 0xa77d, Hi: 0xa77e, Stride: 0x1}, + unicode.Range16{Lo: 0xa780, Hi: 0xa780, Stride: 0x1}, + unicode.Range16{Lo: 0xa782, Hi: 0xa782, Stride: 0x1}, + unicode.Range16{Lo: 0xa784, Hi: 0xa784, Stride: 0x1}, + unicode.Range16{Lo: 0xa786, Hi: 0xa786, Stride: 0x1}, + unicode.Range16{Lo: 0xa78b, Hi: 0xa78b, Stride: 0x1}, + unicode.Range16{Lo: 0xa78d, Hi: 0xa78d, Stride: 0x1}, + unicode.Range16{Lo: 0xa790, Hi: 0xa790, Stride: 0x1}, + unicode.Range16{Lo: 0xa792, Hi: 0xa792, Stride: 0x1}, + unicode.Range16{Lo: 0xa796, Hi: 0xa796, Stride: 0x1}, + unicode.Range16{Lo: 0xa798, Hi: 0xa798, Stride: 0x1}, + unicode.Range16{Lo: 0xa79a, Hi: 0xa79a, Stride: 0x1}, + unicode.Range16{Lo: 0xa79c, Hi: 0xa79c, Stride: 0x1}, + unicode.Range16{Lo: 0xa79e, Hi: 0xa79e, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a0, Hi: 0xa7a0, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a2, Hi: 0xa7a2, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a4, Hi: 0xa7a4, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a6, Hi: 0xa7a6, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a8, Hi: 0xa7a8, Stride: 0x1}, + unicode.Range16{Lo: 0xa7aa, Hi: 0xa7ad, Stride: 0x1}, + unicode.Range16{Lo: 0xa7b0, Hi: 0xa7b1, Stride: 0x1}, + unicode.Range16{Lo: 0xff21, Hi: 0xff3a, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x10400, Hi: 0x10427, Stride: 0x1}, + unicode.Range32{Lo: 0x118a0, Hi: 0x118bf, Stride: 0x1}, + unicode.Range32{Lo: 0x1d400, Hi: 0x1d419, Stride: 0x1}, + unicode.Range32{Lo: 0x1d434, Hi: 0x1d44d, Stride: 0x1}, + unicode.Range32{Lo: 0x1d468, Hi: 0x1d481, Stride: 0x1}, + unicode.Range32{Lo: 0x1d49c, Hi: 0x1d49c, Stride: 0x1}, + unicode.Range32{Lo: 0x1d49e, Hi: 0x1d49f, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4a2, Hi: 0x1d4a2, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4a5, Hi: 0x1d4a6, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4a9, Hi: 0x1d4ac, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4ae, Hi: 0x1d4b5, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4d0, Hi: 0x1d4e9, Stride: 0x1}, + unicode.Range32{Lo: 0x1d504, Hi: 0x1d505, Stride: 0x1}, + unicode.Range32{Lo: 0x1d507, Hi: 0x1d50a, Stride: 0x1}, + unicode.Range32{Lo: 0x1d50d, Hi: 0x1d514, Stride: 0x1}, + unicode.Range32{Lo: 0x1d516, Hi: 0x1d51c, Stride: 0x1}, + unicode.Range32{Lo: 0x1d538, Hi: 0x1d539, Stride: 0x1}, + unicode.Range32{Lo: 0x1d53b, Hi: 0x1d53e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d540, Hi: 0x1d544, Stride: 0x1}, + unicode.Range32{Lo: 0x1d546, Hi: 0x1d546, Stride: 0x1}, + unicode.Range32{Lo: 0x1d54a, Hi: 0x1d550, Stride: 0x1}, + unicode.Range32{Lo: 0x1d56c, Hi: 0x1d585, Stride: 0x1}, + unicode.Range32{Lo: 0x1d5a0, Hi: 0x1d5b9, Stride: 0x1}, + unicode.Range32{Lo: 0x1d5d4, Hi: 0x1d5ed, Stride: 0x1}, + unicode.Range32{Lo: 0x1d608, Hi: 0x1d621, Stride: 0x1}, + unicode.Range32{Lo: 0x1d63c, Hi: 0x1d655, Stride: 0x1}, + unicode.Range32{Lo: 0x1d670, Hi: 0x1d689, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6a8, Hi: 0x1d6c0, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6e2, Hi: 0x1d6fa, Stride: 0x1}, + unicode.Range32{Lo: 0x1d71c, Hi: 0x1d734, Stride: 0x1}, + unicode.Range32{Lo: 0x1d756, Hi: 0x1d76e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d790, Hi: 0x1d7a8, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7ca, Hi: 0x1d7ca, Stride: 0x1}, + unicode.Range32{Lo: 0x1f130, Hi: 0x1f149, Stride: 0x1}, + unicode.Range32{Lo: 0x1f150, Hi: 0x1f169, Stride: 0x1}, + unicode.Range32{Lo: 0x1f170, Hi: 0x1f189, Stride: 0x1}, + }, + LatinOffset: 3, +} + +var _SentenceSContinue = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x2c, Hi: 0x2c, Stride: 0x1}, + unicode.Range16{Lo: 0x2d, Hi: 0x2d, Stride: 0x1}, + unicode.Range16{Lo: 0x3a, Hi: 0x3a, Stride: 0x1}, + unicode.Range16{Lo: 0x55d, Hi: 0x55d, Stride: 0x1}, + unicode.Range16{Lo: 0x60c, Hi: 0x60d, Stride: 0x1}, + unicode.Range16{Lo: 0x7f8, Hi: 0x7f8, Stride: 0x1}, + unicode.Range16{Lo: 0x1802, Hi: 0x1802, Stride: 0x1}, + unicode.Range16{Lo: 0x1808, Hi: 0x1808, Stride: 0x1}, + unicode.Range16{Lo: 0x2013, Hi: 0x2014, Stride: 0x1}, + unicode.Range16{Lo: 0x3001, Hi: 0x3001, Stride: 0x1}, + unicode.Range16{Lo: 0xfe10, Hi: 0xfe11, Stride: 0x1}, + unicode.Range16{Lo: 0xfe13, Hi: 0xfe13, Stride: 0x1}, + unicode.Range16{Lo: 0xfe31, Hi: 0xfe32, Stride: 0x1}, + unicode.Range16{Lo: 0xfe50, Hi: 0xfe51, Stride: 0x1}, + unicode.Range16{Lo: 0xfe55, Hi: 0xfe55, Stride: 0x1}, + unicode.Range16{Lo: 0xfe58, Hi: 0xfe58, Stride: 0x1}, + unicode.Range16{Lo: 0xfe63, Hi: 0xfe63, Stride: 0x1}, + unicode.Range16{Lo: 0xff0c, Hi: 0xff0c, Stride: 0x1}, + unicode.Range16{Lo: 0xff0d, Hi: 0xff0d, Stride: 0x1}, + unicode.Range16{Lo: 0xff1a, Hi: 0xff1a, Stride: 0x1}, + unicode.Range16{Lo: 0xff64, Hi: 0xff64, Stride: 0x1}, + }, + LatinOffset: 3, +} + +var _SentenceExtend = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x300, Hi: 0x36f, Stride: 0x1}, + unicode.Range16{Lo: 0x483, Hi: 0x487, Stride: 0x1}, + unicode.Range16{Lo: 0x488, Hi: 0x489, Stride: 0x1}, + unicode.Range16{Lo: 0x591, Hi: 0x5bd, Stride: 0x1}, + unicode.Range16{Lo: 0x5bf, Hi: 0x5bf, Stride: 0x1}, + unicode.Range16{Lo: 0x5c1, Hi: 0x5c2, Stride: 0x1}, + unicode.Range16{Lo: 0x5c4, Hi: 0x5c5, Stride: 0x1}, + unicode.Range16{Lo: 0x5c7, Hi: 0x5c7, Stride: 0x1}, + unicode.Range16{Lo: 0x610, Hi: 0x61a, Stride: 0x1}, + unicode.Range16{Lo: 0x64b, Hi: 0x65f, Stride: 0x1}, + unicode.Range16{Lo: 0x670, Hi: 0x670, Stride: 0x1}, + unicode.Range16{Lo: 0x6d6, Hi: 0x6dc, Stride: 0x1}, + unicode.Range16{Lo: 0x6df, Hi: 0x6e4, Stride: 0x1}, + unicode.Range16{Lo: 0x6e7, Hi: 0x6e8, Stride: 0x1}, + unicode.Range16{Lo: 0x6ea, Hi: 0x6ed, Stride: 0x1}, + unicode.Range16{Lo: 0x711, Hi: 0x711, Stride: 0x1}, + unicode.Range16{Lo: 0x730, Hi: 0x74a, Stride: 0x1}, + unicode.Range16{Lo: 0x7a6, Hi: 0x7b0, Stride: 0x1}, + unicode.Range16{Lo: 0x7eb, Hi: 0x7f3, Stride: 0x1}, + unicode.Range16{Lo: 0x816, Hi: 0x819, Stride: 0x1}, + unicode.Range16{Lo: 0x81b, Hi: 0x823, Stride: 0x1}, + unicode.Range16{Lo: 0x825, Hi: 0x827, Stride: 0x1}, + unicode.Range16{Lo: 0x829, Hi: 0x82d, Stride: 0x1}, + unicode.Range16{Lo: 0x859, Hi: 0x85b, Stride: 0x1}, + unicode.Range16{Lo: 0x8e4, Hi: 0x902, Stride: 0x1}, + unicode.Range16{Lo: 0x903, Hi: 0x903, Stride: 0x1}, + unicode.Range16{Lo: 0x93a, Hi: 0x93a, Stride: 0x1}, + unicode.Range16{Lo: 0x93b, Hi: 0x93b, Stride: 0x1}, + unicode.Range16{Lo: 0x93c, Hi: 0x93c, Stride: 0x1}, + unicode.Range16{Lo: 0x93e, Hi: 0x940, Stride: 0x1}, + unicode.Range16{Lo: 0x941, Hi: 0x948, Stride: 0x1}, + unicode.Range16{Lo: 0x949, Hi: 0x94c, Stride: 0x1}, + unicode.Range16{Lo: 0x94d, Hi: 0x94d, Stride: 0x1}, + unicode.Range16{Lo: 0x94e, Hi: 0x94f, Stride: 0x1}, + unicode.Range16{Lo: 0x951, Hi: 0x957, Stride: 0x1}, + unicode.Range16{Lo: 0x962, Hi: 0x963, Stride: 0x1}, + unicode.Range16{Lo: 0x981, Hi: 0x981, Stride: 0x1}, + unicode.Range16{Lo: 0x982, Hi: 0x983, Stride: 0x1}, + unicode.Range16{Lo: 0x9bc, Hi: 0x9bc, Stride: 0x1}, + unicode.Range16{Lo: 0x9be, Hi: 0x9c0, Stride: 0x1}, + unicode.Range16{Lo: 0x9c1, Hi: 0x9c4, Stride: 0x1}, + unicode.Range16{Lo: 0x9c7, Hi: 0x9c8, Stride: 0x1}, + unicode.Range16{Lo: 0x9cb, Hi: 0x9cc, Stride: 0x1}, + unicode.Range16{Lo: 0x9cd, Hi: 0x9cd, Stride: 0x1}, + unicode.Range16{Lo: 0x9d7, Hi: 0x9d7, Stride: 0x1}, + unicode.Range16{Lo: 0x9e2, Hi: 0x9e3, Stride: 0x1}, + unicode.Range16{Lo: 0xa01, Hi: 0xa02, Stride: 0x1}, + unicode.Range16{Lo: 0xa03, Hi: 0xa03, Stride: 0x1}, + unicode.Range16{Lo: 0xa3c, Hi: 0xa3c, Stride: 0x1}, + unicode.Range16{Lo: 0xa3e, Hi: 0xa40, Stride: 0x1}, + unicode.Range16{Lo: 0xa41, Hi: 0xa42, Stride: 0x1}, + unicode.Range16{Lo: 0xa47, Hi: 0xa48, Stride: 0x1}, + unicode.Range16{Lo: 0xa4b, Hi: 0xa4d, Stride: 0x1}, + unicode.Range16{Lo: 0xa51, Hi: 0xa51, Stride: 0x1}, + unicode.Range16{Lo: 0xa70, Hi: 0xa71, Stride: 0x1}, + unicode.Range16{Lo: 0xa75, Hi: 0xa75, Stride: 0x1}, + unicode.Range16{Lo: 0xa81, Hi: 0xa82, Stride: 0x1}, + unicode.Range16{Lo: 0xa83, Hi: 0xa83, Stride: 0x1}, + unicode.Range16{Lo: 0xabc, Hi: 0xabc, Stride: 0x1}, + unicode.Range16{Lo: 0xabe, Hi: 0xac0, Stride: 0x1}, + unicode.Range16{Lo: 0xac1, Hi: 0xac5, Stride: 0x1}, + unicode.Range16{Lo: 0xac7, Hi: 0xac8, Stride: 0x1}, + unicode.Range16{Lo: 0xac9, Hi: 0xac9, Stride: 0x1}, + unicode.Range16{Lo: 0xacb, Hi: 0xacc, Stride: 0x1}, + unicode.Range16{Lo: 0xacd, Hi: 0xacd, Stride: 0x1}, + unicode.Range16{Lo: 0xae2, Hi: 0xae3, Stride: 0x1}, + unicode.Range16{Lo: 0xb01, Hi: 0xb01, Stride: 0x1}, + unicode.Range16{Lo: 0xb02, Hi: 0xb03, Stride: 0x1}, + unicode.Range16{Lo: 0xb3c, Hi: 0xb3c, Stride: 0x1}, + unicode.Range16{Lo: 0xb3e, Hi: 0xb3e, Stride: 0x1}, + unicode.Range16{Lo: 0xb3f, Hi: 0xb3f, Stride: 0x1}, + unicode.Range16{Lo: 0xb40, Hi: 0xb40, Stride: 0x1}, + unicode.Range16{Lo: 0xb41, Hi: 0xb44, Stride: 0x1}, + unicode.Range16{Lo: 0xb47, Hi: 0xb48, Stride: 0x1}, + unicode.Range16{Lo: 0xb4b, Hi: 0xb4c, Stride: 0x1}, + unicode.Range16{Lo: 0xb4d, Hi: 0xb4d, Stride: 0x1}, + unicode.Range16{Lo: 0xb56, Hi: 0xb56, Stride: 0x1}, + unicode.Range16{Lo: 0xb57, Hi: 0xb57, Stride: 0x1}, + unicode.Range16{Lo: 0xb62, Hi: 0xb63, Stride: 0x1}, + unicode.Range16{Lo: 0xb82, Hi: 0xb82, Stride: 0x1}, + unicode.Range16{Lo: 0xbbe, Hi: 0xbbf, Stride: 0x1}, + unicode.Range16{Lo: 0xbc0, Hi: 0xbc0, Stride: 0x1}, + unicode.Range16{Lo: 0xbc1, Hi: 0xbc2, Stride: 0x1}, + unicode.Range16{Lo: 0xbc6, Hi: 0xbc8, Stride: 0x1}, + unicode.Range16{Lo: 0xbca, Hi: 0xbcc, Stride: 0x1}, + unicode.Range16{Lo: 0xbcd, Hi: 0xbcd, Stride: 0x1}, + unicode.Range16{Lo: 0xbd7, Hi: 0xbd7, Stride: 0x1}, + unicode.Range16{Lo: 0xc00, Hi: 0xc00, Stride: 0x1}, + unicode.Range16{Lo: 0xc01, Hi: 0xc03, Stride: 0x1}, + unicode.Range16{Lo: 0xc3e, Hi: 0xc40, Stride: 0x1}, + unicode.Range16{Lo: 0xc41, Hi: 0xc44, Stride: 0x1}, + unicode.Range16{Lo: 0xc46, Hi: 0xc48, Stride: 0x1}, + unicode.Range16{Lo: 0xc4a, Hi: 0xc4d, Stride: 0x1}, + unicode.Range16{Lo: 0xc55, Hi: 0xc56, Stride: 0x1}, + unicode.Range16{Lo: 0xc62, Hi: 0xc63, Stride: 0x1}, + unicode.Range16{Lo: 0xc81, Hi: 0xc81, Stride: 0x1}, + unicode.Range16{Lo: 0xc82, Hi: 0xc83, Stride: 0x1}, + unicode.Range16{Lo: 0xcbc, Hi: 0xcbc, Stride: 0x1}, + unicode.Range16{Lo: 0xcbe, Hi: 0xcbe, Stride: 0x1}, + unicode.Range16{Lo: 0xcbf, Hi: 0xcbf, Stride: 0x1}, + unicode.Range16{Lo: 0xcc0, Hi: 0xcc4, Stride: 0x1}, + unicode.Range16{Lo: 0xcc6, Hi: 0xcc6, Stride: 0x1}, + unicode.Range16{Lo: 0xcc7, Hi: 0xcc8, Stride: 0x1}, + unicode.Range16{Lo: 0xcca, Hi: 0xccb, Stride: 0x1}, + unicode.Range16{Lo: 0xccc, Hi: 0xccd, Stride: 0x1}, + unicode.Range16{Lo: 0xcd5, Hi: 0xcd6, Stride: 0x1}, + unicode.Range16{Lo: 0xce2, Hi: 0xce3, Stride: 0x1}, + unicode.Range16{Lo: 0xd01, Hi: 0xd01, Stride: 0x1}, + unicode.Range16{Lo: 0xd02, Hi: 0xd03, Stride: 0x1}, + unicode.Range16{Lo: 0xd3e, Hi: 0xd40, Stride: 0x1}, + unicode.Range16{Lo: 0xd41, Hi: 0xd44, Stride: 0x1}, + unicode.Range16{Lo: 0xd46, Hi: 0xd48, Stride: 0x1}, + unicode.Range16{Lo: 0xd4a, Hi: 0xd4c, Stride: 0x1}, + unicode.Range16{Lo: 0xd4d, Hi: 0xd4d, Stride: 0x1}, + unicode.Range16{Lo: 0xd57, Hi: 0xd57, Stride: 0x1}, + unicode.Range16{Lo: 0xd62, Hi: 0xd63, Stride: 0x1}, + unicode.Range16{Lo: 0xd82, Hi: 0xd83, Stride: 0x1}, + unicode.Range16{Lo: 0xdca, Hi: 0xdca, Stride: 0x1}, + unicode.Range16{Lo: 0xdcf, Hi: 0xdd1, Stride: 0x1}, + unicode.Range16{Lo: 0xdd2, Hi: 0xdd4, Stride: 0x1}, + unicode.Range16{Lo: 0xdd6, Hi: 0xdd6, Stride: 0x1}, + unicode.Range16{Lo: 0xdd8, Hi: 0xddf, Stride: 0x1}, + unicode.Range16{Lo: 0xdf2, Hi: 0xdf3, Stride: 0x1}, + unicode.Range16{Lo: 0xe31, Hi: 0xe31, Stride: 0x1}, + unicode.Range16{Lo: 0xe34, Hi: 0xe3a, Stride: 0x1}, + unicode.Range16{Lo: 0xe47, Hi: 0xe4e, Stride: 0x1}, + unicode.Range16{Lo: 0xeb1, Hi: 0xeb1, Stride: 0x1}, + unicode.Range16{Lo: 0xeb4, Hi: 0xeb9, Stride: 0x1}, + unicode.Range16{Lo: 0xebb, Hi: 0xebc, Stride: 0x1}, + unicode.Range16{Lo: 0xec8, Hi: 0xecd, Stride: 0x1}, + unicode.Range16{Lo: 0xf18, Hi: 0xf19, Stride: 0x1}, + unicode.Range16{Lo: 0xf35, Hi: 0xf35, Stride: 0x1}, + unicode.Range16{Lo: 0xf37, Hi: 0xf37, Stride: 0x1}, + unicode.Range16{Lo: 0xf39, Hi: 0xf39, Stride: 0x1}, + unicode.Range16{Lo: 0xf3e, Hi: 0xf3f, Stride: 0x1}, + unicode.Range16{Lo: 0xf71, Hi: 0xf7e, Stride: 0x1}, + unicode.Range16{Lo: 0xf7f, Hi: 0xf7f, Stride: 0x1}, + unicode.Range16{Lo: 0xf80, Hi: 0xf84, Stride: 0x1}, + unicode.Range16{Lo: 0xf86, Hi: 0xf87, Stride: 0x1}, + unicode.Range16{Lo: 0xf8d, Hi: 0xf97, Stride: 0x1}, + unicode.Range16{Lo: 0xf99, Hi: 0xfbc, Stride: 0x1}, + unicode.Range16{Lo: 0xfc6, Hi: 0xfc6, Stride: 0x1}, + unicode.Range16{Lo: 0x102b, Hi: 0x102c, Stride: 0x1}, + unicode.Range16{Lo: 0x102d, Hi: 0x1030, Stride: 0x1}, + unicode.Range16{Lo: 0x1031, Hi: 0x1031, Stride: 0x1}, + unicode.Range16{Lo: 0x1032, Hi: 0x1037, Stride: 0x1}, + unicode.Range16{Lo: 0x1038, Hi: 0x1038, Stride: 0x1}, + unicode.Range16{Lo: 0x1039, Hi: 0x103a, Stride: 0x1}, + unicode.Range16{Lo: 0x103b, Hi: 0x103c, Stride: 0x1}, + unicode.Range16{Lo: 0x103d, Hi: 0x103e, Stride: 0x1}, + unicode.Range16{Lo: 0x1056, Hi: 0x1057, Stride: 0x1}, + unicode.Range16{Lo: 0x1058, Hi: 0x1059, Stride: 0x1}, + unicode.Range16{Lo: 0x105e, Hi: 0x1060, Stride: 0x1}, + unicode.Range16{Lo: 0x1062, Hi: 0x1064, Stride: 0x1}, + unicode.Range16{Lo: 0x1067, Hi: 0x106d, Stride: 0x1}, + unicode.Range16{Lo: 0x1071, Hi: 0x1074, Stride: 0x1}, + unicode.Range16{Lo: 0x1082, Hi: 0x1082, Stride: 0x1}, + unicode.Range16{Lo: 0x1083, Hi: 0x1084, Stride: 0x1}, + unicode.Range16{Lo: 0x1085, Hi: 0x1086, Stride: 0x1}, + unicode.Range16{Lo: 0x1087, Hi: 0x108c, Stride: 0x1}, + unicode.Range16{Lo: 0x108d, Hi: 0x108d, Stride: 0x1}, + unicode.Range16{Lo: 0x108f, Hi: 0x108f, Stride: 0x1}, + unicode.Range16{Lo: 0x109a, Hi: 0x109c, Stride: 0x1}, + unicode.Range16{Lo: 0x109d, Hi: 0x109d, Stride: 0x1}, + unicode.Range16{Lo: 0x135d, Hi: 0x135f, Stride: 0x1}, + unicode.Range16{Lo: 0x1712, Hi: 0x1714, Stride: 0x1}, + unicode.Range16{Lo: 0x1732, Hi: 0x1734, Stride: 0x1}, + unicode.Range16{Lo: 0x1752, Hi: 0x1753, Stride: 0x1}, + unicode.Range16{Lo: 0x1772, Hi: 0x1773, Stride: 0x1}, + unicode.Range16{Lo: 0x17b4, Hi: 0x17b5, Stride: 0x1}, + unicode.Range16{Lo: 0x17b6, Hi: 0x17b6, Stride: 0x1}, + unicode.Range16{Lo: 0x17b7, Hi: 0x17bd, Stride: 0x1}, + unicode.Range16{Lo: 0x17be, Hi: 0x17c5, Stride: 0x1}, + unicode.Range16{Lo: 0x17c6, Hi: 0x17c6, Stride: 0x1}, + unicode.Range16{Lo: 0x17c7, Hi: 0x17c8, Stride: 0x1}, + unicode.Range16{Lo: 0x17c9, Hi: 0x17d3, Stride: 0x1}, + unicode.Range16{Lo: 0x17dd, Hi: 0x17dd, Stride: 0x1}, + unicode.Range16{Lo: 0x180b, Hi: 0x180d, Stride: 0x1}, + unicode.Range16{Lo: 0x18a9, Hi: 0x18a9, Stride: 0x1}, + unicode.Range16{Lo: 0x1920, Hi: 0x1922, Stride: 0x1}, + unicode.Range16{Lo: 0x1923, Hi: 0x1926, Stride: 0x1}, + unicode.Range16{Lo: 0x1927, Hi: 0x1928, Stride: 0x1}, + unicode.Range16{Lo: 0x1929, Hi: 0x192b, Stride: 0x1}, + unicode.Range16{Lo: 0x1930, Hi: 0x1931, Stride: 0x1}, + unicode.Range16{Lo: 0x1932, Hi: 0x1932, Stride: 0x1}, + unicode.Range16{Lo: 0x1933, Hi: 0x1938, Stride: 0x1}, + unicode.Range16{Lo: 0x1939, Hi: 0x193b, Stride: 0x1}, + unicode.Range16{Lo: 0x19b0, Hi: 0x19c0, Stride: 0x1}, + unicode.Range16{Lo: 0x19c8, Hi: 0x19c9, Stride: 0x1}, + unicode.Range16{Lo: 0x1a17, Hi: 0x1a18, Stride: 0x1}, + unicode.Range16{Lo: 0x1a19, Hi: 0x1a1a, Stride: 0x1}, + unicode.Range16{Lo: 0x1a1b, Hi: 0x1a1b, Stride: 0x1}, + unicode.Range16{Lo: 0x1a55, Hi: 0x1a55, Stride: 0x1}, + unicode.Range16{Lo: 0x1a56, Hi: 0x1a56, Stride: 0x1}, + unicode.Range16{Lo: 0x1a57, Hi: 0x1a57, Stride: 0x1}, + unicode.Range16{Lo: 0x1a58, Hi: 0x1a5e, Stride: 0x1}, + unicode.Range16{Lo: 0x1a60, Hi: 0x1a60, Stride: 0x1}, + unicode.Range16{Lo: 0x1a61, Hi: 0x1a61, Stride: 0x1}, + unicode.Range16{Lo: 0x1a62, Hi: 0x1a62, Stride: 0x1}, + unicode.Range16{Lo: 0x1a63, Hi: 0x1a64, Stride: 0x1}, + unicode.Range16{Lo: 0x1a65, Hi: 0x1a6c, Stride: 0x1}, + unicode.Range16{Lo: 0x1a6d, Hi: 0x1a72, Stride: 0x1}, + unicode.Range16{Lo: 0x1a73, Hi: 0x1a7c, Stride: 0x1}, + unicode.Range16{Lo: 0x1a7f, Hi: 0x1a7f, Stride: 0x1}, + unicode.Range16{Lo: 0x1ab0, Hi: 0x1abd, Stride: 0x1}, + unicode.Range16{Lo: 0x1abe, Hi: 0x1abe, Stride: 0x1}, + unicode.Range16{Lo: 0x1b00, Hi: 0x1b03, Stride: 0x1}, + unicode.Range16{Lo: 0x1b04, Hi: 0x1b04, Stride: 0x1}, + unicode.Range16{Lo: 0x1b34, Hi: 0x1b34, Stride: 0x1}, + unicode.Range16{Lo: 0x1b35, Hi: 0x1b35, Stride: 0x1}, + unicode.Range16{Lo: 0x1b36, Hi: 0x1b3a, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3b, Hi: 0x1b3b, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3c, Hi: 0x1b3c, Stride: 0x1}, + unicode.Range16{Lo: 0x1b3d, Hi: 0x1b41, Stride: 0x1}, + unicode.Range16{Lo: 0x1b42, Hi: 0x1b42, Stride: 0x1}, + unicode.Range16{Lo: 0x1b43, Hi: 0x1b44, Stride: 0x1}, + unicode.Range16{Lo: 0x1b6b, Hi: 0x1b73, Stride: 0x1}, + unicode.Range16{Lo: 0x1b80, Hi: 0x1b81, Stride: 0x1}, + unicode.Range16{Lo: 0x1b82, Hi: 0x1b82, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba1, Hi: 0x1ba1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba2, Hi: 0x1ba5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba6, Hi: 0x1ba7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ba8, Hi: 0x1ba9, Stride: 0x1}, + unicode.Range16{Lo: 0x1baa, Hi: 0x1baa, Stride: 0x1}, + unicode.Range16{Lo: 0x1bab, Hi: 0x1bad, Stride: 0x1}, + unicode.Range16{Lo: 0x1be6, Hi: 0x1be6, Stride: 0x1}, + unicode.Range16{Lo: 0x1be7, Hi: 0x1be7, Stride: 0x1}, + unicode.Range16{Lo: 0x1be8, Hi: 0x1be9, Stride: 0x1}, + unicode.Range16{Lo: 0x1bea, Hi: 0x1bec, Stride: 0x1}, + unicode.Range16{Lo: 0x1bed, Hi: 0x1bed, Stride: 0x1}, + unicode.Range16{Lo: 0x1bee, Hi: 0x1bee, Stride: 0x1}, + unicode.Range16{Lo: 0x1bef, Hi: 0x1bf1, Stride: 0x1}, + unicode.Range16{Lo: 0x1bf2, Hi: 0x1bf3, Stride: 0x1}, + unicode.Range16{Lo: 0x1c24, Hi: 0x1c2b, Stride: 0x1}, + unicode.Range16{Lo: 0x1c2c, Hi: 0x1c33, Stride: 0x1}, + unicode.Range16{Lo: 0x1c34, Hi: 0x1c35, Stride: 0x1}, + unicode.Range16{Lo: 0x1c36, Hi: 0x1c37, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd0, Hi: 0x1cd2, Stride: 0x1}, + unicode.Range16{Lo: 0x1cd4, Hi: 0x1ce0, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce1, Hi: 0x1ce1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce2, Hi: 0x1ce8, Stride: 0x1}, + unicode.Range16{Lo: 0x1ced, Hi: 0x1ced, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf2, Hi: 0x1cf3, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf4, Hi: 0x1cf4, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf8, Hi: 0x1cf9, Stride: 0x1}, + unicode.Range16{Lo: 0x1dc0, Hi: 0x1df5, Stride: 0x1}, + unicode.Range16{Lo: 0x1dfc, Hi: 0x1dff, Stride: 0x1}, + unicode.Range16{Lo: 0x200c, Hi: 0x200d, Stride: 0x1}, + unicode.Range16{Lo: 0x20d0, Hi: 0x20dc, Stride: 0x1}, + unicode.Range16{Lo: 0x20dd, Hi: 0x20e0, Stride: 0x1}, + unicode.Range16{Lo: 0x20e1, Hi: 0x20e1, Stride: 0x1}, + unicode.Range16{Lo: 0x20e2, Hi: 0x20e4, Stride: 0x1}, + unicode.Range16{Lo: 0x20e5, Hi: 0x20f0, Stride: 0x1}, + unicode.Range16{Lo: 0x2cef, Hi: 0x2cf1, Stride: 0x1}, + unicode.Range16{Lo: 0x2d7f, Hi: 0x2d7f, Stride: 0x1}, + unicode.Range16{Lo: 0x2de0, Hi: 0x2dff, Stride: 0x1}, + unicode.Range16{Lo: 0x302a, Hi: 0x302d, Stride: 0x1}, + unicode.Range16{Lo: 0x302e, Hi: 0x302f, Stride: 0x1}, + unicode.Range16{Lo: 0x3099, Hi: 0x309a, Stride: 0x1}, + unicode.Range16{Lo: 0xa66f, Hi: 0xa66f, Stride: 0x1}, + unicode.Range16{Lo: 0xa670, Hi: 0xa672, Stride: 0x1}, + unicode.Range16{Lo: 0xa674, Hi: 0xa67d, Stride: 0x1}, + unicode.Range16{Lo: 0xa69f, Hi: 0xa69f, Stride: 0x1}, + unicode.Range16{Lo: 0xa6f0, Hi: 0xa6f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa802, Hi: 0xa802, Stride: 0x1}, + unicode.Range16{Lo: 0xa806, Hi: 0xa806, Stride: 0x1}, + unicode.Range16{Lo: 0xa80b, Hi: 0xa80b, Stride: 0x1}, + unicode.Range16{Lo: 0xa823, Hi: 0xa824, Stride: 0x1}, + unicode.Range16{Lo: 0xa825, Hi: 0xa826, Stride: 0x1}, + unicode.Range16{Lo: 0xa827, Hi: 0xa827, Stride: 0x1}, + unicode.Range16{Lo: 0xa880, Hi: 0xa881, Stride: 0x1}, + unicode.Range16{Lo: 0xa8b4, Hi: 0xa8c3, Stride: 0x1}, + unicode.Range16{Lo: 0xa8c4, Hi: 0xa8c4, Stride: 0x1}, + unicode.Range16{Lo: 0xa8e0, Hi: 0xa8f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa926, Hi: 0xa92d, Stride: 0x1}, + unicode.Range16{Lo: 0xa947, Hi: 0xa951, Stride: 0x1}, + unicode.Range16{Lo: 0xa952, Hi: 0xa953, Stride: 0x1}, + unicode.Range16{Lo: 0xa980, Hi: 0xa982, Stride: 0x1}, + unicode.Range16{Lo: 0xa983, Hi: 0xa983, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b3, Hi: 0xa9b3, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b4, Hi: 0xa9b5, Stride: 0x1}, + unicode.Range16{Lo: 0xa9b6, Hi: 0xa9b9, Stride: 0x1}, + unicode.Range16{Lo: 0xa9ba, Hi: 0xa9bb, Stride: 0x1}, + unicode.Range16{Lo: 0xa9bc, Hi: 0xa9bc, Stride: 0x1}, + unicode.Range16{Lo: 0xa9bd, Hi: 0xa9c0, Stride: 0x1}, + unicode.Range16{Lo: 0xa9e5, Hi: 0xa9e5, Stride: 0x1}, + unicode.Range16{Lo: 0xaa29, Hi: 0xaa2e, Stride: 0x1}, + unicode.Range16{Lo: 0xaa2f, Hi: 0xaa30, Stride: 0x1}, + unicode.Range16{Lo: 0xaa31, Hi: 0xaa32, Stride: 0x1}, + unicode.Range16{Lo: 0xaa33, Hi: 0xaa34, Stride: 0x1}, + unicode.Range16{Lo: 0xaa35, Hi: 0xaa36, Stride: 0x1}, + unicode.Range16{Lo: 0xaa43, Hi: 0xaa43, Stride: 0x1}, + unicode.Range16{Lo: 0xaa4c, Hi: 0xaa4c, Stride: 0x1}, + unicode.Range16{Lo: 0xaa4d, Hi: 0xaa4d, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7b, Hi: 0xaa7b, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7c, Hi: 0xaa7c, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7d, Hi: 0xaa7d, Stride: 0x1}, + unicode.Range16{Lo: 0xaab0, Hi: 0xaab0, Stride: 0x1}, + unicode.Range16{Lo: 0xaab2, Hi: 0xaab4, Stride: 0x1}, + unicode.Range16{Lo: 0xaab7, Hi: 0xaab8, Stride: 0x1}, + unicode.Range16{Lo: 0xaabe, Hi: 0xaabf, Stride: 0x1}, + unicode.Range16{Lo: 0xaac1, Hi: 0xaac1, Stride: 0x1}, + unicode.Range16{Lo: 0xaaeb, Hi: 0xaaeb, Stride: 0x1}, + unicode.Range16{Lo: 0xaaec, Hi: 0xaaed, Stride: 0x1}, + unicode.Range16{Lo: 0xaaee, Hi: 0xaaef, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf5, Hi: 0xaaf5, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf6, Hi: 0xaaf6, Stride: 0x1}, + unicode.Range16{Lo: 0xabe3, Hi: 0xabe4, Stride: 0x1}, + unicode.Range16{Lo: 0xabe5, Hi: 0xabe5, Stride: 0x1}, + unicode.Range16{Lo: 0xabe6, Hi: 0xabe7, Stride: 0x1}, + unicode.Range16{Lo: 0xabe8, Hi: 0xabe8, Stride: 0x1}, + unicode.Range16{Lo: 0xabe9, Hi: 0xabea, Stride: 0x1}, + unicode.Range16{Lo: 0xabec, Hi: 0xabec, Stride: 0x1}, + unicode.Range16{Lo: 0xabed, Hi: 0xabed, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1e, Hi: 0xfb1e, Stride: 0x1}, + unicode.Range16{Lo: 0xfe00, Hi: 0xfe0f, Stride: 0x1}, + unicode.Range16{Lo: 0xfe20, Hi: 0xfe2d, Stride: 0x1}, + unicode.Range16{Lo: 0xff9e, Hi: 0xff9f, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x101fd, Hi: 0x101fd, Stride: 0x1}, + unicode.Range32{Lo: 0x102e0, Hi: 0x102e0, Stride: 0x1}, + unicode.Range32{Lo: 0x10376, Hi: 0x1037a, Stride: 0x1}, + unicode.Range32{Lo: 0x10a01, Hi: 0x10a03, Stride: 0x1}, + unicode.Range32{Lo: 0x10a05, Hi: 0x10a06, Stride: 0x1}, + unicode.Range32{Lo: 0x10a0c, Hi: 0x10a0f, Stride: 0x1}, + unicode.Range32{Lo: 0x10a38, Hi: 0x10a3a, Stride: 0x1}, + unicode.Range32{Lo: 0x10a3f, Hi: 0x10a3f, Stride: 0x1}, + unicode.Range32{Lo: 0x10ae5, Hi: 0x10ae6, Stride: 0x1}, + unicode.Range32{Lo: 0x11000, Hi: 0x11000, Stride: 0x1}, + unicode.Range32{Lo: 0x11001, Hi: 0x11001, Stride: 0x1}, + unicode.Range32{Lo: 0x11002, Hi: 0x11002, Stride: 0x1}, + unicode.Range32{Lo: 0x11038, Hi: 0x11046, Stride: 0x1}, + unicode.Range32{Lo: 0x1107f, Hi: 0x11081, Stride: 0x1}, + unicode.Range32{Lo: 0x11082, Hi: 0x11082, Stride: 0x1}, + unicode.Range32{Lo: 0x110b0, Hi: 0x110b2, Stride: 0x1}, + unicode.Range32{Lo: 0x110b3, Hi: 0x110b6, Stride: 0x1}, + unicode.Range32{Lo: 0x110b7, Hi: 0x110b8, Stride: 0x1}, + unicode.Range32{Lo: 0x110b9, Hi: 0x110ba, Stride: 0x1}, + unicode.Range32{Lo: 0x11100, Hi: 0x11102, Stride: 0x1}, + unicode.Range32{Lo: 0x11127, Hi: 0x1112b, Stride: 0x1}, + unicode.Range32{Lo: 0x1112c, Hi: 0x1112c, Stride: 0x1}, + unicode.Range32{Lo: 0x1112d, Hi: 0x11134, Stride: 0x1}, + unicode.Range32{Lo: 0x11173, Hi: 0x11173, Stride: 0x1}, + unicode.Range32{Lo: 0x11180, Hi: 0x11181, Stride: 0x1}, + unicode.Range32{Lo: 0x11182, Hi: 0x11182, Stride: 0x1}, + unicode.Range32{Lo: 0x111b3, Hi: 0x111b5, Stride: 0x1}, + unicode.Range32{Lo: 0x111b6, Hi: 0x111be, Stride: 0x1}, + unicode.Range32{Lo: 0x111bf, Hi: 0x111c0, Stride: 0x1}, + unicode.Range32{Lo: 0x1122c, Hi: 0x1122e, Stride: 0x1}, + unicode.Range32{Lo: 0x1122f, Hi: 0x11231, Stride: 0x1}, + unicode.Range32{Lo: 0x11232, Hi: 0x11233, Stride: 0x1}, + unicode.Range32{Lo: 0x11234, Hi: 0x11234, Stride: 0x1}, + unicode.Range32{Lo: 0x11235, Hi: 0x11235, Stride: 0x1}, + unicode.Range32{Lo: 0x11236, Hi: 0x11237, Stride: 0x1}, + unicode.Range32{Lo: 0x112df, Hi: 0x112df, Stride: 0x1}, + unicode.Range32{Lo: 0x112e0, Hi: 0x112e2, Stride: 0x1}, + unicode.Range32{Lo: 0x112e3, Hi: 0x112ea, Stride: 0x1}, + unicode.Range32{Lo: 0x11301, Hi: 0x11301, Stride: 0x1}, + unicode.Range32{Lo: 0x11302, Hi: 0x11303, Stride: 0x1}, + unicode.Range32{Lo: 0x1133c, Hi: 0x1133c, Stride: 0x1}, + unicode.Range32{Lo: 0x1133e, Hi: 0x1133f, Stride: 0x1}, + unicode.Range32{Lo: 0x11340, Hi: 0x11340, Stride: 0x1}, + unicode.Range32{Lo: 0x11341, Hi: 0x11344, Stride: 0x1}, + unicode.Range32{Lo: 0x11347, Hi: 0x11348, Stride: 0x1}, + unicode.Range32{Lo: 0x1134b, Hi: 0x1134d, Stride: 0x1}, + unicode.Range32{Lo: 0x11357, Hi: 0x11357, Stride: 0x1}, + unicode.Range32{Lo: 0x11362, Hi: 0x11363, Stride: 0x1}, + unicode.Range32{Lo: 0x11366, Hi: 0x1136c, Stride: 0x1}, + unicode.Range32{Lo: 0x11370, Hi: 0x11374, Stride: 0x1}, + unicode.Range32{Lo: 0x114b0, Hi: 0x114b2, Stride: 0x1}, + unicode.Range32{Lo: 0x114b3, Hi: 0x114b8, Stride: 0x1}, + unicode.Range32{Lo: 0x114b9, Hi: 0x114b9, Stride: 0x1}, + unicode.Range32{Lo: 0x114ba, Hi: 0x114ba, Stride: 0x1}, + unicode.Range32{Lo: 0x114bb, Hi: 0x114be, Stride: 0x1}, + unicode.Range32{Lo: 0x114bf, Hi: 0x114c0, Stride: 0x1}, + unicode.Range32{Lo: 0x114c1, Hi: 0x114c1, Stride: 0x1}, + unicode.Range32{Lo: 0x114c2, Hi: 0x114c3, Stride: 0x1}, + unicode.Range32{Lo: 0x115af, Hi: 0x115b1, Stride: 0x1}, + unicode.Range32{Lo: 0x115b2, Hi: 0x115b5, Stride: 0x1}, + unicode.Range32{Lo: 0x115b8, Hi: 0x115bb, Stride: 0x1}, + unicode.Range32{Lo: 0x115bc, Hi: 0x115bd, Stride: 0x1}, + unicode.Range32{Lo: 0x115be, Hi: 0x115be, Stride: 0x1}, + unicode.Range32{Lo: 0x115bf, Hi: 0x115c0, Stride: 0x1}, + unicode.Range32{Lo: 0x11630, Hi: 0x11632, Stride: 0x1}, + unicode.Range32{Lo: 0x11633, Hi: 0x1163a, Stride: 0x1}, + unicode.Range32{Lo: 0x1163b, Hi: 0x1163c, Stride: 0x1}, + unicode.Range32{Lo: 0x1163d, Hi: 0x1163d, Stride: 0x1}, + unicode.Range32{Lo: 0x1163e, Hi: 0x1163e, Stride: 0x1}, + unicode.Range32{Lo: 0x1163f, Hi: 0x11640, Stride: 0x1}, + unicode.Range32{Lo: 0x116ab, Hi: 0x116ab, Stride: 0x1}, + unicode.Range32{Lo: 0x116ac, Hi: 0x116ac, Stride: 0x1}, + unicode.Range32{Lo: 0x116ad, Hi: 0x116ad, Stride: 0x1}, + unicode.Range32{Lo: 0x116ae, Hi: 0x116af, Stride: 0x1}, + unicode.Range32{Lo: 0x116b0, Hi: 0x116b5, Stride: 0x1}, + unicode.Range32{Lo: 0x116b6, Hi: 0x116b6, Stride: 0x1}, + unicode.Range32{Lo: 0x116b7, Hi: 0x116b7, Stride: 0x1}, + unicode.Range32{Lo: 0x16af0, Hi: 0x16af4, Stride: 0x1}, + unicode.Range32{Lo: 0x16b30, Hi: 0x16b36, Stride: 0x1}, + unicode.Range32{Lo: 0x16f51, Hi: 0x16f7e, Stride: 0x1}, + unicode.Range32{Lo: 0x16f8f, Hi: 0x16f92, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc9d, Hi: 0x1bc9e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d165, Hi: 0x1d166, Stride: 0x1}, + unicode.Range32{Lo: 0x1d167, Hi: 0x1d169, Stride: 0x1}, + unicode.Range32{Lo: 0x1d16d, Hi: 0x1d172, Stride: 0x1}, + unicode.Range32{Lo: 0x1d17b, Hi: 0x1d182, Stride: 0x1}, + unicode.Range32{Lo: 0x1d185, Hi: 0x1d18b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d1aa, Hi: 0x1d1ad, Stride: 0x1}, + unicode.Range32{Lo: 0x1d242, Hi: 0x1d244, Stride: 0x1}, + unicode.Range32{Lo: 0x1e8d0, Hi: 0x1e8d6, Stride: 0x1}, + unicode.Range32{Lo: 0xe0100, Hi: 0xe01ef, Stride: 0x1}, + }, + LatinOffset: 0, +} + +var _SentenceLower = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x61, Hi: 0x7a, Stride: 0x1}, + unicode.Range16{Lo: 0xaa, Hi: 0xaa, Stride: 0x1}, + unicode.Range16{Lo: 0xb5, Hi: 0xb5, Stride: 0x1}, + unicode.Range16{Lo: 0xba, Hi: 0xba, Stride: 0x1}, + unicode.Range16{Lo: 0xdf, Hi: 0xf6, Stride: 0x1}, + unicode.Range16{Lo: 0xf8, Hi: 0xff, Stride: 0x1}, + unicode.Range16{Lo: 0x101, Hi: 0x101, Stride: 0x1}, + unicode.Range16{Lo: 0x103, Hi: 0x103, Stride: 0x1}, + unicode.Range16{Lo: 0x105, Hi: 0x105, Stride: 0x1}, + unicode.Range16{Lo: 0x107, Hi: 0x107, Stride: 0x1}, + unicode.Range16{Lo: 0x109, Hi: 0x109, Stride: 0x1}, + unicode.Range16{Lo: 0x10b, Hi: 0x10b, Stride: 0x1}, + unicode.Range16{Lo: 0x10d, Hi: 0x10d, Stride: 0x1}, + unicode.Range16{Lo: 0x10f, Hi: 0x10f, Stride: 0x1}, + unicode.Range16{Lo: 0x111, Hi: 0x111, Stride: 0x1}, + unicode.Range16{Lo: 0x113, Hi: 0x113, Stride: 0x1}, + unicode.Range16{Lo: 0x115, Hi: 0x115, Stride: 0x1}, + unicode.Range16{Lo: 0x117, Hi: 0x117, Stride: 0x1}, + unicode.Range16{Lo: 0x119, Hi: 0x119, Stride: 0x1}, + unicode.Range16{Lo: 0x11b, Hi: 0x11b, Stride: 0x1}, + unicode.Range16{Lo: 0x11d, Hi: 0x11d, Stride: 0x1}, + unicode.Range16{Lo: 0x11f, Hi: 0x11f, Stride: 0x1}, + unicode.Range16{Lo: 0x121, Hi: 0x121, Stride: 0x1}, + unicode.Range16{Lo: 0x123, Hi: 0x123, Stride: 0x1}, + unicode.Range16{Lo: 0x125, Hi: 0x125, Stride: 0x1}, + unicode.Range16{Lo: 0x127, Hi: 0x127, Stride: 0x1}, + unicode.Range16{Lo: 0x129, Hi: 0x129, Stride: 0x1}, + unicode.Range16{Lo: 0x12b, Hi: 0x12b, Stride: 0x1}, + unicode.Range16{Lo: 0x12d, Hi: 0x12d, Stride: 0x1}, + unicode.Range16{Lo: 0x12f, Hi: 0x12f, Stride: 0x1}, + unicode.Range16{Lo: 0x131, Hi: 0x131, Stride: 0x1}, + unicode.Range16{Lo: 0x133, Hi: 0x133, Stride: 0x1}, + unicode.Range16{Lo: 0x135, Hi: 0x135, Stride: 0x1}, + unicode.Range16{Lo: 0x137, Hi: 0x138, Stride: 0x1}, + unicode.Range16{Lo: 0x13a, Hi: 0x13a, Stride: 0x1}, + unicode.Range16{Lo: 0x13c, Hi: 0x13c, Stride: 0x1}, + unicode.Range16{Lo: 0x13e, Hi: 0x13e, Stride: 0x1}, + unicode.Range16{Lo: 0x140, Hi: 0x140, Stride: 0x1}, + unicode.Range16{Lo: 0x142, Hi: 0x142, Stride: 0x1}, + unicode.Range16{Lo: 0x144, Hi: 0x144, Stride: 0x1}, + unicode.Range16{Lo: 0x146, Hi: 0x146, Stride: 0x1}, + unicode.Range16{Lo: 0x148, Hi: 0x149, Stride: 0x1}, + unicode.Range16{Lo: 0x14b, Hi: 0x14b, Stride: 0x1}, + unicode.Range16{Lo: 0x14d, Hi: 0x14d, Stride: 0x1}, + unicode.Range16{Lo: 0x14f, Hi: 0x14f, Stride: 0x1}, + unicode.Range16{Lo: 0x151, Hi: 0x151, Stride: 0x1}, + unicode.Range16{Lo: 0x153, Hi: 0x153, Stride: 0x1}, + unicode.Range16{Lo: 0x155, Hi: 0x155, Stride: 0x1}, + unicode.Range16{Lo: 0x157, Hi: 0x157, Stride: 0x1}, + unicode.Range16{Lo: 0x159, Hi: 0x159, Stride: 0x1}, + unicode.Range16{Lo: 0x15b, Hi: 0x15b, Stride: 0x1}, + unicode.Range16{Lo: 0x15d, Hi: 0x15d, Stride: 0x1}, + unicode.Range16{Lo: 0x15f, Hi: 0x15f, Stride: 0x1}, + unicode.Range16{Lo: 0x161, Hi: 0x161, Stride: 0x1}, + unicode.Range16{Lo: 0x163, Hi: 0x163, Stride: 0x1}, + unicode.Range16{Lo: 0x165, Hi: 0x165, Stride: 0x1}, + unicode.Range16{Lo: 0x167, Hi: 0x167, Stride: 0x1}, + unicode.Range16{Lo: 0x169, Hi: 0x169, Stride: 0x1}, + unicode.Range16{Lo: 0x16b, Hi: 0x16b, Stride: 0x1}, + unicode.Range16{Lo: 0x16d, Hi: 0x16d, Stride: 0x1}, + unicode.Range16{Lo: 0x16f, Hi: 0x16f, Stride: 0x1}, + unicode.Range16{Lo: 0x171, Hi: 0x171, Stride: 0x1}, + unicode.Range16{Lo: 0x173, Hi: 0x173, Stride: 0x1}, + unicode.Range16{Lo: 0x175, Hi: 0x175, Stride: 0x1}, + unicode.Range16{Lo: 0x177, Hi: 0x177, Stride: 0x1}, + unicode.Range16{Lo: 0x17a, Hi: 0x17a, Stride: 0x1}, + unicode.Range16{Lo: 0x17c, Hi: 0x17c, Stride: 0x1}, + unicode.Range16{Lo: 0x17e, Hi: 0x180, Stride: 0x1}, + unicode.Range16{Lo: 0x183, Hi: 0x183, Stride: 0x1}, + unicode.Range16{Lo: 0x185, Hi: 0x185, Stride: 0x1}, + unicode.Range16{Lo: 0x188, Hi: 0x188, Stride: 0x1}, + unicode.Range16{Lo: 0x18c, Hi: 0x18d, Stride: 0x1}, + unicode.Range16{Lo: 0x192, Hi: 0x192, Stride: 0x1}, + unicode.Range16{Lo: 0x195, Hi: 0x195, Stride: 0x1}, + unicode.Range16{Lo: 0x199, Hi: 0x19b, Stride: 0x1}, + unicode.Range16{Lo: 0x19e, Hi: 0x19e, Stride: 0x1}, + unicode.Range16{Lo: 0x1a1, Hi: 0x1a1, Stride: 0x1}, + unicode.Range16{Lo: 0x1a3, Hi: 0x1a3, Stride: 0x1}, + unicode.Range16{Lo: 0x1a5, Hi: 0x1a5, Stride: 0x1}, + unicode.Range16{Lo: 0x1a8, Hi: 0x1a8, Stride: 0x1}, + unicode.Range16{Lo: 0x1aa, Hi: 0x1ab, Stride: 0x1}, + unicode.Range16{Lo: 0x1ad, Hi: 0x1ad, Stride: 0x1}, + unicode.Range16{Lo: 0x1b0, Hi: 0x1b0, Stride: 0x1}, + unicode.Range16{Lo: 0x1b4, Hi: 0x1b4, Stride: 0x1}, + unicode.Range16{Lo: 0x1b6, Hi: 0x1b6, Stride: 0x1}, + unicode.Range16{Lo: 0x1b9, Hi: 0x1ba, Stride: 0x1}, + unicode.Range16{Lo: 0x1bd, Hi: 0x1bf, Stride: 0x1}, + unicode.Range16{Lo: 0x1c6, Hi: 0x1c6, Stride: 0x1}, + unicode.Range16{Lo: 0x1c9, Hi: 0x1c9, Stride: 0x1}, + unicode.Range16{Lo: 0x1cc, Hi: 0x1cc, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce, Hi: 0x1ce, Stride: 0x1}, + unicode.Range16{Lo: 0x1d0, Hi: 0x1d0, Stride: 0x1}, + unicode.Range16{Lo: 0x1d2, Hi: 0x1d2, Stride: 0x1}, + unicode.Range16{Lo: 0x1d4, Hi: 0x1d4, Stride: 0x1}, + unicode.Range16{Lo: 0x1d6, Hi: 0x1d6, Stride: 0x1}, + unicode.Range16{Lo: 0x1d8, Hi: 0x1d8, Stride: 0x1}, + unicode.Range16{Lo: 0x1da, Hi: 0x1da, Stride: 0x1}, + unicode.Range16{Lo: 0x1dc, Hi: 0x1dd, Stride: 0x1}, + unicode.Range16{Lo: 0x1df, Hi: 0x1df, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1, Hi: 0x1e1, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3, Hi: 0x1e3, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5, Hi: 0x1e5, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7, Hi: 0x1e7, Stride: 0x1}, + unicode.Range16{Lo: 0x1e9, Hi: 0x1e9, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb, Hi: 0x1eb, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed, Hi: 0x1ed, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef, Hi: 0x1f0, Stride: 0x1}, + unicode.Range16{Lo: 0x1f3, Hi: 0x1f3, Stride: 0x1}, + unicode.Range16{Lo: 0x1f5, Hi: 0x1f5, Stride: 0x1}, + unicode.Range16{Lo: 0x1f9, Hi: 0x1f9, Stride: 0x1}, + unicode.Range16{Lo: 0x1fb, Hi: 0x1fb, Stride: 0x1}, + unicode.Range16{Lo: 0x1fd, Hi: 0x1fd, Stride: 0x1}, + unicode.Range16{Lo: 0x1ff, Hi: 0x1ff, Stride: 0x1}, + unicode.Range16{Lo: 0x201, Hi: 0x201, Stride: 0x1}, + unicode.Range16{Lo: 0x203, Hi: 0x203, Stride: 0x1}, + unicode.Range16{Lo: 0x205, Hi: 0x205, Stride: 0x1}, + unicode.Range16{Lo: 0x207, Hi: 0x207, Stride: 0x1}, + unicode.Range16{Lo: 0x209, Hi: 0x209, Stride: 0x1}, + unicode.Range16{Lo: 0x20b, Hi: 0x20b, Stride: 0x1}, + unicode.Range16{Lo: 0x20d, Hi: 0x20d, Stride: 0x1}, + unicode.Range16{Lo: 0x20f, Hi: 0x20f, Stride: 0x1}, + unicode.Range16{Lo: 0x211, Hi: 0x211, Stride: 0x1}, + unicode.Range16{Lo: 0x213, Hi: 0x213, Stride: 0x1}, + unicode.Range16{Lo: 0x215, Hi: 0x215, Stride: 0x1}, + unicode.Range16{Lo: 0x217, Hi: 0x217, Stride: 0x1}, + unicode.Range16{Lo: 0x219, Hi: 0x219, Stride: 0x1}, + unicode.Range16{Lo: 0x21b, Hi: 0x21b, Stride: 0x1}, + unicode.Range16{Lo: 0x21d, Hi: 0x21d, Stride: 0x1}, + unicode.Range16{Lo: 0x21f, Hi: 0x21f, Stride: 0x1}, + unicode.Range16{Lo: 0x221, Hi: 0x221, Stride: 0x1}, + unicode.Range16{Lo: 0x223, Hi: 0x223, Stride: 0x1}, + unicode.Range16{Lo: 0x225, Hi: 0x225, Stride: 0x1}, + unicode.Range16{Lo: 0x227, Hi: 0x227, Stride: 0x1}, + unicode.Range16{Lo: 0x229, Hi: 0x229, Stride: 0x1}, + unicode.Range16{Lo: 0x22b, Hi: 0x22b, Stride: 0x1}, + unicode.Range16{Lo: 0x22d, Hi: 0x22d, Stride: 0x1}, + unicode.Range16{Lo: 0x22f, Hi: 0x22f, Stride: 0x1}, + unicode.Range16{Lo: 0x231, Hi: 0x231, Stride: 0x1}, + unicode.Range16{Lo: 0x233, Hi: 0x239, Stride: 0x1}, + unicode.Range16{Lo: 0x23c, Hi: 0x23c, Stride: 0x1}, + unicode.Range16{Lo: 0x23f, Hi: 0x240, Stride: 0x1}, + unicode.Range16{Lo: 0x242, Hi: 0x242, Stride: 0x1}, + unicode.Range16{Lo: 0x247, Hi: 0x247, Stride: 0x1}, + unicode.Range16{Lo: 0x249, Hi: 0x249, Stride: 0x1}, + unicode.Range16{Lo: 0x24b, Hi: 0x24b, Stride: 0x1}, + unicode.Range16{Lo: 0x24d, Hi: 0x24d, Stride: 0x1}, + unicode.Range16{Lo: 0x24f, Hi: 0x293, Stride: 0x1}, + unicode.Range16{Lo: 0x295, Hi: 0x2af, Stride: 0x1}, + unicode.Range16{Lo: 0x2b0, Hi: 0x2b8, Stride: 0x1}, + unicode.Range16{Lo: 0x2c0, Hi: 0x2c1, Stride: 0x1}, + unicode.Range16{Lo: 0x2e0, Hi: 0x2e4, Stride: 0x1}, + unicode.Range16{Lo: 0x371, Hi: 0x371, Stride: 0x1}, + unicode.Range16{Lo: 0x373, Hi: 0x373, Stride: 0x1}, + unicode.Range16{Lo: 0x377, Hi: 0x377, Stride: 0x1}, + unicode.Range16{Lo: 0x37a, Hi: 0x37a, Stride: 0x1}, + unicode.Range16{Lo: 0x37b, Hi: 0x37d, Stride: 0x1}, + unicode.Range16{Lo: 0x390, Hi: 0x390, Stride: 0x1}, + unicode.Range16{Lo: 0x3ac, Hi: 0x3ce, Stride: 0x1}, + unicode.Range16{Lo: 0x3d0, Hi: 0x3d1, Stride: 0x1}, + unicode.Range16{Lo: 0x3d5, Hi: 0x3d7, Stride: 0x1}, + unicode.Range16{Lo: 0x3d9, Hi: 0x3d9, Stride: 0x1}, + unicode.Range16{Lo: 0x3db, Hi: 0x3db, Stride: 0x1}, + unicode.Range16{Lo: 0x3dd, Hi: 0x3dd, Stride: 0x1}, + unicode.Range16{Lo: 0x3df, Hi: 0x3df, Stride: 0x1}, + unicode.Range16{Lo: 0x3e1, Hi: 0x3e1, Stride: 0x1}, + unicode.Range16{Lo: 0x3e3, Hi: 0x3e3, Stride: 0x1}, + unicode.Range16{Lo: 0x3e5, Hi: 0x3e5, Stride: 0x1}, + unicode.Range16{Lo: 0x3e7, Hi: 0x3e7, Stride: 0x1}, + unicode.Range16{Lo: 0x3e9, Hi: 0x3e9, Stride: 0x1}, + unicode.Range16{Lo: 0x3eb, Hi: 0x3eb, Stride: 0x1}, + unicode.Range16{Lo: 0x3ed, Hi: 0x3ed, Stride: 0x1}, + unicode.Range16{Lo: 0x3ef, Hi: 0x3f3, Stride: 0x1}, + unicode.Range16{Lo: 0x3f5, Hi: 0x3f5, Stride: 0x1}, + unicode.Range16{Lo: 0x3f8, Hi: 0x3f8, Stride: 0x1}, + unicode.Range16{Lo: 0x3fb, Hi: 0x3fc, Stride: 0x1}, + unicode.Range16{Lo: 0x430, Hi: 0x45f, Stride: 0x1}, + unicode.Range16{Lo: 0x461, Hi: 0x461, Stride: 0x1}, + unicode.Range16{Lo: 0x463, Hi: 0x463, Stride: 0x1}, + unicode.Range16{Lo: 0x465, Hi: 0x465, Stride: 0x1}, + unicode.Range16{Lo: 0x467, Hi: 0x467, Stride: 0x1}, + unicode.Range16{Lo: 0x469, Hi: 0x469, Stride: 0x1}, + unicode.Range16{Lo: 0x46b, Hi: 0x46b, Stride: 0x1}, + unicode.Range16{Lo: 0x46d, Hi: 0x46d, Stride: 0x1}, + unicode.Range16{Lo: 0x46f, Hi: 0x46f, Stride: 0x1}, + unicode.Range16{Lo: 0x471, Hi: 0x471, Stride: 0x1}, + unicode.Range16{Lo: 0x473, Hi: 0x473, Stride: 0x1}, + unicode.Range16{Lo: 0x475, Hi: 0x475, Stride: 0x1}, + unicode.Range16{Lo: 0x477, Hi: 0x477, Stride: 0x1}, + unicode.Range16{Lo: 0x479, Hi: 0x479, Stride: 0x1}, + unicode.Range16{Lo: 0x47b, Hi: 0x47b, Stride: 0x1}, + unicode.Range16{Lo: 0x47d, Hi: 0x47d, Stride: 0x1}, + unicode.Range16{Lo: 0x47f, Hi: 0x47f, Stride: 0x1}, + unicode.Range16{Lo: 0x481, Hi: 0x481, Stride: 0x1}, + unicode.Range16{Lo: 0x48b, Hi: 0x48b, Stride: 0x1}, + unicode.Range16{Lo: 0x48d, Hi: 0x48d, Stride: 0x1}, + unicode.Range16{Lo: 0x48f, Hi: 0x48f, Stride: 0x1}, + unicode.Range16{Lo: 0x491, Hi: 0x491, Stride: 0x1}, + unicode.Range16{Lo: 0x493, Hi: 0x493, Stride: 0x1}, + unicode.Range16{Lo: 0x495, Hi: 0x495, Stride: 0x1}, + unicode.Range16{Lo: 0x497, Hi: 0x497, Stride: 0x1}, + unicode.Range16{Lo: 0x499, Hi: 0x499, Stride: 0x1}, + unicode.Range16{Lo: 0x49b, Hi: 0x49b, Stride: 0x1}, + unicode.Range16{Lo: 0x49d, Hi: 0x49d, Stride: 0x1}, + unicode.Range16{Lo: 0x49f, Hi: 0x49f, Stride: 0x1}, + unicode.Range16{Lo: 0x4a1, Hi: 0x4a1, Stride: 0x1}, + unicode.Range16{Lo: 0x4a3, Hi: 0x4a3, Stride: 0x1}, + unicode.Range16{Lo: 0x4a5, Hi: 0x4a5, Stride: 0x1}, + unicode.Range16{Lo: 0x4a7, Hi: 0x4a7, Stride: 0x1}, + unicode.Range16{Lo: 0x4a9, Hi: 0x4a9, Stride: 0x1}, + unicode.Range16{Lo: 0x4ab, Hi: 0x4ab, Stride: 0x1}, + unicode.Range16{Lo: 0x4ad, Hi: 0x4ad, Stride: 0x1}, + unicode.Range16{Lo: 0x4af, Hi: 0x4af, Stride: 0x1}, + unicode.Range16{Lo: 0x4b1, Hi: 0x4b1, Stride: 0x1}, + unicode.Range16{Lo: 0x4b3, Hi: 0x4b3, Stride: 0x1}, + unicode.Range16{Lo: 0x4b5, Hi: 0x4b5, Stride: 0x1}, + unicode.Range16{Lo: 0x4b7, Hi: 0x4b7, Stride: 0x1}, + unicode.Range16{Lo: 0x4b9, Hi: 0x4b9, Stride: 0x1}, + unicode.Range16{Lo: 0x4bb, Hi: 0x4bb, Stride: 0x1}, + unicode.Range16{Lo: 0x4bd, Hi: 0x4bd, Stride: 0x1}, + unicode.Range16{Lo: 0x4bf, Hi: 0x4bf, Stride: 0x1}, + unicode.Range16{Lo: 0x4c2, Hi: 0x4c2, Stride: 0x1}, + unicode.Range16{Lo: 0x4c4, Hi: 0x4c4, Stride: 0x1}, + unicode.Range16{Lo: 0x4c6, Hi: 0x4c6, Stride: 0x1}, + unicode.Range16{Lo: 0x4c8, Hi: 0x4c8, Stride: 0x1}, + unicode.Range16{Lo: 0x4ca, Hi: 0x4ca, Stride: 0x1}, + unicode.Range16{Lo: 0x4cc, Hi: 0x4cc, Stride: 0x1}, + unicode.Range16{Lo: 0x4ce, Hi: 0x4cf, Stride: 0x1}, + unicode.Range16{Lo: 0x4d1, Hi: 0x4d1, Stride: 0x1}, + unicode.Range16{Lo: 0x4d3, Hi: 0x4d3, Stride: 0x1}, + unicode.Range16{Lo: 0x4d5, Hi: 0x4d5, Stride: 0x1}, + unicode.Range16{Lo: 0x4d7, Hi: 0x4d7, Stride: 0x1}, + unicode.Range16{Lo: 0x4d9, Hi: 0x4d9, Stride: 0x1}, + unicode.Range16{Lo: 0x4db, Hi: 0x4db, Stride: 0x1}, + unicode.Range16{Lo: 0x4dd, Hi: 0x4dd, Stride: 0x1}, + unicode.Range16{Lo: 0x4df, Hi: 0x4df, Stride: 0x1}, + unicode.Range16{Lo: 0x4e1, Hi: 0x4e1, Stride: 0x1}, + unicode.Range16{Lo: 0x4e3, Hi: 0x4e3, Stride: 0x1}, + unicode.Range16{Lo: 0x4e5, Hi: 0x4e5, Stride: 0x1}, + unicode.Range16{Lo: 0x4e7, Hi: 0x4e7, Stride: 0x1}, + unicode.Range16{Lo: 0x4e9, Hi: 0x4e9, Stride: 0x1}, + unicode.Range16{Lo: 0x4eb, Hi: 0x4eb, Stride: 0x1}, + unicode.Range16{Lo: 0x4ed, Hi: 0x4ed, Stride: 0x1}, + unicode.Range16{Lo: 0x4ef, Hi: 0x4ef, Stride: 0x1}, + unicode.Range16{Lo: 0x4f1, Hi: 0x4f1, Stride: 0x1}, + unicode.Range16{Lo: 0x4f3, Hi: 0x4f3, Stride: 0x1}, + unicode.Range16{Lo: 0x4f5, Hi: 0x4f5, Stride: 0x1}, + unicode.Range16{Lo: 0x4f7, Hi: 0x4f7, Stride: 0x1}, + unicode.Range16{Lo: 0x4f9, Hi: 0x4f9, Stride: 0x1}, + unicode.Range16{Lo: 0x4fb, Hi: 0x4fb, Stride: 0x1}, + unicode.Range16{Lo: 0x4fd, Hi: 0x4fd, Stride: 0x1}, + unicode.Range16{Lo: 0x4ff, Hi: 0x4ff, Stride: 0x1}, + unicode.Range16{Lo: 0x501, Hi: 0x501, Stride: 0x1}, + unicode.Range16{Lo: 0x503, Hi: 0x503, Stride: 0x1}, + unicode.Range16{Lo: 0x505, Hi: 0x505, Stride: 0x1}, + unicode.Range16{Lo: 0x507, Hi: 0x507, Stride: 0x1}, + unicode.Range16{Lo: 0x509, Hi: 0x509, Stride: 0x1}, + unicode.Range16{Lo: 0x50b, Hi: 0x50b, Stride: 0x1}, + unicode.Range16{Lo: 0x50d, Hi: 0x50d, Stride: 0x1}, + unicode.Range16{Lo: 0x50f, Hi: 0x50f, Stride: 0x1}, + unicode.Range16{Lo: 0x511, Hi: 0x511, Stride: 0x1}, + unicode.Range16{Lo: 0x513, Hi: 0x513, Stride: 0x1}, + unicode.Range16{Lo: 0x515, Hi: 0x515, Stride: 0x1}, + unicode.Range16{Lo: 0x517, Hi: 0x517, Stride: 0x1}, + unicode.Range16{Lo: 0x519, Hi: 0x519, Stride: 0x1}, + unicode.Range16{Lo: 0x51b, Hi: 0x51b, Stride: 0x1}, + unicode.Range16{Lo: 0x51d, Hi: 0x51d, Stride: 0x1}, + unicode.Range16{Lo: 0x51f, Hi: 0x51f, Stride: 0x1}, + unicode.Range16{Lo: 0x521, Hi: 0x521, Stride: 0x1}, + unicode.Range16{Lo: 0x523, Hi: 0x523, Stride: 0x1}, + unicode.Range16{Lo: 0x525, Hi: 0x525, Stride: 0x1}, + unicode.Range16{Lo: 0x527, Hi: 0x527, Stride: 0x1}, + unicode.Range16{Lo: 0x529, Hi: 0x529, Stride: 0x1}, + unicode.Range16{Lo: 0x52b, Hi: 0x52b, Stride: 0x1}, + unicode.Range16{Lo: 0x52d, Hi: 0x52d, Stride: 0x1}, + unicode.Range16{Lo: 0x52f, Hi: 0x52f, Stride: 0x1}, + unicode.Range16{Lo: 0x561, Hi: 0x587, Stride: 0x1}, + unicode.Range16{Lo: 0x1d00, Hi: 0x1d2b, Stride: 0x1}, + unicode.Range16{Lo: 0x1d2c, Hi: 0x1d6a, Stride: 0x1}, + unicode.Range16{Lo: 0x1d6b, Hi: 0x1d77, Stride: 0x1}, + unicode.Range16{Lo: 0x1d78, Hi: 0x1d78, Stride: 0x1}, + unicode.Range16{Lo: 0x1d79, Hi: 0x1d9a, Stride: 0x1}, + unicode.Range16{Lo: 0x1d9b, Hi: 0x1dbf, Stride: 0x1}, + unicode.Range16{Lo: 0x1e01, Hi: 0x1e01, Stride: 0x1}, + unicode.Range16{Lo: 0x1e03, Hi: 0x1e03, Stride: 0x1}, + unicode.Range16{Lo: 0x1e05, Hi: 0x1e05, Stride: 0x1}, + unicode.Range16{Lo: 0x1e07, Hi: 0x1e07, Stride: 0x1}, + unicode.Range16{Lo: 0x1e09, Hi: 0x1e09, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0b, Hi: 0x1e0b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0d, Hi: 0x1e0d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e0f, Hi: 0x1e0f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e11, Hi: 0x1e11, Stride: 0x1}, + unicode.Range16{Lo: 0x1e13, Hi: 0x1e13, Stride: 0x1}, + unicode.Range16{Lo: 0x1e15, Hi: 0x1e15, Stride: 0x1}, + unicode.Range16{Lo: 0x1e17, Hi: 0x1e17, Stride: 0x1}, + unicode.Range16{Lo: 0x1e19, Hi: 0x1e19, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1b, Hi: 0x1e1b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1d, Hi: 0x1e1d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e1f, Hi: 0x1e1f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e21, Hi: 0x1e21, Stride: 0x1}, + unicode.Range16{Lo: 0x1e23, Hi: 0x1e23, Stride: 0x1}, + unicode.Range16{Lo: 0x1e25, Hi: 0x1e25, Stride: 0x1}, + unicode.Range16{Lo: 0x1e27, Hi: 0x1e27, Stride: 0x1}, + unicode.Range16{Lo: 0x1e29, Hi: 0x1e29, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2b, Hi: 0x1e2b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2d, Hi: 0x1e2d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e2f, Hi: 0x1e2f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e31, Hi: 0x1e31, Stride: 0x1}, + unicode.Range16{Lo: 0x1e33, Hi: 0x1e33, Stride: 0x1}, + unicode.Range16{Lo: 0x1e35, Hi: 0x1e35, Stride: 0x1}, + unicode.Range16{Lo: 0x1e37, Hi: 0x1e37, Stride: 0x1}, + unicode.Range16{Lo: 0x1e39, Hi: 0x1e39, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3b, Hi: 0x1e3b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3d, Hi: 0x1e3d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e3f, Hi: 0x1e3f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e41, Hi: 0x1e41, Stride: 0x1}, + unicode.Range16{Lo: 0x1e43, Hi: 0x1e43, Stride: 0x1}, + unicode.Range16{Lo: 0x1e45, Hi: 0x1e45, Stride: 0x1}, + unicode.Range16{Lo: 0x1e47, Hi: 0x1e47, Stride: 0x1}, + unicode.Range16{Lo: 0x1e49, Hi: 0x1e49, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4b, Hi: 0x1e4b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4d, Hi: 0x1e4d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e4f, Hi: 0x1e4f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e51, Hi: 0x1e51, Stride: 0x1}, + unicode.Range16{Lo: 0x1e53, Hi: 0x1e53, Stride: 0x1}, + unicode.Range16{Lo: 0x1e55, Hi: 0x1e55, Stride: 0x1}, + unicode.Range16{Lo: 0x1e57, Hi: 0x1e57, Stride: 0x1}, + unicode.Range16{Lo: 0x1e59, Hi: 0x1e59, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5b, Hi: 0x1e5b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5d, Hi: 0x1e5d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e5f, Hi: 0x1e5f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e61, Hi: 0x1e61, Stride: 0x1}, + unicode.Range16{Lo: 0x1e63, Hi: 0x1e63, Stride: 0x1}, + unicode.Range16{Lo: 0x1e65, Hi: 0x1e65, Stride: 0x1}, + unicode.Range16{Lo: 0x1e67, Hi: 0x1e67, Stride: 0x1}, + unicode.Range16{Lo: 0x1e69, Hi: 0x1e69, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6b, Hi: 0x1e6b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6d, Hi: 0x1e6d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e6f, Hi: 0x1e6f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e71, Hi: 0x1e71, Stride: 0x1}, + unicode.Range16{Lo: 0x1e73, Hi: 0x1e73, Stride: 0x1}, + unicode.Range16{Lo: 0x1e75, Hi: 0x1e75, Stride: 0x1}, + unicode.Range16{Lo: 0x1e77, Hi: 0x1e77, Stride: 0x1}, + unicode.Range16{Lo: 0x1e79, Hi: 0x1e79, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7b, Hi: 0x1e7b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7d, Hi: 0x1e7d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e7f, Hi: 0x1e7f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e81, Hi: 0x1e81, Stride: 0x1}, + unicode.Range16{Lo: 0x1e83, Hi: 0x1e83, Stride: 0x1}, + unicode.Range16{Lo: 0x1e85, Hi: 0x1e85, Stride: 0x1}, + unicode.Range16{Lo: 0x1e87, Hi: 0x1e87, Stride: 0x1}, + unicode.Range16{Lo: 0x1e89, Hi: 0x1e89, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8b, Hi: 0x1e8b, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8d, Hi: 0x1e8d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e8f, Hi: 0x1e8f, Stride: 0x1}, + unicode.Range16{Lo: 0x1e91, Hi: 0x1e91, Stride: 0x1}, + unicode.Range16{Lo: 0x1e93, Hi: 0x1e93, Stride: 0x1}, + unicode.Range16{Lo: 0x1e95, Hi: 0x1e9d, Stride: 0x1}, + unicode.Range16{Lo: 0x1e9f, Hi: 0x1e9f, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea1, Hi: 0x1ea1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea3, Hi: 0x1ea3, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea5, Hi: 0x1ea5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea7, Hi: 0x1ea7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ea9, Hi: 0x1ea9, Stride: 0x1}, + unicode.Range16{Lo: 0x1eab, Hi: 0x1eab, Stride: 0x1}, + unicode.Range16{Lo: 0x1ead, Hi: 0x1ead, Stride: 0x1}, + unicode.Range16{Lo: 0x1eaf, Hi: 0x1eaf, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb1, Hi: 0x1eb1, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb3, Hi: 0x1eb3, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb5, Hi: 0x1eb5, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb7, Hi: 0x1eb7, Stride: 0x1}, + unicode.Range16{Lo: 0x1eb9, Hi: 0x1eb9, Stride: 0x1}, + unicode.Range16{Lo: 0x1ebb, Hi: 0x1ebb, Stride: 0x1}, + unicode.Range16{Lo: 0x1ebd, Hi: 0x1ebd, Stride: 0x1}, + unicode.Range16{Lo: 0x1ebf, Hi: 0x1ebf, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec1, Hi: 0x1ec1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec3, Hi: 0x1ec3, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec5, Hi: 0x1ec5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec7, Hi: 0x1ec7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ec9, Hi: 0x1ec9, Stride: 0x1}, + unicode.Range16{Lo: 0x1ecb, Hi: 0x1ecb, Stride: 0x1}, + unicode.Range16{Lo: 0x1ecd, Hi: 0x1ecd, Stride: 0x1}, + unicode.Range16{Lo: 0x1ecf, Hi: 0x1ecf, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed1, Hi: 0x1ed1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed3, Hi: 0x1ed3, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed5, Hi: 0x1ed5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed7, Hi: 0x1ed7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ed9, Hi: 0x1ed9, Stride: 0x1}, + unicode.Range16{Lo: 0x1edb, Hi: 0x1edb, Stride: 0x1}, + unicode.Range16{Lo: 0x1edd, Hi: 0x1edd, Stride: 0x1}, + unicode.Range16{Lo: 0x1edf, Hi: 0x1edf, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee1, Hi: 0x1ee1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee3, Hi: 0x1ee3, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee5, Hi: 0x1ee5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee7, Hi: 0x1ee7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ee9, Hi: 0x1ee9, Stride: 0x1}, + unicode.Range16{Lo: 0x1eeb, Hi: 0x1eeb, Stride: 0x1}, + unicode.Range16{Lo: 0x1eed, Hi: 0x1eed, Stride: 0x1}, + unicode.Range16{Lo: 0x1eef, Hi: 0x1eef, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef1, Hi: 0x1ef1, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef3, Hi: 0x1ef3, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef5, Hi: 0x1ef5, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef7, Hi: 0x1ef7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ef9, Hi: 0x1ef9, Stride: 0x1}, + unicode.Range16{Lo: 0x1efb, Hi: 0x1efb, Stride: 0x1}, + unicode.Range16{Lo: 0x1efd, Hi: 0x1efd, Stride: 0x1}, + unicode.Range16{Lo: 0x1eff, Hi: 0x1f07, Stride: 0x1}, + unicode.Range16{Lo: 0x1f10, Hi: 0x1f15, Stride: 0x1}, + unicode.Range16{Lo: 0x1f20, Hi: 0x1f27, Stride: 0x1}, + unicode.Range16{Lo: 0x1f30, Hi: 0x1f37, Stride: 0x1}, + unicode.Range16{Lo: 0x1f40, Hi: 0x1f45, Stride: 0x1}, + unicode.Range16{Lo: 0x1f50, Hi: 0x1f57, Stride: 0x1}, + unicode.Range16{Lo: 0x1f60, Hi: 0x1f67, Stride: 0x1}, + unicode.Range16{Lo: 0x1f70, Hi: 0x1f7d, Stride: 0x1}, + unicode.Range16{Lo: 0x1f80, Hi: 0x1f87, Stride: 0x1}, + unicode.Range16{Lo: 0x1f90, Hi: 0x1f97, Stride: 0x1}, + unicode.Range16{Lo: 0x1fa0, Hi: 0x1fa7, Stride: 0x1}, + unicode.Range16{Lo: 0x1fb0, Hi: 0x1fb4, Stride: 0x1}, + unicode.Range16{Lo: 0x1fb6, Hi: 0x1fb7, Stride: 0x1}, + unicode.Range16{Lo: 0x1fbe, Hi: 0x1fbe, Stride: 0x1}, + unicode.Range16{Lo: 0x1fc2, Hi: 0x1fc4, Stride: 0x1}, + unicode.Range16{Lo: 0x1fc6, Hi: 0x1fc7, Stride: 0x1}, + unicode.Range16{Lo: 0x1fd0, Hi: 0x1fd3, Stride: 0x1}, + unicode.Range16{Lo: 0x1fd6, Hi: 0x1fd7, Stride: 0x1}, + unicode.Range16{Lo: 0x1fe0, Hi: 0x1fe7, Stride: 0x1}, + unicode.Range16{Lo: 0x1ff2, Hi: 0x1ff4, Stride: 0x1}, + unicode.Range16{Lo: 0x1ff6, Hi: 0x1ff7, Stride: 0x1}, + unicode.Range16{Lo: 0x2071, Hi: 0x2071, Stride: 0x1}, + unicode.Range16{Lo: 0x207f, Hi: 0x207f, Stride: 0x1}, + unicode.Range16{Lo: 0x2090, Hi: 0x209c, Stride: 0x1}, + unicode.Range16{Lo: 0x210a, Hi: 0x210a, Stride: 0x1}, + unicode.Range16{Lo: 0x210e, Hi: 0x210f, Stride: 0x1}, + unicode.Range16{Lo: 0x2113, Hi: 0x2113, Stride: 0x1}, + unicode.Range16{Lo: 0x212f, Hi: 0x212f, Stride: 0x1}, + unicode.Range16{Lo: 0x2134, Hi: 0x2134, Stride: 0x1}, + unicode.Range16{Lo: 0x2139, Hi: 0x2139, Stride: 0x1}, + unicode.Range16{Lo: 0x213c, Hi: 0x213d, Stride: 0x1}, + unicode.Range16{Lo: 0x2146, Hi: 0x2149, Stride: 0x1}, + unicode.Range16{Lo: 0x214e, Hi: 0x214e, Stride: 0x1}, + unicode.Range16{Lo: 0x2170, Hi: 0x217f, Stride: 0x1}, + unicode.Range16{Lo: 0x2184, Hi: 0x2184, Stride: 0x1}, + unicode.Range16{Lo: 0x24d0, Hi: 0x24e9, Stride: 0x1}, + unicode.Range16{Lo: 0x2c30, Hi: 0x2c5e, Stride: 0x1}, + unicode.Range16{Lo: 0x2c61, Hi: 0x2c61, Stride: 0x1}, + unicode.Range16{Lo: 0x2c65, Hi: 0x2c66, Stride: 0x1}, + unicode.Range16{Lo: 0x2c68, Hi: 0x2c68, Stride: 0x1}, + unicode.Range16{Lo: 0x2c6a, Hi: 0x2c6a, Stride: 0x1}, + unicode.Range16{Lo: 0x2c6c, Hi: 0x2c6c, Stride: 0x1}, + unicode.Range16{Lo: 0x2c71, Hi: 0x2c71, Stride: 0x1}, + unicode.Range16{Lo: 0x2c73, Hi: 0x2c74, Stride: 0x1}, + unicode.Range16{Lo: 0x2c76, Hi: 0x2c7b, Stride: 0x1}, + unicode.Range16{Lo: 0x2c7c, Hi: 0x2c7d, Stride: 0x1}, + unicode.Range16{Lo: 0x2c81, Hi: 0x2c81, Stride: 0x1}, + unicode.Range16{Lo: 0x2c83, Hi: 0x2c83, Stride: 0x1}, + unicode.Range16{Lo: 0x2c85, Hi: 0x2c85, Stride: 0x1}, + unicode.Range16{Lo: 0x2c87, Hi: 0x2c87, Stride: 0x1}, + unicode.Range16{Lo: 0x2c89, Hi: 0x2c89, Stride: 0x1}, + unicode.Range16{Lo: 0x2c8b, Hi: 0x2c8b, Stride: 0x1}, + unicode.Range16{Lo: 0x2c8d, Hi: 0x2c8d, Stride: 0x1}, + unicode.Range16{Lo: 0x2c8f, Hi: 0x2c8f, Stride: 0x1}, + unicode.Range16{Lo: 0x2c91, Hi: 0x2c91, Stride: 0x1}, + unicode.Range16{Lo: 0x2c93, Hi: 0x2c93, Stride: 0x1}, + unicode.Range16{Lo: 0x2c95, Hi: 0x2c95, Stride: 0x1}, + unicode.Range16{Lo: 0x2c97, Hi: 0x2c97, Stride: 0x1}, + unicode.Range16{Lo: 0x2c99, Hi: 0x2c99, Stride: 0x1}, + unicode.Range16{Lo: 0x2c9b, Hi: 0x2c9b, Stride: 0x1}, + unicode.Range16{Lo: 0x2c9d, Hi: 0x2c9d, Stride: 0x1}, + unicode.Range16{Lo: 0x2c9f, Hi: 0x2c9f, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca1, Hi: 0x2ca1, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca3, Hi: 0x2ca3, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca5, Hi: 0x2ca5, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca7, Hi: 0x2ca7, Stride: 0x1}, + unicode.Range16{Lo: 0x2ca9, Hi: 0x2ca9, Stride: 0x1}, + unicode.Range16{Lo: 0x2cab, Hi: 0x2cab, Stride: 0x1}, + unicode.Range16{Lo: 0x2cad, Hi: 0x2cad, Stride: 0x1}, + unicode.Range16{Lo: 0x2caf, Hi: 0x2caf, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb1, Hi: 0x2cb1, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb3, Hi: 0x2cb3, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb5, Hi: 0x2cb5, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb7, Hi: 0x2cb7, Stride: 0x1}, + unicode.Range16{Lo: 0x2cb9, Hi: 0x2cb9, Stride: 0x1}, + unicode.Range16{Lo: 0x2cbb, Hi: 0x2cbb, Stride: 0x1}, + unicode.Range16{Lo: 0x2cbd, Hi: 0x2cbd, Stride: 0x1}, + unicode.Range16{Lo: 0x2cbf, Hi: 0x2cbf, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc1, Hi: 0x2cc1, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc3, Hi: 0x2cc3, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc5, Hi: 0x2cc5, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc7, Hi: 0x2cc7, Stride: 0x1}, + unicode.Range16{Lo: 0x2cc9, Hi: 0x2cc9, Stride: 0x1}, + unicode.Range16{Lo: 0x2ccb, Hi: 0x2ccb, Stride: 0x1}, + unicode.Range16{Lo: 0x2ccd, Hi: 0x2ccd, Stride: 0x1}, + unicode.Range16{Lo: 0x2ccf, Hi: 0x2ccf, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd1, Hi: 0x2cd1, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd3, Hi: 0x2cd3, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd5, Hi: 0x2cd5, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd7, Hi: 0x2cd7, Stride: 0x1}, + unicode.Range16{Lo: 0x2cd9, Hi: 0x2cd9, Stride: 0x1}, + unicode.Range16{Lo: 0x2cdb, Hi: 0x2cdb, Stride: 0x1}, + unicode.Range16{Lo: 0x2cdd, Hi: 0x2cdd, Stride: 0x1}, + unicode.Range16{Lo: 0x2cdf, Hi: 0x2cdf, Stride: 0x1}, + unicode.Range16{Lo: 0x2ce1, Hi: 0x2ce1, Stride: 0x1}, + unicode.Range16{Lo: 0x2ce3, Hi: 0x2ce4, Stride: 0x1}, + unicode.Range16{Lo: 0x2cec, Hi: 0x2cec, Stride: 0x1}, + unicode.Range16{Lo: 0x2cee, Hi: 0x2cee, Stride: 0x1}, + unicode.Range16{Lo: 0x2cf3, Hi: 0x2cf3, Stride: 0x1}, + unicode.Range16{Lo: 0x2d00, Hi: 0x2d25, Stride: 0x1}, + unicode.Range16{Lo: 0x2d27, Hi: 0x2d27, Stride: 0x1}, + unicode.Range16{Lo: 0x2d2d, Hi: 0x2d2d, Stride: 0x1}, + unicode.Range16{Lo: 0xa641, Hi: 0xa641, Stride: 0x1}, + unicode.Range16{Lo: 0xa643, Hi: 0xa643, Stride: 0x1}, + unicode.Range16{Lo: 0xa645, Hi: 0xa645, Stride: 0x1}, + unicode.Range16{Lo: 0xa647, Hi: 0xa647, Stride: 0x1}, + unicode.Range16{Lo: 0xa649, Hi: 0xa649, Stride: 0x1}, + unicode.Range16{Lo: 0xa64b, Hi: 0xa64b, Stride: 0x1}, + unicode.Range16{Lo: 0xa64d, Hi: 0xa64d, Stride: 0x1}, + unicode.Range16{Lo: 0xa64f, Hi: 0xa64f, Stride: 0x1}, + unicode.Range16{Lo: 0xa651, Hi: 0xa651, Stride: 0x1}, + unicode.Range16{Lo: 0xa653, Hi: 0xa653, Stride: 0x1}, + unicode.Range16{Lo: 0xa655, Hi: 0xa655, Stride: 0x1}, + unicode.Range16{Lo: 0xa657, Hi: 0xa657, Stride: 0x1}, + unicode.Range16{Lo: 0xa659, Hi: 0xa659, Stride: 0x1}, + unicode.Range16{Lo: 0xa65b, Hi: 0xa65b, Stride: 0x1}, + unicode.Range16{Lo: 0xa65d, Hi: 0xa65d, Stride: 0x1}, + unicode.Range16{Lo: 0xa65f, Hi: 0xa65f, Stride: 0x1}, + unicode.Range16{Lo: 0xa661, Hi: 0xa661, Stride: 0x1}, + unicode.Range16{Lo: 0xa663, Hi: 0xa663, Stride: 0x1}, + unicode.Range16{Lo: 0xa665, Hi: 0xa665, Stride: 0x1}, + unicode.Range16{Lo: 0xa667, Hi: 0xa667, Stride: 0x1}, + unicode.Range16{Lo: 0xa669, Hi: 0xa669, Stride: 0x1}, + unicode.Range16{Lo: 0xa66b, Hi: 0xa66b, Stride: 0x1}, + unicode.Range16{Lo: 0xa66d, Hi: 0xa66d, Stride: 0x1}, + unicode.Range16{Lo: 0xa681, Hi: 0xa681, Stride: 0x1}, + unicode.Range16{Lo: 0xa683, Hi: 0xa683, Stride: 0x1}, + unicode.Range16{Lo: 0xa685, Hi: 0xa685, Stride: 0x1}, + unicode.Range16{Lo: 0xa687, Hi: 0xa687, Stride: 0x1}, + unicode.Range16{Lo: 0xa689, Hi: 0xa689, Stride: 0x1}, + unicode.Range16{Lo: 0xa68b, Hi: 0xa68b, Stride: 0x1}, + unicode.Range16{Lo: 0xa68d, Hi: 0xa68d, Stride: 0x1}, + unicode.Range16{Lo: 0xa68f, Hi: 0xa68f, Stride: 0x1}, + unicode.Range16{Lo: 0xa691, Hi: 0xa691, Stride: 0x1}, + unicode.Range16{Lo: 0xa693, Hi: 0xa693, Stride: 0x1}, + unicode.Range16{Lo: 0xa695, Hi: 0xa695, Stride: 0x1}, + unicode.Range16{Lo: 0xa697, Hi: 0xa697, Stride: 0x1}, + unicode.Range16{Lo: 0xa699, Hi: 0xa699, Stride: 0x1}, + unicode.Range16{Lo: 0xa69b, Hi: 0xa69b, Stride: 0x1}, + unicode.Range16{Lo: 0xa69c, Hi: 0xa69d, Stride: 0x1}, + unicode.Range16{Lo: 0xa723, Hi: 0xa723, Stride: 0x1}, + unicode.Range16{Lo: 0xa725, Hi: 0xa725, Stride: 0x1}, + unicode.Range16{Lo: 0xa727, Hi: 0xa727, Stride: 0x1}, + unicode.Range16{Lo: 0xa729, Hi: 0xa729, Stride: 0x1}, + unicode.Range16{Lo: 0xa72b, Hi: 0xa72b, Stride: 0x1}, + unicode.Range16{Lo: 0xa72d, Hi: 0xa72d, Stride: 0x1}, + unicode.Range16{Lo: 0xa72f, Hi: 0xa731, Stride: 0x1}, + unicode.Range16{Lo: 0xa733, Hi: 0xa733, Stride: 0x1}, + unicode.Range16{Lo: 0xa735, Hi: 0xa735, Stride: 0x1}, + unicode.Range16{Lo: 0xa737, Hi: 0xa737, Stride: 0x1}, + unicode.Range16{Lo: 0xa739, Hi: 0xa739, Stride: 0x1}, + unicode.Range16{Lo: 0xa73b, Hi: 0xa73b, Stride: 0x1}, + unicode.Range16{Lo: 0xa73d, Hi: 0xa73d, Stride: 0x1}, + unicode.Range16{Lo: 0xa73f, Hi: 0xa73f, Stride: 0x1}, + unicode.Range16{Lo: 0xa741, Hi: 0xa741, Stride: 0x1}, + unicode.Range16{Lo: 0xa743, Hi: 0xa743, Stride: 0x1}, + unicode.Range16{Lo: 0xa745, Hi: 0xa745, Stride: 0x1}, + unicode.Range16{Lo: 0xa747, Hi: 0xa747, Stride: 0x1}, + unicode.Range16{Lo: 0xa749, Hi: 0xa749, Stride: 0x1}, + unicode.Range16{Lo: 0xa74b, Hi: 0xa74b, Stride: 0x1}, + unicode.Range16{Lo: 0xa74d, Hi: 0xa74d, Stride: 0x1}, + unicode.Range16{Lo: 0xa74f, Hi: 0xa74f, Stride: 0x1}, + unicode.Range16{Lo: 0xa751, Hi: 0xa751, Stride: 0x1}, + unicode.Range16{Lo: 0xa753, Hi: 0xa753, Stride: 0x1}, + unicode.Range16{Lo: 0xa755, Hi: 0xa755, Stride: 0x1}, + unicode.Range16{Lo: 0xa757, Hi: 0xa757, Stride: 0x1}, + unicode.Range16{Lo: 0xa759, Hi: 0xa759, Stride: 0x1}, + unicode.Range16{Lo: 0xa75b, Hi: 0xa75b, Stride: 0x1}, + unicode.Range16{Lo: 0xa75d, Hi: 0xa75d, Stride: 0x1}, + unicode.Range16{Lo: 0xa75f, Hi: 0xa75f, Stride: 0x1}, + unicode.Range16{Lo: 0xa761, Hi: 0xa761, Stride: 0x1}, + unicode.Range16{Lo: 0xa763, Hi: 0xa763, Stride: 0x1}, + unicode.Range16{Lo: 0xa765, Hi: 0xa765, Stride: 0x1}, + unicode.Range16{Lo: 0xa767, Hi: 0xa767, Stride: 0x1}, + unicode.Range16{Lo: 0xa769, Hi: 0xa769, Stride: 0x1}, + unicode.Range16{Lo: 0xa76b, Hi: 0xa76b, Stride: 0x1}, + unicode.Range16{Lo: 0xa76d, Hi: 0xa76d, Stride: 0x1}, + unicode.Range16{Lo: 0xa76f, Hi: 0xa76f, Stride: 0x1}, + unicode.Range16{Lo: 0xa770, Hi: 0xa770, Stride: 0x1}, + unicode.Range16{Lo: 0xa771, Hi: 0xa778, Stride: 0x1}, + unicode.Range16{Lo: 0xa77a, Hi: 0xa77a, Stride: 0x1}, + unicode.Range16{Lo: 0xa77c, Hi: 0xa77c, Stride: 0x1}, + unicode.Range16{Lo: 0xa77f, Hi: 0xa77f, Stride: 0x1}, + unicode.Range16{Lo: 0xa781, Hi: 0xa781, Stride: 0x1}, + unicode.Range16{Lo: 0xa783, Hi: 0xa783, Stride: 0x1}, + unicode.Range16{Lo: 0xa785, Hi: 0xa785, Stride: 0x1}, + unicode.Range16{Lo: 0xa787, Hi: 0xa787, Stride: 0x1}, + unicode.Range16{Lo: 0xa78c, Hi: 0xa78c, Stride: 0x1}, + unicode.Range16{Lo: 0xa78e, Hi: 0xa78e, Stride: 0x1}, + unicode.Range16{Lo: 0xa791, Hi: 0xa791, Stride: 0x1}, + unicode.Range16{Lo: 0xa793, Hi: 0xa795, Stride: 0x1}, + unicode.Range16{Lo: 0xa797, Hi: 0xa797, Stride: 0x1}, + unicode.Range16{Lo: 0xa799, Hi: 0xa799, Stride: 0x1}, + unicode.Range16{Lo: 0xa79b, Hi: 0xa79b, Stride: 0x1}, + unicode.Range16{Lo: 0xa79d, Hi: 0xa79d, Stride: 0x1}, + unicode.Range16{Lo: 0xa79f, Hi: 0xa79f, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a1, Hi: 0xa7a1, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a3, Hi: 0xa7a3, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a5, Hi: 0xa7a5, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a7, Hi: 0xa7a7, Stride: 0x1}, + unicode.Range16{Lo: 0xa7a9, Hi: 0xa7a9, Stride: 0x1}, + unicode.Range16{Lo: 0xa7f8, Hi: 0xa7f9, Stride: 0x1}, + unicode.Range16{Lo: 0xa7fa, Hi: 0xa7fa, Stride: 0x1}, + unicode.Range16{Lo: 0xab30, Hi: 0xab5a, Stride: 0x1}, + unicode.Range16{Lo: 0xab5c, Hi: 0xab5f, Stride: 0x1}, + unicode.Range16{Lo: 0xab64, Hi: 0xab65, Stride: 0x1}, + unicode.Range16{Lo: 0xfb00, Hi: 0xfb06, Stride: 0x1}, + unicode.Range16{Lo: 0xfb13, Hi: 0xfb17, Stride: 0x1}, + unicode.Range16{Lo: 0xff41, Hi: 0xff5a, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x10428, Hi: 0x1044f, Stride: 0x1}, + unicode.Range32{Lo: 0x118c0, Hi: 0x118df, Stride: 0x1}, + unicode.Range32{Lo: 0x1d41a, Hi: 0x1d433, Stride: 0x1}, + unicode.Range32{Lo: 0x1d44e, Hi: 0x1d454, Stride: 0x1}, + unicode.Range32{Lo: 0x1d456, Hi: 0x1d467, Stride: 0x1}, + unicode.Range32{Lo: 0x1d482, Hi: 0x1d49b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4b6, Hi: 0x1d4b9, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4bb, Hi: 0x1d4bb, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4bd, Hi: 0x1d4c3, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4c5, Hi: 0x1d4cf, Stride: 0x1}, + unicode.Range32{Lo: 0x1d4ea, Hi: 0x1d503, Stride: 0x1}, + unicode.Range32{Lo: 0x1d51e, Hi: 0x1d537, Stride: 0x1}, + unicode.Range32{Lo: 0x1d552, Hi: 0x1d56b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d586, Hi: 0x1d59f, Stride: 0x1}, + unicode.Range32{Lo: 0x1d5ba, Hi: 0x1d5d3, Stride: 0x1}, + unicode.Range32{Lo: 0x1d5ee, Hi: 0x1d607, Stride: 0x1}, + unicode.Range32{Lo: 0x1d622, Hi: 0x1d63b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d656, Hi: 0x1d66f, Stride: 0x1}, + unicode.Range32{Lo: 0x1d68a, Hi: 0x1d6a5, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6c2, Hi: 0x1d6da, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6dc, Hi: 0x1d6e1, Stride: 0x1}, + unicode.Range32{Lo: 0x1d6fc, Hi: 0x1d714, Stride: 0x1}, + unicode.Range32{Lo: 0x1d716, Hi: 0x1d71b, Stride: 0x1}, + unicode.Range32{Lo: 0x1d736, Hi: 0x1d74e, Stride: 0x1}, + unicode.Range32{Lo: 0x1d750, Hi: 0x1d755, Stride: 0x1}, + unicode.Range32{Lo: 0x1d770, Hi: 0x1d788, Stride: 0x1}, + unicode.Range32{Lo: 0x1d78a, Hi: 0x1d78f, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7aa, Hi: 0x1d7c2, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7c4, Hi: 0x1d7c9, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7cb, Hi: 0x1d7cb, Stride: 0x1}, + }, + LatinOffset: 6, +} + +var _SentenceLF = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xa, Hi: 0xa, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceSp = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x9, Hi: 0x9, Stride: 0x1}, + unicode.Range16{Lo: 0xb, Hi: 0xc, Stride: 0x1}, + unicode.Range16{Lo: 0x20, Hi: 0x20, Stride: 0x1}, + unicode.Range16{Lo: 0xa0, Hi: 0xa0, Stride: 0x1}, + unicode.Range16{Lo: 0x1680, Hi: 0x1680, Stride: 0x1}, + unicode.Range16{Lo: 0x2000, Hi: 0x200a, Stride: 0x1}, + unicode.Range16{Lo: 0x202f, Hi: 0x202f, Stride: 0x1}, + unicode.Range16{Lo: 0x205f, Hi: 0x205f, Stride: 0x1}, + unicode.Range16{Lo: 0x3000, Hi: 0x3000, Stride: 0x1}, + }, + LatinOffset: 4, +} + +var _SentenceNumeric = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x30, Hi: 0x39, Stride: 0x1}, + unicode.Range16{Lo: 0x660, Hi: 0x669, Stride: 0x1}, + unicode.Range16{Lo: 0x66b, Hi: 0x66c, Stride: 0x1}, + unicode.Range16{Lo: 0x6f0, Hi: 0x6f9, Stride: 0x1}, + unicode.Range16{Lo: 0x7c0, Hi: 0x7c9, Stride: 0x1}, + unicode.Range16{Lo: 0x966, Hi: 0x96f, Stride: 0x1}, + unicode.Range16{Lo: 0x9e6, Hi: 0x9ef, Stride: 0x1}, + unicode.Range16{Lo: 0xa66, Hi: 0xa6f, Stride: 0x1}, + unicode.Range16{Lo: 0xae6, Hi: 0xaef, Stride: 0x1}, + unicode.Range16{Lo: 0xb66, Hi: 0xb6f, Stride: 0x1}, + unicode.Range16{Lo: 0xbe6, Hi: 0xbef, Stride: 0x1}, + unicode.Range16{Lo: 0xc66, Hi: 0xc6f, Stride: 0x1}, + unicode.Range16{Lo: 0xce6, Hi: 0xcef, Stride: 0x1}, + unicode.Range16{Lo: 0xd66, Hi: 0xd6f, Stride: 0x1}, + unicode.Range16{Lo: 0xde6, Hi: 0xdef, Stride: 0x1}, + unicode.Range16{Lo: 0xe50, Hi: 0xe59, Stride: 0x1}, + unicode.Range16{Lo: 0xed0, Hi: 0xed9, Stride: 0x1}, + unicode.Range16{Lo: 0xf20, Hi: 0xf29, Stride: 0x1}, + unicode.Range16{Lo: 0x1040, Hi: 0x1049, Stride: 0x1}, + unicode.Range16{Lo: 0x1090, Hi: 0x1099, Stride: 0x1}, + unicode.Range16{Lo: 0x17e0, Hi: 0x17e9, Stride: 0x1}, + unicode.Range16{Lo: 0x1810, Hi: 0x1819, Stride: 0x1}, + unicode.Range16{Lo: 0x1946, Hi: 0x194f, Stride: 0x1}, + unicode.Range16{Lo: 0x19d0, Hi: 0x19d9, Stride: 0x1}, + unicode.Range16{Lo: 0x1a80, Hi: 0x1a89, Stride: 0x1}, + unicode.Range16{Lo: 0x1a90, Hi: 0x1a99, Stride: 0x1}, + unicode.Range16{Lo: 0x1b50, Hi: 0x1b59, Stride: 0x1}, + unicode.Range16{Lo: 0x1bb0, Hi: 0x1bb9, Stride: 0x1}, + unicode.Range16{Lo: 0x1c40, Hi: 0x1c49, Stride: 0x1}, + unicode.Range16{Lo: 0x1c50, Hi: 0x1c59, Stride: 0x1}, + unicode.Range16{Lo: 0xa620, Hi: 0xa629, Stride: 0x1}, + unicode.Range16{Lo: 0xa8d0, Hi: 0xa8d9, Stride: 0x1}, + unicode.Range16{Lo: 0xa900, Hi: 0xa909, Stride: 0x1}, + unicode.Range16{Lo: 0xa9d0, Hi: 0xa9d9, Stride: 0x1}, + unicode.Range16{Lo: 0xa9f0, Hi: 0xa9f9, Stride: 0x1}, + unicode.Range16{Lo: 0xaa50, Hi: 0xaa59, Stride: 0x1}, + unicode.Range16{Lo: 0xabf0, Hi: 0xabf9, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x104a0, Hi: 0x104a9, Stride: 0x1}, + unicode.Range32{Lo: 0x11066, Hi: 0x1106f, Stride: 0x1}, + unicode.Range32{Lo: 0x110f0, Hi: 0x110f9, Stride: 0x1}, + unicode.Range32{Lo: 0x11136, Hi: 0x1113f, Stride: 0x1}, + unicode.Range32{Lo: 0x111d0, Hi: 0x111d9, Stride: 0x1}, + unicode.Range32{Lo: 0x112f0, Hi: 0x112f9, Stride: 0x1}, + unicode.Range32{Lo: 0x114d0, Hi: 0x114d9, Stride: 0x1}, + unicode.Range32{Lo: 0x11650, Hi: 0x11659, Stride: 0x1}, + unicode.Range32{Lo: 0x116c0, Hi: 0x116c9, Stride: 0x1}, + unicode.Range32{Lo: 0x118e0, Hi: 0x118e9, Stride: 0x1}, + unicode.Range32{Lo: 0x16a60, Hi: 0x16a69, Stride: 0x1}, + unicode.Range32{Lo: 0x16b50, Hi: 0x16b59, Stride: 0x1}, + unicode.Range32{Lo: 0x1d7ce, Hi: 0x1d7ff, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceClose = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x22, Hi: 0x22, Stride: 0x1}, + unicode.Range16{Lo: 0x27, Hi: 0x27, Stride: 0x1}, + unicode.Range16{Lo: 0x28, Hi: 0x28, Stride: 0x1}, + unicode.Range16{Lo: 0x29, Hi: 0x29, Stride: 0x1}, + unicode.Range16{Lo: 0x5b, Hi: 0x5b, Stride: 0x1}, + unicode.Range16{Lo: 0x5d, Hi: 0x5d, Stride: 0x1}, + unicode.Range16{Lo: 0x7b, Hi: 0x7b, Stride: 0x1}, + unicode.Range16{Lo: 0x7d, Hi: 0x7d, Stride: 0x1}, + unicode.Range16{Lo: 0xab, Hi: 0xab, Stride: 0x1}, + unicode.Range16{Lo: 0xbb, Hi: 0xbb, Stride: 0x1}, + unicode.Range16{Lo: 0xf3a, Hi: 0xf3a, Stride: 0x1}, + unicode.Range16{Lo: 0xf3b, Hi: 0xf3b, Stride: 0x1}, + unicode.Range16{Lo: 0xf3c, Hi: 0xf3c, Stride: 0x1}, + unicode.Range16{Lo: 0xf3d, Hi: 0xf3d, Stride: 0x1}, + unicode.Range16{Lo: 0x169b, Hi: 0x169b, Stride: 0x1}, + unicode.Range16{Lo: 0x169c, Hi: 0x169c, Stride: 0x1}, + unicode.Range16{Lo: 0x2018, Hi: 0x2018, Stride: 0x1}, + unicode.Range16{Lo: 0x2019, Hi: 0x2019, Stride: 0x1}, + unicode.Range16{Lo: 0x201a, Hi: 0x201a, Stride: 0x1}, + unicode.Range16{Lo: 0x201b, Hi: 0x201c, Stride: 0x1}, + unicode.Range16{Lo: 0x201d, Hi: 0x201d, Stride: 0x1}, + unicode.Range16{Lo: 0x201e, Hi: 0x201e, Stride: 0x1}, + unicode.Range16{Lo: 0x201f, Hi: 0x201f, Stride: 0x1}, + unicode.Range16{Lo: 0x2039, Hi: 0x2039, Stride: 0x1}, + unicode.Range16{Lo: 0x203a, Hi: 0x203a, Stride: 0x1}, + unicode.Range16{Lo: 0x2045, Hi: 0x2045, Stride: 0x1}, + unicode.Range16{Lo: 0x2046, Hi: 0x2046, Stride: 0x1}, + unicode.Range16{Lo: 0x207d, Hi: 0x207d, Stride: 0x1}, + unicode.Range16{Lo: 0x207e, Hi: 0x207e, Stride: 0x1}, + unicode.Range16{Lo: 0x208d, Hi: 0x208d, Stride: 0x1}, + unicode.Range16{Lo: 0x208e, Hi: 0x208e, Stride: 0x1}, + unicode.Range16{Lo: 0x2308, Hi: 0x2308, Stride: 0x1}, + unicode.Range16{Lo: 0x2309, Hi: 0x2309, Stride: 0x1}, + unicode.Range16{Lo: 0x230a, Hi: 0x230a, Stride: 0x1}, + unicode.Range16{Lo: 0x230b, Hi: 0x230b, Stride: 0x1}, + unicode.Range16{Lo: 0x2329, Hi: 0x2329, Stride: 0x1}, + unicode.Range16{Lo: 0x232a, Hi: 0x232a, Stride: 0x1}, + unicode.Range16{Lo: 0x275b, Hi: 0x2760, Stride: 0x1}, + unicode.Range16{Lo: 0x2768, Hi: 0x2768, Stride: 0x1}, + unicode.Range16{Lo: 0x2769, Hi: 0x2769, Stride: 0x1}, + unicode.Range16{Lo: 0x276a, Hi: 0x276a, Stride: 0x1}, + unicode.Range16{Lo: 0x276b, Hi: 0x276b, Stride: 0x1}, + unicode.Range16{Lo: 0x276c, Hi: 0x276c, Stride: 0x1}, + unicode.Range16{Lo: 0x276d, Hi: 0x276d, Stride: 0x1}, + unicode.Range16{Lo: 0x276e, Hi: 0x276e, Stride: 0x1}, + unicode.Range16{Lo: 0x276f, Hi: 0x276f, Stride: 0x1}, + unicode.Range16{Lo: 0x2770, Hi: 0x2770, Stride: 0x1}, + unicode.Range16{Lo: 0x2771, Hi: 0x2771, Stride: 0x1}, + unicode.Range16{Lo: 0x2772, Hi: 0x2772, Stride: 0x1}, + unicode.Range16{Lo: 0x2773, Hi: 0x2773, Stride: 0x1}, + unicode.Range16{Lo: 0x2774, Hi: 0x2774, Stride: 0x1}, + unicode.Range16{Lo: 0x2775, Hi: 0x2775, Stride: 0x1}, + unicode.Range16{Lo: 0x27c5, Hi: 0x27c5, Stride: 0x1}, + unicode.Range16{Lo: 0x27c6, Hi: 0x27c6, Stride: 0x1}, + unicode.Range16{Lo: 0x27e6, Hi: 0x27e6, Stride: 0x1}, + unicode.Range16{Lo: 0x27e7, Hi: 0x27e7, Stride: 0x1}, + unicode.Range16{Lo: 0x27e8, Hi: 0x27e8, Stride: 0x1}, + unicode.Range16{Lo: 0x27e9, Hi: 0x27e9, Stride: 0x1}, + unicode.Range16{Lo: 0x27ea, Hi: 0x27ea, Stride: 0x1}, + unicode.Range16{Lo: 0x27eb, Hi: 0x27eb, Stride: 0x1}, + unicode.Range16{Lo: 0x27ec, Hi: 0x27ec, Stride: 0x1}, + unicode.Range16{Lo: 0x27ed, Hi: 0x27ed, Stride: 0x1}, + unicode.Range16{Lo: 0x27ee, Hi: 0x27ee, Stride: 0x1}, + unicode.Range16{Lo: 0x27ef, Hi: 0x27ef, Stride: 0x1}, + unicode.Range16{Lo: 0x2983, Hi: 0x2983, Stride: 0x1}, + unicode.Range16{Lo: 0x2984, Hi: 0x2984, Stride: 0x1}, + unicode.Range16{Lo: 0x2985, Hi: 0x2985, Stride: 0x1}, + unicode.Range16{Lo: 0x2986, Hi: 0x2986, Stride: 0x1}, + unicode.Range16{Lo: 0x2987, Hi: 0x2987, Stride: 0x1}, + unicode.Range16{Lo: 0x2988, Hi: 0x2988, Stride: 0x1}, + unicode.Range16{Lo: 0x2989, Hi: 0x2989, Stride: 0x1}, + unicode.Range16{Lo: 0x298a, Hi: 0x298a, Stride: 0x1}, + unicode.Range16{Lo: 0x298b, Hi: 0x298b, Stride: 0x1}, + unicode.Range16{Lo: 0x298c, Hi: 0x298c, Stride: 0x1}, + unicode.Range16{Lo: 0x298d, Hi: 0x298d, Stride: 0x1}, + unicode.Range16{Lo: 0x298e, Hi: 0x298e, Stride: 0x1}, + unicode.Range16{Lo: 0x298f, Hi: 0x298f, Stride: 0x1}, + unicode.Range16{Lo: 0x2990, Hi: 0x2990, Stride: 0x1}, + unicode.Range16{Lo: 0x2991, Hi: 0x2991, Stride: 0x1}, + unicode.Range16{Lo: 0x2992, Hi: 0x2992, Stride: 0x1}, + unicode.Range16{Lo: 0x2993, Hi: 0x2993, Stride: 0x1}, + unicode.Range16{Lo: 0x2994, Hi: 0x2994, Stride: 0x1}, + unicode.Range16{Lo: 0x2995, Hi: 0x2995, Stride: 0x1}, + unicode.Range16{Lo: 0x2996, Hi: 0x2996, Stride: 0x1}, + unicode.Range16{Lo: 0x2997, Hi: 0x2997, Stride: 0x1}, + unicode.Range16{Lo: 0x2998, Hi: 0x2998, Stride: 0x1}, + unicode.Range16{Lo: 0x29d8, Hi: 0x29d8, Stride: 0x1}, + unicode.Range16{Lo: 0x29d9, Hi: 0x29d9, Stride: 0x1}, + unicode.Range16{Lo: 0x29da, Hi: 0x29da, Stride: 0x1}, + unicode.Range16{Lo: 0x29db, Hi: 0x29db, Stride: 0x1}, + unicode.Range16{Lo: 0x29fc, Hi: 0x29fc, Stride: 0x1}, + unicode.Range16{Lo: 0x29fd, Hi: 0x29fd, Stride: 0x1}, + unicode.Range16{Lo: 0x2e00, Hi: 0x2e01, Stride: 0x1}, + unicode.Range16{Lo: 0x2e02, Hi: 0x2e02, Stride: 0x1}, + unicode.Range16{Lo: 0x2e03, Hi: 0x2e03, Stride: 0x1}, + unicode.Range16{Lo: 0x2e04, Hi: 0x2e04, Stride: 0x1}, + unicode.Range16{Lo: 0x2e05, Hi: 0x2e05, Stride: 0x1}, + unicode.Range16{Lo: 0x2e06, Hi: 0x2e08, Stride: 0x1}, + unicode.Range16{Lo: 0x2e09, Hi: 0x2e09, Stride: 0x1}, + unicode.Range16{Lo: 0x2e0a, Hi: 0x2e0a, Stride: 0x1}, + unicode.Range16{Lo: 0x2e0b, Hi: 0x2e0b, Stride: 0x1}, + unicode.Range16{Lo: 0x2e0c, Hi: 0x2e0c, Stride: 0x1}, + unicode.Range16{Lo: 0x2e0d, Hi: 0x2e0d, Stride: 0x1}, + unicode.Range16{Lo: 0x2e1c, Hi: 0x2e1c, Stride: 0x1}, + unicode.Range16{Lo: 0x2e1d, Hi: 0x2e1d, Stride: 0x1}, + unicode.Range16{Lo: 0x2e20, Hi: 0x2e20, Stride: 0x1}, + unicode.Range16{Lo: 0x2e21, Hi: 0x2e21, Stride: 0x1}, + unicode.Range16{Lo: 0x2e22, Hi: 0x2e22, Stride: 0x1}, + unicode.Range16{Lo: 0x2e23, Hi: 0x2e23, Stride: 0x1}, + unicode.Range16{Lo: 0x2e24, Hi: 0x2e24, Stride: 0x1}, + unicode.Range16{Lo: 0x2e25, Hi: 0x2e25, Stride: 0x1}, + unicode.Range16{Lo: 0x2e26, Hi: 0x2e26, Stride: 0x1}, + unicode.Range16{Lo: 0x2e27, Hi: 0x2e27, Stride: 0x1}, + unicode.Range16{Lo: 0x2e28, Hi: 0x2e28, Stride: 0x1}, + unicode.Range16{Lo: 0x2e29, Hi: 0x2e29, Stride: 0x1}, + unicode.Range16{Lo: 0x2e42, Hi: 0x2e42, Stride: 0x1}, + unicode.Range16{Lo: 0x3008, Hi: 0x3008, Stride: 0x1}, + unicode.Range16{Lo: 0x3009, Hi: 0x3009, Stride: 0x1}, + unicode.Range16{Lo: 0x300a, Hi: 0x300a, Stride: 0x1}, + unicode.Range16{Lo: 0x300b, Hi: 0x300b, Stride: 0x1}, + unicode.Range16{Lo: 0x300c, Hi: 0x300c, Stride: 0x1}, + unicode.Range16{Lo: 0x300d, Hi: 0x300d, Stride: 0x1}, + unicode.Range16{Lo: 0x300e, Hi: 0x300e, Stride: 0x1}, + unicode.Range16{Lo: 0x300f, Hi: 0x300f, Stride: 0x1}, + unicode.Range16{Lo: 0x3010, Hi: 0x3010, Stride: 0x1}, + unicode.Range16{Lo: 0x3011, Hi: 0x3011, Stride: 0x1}, + unicode.Range16{Lo: 0x3014, Hi: 0x3014, Stride: 0x1}, + unicode.Range16{Lo: 0x3015, Hi: 0x3015, Stride: 0x1}, + unicode.Range16{Lo: 0x3016, Hi: 0x3016, Stride: 0x1}, + unicode.Range16{Lo: 0x3017, Hi: 0x3017, Stride: 0x1}, + unicode.Range16{Lo: 0x3018, Hi: 0x3018, Stride: 0x1}, + unicode.Range16{Lo: 0x3019, Hi: 0x3019, Stride: 0x1}, + unicode.Range16{Lo: 0x301a, Hi: 0x301a, Stride: 0x1}, + unicode.Range16{Lo: 0x301b, Hi: 0x301b, Stride: 0x1}, + unicode.Range16{Lo: 0x301d, Hi: 0x301d, Stride: 0x1}, + unicode.Range16{Lo: 0x301e, Hi: 0x301f, Stride: 0x1}, + unicode.Range16{Lo: 0xfd3e, Hi: 0xfd3e, Stride: 0x1}, + unicode.Range16{Lo: 0xfd3f, Hi: 0xfd3f, Stride: 0x1}, + unicode.Range16{Lo: 0xfe17, Hi: 0xfe17, Stride: 0x1}, + unicode.Range16{Lo: 0xfe18, Hi: 0xfe18, Stride: 0x1}, + unicode.Range16{Lo: 0xfe35, Hi: 0xfe35, Stride: 0x1}, + unicode.Range16{Lo: 0xfe36, Hi: 0xfe36, Stride: 0x1}, + unicode.Range16{Lo: 0xfe37, Hi: 0xfe37, Stride: 0x1}, + unicode.Range16{Lo: 0xfe38, Hi: 0xfe38, Stride: 0x1}, + unicode.Range16{Lo: 0xfe39, Hi: 0xfe39, Stride: 0x1}, + unicode.Range16{Lo: 0xfe3a, Hi: 0xfe3a, Stride: 0x1}, + unicode.Range16{Lo: 0xfe3b, Hi: 0xfe3b, Stride: 0x1}, + unicode.Range16{Lo: 0xfe3c, Hi: 0xfe3c, Stride: 0x1}, + unicode.Range16{Lo: 0xfe3d, Hi: 0xfe3d, Stride: 0x1}, + unicode.Range16{Lo: 0xfe3e, Hi: 0xfe3e, Stride: 0x1}, + unicode.Range16{Lo: 0xfe3f, Hi: 0xfe3f, Stride: 0x1}, + unicode.Range16{Lo: 0xfe40, Hi: 0xfe40, Stride: 0x1}, + unicode.Range16{Lo: 0xfe41, Hi: 0xfe41, Stride: 0x1}, + unicode.Range16{Lo: 0xfe42, Hi: 0xfe42, Stride: 0x1}, + unicode.Range16{Lo: 0xfe43, Hi: 0xfe43, Stride: 0x1}, + unicode.Range16{Lo: 0xfe44, Hi: 0xfe44, Stride: 0x1}, + unicode.Range16{Lo: 0xfe47, Hi: 0xfe47, Stride: 0x1}, + unicode.Range16{Lo: 0xfe48, Hi: 0xfe48, Stride: 0x1}, + unicode.Range16{Lo: 0xfe59, Hi: 0xfe59, Stride: 0x1}, + unicode.Range16{Lo: 0xfe5a, Hi: 0xfe5a, Stride: 0x1}, + unicode.Range16{Lo: 0xfe5b, Hi: 0xfe5b, Stride: 0x1}, + unicode.Range16{Lo: 0xfe5c, Hi: 0xfe5c, Stride: 0x1}, + unicode.Range16{Lo: 0xfe5d, Hi: 0xfe5d, Stride: 0x1}, + unicode.Range16{Lo: 0xfe5e, Hi: 0xfe5e, Stride: 0x1}, + unicode.Range16{Lo: 0xff08, Hi: 0xff08, Stride: 0x1}, + unicode.Range16{Lo: 0xff09, Hi: 0xff09, Stride: 0x1}, + unicode.Range16{Lo: 0xff3b, Hi: 0xff3b, Stride: 0x1}, + unicode.Range16{Lo: 0xff3d, Hi: 0xff3d, Stride: 0x1}, + unicode.Range16{Lo: 0xff5b, Hi: 0xff5b, Stride: 0x1}, + unicode.Range16{Lo: 0xff5d, Hi: 0xff5d, Stride: 0x1}, + unicode.Range16{Lo: 0xff5f, Hi: 0xff5f, Stride: 0x1}, + unicode.Range16{Lo: 0xff60, Hi: 0xff60, Stride: 0x1}, + unicode.Range16{Lo: 0xff62, Hi: 0xff62, Stride: 0x1}, + unicode.Range16{Lo: 0xff63, Hi: 0xff63, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x1f676, Hi: 0x1f678, Stride: 0x1}, + }, + LatinOffset: 10, +} + +var _SentenceATerm = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x2e, Hi: 0x2e, Stride: 0x1}, + unicode.Range16{Lo: 0x2024, Hi: 0x2024, Stride: 0x1}, + unicode.Range16{Lo: 0xfe52, Hi: 0xfe52, Stride: 0x1}, + unicode.Range16{Lo: 0xff0e, Hi: 0xff0e, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceSTerm = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x21, Hi: 0x21, Stride: 0x1}, + unicode.Range16{Lo: 0x3f, Hi: 0x3f, Stride: 0x1}, + unicode.Range16{Lo: 0x589, Hi: 0x589, Stride: 0x1}, + unicode.Range16{Lo: 0x61f, Hi: 0x61f, Stride: 0x1}, + unicode.Range16{Lo: 0x6d4, Hi: 0x6d4, Stride: 0x1}, + unicode.Range16{Lo: 0x700, Hi: 0x702, Stride: 0x1}, + unicode.Range16{Lo: 0x7f9, Hi: 0x7f9, Stride: 0x1}, + unicode.Range16{Lo: 0x964, Hi: 0x965, Stride: 0x1}, + unicode.Range16{Lo: 0x104a, Hi: 0x104b, Stride: 0x1}, + unicode.Range16{Lo: 0x1362, Hi: 0x1362, Stride: 0x1}, + unicode.Range16{Lo: 0x1367, Hi: 0x1368, Stride: 0x1}, + unicode.Range16{Lo: 0x166e, Hi: 0x166e, Stride: 0x1}, + unicode.Range16{Lo: 0x1735, Hi: 0x1736, Stride: 0x1}, + unicode.Range16{Lo: 0x1803, Hi: 0x1803, Stride: 0x1}, + unicode.Range16{Lo: 0x1809, Hi: 0x1809, Stride: 0x1}, + unicode.Range16{Lo: 0x1944, Hi: 0x1945, Stride: 0x1}, + unicode.Range16{Lo: 0x1aa8, Hi: 0x1aab, Stride: 0x1}, + unicode.Range16{Lo: 0x1b5a, Hi: 0x1b5b, Stride: 0x1}, + unicode.Range16{Lo: 0x1b5e, Hi: 0x1b5f, Stride: 0x1}, + unicode.Range16{Lo: 0x1c3b, Hi: 0x1c3c, Stride: 0x1}, + unicode.Range16{Lo: 0x1c7e, Hi: 0x1c7f, Stride: 0x1}, + unicode.Range16{Lo: 0x203c, Hi: 0x203d, Stride: 0x1}, + unicode.Range16{Lo: 0x2047, Hi: 0x2049, Stride: 0x1}, + unicode.Range16{Lo: 0x2e2e, Hi: 0x2e2e, Stride: 0x1}, + unicode.Range16{Lo: 0x2e3c, Hi: 0x2e3c, Stride: 0x1}, + unicode.Range16{Lo: 0x3002, Hi: 0x3002, Stride: 0x1}, + unicode.Range16{Lo: 0xa4ff, Hi: 0xa4ff, Stride: 0x1}, + unicode.Range16{Lo: 0xa60e, Hi: 0xa60f, Stride: 0x1}, + unicode.Range16{Lo: 0xa6f3, Hi: 0xa6f3, Stride: 0x1}, + unicode.Range16{Lo: 0xa6f7, Hi: 0xa6f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa876, Hi: 0xa877, Stride: 0x1}, + unicode.Range16{Lo: 0xa8ce, Hi: 0xa8cf, Stride: 0x1}, + unicode.Range16{Lo: 0xa92f, Hi: 0xa92f, Stride: 0x1}, + unicode.Range16{Lo: 0xa9c8, Hi: 0xa9c9, Stride: 0x1}, + unicode.Range16{Lo: 0xaa5d, Hi: 0xaa5f, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf0, Hi: 0xaaf1, Stride: 0x1}, + unicode.Range16{Lo: 0xabeb, Hi: 0xabeb, Stride: 0x1}, + unicode.Range16{Lo: 0xfe56, Hi: 0xfe57, Stride: 0x1}, + unicode.Range16{Lo: 0xff01, Hi: 0xff01, Stride: 0x1}, + unicode.Range16{Lo: 0xff1f, Hi: 0xff1f, Stride: 0x1}, + unicode.Range16{Lo: 0xff61, Hi: 0xff61, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x10a56, Hi: 0x10a57, Stride: 0x1}, + unicode.Range32{Lo: 0x11047, Hi: 0x11048, Stride: 0x1}, + unicode.Range32{Lo: 0x110be, Hi: 0x110c1, Stride: 0x1}, + unicode.Range32{Lo: 0x11141, Hi: 0x11143, Stride: 0x1}, + unicode.Range32{Lo: 0x111c5, Hi: 0x111c6, Stride: 0x1}, + unicode.Range32{Lo: 0x111cd, Hi: 0x111cd, Stride: 0x1}, + unicode.Range32{Lo: 0x11238, Hi: 0x11239, Stride: 0x1}, + unicode.Range32{Lo: 0x1123b, Hi: 0x1123c, Stride: 0x1}, + unicode.Range32{Lo: 0x115c2, Hi: 0x115c3, Stride: 0x1}, + unicode.Range32{Lo: 0x115c9, Hi: 0x115c9, Stride: 0x1}, + unicode.Range32{Lo: 0x11641, Hi: 0x11642, Stride: 0x1}, + unicode.Range32{Lo: 0x16a6e, Hi: 0x16a6f, Stride: 0x1}, + unicode.Range32{Lo: 0x16af5, Hi: 0x16af5, Stride: 0x1}, + unicode.Range32{Lo: 0x16b37, Hi: 0x16b38, Stride: 0x1}, + unicode.Range32{Lo: 0x16b44, Hi: 0x16b44, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc9f, Hi: 0x1bc9f, Stride: 0x1}, + }, + LatinOffset: 2, +} + +var _SentenceCR = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xd, Hi: 0xd, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceSep = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x85, Hi: 0x85, Stride: 0x1}, + unicode.Range16{Lo: 0x2028, Hi: 0x2028, Stride: 0x1}, + unicode.Range16{Lo: 0x2029, Hi: 0x2029, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceFormat = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0xad, Hi: 0xad, Stride: 0x1}, + unicode.Range16{Lo: 0x600, Hi: 0x605, Stride: 0x1}, + unicode.Range16{Lo: 0x61c, Hi: 0x61c, Stride: 0x1}, + unicode.Range16{Lo: 0x6dd, Hi: 0x6dd, Stride: 0x1}, + unicode.Range16{Lo: 0x70f, Hi: 0x70f, Stride: 0x1}, + unicode.Range16{Lo: 0x180e, Hi: 0x180e, Stride: 0x1}, + unicode.Range16{Lo: 0x200b, Hi: 0x200b, Stride: 0x1}, + unicode.Range16{Lo: 0x200e, Hi: 0x200f, Stride: 0x1}, + unicode.Range16{Lo: 0x202a, Hi: 0x202e, Stride: 0x1}, + unicode.Range16{Lo: 0x2060, Hi: 0x2064, Stride: 0x1}, + unicode.Range16{Lo: 0x2066, Hi: 0x206f, Stride: 0x1}, + unicode.Range16{Lo: 0xfeff, Hi: 0xfeff, Stride: 0x1}, + unicode.Range16{Lo: 0xfff9, Hi: 0xfffb, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x110bd, Hi: 0x110bd, Stride: 0x1}, + unicode.Range32{Lo: 0x1bca0, Hi: 0x1bca3, Stride: 0x1}, + unicode.Range32{Lo: 0x1d173, Hi: 0x1d17a, Stride: 0x1}, + unicode.Range32{Lo: 0xe0001, Hi: 0xe0001, Stride: 0x1}, + unicode.Range32{Lo: 0xe0020, Hi: 0xe007f, Stride: 0x1}, + }, + LatinOffset: 1, +} + +var _SentenceOLetter = &unicode.RangeTable{ + R16: []unicode.Range16{ + unicode.Range16{Lo: 0x1bb, Hi: 0x1bb, Stride: 0x1}, + unicode.Range16{Lo: 0x1c0, Hi: 0x1c3, Stride: 0x1}, + unicode.Range16{Lo: 0x294, Hi: 0x294, Stride: 0x1}, + unicode.Range16{Lo: 0x2b9, Hi: 0x2bf, Stride: 0x1}, + unicode.Range16{Lo: 0x2c6, Hi: 0x2d1, Stride: 0x1}, + unicode.Range16{Lo: 0x2ec, Hi: 0x2ec, Stride: 0x1}, + unicode.Range16{Lo: 0x2ee, Hi: 0x2ee, Stride: 0x1}, + unicode.Range16{Lo: 0x374, Hi: 0x374, Stride: 0x1}, + unicode.Range16{Lo: 0x559, Hi: 0x559, Stride: 0x1}, + unicode.Range16{Lo: 0x5d0, Hi: 0x5ea, Stride: 0x1}, + unicode.Range16{Lo: 0x5f0, Hi: 0x5f2, Stride: 0x1}, + unicode.Range16{Lo: 0x5f3, Hi: 0x5f3, Stride: 0x1}, + unicode.Range16{Lo: 0x620, Hi: 0x63f, Stride: 0x1}, + unicode.Range16{Lo: 0x640, Hi: 0x640, Stride: 0x1}, + unicode.Range16{Lo: 0x641, Hi: 0x64a, Stride: 0x1}, + unicode.Range16{Lo: 0x66e, Hi: 0x66f, Stride: 0x1}, + unicode.Range16{Lo: 0x671, Hi: 0x6d3, Stride: 0x1}, + unicode.Range16{Lo: 0x6d5, Hi: 0x6d5, Stride: 0x1}, + unicode.Range16{Lo: 0x6e5, Hi: 0x6e6, Stride: 0x1}, + unicode.Range16{Lo: 0x6ee, Hi: 0x6ef, Stride: 0x1}, + unicode.Range16{Lo: 0x6fa, Hi: 0x6fc, Stride: 0x1}, + unicode.Range16{Lo: 0x6ff, Hi: 0x6ff, Stride: 0x1}, + unicode.Range16{Lo: 0x710, Hi: 0x710, Stride: 0x1}, + unicode.Range16{Lo: 0x712, Hi: 0x72f, Stride: 0x1}, + unicode.Range16{Lo: 0x74d, Hi: 0x7a5, Stride: 0x1}, + unicode.Range16{Lo: 0x7b1, Hi: 0x7b1, Stride: 0x1}, + unicode.Range16{Lo: 0x7ca, Hi: 0x7ea, Stride: 0x1}, + unicode.Range16{Lo: 0x7f4, Hi: 0x7f5, Stride: 0x1}, + unicode.Range16{Lo: 0x7fa, Hi: 0x7fa, Stride: 0x1}, + unicode.Range16{Lo: 0x800, Hi: 0x815, Stride: 0x1}, + unicode.Range16{Lo: 0x81a, Hi: 0x81a, Stride: 0x1}, + unicode.Range16{Lo: 0x824, Hi: 0x824, Stride: 0x1}, + unicode.Range16{Lo: 0x828, Hi: 0x828, Stride: 0x1}, + unicode.Range16{Lo: 0x840, Hi: 0x858, Stride: 0x1}, + unicode.Range16{Lo: 0x8a0, Hi: 0x8b2, Stride: 0x1}, + unicode.Range16{Lo: 0x904, Hi: 0x939, Stride: 0x1}, + unicode.Range16{Lo: 0x93d, Hi: 0x93d, Stride: 0x1}, + unicode.Range16{Lo: 0x950, Hi: 0x950, Stride: 0x1}, + unicode.Range16{Lo: 0x958, Hi: 0x961, Stride: 0x1}, + unicode.Range16{Lo: 0x971, Hi: 0x971, Stride: 0x1}, + unicode.Range16{Lo: 0x972, Hi: 0x980, Stride: 0x1}, + unicode.Range16{Lo: 0x985, Hi: 0x98c, Stride: 0x1}, + unicode.Range16{Lo: 0x98f, Hi: 0x990, Stride: 0x1}, + unicode.Range16{Lo: 0x993, Hi: 0x9a8, Stride: 0x1}, + unicode.Range16{Lo: 0x9aa, Hi: 0x9b0, Stride: 0x1}, + unicode.Range16{Lo: 0x9b2, Hi: 0x9b2, Stride: 0x1}, + unicode.Range16{Lo: 0x9b6, Hi: 0x9b9, Stride: 0x1}, + unicode.Range16{Lo: 0x9bd, Hi: 0x9bd, Stride: 0x1}, + unicode.Range16{Lo: 0x9ce, Hi: 0x9ce, Stride: 0x1}, + unicode.Range16{Lo: 0x9dc, Hi: 0x9dd, Stride: 0x1}, + unicode.Range16{Lo: 0x9df, Hi: 0x9e1, Stride: 0x1}, + unicode.Range16{Lo: 0x9f0, Hi: 0x9f1, Stride: 0x1}, + unicode.Range16{Lo: 0xa05, Hi: 0xa0a, Stride: 0x1}, + unicode.Range16{Lo: 0xa0f, Hi: 0xa10, Stride: 0x1}, + unicode.Range16{Lo: 0xa13, Hi: 0xa28, Stride: 0x1}, + unicode.Range16{Lo: 0xa2a, Hi: 0xa30, Stride: 0x1}, + unicode.Range16{Lo: 0xa32, Hi: 0xa33, Stride: 0x1}, + unicode.Range16{Lo: 0xa35, Hi: 0xa36, Stride: 0x1}, + unicode.Range16{Lo: 0xa38, Hi: 0xa39, Stride: 0x1}, + unicode.Range16{Lo: 0xa59, Hi: 0xa5c, Stride: 0x1}, + unicode.Range16{Lo: 0xa5e, Hi: 0xa5e, Stride: 0x1}, + unicode.Range16{Lo: 0xa72, Hi: 0xa74, Stride: 0x1}, + unicode.Range16{Lo: 0xa85, Hi: 0xa8d, Stride: 0x1}, + unicode.Range16{Lo: 0xa8f, Hi: 0xa91, Stride: 0x1}, + unicode.Range16{Lo: 0xa93, Hi: 0xaa8, Stride: 0x1}, + unicode.Range16{Lo: 0xaaa, Hi: 0xab0, Stride: 0x1}, + unicode.Range16{Lo: 0xab2, Hi: 0xab3, Stride: 0x1}, + unicode.Range16{Lo: 0xab5, Hi: 0xab9, Stride: 0x1}, + unicode.Range16{Lo: 0xabd, Hi: 0xabd, Stride: 0x1}, + unicode.Range16{Lo: 0xad0, Hi: 0xad0, Stride: 0x1}, + unicode.Range16{Lo: 0xae0, Hi: 0xae1, Stride: 0x1}, + unicode.Range16{Lo: 0xb05, Hi: 0xb0c, Stride: 0x1}, + unicode.Range16{Lo: 0xb0f, Hi: 0xb10, Stride: 0x1}, + unicode.Range16{Lo: 0xb13, Hi: 0xb28, Stride: 0x1}, + unicode.Range16{Lo: 0xb2a, Hi: 0xb30, Stride: 0x1}, + unicode.Range16{Lo: 0xb32, Hi: 0xb33, Stride: 0x1}, + unicode.Range16{Lo: 0xb35, Hi: 0xb39, Stride: 0x1}, + unicode.Range16{Lo: 0xb3d, Hi: 0xb3d, Stride: 0x1}, + unicode.Range16{Lo: 0xb5c, Hi: 0xb5d, Stride: 0x1}, + unicode.Range16{Lo: 0xb5f, Hi: 0xb61, Stride: 0x1}, + unicode.Range16{Lo: 0xb71, Hi: 0xb71, Stride: 0x1}, + unicode.Range16{Lo: 0xb83, Hi: 0xb83, Stride: 0x1}, + unicode.Range16{Lo: 0xb85, Hi: 0xb8a, Stride: 0x1}, + unicode.Range16{Lo: 0xb8e, Hi: 0xb90, Stride: 0x1}, + unicode.Range16{Lo: 0xb92, Hi: 0xb95, Stride: 0x1}, + unicode.Range16{Lo: 0xb99, Hi: 0xb9a, Stride: 0x1}, + unicode.Range16{Lo: 0xb9c, Hi: 0xb9c, Stride: 0x1}, + unicode.Range16{Lo: 0xb9e, Hi: 0xb9f, Stride: 0x1}, + unicode.Range16{Lo: 0xba3, Hi: 0xba4, Stride: 0x1}, + unicode.Range16{Lo: 0xba8, Hi: 0xbaa, Stride: 0x1}, + unicode.Range16{Lo: 0xbae, Hi: 0xbb9, Stride: 0x1}, + unicode.Range16{Lo: 0xbd0, Hi: 0xbd0, Stride: 0x1}, + unicode.Range16{Lo: 0xc05, Hi: 0xc0c, Stride: 0x1}, + unicode.Range16{Lo: 0xc0e, Hi: 0xc10, Stride: 0x1}, + unicode.Range16{Lo: 0xc12, Hi: 0xc28, Stride: 0x1}, + unicode.Range16{Lo: 0xc2a, Hi: 0xc39, Stride: 0x1}, + unicode.Range16{Lo: 0xc3d, Hi: 0xc3d, Stride: 0x1}, + unicode.Range16{Lo: 0xc58, Hi: 0xc59, Stride: 0x1}, + unicode.Range16{Lo: 0xc60, Hi: 0xc61, Stride: 0x1}, + unicode.Range16{Lo: 0xc85, Hi: 0xc8c, Stride: 0x1}, + unicode.Range16{Lo: 0xc8e, Hi: 0xc90, Stride: 0x1}, + unicode.Range16{Lo: 0xc92, Hi: 0xca8, Stride: 0x1}, + unicode.Range16{Lo: 0xcaa, Hi: 0xcb3, Stride: 0x1}, + unicode.Range16{Lo: 0xcb5, Hi: 0xcb9, Stride: 0x1}, + unicode.Range16{Lo: 0xcbd, Hi: 0xcbd, Stride: 0x1}, + unicode.Range16{Lo: 0xcde, Hi: 0xcde, Stride: 0x1}, + unicode.Range16{Lo: 0xce0, Hi: 0xce1, Stride: 0x1}, + unicode.Range16{Lo: 0xcf1, Hi: 0xcf2, Stride: 0x1}, + unicode.Range16{Lo: 0xd05, Hi: 0xd0c, Stride: 0x1}, + unicode.Range16{Lo: 0xd0e, Hi: 0xd10, Stride: 0x1}, + unicode.Range16{Lo: 0xd12, Hi: 0xd3a, Stride: 0x1}, + unicode.Range16{Lo: 0xd3d, Hi: 0xd3d, Stride: 0x1}, + unicode.Range16{Lo: 0xd4e, Hi: 0xd4e, Stride: 0x1}, + unicode.Range16{Lo: 0xd60, Hi: 0xd61, Stride: 0x1}, + unicode.Range16{Lo: 0xd7a, Hi: 0xd7f, Stride: 0x1}, + unicode.Range16{Lo: 0xd85, Hi: 0xd96, Stride: 0x1}, + unicode.Range16{Lo: 0xd9a, Hi: 0xdb1, Stride: 0x1}, + unicode.Range16{Lo: 0xdb3, Hi: 0xdbb, Stride: 0x1}, + unicode.Range16{Lo: 0xdbd, Hi: 0xdbd, Stride: 0x1}, + unicode.Range16{Lo: 0xdc0, Hi: 0xdc6, Stride: 0x1}, + unicode.Range16{Lo: 0xe01, Hi: 0xe30, Stride: 0x1}, + unicode.Range16{Lo: 0xe32, Hi: 0xe33, Stride: 0x1}, + unicode.Range16{Lo: 0xe40, Hi: 0xe45, Stride: 0x1}, + unicode.Range16{Lo: 0xe46, Hi: 0xe46, Stride: 0x1}, + unicode.Range16{Lo: 0xe81, Hi: 0xe82, Stride: 0x1}, + unicode.Range16{Lo: 0xe84, Hi: 0xe84, Stride: 0x1}, + unicode.Range16{Lo: 0xe87, Hi: 0xe88, Stride: 0x1}, + unicode.Range16{Lo: 0xe8a, Hi: 0xe8a, Stride: 0x1}, + unicode.Range16{Lo: 0xe8d, Hi: 0xe8d, Stride: 0x1}, + unicode.Range16{Lo: 0xe94, Hi: 0xe97, Stride: 0x1}, + unicode.Range16{Lo: 0xe99, Hi: 0xe9f, Stride: 0x1}, + unicode.Range16{Lo: 0xea1, Hi: 0xea3, Stride: 0x1}, + unicode.Range16{Lo: 0xea5, Hi: 0xea5, Stride: 0x1}, + unicode.Range16{Lo: 0xea7, Hi: 0xea7, Stride: 0x1}, + unicode.Range16{Lo: 0xeaa, Hi: 0xeab, Stride: 0x1}, + unicode.Range16{Lo: 0xead, Hi: 0xeb0, Stride: 0x1}, + unicode.Range16{Lo: 0xeb2, Hi: 0xeb3, Stride: 0x1}, + unicode.Range16{Lo: 0xebd, Hi: 0xebd, Stride: 0x1}, + unicode.Range16{Lo: 0xec0, Hi: 0xec4, Stride: 0x1}, + unicode.Range16{Lo: 0xec6, Hi: 0xec6, Stride: 0x1}, + unicode.Range16{Lo: 0xedc, Hi: 0xedf, Stride: 0x1}, + unicode.Range16{Lo: 0xf00, Hi: 0xf00, Stride: 0x1}, + unicode.Range16{Lo: 0xf40, Hi: 0xf47, Stride: 0x1}, + unicode.Range16{Lo: 0xf49, Hi: 0xf6c, Stride: 0x1}, + unicode.Range16{Lo: 0xf88, Hi: 0xf8c, Stride: 0x1}, + unicode.Range16{Lo: 0x1000, Hi: 0x102a, Stride: 0x1}, + unicode.Range16{Lo: 0x103f, Hi: 0x103f, Stride: 0x1}, + unicode.Range16{Lo: 0x1050, Hi: 0x1055, Stride: 0x1}, + unicode.Range16{Lo: 0x105a, Hi: 0x105d, Stride: 0x1}, + unicode.Range16{Lo: 0x1061, Hi: 0x1061, Stride: 0x1}, + unicode.Range16{Lo: 0x1065, Hi: 0x1066, Stride: 0x1}, + unicode.Range16{Lo: 0x106e, Hi: 0x1070, Stride: 0x1}, + unicode.Range16{Lo: 0x1075, Hi: 0x1081, Stride: 0x1}, + unicode.Range16{Lo: 0x108e, Hi: 0x108e, Stride: 0x1}, + unicode.Range16{Lo: 0x10d0, Hi: 0x10fa, Stride: 0x1}, + unicode.Range16{Lo: 0x10fc, Hi: 0x10fc, Stride: 0x1}, + unicode.Range16{Lo: 0x10fd, Hi: 0x1248, Stride: 0x1}, + unicode.Range16{Lo: 0x124a, Hi: 0x124d, Stride: 0x1}, + unicode.Range16{Lo: 0x1250, Hi: 0x1256, Stride: 0x1}, + unicode.Range16{Lo: 0x1258, Hi: 0x1258, Stride: 0x1}, + unicode.Range16{Lo: 0x125a, Hi: 0x125d, Stride: 0x1}, + unicode.Range16{Lo: 0x1260, Hi: 0x1288, Stride: 0x1}, + unicode.Range16{Lo: 0x128a, Hi: 0x128d, Stride: 0x1}, + unicode.Range16{Lo: 0x1290, Hi: 0x12b0, Stride: 0x1}, + unicode.Range16{Lo: 0x12b2, Hi: 0x12b5, Stride: 0x1}, + unicode.Range16{Lo: 0x12b8, Hi: 0x12be, Stride: 0x1}, + unicode.Range16{Lo: 0x12c0, Hi: 0x12c0, Stride: 0x1}, + unicode.Range16{Lo: 0x12c2, Hi: 0x12c5, Stride: 0x1}, + unicode.Range16{Lo: 0x12c8, Hi: 0x12d6, Stride: 0x1}, + unicode.Range16{Lo: 0x12d8, Hi: 0x1310, Stride: 0x1}, + unicode.Range16{Lo: 0x1312, Hi: 0x1315, Stride: 0x1}, + unicode.Range16{Lo: 0x1318, Hi: 0x135a, Stride: 0x1}, + unicode.Range16{Lo: 0x1380, Hi: 0x138f, Stride: 0x1}, + unicode.Range16{Lo: 0x13a0, Hi: 0x13f4, Stride: 0x1}, + unicode.Range16{Lo: 0x1401, Hi: 0x166c, Stride: 0x1}, + unicode.Range16{Lo: 0x166f, Hi: 0x167f, Stride: 0x1}, + unicode.Range16{Lo: 0x1681, Hi: 0x169a, Stride: 0x1}, + unicode.Range16{Lo: 0x16a0, Hi: 0x16ea, Stride: 0x1}, + unicode.Range16{Lo: 0x16ee, Hi: 0x16f0, Stride: 0x1}, + unicode.Range16{Lo: 0x16f1, Hi: 0x16f8, Stride: 0x1}, + unicode.Range16{Lo: 0x1700, Hi: 0x170c, Stride: 0x1}, + unicode.Range16{Lo: 0x170e, Hi: 0x1711, Stride: 0x1}, + unicode.Range16{Lo: 0x1720, Hi: 0x1731, Stride: 0x1}, + unicode.Range16{Lo: 0x1740, Hi: 0x1751, Stride: 0x1}, + unicode.Range16{Lo: 0x1760, Hi: 0x176c, Stride: 0x1}, + unicode.Range16{Lo: 0x176e, Hi: 0x1770, Stride: 0x1}, + unicode.Range16{Lo: 0x1780, Hi: 0x17b3, Stride: 0x1}, + unicode.Range16{Lo: 0x17d7, Hi: 0x17d7, Stride: 0x1}, + unicode.Range16{Lo: 0x17dc, Hi: 0x17dc, Stride: 0x1}, + unicode.Range16{Lo: 0x1820, Hi: 0x1842, Stride: 0x1}, + unicode.Range16{Lo: 0x1843, Hi: 0x1843, Stride: 0x1}, + unicode.Range16{Lo: 0x1844, Hi: 0x1877, Stride: 0x1}, + unicode.Range16{Lo: 0x1880, Hi: 0x18a8, Stride: 0x1}, + unicode.Range16{Lo: 0x18aa, Hi: 0x18aa, Stride: 0x1}, + unicode.Range16{Lo: 0x18b0, Hi: 0x18f5, Stride: 0x1}, + unicode.Range16{Lo: 0x1900, Hi: 0x191e, Stride: 0x1}, + unicode.Range16{Lo: 0x1950, Hi: 0x196d, Stride: 0x1}, + unicode.Range16{Lo: 0x1970, Hi: 0x1974, Stride: 0x1}, + unicode.Range16{Lo: 0x1980, Hi: 0x19ab, Stride: 0x1}, + unicode.Range16{Lo: 0x19c1, Hi: 0x19c7, Stride: 0x1}, + unicode.Range16{Lo: 0x1a00, Hi: 0x1a16, Stride: 0x1}, + unicode.Range16{Lo: 0x1a20, Hi: 0x1a54, Stride: 0x1}, + unicode.Range16{Lo: 0x1aa7, Hi: 0x1aa7, Stride: 0x1}, + unicode.Range16{Lo: 0x1b05, Hi: 0x1b33, Stride: 0x1}, + unicode.Range16{Lo: 0x1b45, Hi: 0x1b4b, Stride: 0x1}, + unicode.Range16{Lo: 0x1b83, Hi: 0x1ba0, Stride: 0x1}, + unicode.Range16{Lo: 0x1bae, Hi: 0x1baf, Stride: 0x1}, + unicode.Range16{Lo: 0x1bba, Hi: 0x1be5, Stride: 0x1}, + unicode.Range16{Lo: 0x1c00, Hi: 0x1c23, Stride: 0x1}, + unicode.Range16{Lo: 0x1c4d, Hi: 0x1c4f, Stride: 0x1}, + unicode.Range16{Lo: 0x1c5a, Hi: 0x1c77, Stride: 0x1}, + unicode.Range16{Lo: 0x1c78, Hi: 0x1c7d, Stride: 0x1}, + unicode.Range16{Lo: 0x1ce9, Hi: 0x1cec, Stride: 0x1}, + unicode.Range16{Lo: 0x1cee, Hi: 0x1cf1, Stride: 0x1}, + unicode.Range16{Lo: 0x1cf5, Hi: 0x1cf6, Stride: 0x1}, + unicode.Range16{Lo: 0x2135, Hi: 0x2138, Stride: 0x1}, + unicode.Range16{Lo: 0x2180, Hi: 0x2182, Stride: 0x1}, + unicode.Range16{Lo: 0x2185, Hi: 0x2188, Stride: 0x1}, + unicode.Range16{Lo: 0x2d30, Hi: 0x2d67, Stride: 0x1}, + unicode.Range16{Lo: 0x2d6f, Hi: 0x2d6f, Stride: 0x1}, + unicode.Range16{Lo: 0x2d80, Hi: 0x2d96, Stride: 0x1}, + unicode.Range16{Lo: 0x2da0, Hi: 0x2da6, Stride: 0x1}, + unicode.Range16{Lo: 0x2da8, Hi: 0x2dae, Stride: 0x1}, + unicode.Range16{Lo: 0x2db0, Hi: 0x2db6, Stride: 0x1}, + unicode.Range16{Lo: 0x2db8, Hi: 0x2dbe, Stride: 0x1}, + unicode.Range16{Lo: 0x2dc0, Hi: 0x2dc6, Stride: 0x1}, + unicode.Range16{Lo: 0x2dc8, Hi: 0x2dce, Stride: 0x1}, + unicode.Range16{Lo: 0x2dd0, Hi: 0x2dd6, Stride: 0x1}, + unicode.Range16{Lo: 0x2dd8, Hi: 0x2dde, Stride: 0x1}, + unicode.Range16{Lo: 0x2e2f, Hi: 0x2e2f, Stride: 0x1}, + unicode.Range16{Lo: 0x3005, Hi: 0x3005, Stride: 0x1}, + unicode.Range16{Lo: 0x3006, Hi: 0x3006, Stride: 0x1}, + unicode.Range16{Lo: 0x3007, Hi: 0x3007, Stride: 0x1}, + unicode.Range16{Lo: 0x3021, Hi: 0x3029, Stride: 0x1}, + unicode.Range16{Lo: 0x3031, Hi: 0x3035, Stride: 0x1}, + unicode.Range16{Lo: 0x3038, Hi: 0x303a, Stride: 0x1}, + unicode.Range16{Lo: 0x303b, Hi: 0x303b, Stride: 0x1}, + unicode.Range16{Lo: 0x303c, Hi: 0x303c, Stride: 0x1}, + unicode.Range16{Lo: 0x3041, Hi: 0x3096, Stride: 0x1}, + unicode.Range16{Lo: 0x309d, Hi: 0x309e, Stride: 0x1}, + unicode.Range16{Lo: 0x309f, Hi: 0x309f, Stride: 0x1}, + unicode.Range16{Lo: 0x30a1, Hi: 0x30fa, Stride: 0x1}, + unicode.Range16{Lo: 0x30fc, Hi: 0x30fe, Stride: 0x1}, + unicode.Range16{Lo: 0x30ff, Hi: 0x30ff, Stride: 0x1}, + unicode.Range16{Lo: 0x3105, Hi: 0x312d, Stride: 0x1}, + unicode.Range16{Lo: 0x3131, Hi: 0x318e, Stride: 0x1}, + unicode.Range16{Lo: 0x31a0, Hi: 0x31ba, Stride: 0x1}, + unicode.Range16{Lo: 0x31f0, Hi: 0x31ff, Stride: 0x1}, + unicode.Range16{Lo: 0x3400, Hi: 0x4db5, Stride: 0x1}, + unicode.Range16{Lo: 0x4e00, Hi: 0x9fcc, Stride: 0x1}, + unicode.Range16{Lo: 0xa000, Hi: 0xa014, Stride: 0x1}, + unicode.Range16{Lo: 0xa015, Hi: 0xa015, Stride: 0x1}, + unicode.Range16{Lo: 0xa016, Hi: 0xa48c, Stride: 0x1}, + unicode.Range16{Lo: 0xa4d0, Hi: 0xa4f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa4f8, Hi: 0xa4fd, Stride: 0x1}, + unicode.Range16{Lo: 0xa500, Hi: 0xa60b, Stride: 0x1}, + unicode.Range16{Lo: 0xa60c, Hi: 0xa60c, Stride: 0x1}, + unicode.Range16{Lo: 0xa610, Hi: 0xa61f, Stride: 0x1}, + unicode.Range16{Lo: 0xa62a, Hi: 0xa62b, Stride: 0x1}, + unicode.Range16{Lo: 0xa66e, Hi: 0xa66e, Stride: 0x1}, + unicode.Range16{Lo: 0xa67f, Hi: 0xa67f, Stride: 0x1}, + unicode.Range16{Lo: 0xa6a0, Hi: 0xa6e5, Stride: 0x1}, + unicode.Range16{Lo: 0xa6e6, Hi: 0xa6ef, Stride: 0x1}, + unicode.Range16{Lo: 0xa717, Hi: 0xa71f, Stride: 0x1}, + unicode.Range16{Lo: 0xa788, Hi: 0xa788, Stride: 0x1}, + unicode.Range16{Lo: 0xa7f7, Hi: 0xa7f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa7fb, Hi: 0xa801, Stride: 0x1}, + unicode.Range16{Lo: 0xa803, Hi: 0xa805, Stride: 0x1}, + unicode.Range16{Lo: 0xa807, Hi: 0xa80a, Stride: 0x1}, + unicode.Range16{Lo: 0xa80c, Hi: 0xa822, Stride: 0x1}, + unicode.Range16{Lo: 0xa840, Hi: 0xa873, Stride: 0x1}, + unicode.Range16{Lo: 0xa882, Hi: 0xa8b3, Stride: 0x1}, + unicode.Range16{Lo: 0xa8f2, Hi: 0xa8f7, Stride: 0x1}, + unicode.Range16{Lo: 0xa8fb, Hi: 0xa8fb, Stride: 0x1}, + unicode.Range16{Lo: 0xa90a, Hi: 0xa925, Stride: 0x1}, + unicode.Range16{Lo: 0xa930, Hi: 0xa946, Stride: 0x1}, + unicode.Range16{Lo: 0xa960, Hi: 0xa97c, Stride: 0x1}, + unicode.Range16{Lo: 0xa984, Hi: 0xa9b2, Stride: 0x1}, + unicode.Range16{Lo: 0xa9cf, Hi: 0xa9cf, Stride: 0x1}, + unicode.Range16{Lo: 0xa9e0, Hi: 0xa9e4, Stride: 0x1}, + unicode.Range16{Lo: 0xa9e6, Hi: 0xa9e6, Stride: 0x1}, + unicode.Range16{Lo: 0xa9e7, Hi: 0xa9ef, Stride: 0x1}, + unicode.Range16{Lo: 0xa9fa, Hi: 0xa9fe, Stride: 0x1}, + unicode.Range16{Lo: 0xaa00, Hi: 0xaa28, Stride: 0x1}, + unicode.Range16{Lo: 0xaa40, Hi: 0xaa42, Stride: 0x1}, + unicode.Range16{Lo: 0xaa44, Hi: 0xaa4b, Stride: 0x1}, + unicode.Range16{Lo: 0xaa60, Hi: 0xaa6f, Stride: 0x1}, + unicode.Range16{Lo: 0xaa70, Hi: 0xaa70, Stride: 0x1}, + unicode.Range16{Lo: 0xaa71, Hi: 0xaa76, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7a, Hi: 0xaa7a, Stride: 0x1}, + unicode.Range16{Lo: 0xaa7e, Hi: 0xaaaf, Stride: 0x1}, + unicode.Range16{Lo: 0xaab1, Hi: 0xaab1, Stride: 0x1}, + unicode.Range16{Lo: 0xaab5, Hi: 0xaab6, Stride: 0x1}, + unicode.Range16{Lo: 0xaab9, Hi: 0xaabd, Stride: 0x1}, + unicode.Range16{Lo: 0xaac0, Hi: 0xaac0, Stride: 0x1}, + unicode.Range16{Lo: 0xaac2, Hi: 0xaac2, Stride: 0x1}, + unicode.Range16{Lo: 0xaadb, Hi: 0xaadc, Stride: 0x1}, + unicode.Range16{Lo: 0xaadd, Hi: 0xaadd, Stride: 0x1}, + unicode.Range16{Lo: 0xaae0, Hi: 0xaaea, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf2, Hi: 0xaaf2, Stride: 0x1}, + unicode.Range16{Lo: 0xaaf3, Hi: 0xaaf4, Stride: 0x1}, + unicode.Range16{Lo: 0xab01, Hi: 0xab06, Stride: 0x1}, + unicode.Range16{Lo: 0xab09, Hi: 0xab0e, Stride: 0x1}, + unicode.Range16{Lo: 0xab11, Hi: 0xab16, Stride: 0x1}, + unicode.Range16{Lo: 0xab20, Hi: 0xab26, Stride: 0x1}, + unicode.Range16{Lo: 0xab28, Hi: 0xab2e, Stride: 0x1}, + unicode.Range16{Lo: 0xabc0, Hi: 0xabe2, Stride: 0x1}, + unicode.Range16{Lo: 0xac00, Hi: 0xd7a3, Stride: 0x1}, + unicode.Range16{Lo: 0xd7b0, Hi: 0xd7c6, Stride: 0x1}, + unicode.Range16{Lo: 0xd7cb, Hi: 0xd7fb, Stride: 0x1}, + unicode.Range16{Lo: 0xf900, Hi: 0xfa6d, Stride: 0x1}, + unicode.Range16{Lo: 0xfa70, Hi: 0xfad9, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1d, Hi: 0xfb1d, Stride: 0x1}, + unicode.Range16{Lo: 0xfb1f, Hi: 0xfb28, Stride: 0x1}, + unicode.Range16{Lo: 0xfb2a, Hi: 0xfb36, Stride: 0x1}, + unicode.Range16{Lo: 0xfb38, Hi: 0xfb3c, Stride: 0x1}, + unicode.Range16{Lo: 0xfb3e, Hi: 0xfb3e, Stride: 0x1}, + unicode.Range16{Lo: 0xfb40, Hi: 0xfb41, Stride: 0x1}, + unicode.Range16{Lo: 0xfb43, Hi: 0xfb44, Stride: 0x1}, + unicode.Range16{Lo: 0xfb46, Hi: 0xfbb1, Stride: 0x1}, + unicode.Range16{Lo: 0xfbd3, Hi: 0xfd3d, Stride: 0x1}, + unicode.Range16{Lo: 0xfd50, Hi: 0xfd8f, Stride: 0x1}, + unicode.Range16{Lo: 0xfd92, Hi: 0xfdc7, Stride: 0x1}, + unicode.Range16{Lo: 0xfdf0, Hi: 0xfdfb, Stride: 0x1}, + unicode.Range16{Lo: 0xfe70, Hi: 0xfe74, Stride: 0x1}, + unicode.Range16{Lo: 0xfe76, Hi: 0xfefc, Stride: 0x1}, + unicode.Range16{Lo: 0xff66, Hi: 0xff6f, Stride: 0x1}, + unicode.Range16{Lo: 0xff70, Hi: 0xff70, Stride: 0x1}, + unicode.Range16{Lo: 0xff71, Hi: 0xff9d, Stride: 0x1}, + unicode.Range16{Lo: 0xffa0, Hi: 0xffbe, Stride: 0x1}, + unicode.Range16{Lo: 0xffc2, Hi: 0xffc7, Stride: 0x1}, + unicode.Range16{Lo: 0xffca, Hi: 0xffcf, Stride: 0x1}, + unicode.Range16{Lo: 0xffd2, Hi: 0xffd7, Stride: 0x1}, + unicode.Range16{Lo: 0xffda, Hi: 0xffdc, Stride: 0x1}, + }, + R32: []unicode.Range32{ + unicode.Range32{Lo: 0x10000, Hi: 0x1000b, Stride: 0x1}, + unicode.Range32{Lo: 0x1000d, Hi: 0x10026, Stride: 0x1}, + unicode.Range32{Lo: 0x10028, Hi: 0x1003a, Stride: 0x1}, + unicode.Range32{Lo: 0x1003c, Hi: 0x1003d, Stride: 0x1}, + unicode.Range32{Lo: 0x1003f, Hi: 0x1004d, Stride: 0x1}, + unicode.Range32{Lo: 0x10050, Hi: 0x1005d, Stride: 0x1}, + unicode.Range32{Lo: 0x10080, Hi: 0x100fa, Stride: 0x1}, + unicode.Range32{Lo: 0x10140, Hi: 0x10174, Stride: 0x1}, + unicode.Range32{Lo: 0x10280, Hi: 0x1029c, Stride: 0x1}, + unicode.Range32{Lo: 0x102a0, Hi: 0x102d0, Stride: 0x1}, + unicode.Range32{Lo: 0x10300, Hi: 0x1031f, Stride: 0x1}, + unicode.Range32{Lo: 0x10330, Hi: 0x10340, Stride: 0x1}, + unicode.Range32{Lo: 0x10341, Hi: 0x10341, Stride: 0x1}, + unicode.Range32{Lo: 0x10342, Hi: 0x10349, Stride: 0x1}, + unicode.Range32{Lo: 0x1034a, Hi: 0x1034a, Stride: 0x1}, + unicode.Range32{Lo: 0x10350, Hi: 0x10375, Stride: 0x1}, + unicode.Range32{Lo: 0x10380, Hi: 0x1039d, Stride: 0x1}, + unicode.Range32{Lo: 0x103a0, Hi: 0x103c3, Stride: 0x1}, + unicode.Range32{Lo: 0x103c8, Hi: 0x103cf, Stride: 0x1}, + unicode.Range32{Lo: 0x103d1, Hi: 0x103d5, Stride: 0x1}, + unicode.Range32{Lo: 0x10450, Hi: 0x1049d, Stride: 0x1}, + unicode.Range32{Lo: 0x10500, Hi: 0x10527, Stride: 0x1}, + unicode.Range32{Lo: 0x10530, Hi: 0x10563, Stride: 0x1}, + unicode.Range32{Lo: 0x10600, Hi: 0x10736, Stride: 0x1}, + unicode.Range32{Lo: 0x10740, Hi: 0x10755, Stride: 0x1}, + unicode.Range32{Lo: 0x10760, Hi: 0x10767, Stride: 0x1}, + unicode.Range32{Lo: 0x10800, Hi: 0x10805, Stride: 0x1}, + unicode.Range32{Lo: 0x10808, Hi: 0x10808, Stride: 0x1}, + unicode.Range32{Lo: 0x1080a, Hi: 0x10835, Stride: 0x1}, + unicode.Range32{Lo: 0x10837, Hi: 0x10838, Stride: 0x1}, + unicode.Range32{Lo: 0x1083c, Hi: 0x1083c, Stride: 0x1}, + unicode.Range32{Lo: 0x1083f, Hi: 0x10855, Stride: 0x1}, + unicode.Range32{Lo: 0x10860, Hi: 0x10876, Stride: 0x1}, + unicode.Range32{Lo: 0x10880, Hi: 0x1089e, Stride: 0x1}, + unicode.Range32{Lo: 0x10900, Hi: 0x10915, Stride: 0x1}, + unicode.Range32{Lo: 0x10920, Hi: 0x10939, Stride: 0x1}, + unicode.Range32{Lo: 0x10980, Hi: 0x109b7, Stride: 0x1}, + unicode.Range32{Lo: 0x109be, Hi: 0x109bf, Stride: 0x1}, + unicode.Range32{Lo: 0x10a00, Hi: 0x10a00, Stride: 0x1}, + unicode.Range32{Lo: 0x10a10, Hi: 0x10a13, Stride: 0x1}, + unicode.Range32{Lo: 0x10a15, Hi: 0x10a17, Stride: 0x1}, + unicode.Range32{Lo: 0x10a19, Hi: 0x10a33, Stride: 0x1}, + unicode.Range32{Lo: 0x10a60, Hi: 0x10a7c, Stride: 0x1}, + unicode.Range32{Lo: 0x10a80, Hi: 0x10a9c, Stride: 0x1}, + unicode.Range32{Lo: 0x10ac0, Hi: 0x10ac7, Stride: 0x1}, + unicode.Range32{Lo: 0x10ac9, Hi: 0x10ae4, Stride: 0x1}, + unicode.Range32{Lo: 0x10b00, Hi: 0x10b35, Stride: 0x1}, + unicode.Range32{Lo: 0x10b40, Hi: 0x10b55, Stride: 0x1}, + unicode.Range32{Lo: 0x10b60, Hi: 0x10b72, Stride: 0x1}, + unicode.Range32{Lo: 0x10b80, Hi: 0x10b91, Stride: 0x1}, + unicode.Range32{Lo: 0x10c00, Hi: 0x10c48, Stride: 0x1}, + unicode.Range32{Lo: 0x11003, Hi: 0x11037, Stride: 0x1}, + unicode.Range32{Lo: 0x11083, Hi: 0x110af, Stride: 0x1}, + unicode.Range32{Lo: 0x110d0, Hi: 0x110e8, Stride: 0x1}, + unicode.Range32{Lo: 0x11103, Hi: 0x11126, Stride: 0x1}, + unicode.Range32{Lo: 0x11150, Hi: 0x11172, Stride: 0x1}, + unicode.Range32{Lo: 0x11176, Hi: 0x11176, Stride: 0x1}, + unicode.Range32{Lo: 0x11183, Hi: 0x111b2, Stride: 0x1}, + unicode.Range32{Lo: 0x111c1, Hi: 0x111c4, Stride: 0x1}, + unicode.Range32{Lo: 0x111da, Hi: 0x111da, Stride: 0x1}, + unicode.Range32{Lo: 0x11200, Hi: 0x11211, Stride: 0x1}, + unicode.Range32{Lo: 0x11213, Hi: 0x1122b, Stride: 0x1}, + unicode.Range32{Lo: 0x112b0, Hi: 0x112de, Stride: 0x1}, + unicode.Range32{Lo: 0x11305, Hi: 0x1130c, Stride: 0x1}, + unicode.Range32{Lo: 0x1130f, Hi: 0x11310, Stride: 0x1}, + unicode.Range32{Lo: 0x11313, Hi: 0x11328, Stride: 0x1}, + unicode.Range32{Lo: 0x1132a, Hi: 0x11330, Stride: 0x1}, + unicode.Range32{Lo: 0x11332, Hi: 0x11333, Stride: 0x1}, + unicode.Range32{Lo: 0x11335, Hi: 0x11339, Stride: 0x1}, + unicode.Range32{Lo: 0x1133d, Hi: 0x1133d, Stride: 0x1}, + unicode.Range32{Lo: 0x1135d, Hi: 0x11361, Stride: 0x1}, + unicode.Range32{Lo: 0x11480, Hi: 0x114af, Stride: 0x1}, + unicode.Range32{Lo: 0x114c4, Hi: 0x114c5, Stride: 0x1}, + unicode.Range32{Lo: 0x114c7, Hi: 0x114c7, Stride: 0x1}, + unicode.Range32{Lo: 0x11580, Hi: 0x115ae, Stride: 0x1}, + unicode.Range32{Lo: 0x11600, Hi: 0x1162f, Stride: 0x1}, + unicode.Range32{Lo: 0x11644, Hi: 0x11644, Stride: 0x1}, + unicode.Range32{Lo: 0x11680, Hi: 0x116aa, Stride: 0x1}, + unicode.Range32{Lo: 0x118ff, Hi: 0x118ff, Stride: 0x1}, + unicode.Range32{Lo: 0x11ac0, Hi: 0x11af8, Stride: 0x1}, + unicode.Range32{Lo: 0x12000, Hi: 0x12398, Stride: 0x1}, + unicode.Range32{Lo: 0x12400, Hi: 0x1246e, Stride: 0x1}, + unicode.Range32{Lo: 0x13000, Hi: 0x1342e, Stride: 0x1}, + unicode.Range32{Lo: 0x16800, Hi: 0x16a38, Stride: 0x1}, + unicode.Range32{Lo: 0x16a40, Hi: 0x16a5e, Stride: 0x1}, + unicode.Range32{Lo: 0x16ad0, Hi: 0x16aed, Stride: 0x1}, + unicode.Range32{Lo: 0x16b00, Hi: 0x16b2f, Stride: 0x1}, + unicode.Range32{Lo: 0x16b40, Hi: 0x16b43, Stride: 0x1}, + unicode.Range32{Lo: 0x16b63, Hi: 0x16b77, Stride: 0x1}, + unicode.Range32{Lo: 0x16b7d, Hi: 0x16b8f, Stride: 0x1}, + unicode.Range32{Lo: 0x16f00, Hi: 0x16f44, Stride: 0x1}, + unicode.Range32{Lo: 0x16f50, Hi: 0x16f50, Stride: 0x1}, + unicode.Range32{Lo: 0x16f93, Hi: 0x16f9f, Stride: 0x1}, + unicode.Range32{Lo: 0x1b000, Hi: 0x1b001, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc00, Hi: 0x1bc6a, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc70, Hi: 0x1bc7c, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc80, Hi: 0x1bc88, Stride: 0x1}, + unicode.Range32{Lo: 0x1bc90, Hi: 0x1bc99, Stride: 0x1}, + unicode.Range32{Lo: 0x1e800, Hi: 0x1e8c4, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee00, Hi: 0x1ee03, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee05, Hi: 0x1ee1f, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee21, Hi: 0x1ee22, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee24, Hi: 0x1ee24, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee27, Hi: 0x1ee27, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee29, Hi: 0x1ee32, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee34, Hi: 0x1ee37, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee39, Hi: 0x1ee39, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee3b, Hi: 0x1ee3b, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee42, Hi: 0x1ee42, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee47, Hi: 0x1ee47, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee49, Hi: 0x1ee49, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee4b, Hi: 0x1ee4b, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee4d, Hi: 0x1ee4f, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee51, Hi: 0x1ee52, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee54, Hi: 0x1ee54, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee57, Hi: 0x1ee57, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee59, Hi: 0x1ee59, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee5b, Hi: 0x1ee5b, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee5d, Hi: 0x1ee5d, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee5f, Hi: 0x1ee5f, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee61, Hi: 0x1ee62, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee64, Hi: 0x1ee64, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee67, Hi: 0x1ee6a, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee6c, Hi: 0x1ee72, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee74, Hi: 0x1ee77, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee79, Hi: 0x1ee7c, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee7e, Hi: 0x1ee7e, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee80, Hi: 0x1ee89, Stride: 0x1}, + unicode.Range32{Lo: 0x1ee8b, Hi: 0x1ee9b, Stride: 0x1}, + unicode.Range32{Lo: 0x1eea1, Hi: 0x1eea3, Stride: 0x1}, + unicode.Range32{Lo: 0x1eea5, Hi: 0x1eea9, Stride: 0x1}, + unicode.Range32{Lo: 0x1eeab, Hi: 0x1eebb, Stride: 0x1}, + unicode.Range32{Lo: 0x20000, Hi: 0x2a6d6, Stride: 0x1}, + unicode.Range32{Lo: 0x2a700, Hi: 0x2b734, Stride: 0x1}, + unicode.Range32{Lo: 0x2b740, Hi: 0x2b81d, Stride: 0x1}, + unicode.Range32{Lo: 0x2f800, Hi: 0x2fa1d, Stride: 0x1}, + }, + LatinOffset: 0, +} diff --git a/Godeps/_workspace/src/github.com/blevesearch/segment/tables_test.go b/Godeps/_workspace/src/github.com/blevesearch/segment/tables_test.go new file mode 100644 index 00000000..0b9652f6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/blevesearch/segment/tables_test.go @@ -0,0 +1,9097 @@ +// Generated by running +// maketesttables --url=http://www.unicode.org/Public/7.0.0/ucd/auxiliary/ +// DO NOT EDIT + +package segment + +var unicodeGraphemeTests = []struct { + input []byte + output [][]byte +}{ + { + input: []byte{0x20, 0x20}, + output: [][]byte{[]byte{0x20}, []byte{0x20}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0x20, 0xd}, + output: [][]byte{[]byte{0x20}, []byte{0xd}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x20, 0xa}, + output: [][]byte{[]byte{0x20}, []byte{0xa}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x20, 0x1}, + output: [][]byte{[]byte{0x20}, []byte{0x1}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x20, 0xcc, 0x80}, + output: [][]byte{[]byte{0x20, 0xcc, 0x80}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x20, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0x20, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0x20, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0x20}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0x20, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0x20}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0x20, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0x20}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0x20, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0x20}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0x20, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0x20}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0x20, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x20}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x20, 0xcd, 0xb8}, + output: [][]byte{[]byte{0x20}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0x20, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0x20}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0x20, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0x20, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xd, 0x20}, + output: [][]byte{[]byte{0xd}, []byte{0x20}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xd, 0xd}, + output: [][]byte{[]byte{0xd}, []byte{0xd}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xd, 0xa}, + output: [][]byte{[]byte{0xd, 0xa}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xd, 0x1}, + output: [][]byte{[]byte{0xd}, []byte{0x1}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xd, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xd, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xd}, []byte{0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xd, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xd, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xd, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xd}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xd, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xd, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xd}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xd, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xd}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xd, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xd}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xd, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xd}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xa, 0x20}, + output: [][]byte{[]byte{0xa}, []byte{0x20}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xa, 0xd}, + output: [][]byte{[]byte{0xa}, []byte{0xd}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xa, 0xa}, + output: [][]byte{[]byte{0xa}, []byte{0xa}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xa, 0x1}, + output: [][]byte{[]byte{0xa}, []byte{0x1}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xa, 0xcc, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xa, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xa}, []byte{0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xa, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xa, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xa, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xa}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xa, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xa, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xa}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xa, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xa}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xa, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xa}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xa, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xa}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0x1, 0x20}, + output: [][]byte{[]byte{0x1}, []byte{0x20}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0x1, 0xd}, + output: [][]byte{[]byte{0x1}, []byte{0xd}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x1, 0xa}, + output: [][]byte{[]byte{0x1}, []byte{0xa}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x1, 0x1}, + output: [][]byte{[]byte{0x1}, []byte{0x1}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x1, 0xcc, 0x80}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x1, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0x1}, []byte{0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0x1, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0x1}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0x1, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0x1}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0x1, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0x1}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0x1, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0x1}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0x1, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0x1}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0x1, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x1}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x1, 0xcd, 0xb8}, + output: [][]byte{[]byte{0x1}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0x1, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0x1}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0x1}, []byte{0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xcc, 0x80, 0x20}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x20}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xcc, 0x80, 0xd}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xd}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xcc, 0x80, 0xa}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xa}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xcc, 0x80, 0x1}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x1}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xcc, 0x80, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xcc, 0x80, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xcc, 0x80, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xcc, 0x80, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xcc, 0x80, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xcc, 0x80, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0x20}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0x20}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xd}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xd}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xa}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xa}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0x1}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0x1}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x80}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe0, 0xa4, 0x83, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe0, 0xa4, 0x83, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0x20}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0x20}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xd}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0xd}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xa}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0xa}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0x1}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0x1}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x80}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe1, 0x84, 0x80, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe1, 0x84, 0x80, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0x20}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0x20}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xd}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xd}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xa}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xa}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0x1}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0x1}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x80}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe1, 0x85, 0xa0, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe1, 0x85, 0xa0, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0x20}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0x20}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xd}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xd}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xa}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xa}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0x1}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0x1}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x80}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xe1, 0x86, 0xa8, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xe1, 0x86, 0xa8, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0x20}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0x20}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xd}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xa}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xa}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0x1}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0x1}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xea, 0xb0, 0x80, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x80, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0x20}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0x20}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xd}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xa}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xa}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0x1}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0x1}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xea, 0xb0, 0x81, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xea, 0xb0, 0x81, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x20}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x20}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xd}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xd}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x1}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x1}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xcd, 0xb8, 0x20}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0x20}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xcd, 0xb8, 0xd}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xd}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xcd, 0xb8, 0xa}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xa}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xcd, 0xb8, 0x1}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0x1}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x80}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xcd, 0xb8, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xcd, 0xb8, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xcd, 0xb8, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xcd, 0xb8, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xcd, 0xb8, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xcd, 0xb8, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xcd, 0xb8, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xcd, 0xb8, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xcd, 0xb8}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xcd, 0xb8, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xcd, 0xb8, 0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0x20}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0x20}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0x20}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0x20}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xd}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xd}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xa}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xa}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0x1}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0x1}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x80}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xe0, 0xa4, 0x83}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88, 0xe0, 0xa4, 0x83}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xe1, 0x84, 0x80}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xe1, 0x84, 0x80}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xe1, 0x85, 0xa0}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xe1, 0x85, 0xa0}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xe1, 0x86, 0xa8}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xe1, 0x86, 0xa8}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xea, 0xb0, 0x80}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x80}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xea, 0xb0, 0x81}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xea, 0xb0, 0x81}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xcd, 0xb8}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xcd, 0xb8}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0xef, 0xbf, 0xbd, 0xcc, 0x88, 0xef, 0xbf, 0xbd}, + output: [][]byte{[]byte{0xef, 0xbf, 0xbd}, []byte{0xcc, 0x88}, []byte{0xef, 0xbf, 0xbd}}, + }, + { + input: []byte{0x61, 0xf0, 0x9f, 0x87, 0xa6, 0x62}, + output: [][]byte{[]byte{0x61}, []byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x62}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xe2, 0x80, 0x8b, 0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba}, []byte{0xe2, 0x80, 0x8b}, []byte{0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xe2, 0x80, 0x8d}, []byte{0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xe2, 0x80, 0x8d}, []byte{0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0x20, 0xe2, 0x80, 0x8d, 0xd9, 0x86}, + output: [][]byte{[]byte{0x20, 0xe2, 0x80, 0x8d}, []byte{0xd9, 0x86}}, + }, + { + input: []byte{0xd9, 0x86, 0xe2, 0x80, 0x8d, 0x20}, + output: [][]byte{[]byte{0xd9, 0x86, 0xe2, 0x80, 0x8d}, []byte{0x20}}, + }, +} +var unicodeWordTests = []struct { + input []byte + output [][]byte +}{ + { + input: []byte{0x1, 0x1}, + output: [][]byte{[]byte{0x1}, []byte{0x1}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x1, 0xd}, + output: [][]byte{[]byte{0x1}, []byte{0xd}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x1, 0xa}, + output: [][]byte{[]byte{0x1}, []byte{0xa}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x1, 0xb}, + output: [][]byte{[]byte{0x1}, []byte{0xb}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x1, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x1}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x1, 0x41}, + output: [][]byte{[]byte{0x1}, []byte{0x41}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x1, 0x3a}, + output: [][]byte{[]byte{0x1}, []byte{0x3a}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x1, 0x2c}, + output: [][]byte{[]byte{0x1}, []byte{0x2c}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x1, 0x2e}, + output: [][]byte{[]byte{0x1}, []byte{0x2e}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x1, 0x30}, + output: [][]byte{[]byte{0x1}, []byte{0x30}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x1, 0x5f}, + output: [][]byte{[]byte{0x1}, []byte{0x5f}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x1, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x1}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x1, 0xd7, 0x90}, + output: [][]byte{[]byte{0x1}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x1, 0x22}, + output: [][]byte{[]byte{0x1}, []byte{0x22}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x1, 0x27}, + output: [][]byte{[]byte{0x1}, []byte{0x27}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x1, 0xc2, 0xad}, + output: [][]byte{[]byte{0x1, 0xc2, 0xad}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x1, 0xcc, 0x80}, + output: [][]byte{[]byte{0x1, 0xcc, 0x80}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x1, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x1}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x1, 0x61, 0x3a}, + output: [][]byte{[]byte{0x1}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x1, 0x61, 0x27}, + output: [][]byte{[]byte{0x1}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x1, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x1}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x1, 0x61, 0x2c}, + output: [][]byte{[]byte{0x1}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x1, 0x31, 0x3a}, + output: [][]byte{[]byte{0x1}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x1, 0x31, 0x27}, + output: [][]byte{[]byte{0x1}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x1, 0x31, 0x2c}, + output: [][]byte{[]byte{0x1}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x1, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x1}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd, 0x1}, + output: [][]byte{[]byte{0xd}, []byte{0x1}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xd, 0xd}, + output: [][]byte{[]byte{0xd}, []byte{0xd}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xd, 0xa}, + output: [][]byte{[]byte{0xd, 0xa}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xd, 0xb}, + output: [][]byte{[]byte{0xd}, []byte{0xb}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xd, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xd}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xd, 0x41}, + output: [][]byte{[]byte{0xd}, []byte{0x41}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xd, 0x3a}, + output: [][]byte{[]byte{0xd}, []byte{0x3a}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xd, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0x2e}, + output: [][]byte{[]byte{0xd}, []byte{0x2e}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xd, 0x30}, + output: [][]byte{[]byte{0xd}, []byte{0x30}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xd, 0x5f}, + output: [][]byte{[]byte{0xd}, []byte{0x5f}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0xd, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xd}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xd, 0xd7, 0x90}, + output: [][]byte{[]byte{0xd}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xd, 0x22}, + output: [][]byte{[]byte{0xd}, []byte{0x22}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xd, 0x27}, + output: [][]byte{[]byte{0xd}, []byte{0x27}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xd, 0xc2, 0xad}, + output: [][]byte{[]byte{0xd}, []byte{0xc2, 0xad}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xd, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xd, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd, 0x61, 0x3a}, + output: [][]byte{[]byte{0xd}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xd, 0x61, 0x27}, + output: [][]byte{[]byte{0xd}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xd, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd, 0x61, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0x31, 0x3a}, + output: [][]byte{[]byte{0xd}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xd, 0x31, 0x27}, + output: [][]byte{[]byte{0xd}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xd, 0x31, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xa, 0x1}, + output: [][]byte{[]byte{0xa}, []byte{0x1}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xa, 0xd}, + output: [][]byte{[]byte{0xa}, []byte{0xd}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xa, 0xa}, + output: [][]byte{[]byte{0xa}, []byte{0xa}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xa, 0xb}, + output: [][]byte{[]byte{0xa}, []byte{0xb}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xa, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xa}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xa, 0x41}, + output: [][]byte{[]byte{0xa}, []byte{0x41}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xa, 0x3a}, + output: [][]byte{[]byte{0xa}, []byte{0x3a}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xa, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0x2e}, + output: [][]byte{[]byte{0xa}, []byte{0x2e}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xa, 0x30}, + output: [][]byte{[]byte{0xa}, []byte{0x30}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xa, 0x5f}, + output: [][]byte{[]byte{0xa}, []byte{0x5f}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0xa, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xa}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xa, 0xd7, 0x90}, + output: [][]byte{[]byte{0xa}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xa, 0x22}, + output: [][]byte{[]byte{0xa}, []byte{0x22}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xa, 0x27}, + output: [][]byte{[]byte{0xa}, []byte{0x27}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xa, 0xc2, 0xad}, + output: [][]byte{[]byte{0xa}, []byte{0xc2, 0xad}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xa, 0xcc, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xa, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xa, 0x61, 0x3a}, + output: [][]byte{[]byte{0xa}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xa, 0x61, 0x27}, + output: [][]byte{[]byte{0xa}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xa, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xa, 0x61, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0x31, 0x3a}, + output: [][]byte{[]byte{0xa}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xa, 0x31, 0x27}, + output: [][]byte{[]byte{0xa}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xa, 0x31, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xb, 0x1}, + output: [][]byte{[]byte{0xb}, []byte{0x1}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xb, 0xd}, + output: [][]byte{[]byte{0xb}, []byte{0xd}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xb, 0xa}, + output: [][]byte{[]byte{0xb}, []byte{0xa}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xb, 0xb}, + output: [][]byte{[]byte{0xb}, []byte{0xb}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xb, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xb}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xb, 0x41}, + output: [][]byte{[]byte{0xb}, []byte{0x41}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xb, 0x3a}, + output: [][]byte{[]byte{0xb}, []byte{0x3a}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xb, 0x2c}, + output: [][]byte{[]byte{0xb}, []byte{0x2c}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xb, 0x2e}, + output: [][]byte{[]byte{0xb}, []byte{0x2e}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xb, 0x30}, + output: [][]byte{[]byte{0xb}, []byte{0x30}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xb, 0x5f}, + output: [][]byte{[]byte{0xb}, []byte{0x5f}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0xb, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xb}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xb, 0xd7, 0x90}, + output: [][]byte{[]byte{0xb}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xb, 0x22}, + output: [][]byte{[]byte{0xb}, []byte{0x22}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xb, 0x27}, + output: [][]byte{[]byte{0xb}, []byte{0x27}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xb, 0xc2, 0xad}, + output: [][]byte{[]byte{0xb}, []byte{0xc2, 0xad}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xb, 0xcc, 0x80}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xb, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xb}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xb, 0x61, 0x3a}, + output: [][]byte{[]byte{0xb}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xb, 0x61, 0x27}, + output: [][]byte{[]byte{0xb}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xb, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xb}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xb, 0x61, 0x2c}, + output: [][]byte{[]byte{0xb}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xb, 0x31, 0x3a}, + output: [][]byte{[]byte{0xb}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xb, 0x31, 0x27}, + output: [][]byte{[]byte{0xb}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xb, 0x31, 0x2c}, + output: [][]byte{[]byte{0xb}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xb, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xb}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xb, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xb}, []byte{0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x1}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x1}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xd}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0xd}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xa}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0xa}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xb}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0xb}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x41}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x41}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x3a}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x3a}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x2c}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x2c}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x2e}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x2e}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x30}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x30}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x5f}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0x5f}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x5f}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xd7, 0x90}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x22}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x22}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x27}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x27}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xc2, 0xad}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xc2, 0xad}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x80}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x61, 0x3a}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x61, 0x27}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x61, 0x2c}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x31, 0x3a}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x31, 0x27}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x31, 0x2c}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe3, 0x80, 0xb1, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe3, 0x80, 0xb1, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x41, 0x1}, + output: [][]byte{[]byte{0x41}, []byte{0x1}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x41, 0xd}, + output: [][]byte{[]byte{0x41}, []byte{0xd}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x41, 0xa}, + output: [][]byte{[]byte{0x41}, []byte{0xa}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x41, 0xb}, + output: [][]byte{[]byte{0x41}, []byte{0xb}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x41, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x41}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x41, 0x41}, + output: [][]byte{[]byte{0x41, 0x41}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x41, 0x3a}, + output: [][]byte{[]byte{0x41}, []byte{0x3a}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x41, 0x2c}, + output: [][]byte{[]byte{0x41}, []byte{0x2c}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x41, 0x2e}, + output: [][]byte{[]byte{0x41}, []byte{0x2e}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x41, 0x30}, + output: [][]byte{[]byte{0x41, 0x30}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x41, 0x5f}, + output: [][]byte{[]byte{0x41, 0x5f}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x5f}}, + }, + { + input: []byte{0x41, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x41}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x41, 0xd7, 0x90}, + output: [][]byte{[]byte{0x41, 0xd7, 0x90}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x41, 0x22}, + output: [][]byte{[]byte{0x41}, []byte{0x22}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x41, 0x27}, + output: [][]byte{[]byte{0x41}, []byte{0x27}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x41, 0xc2, 0xad}, + output: [][]byte{[]byte{0x41, 0xc2, 0xad}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x41, 0xcc, 0x80}, + output: [][]byte{[]byte{0x41, 0xcc, 0x80}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x41, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x41, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x41, 0x61, 0x3a}, + output: [][]byte{[]byte{0x41, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x41, 0x61, 0x27}, + output: [][]byte{[]byte{0x41, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x41, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x41, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x41, 0x61, 0x2c}, + output: [][]byte{[]byte{0x41, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x41, 0x31, 0x3a}, + output: [][]byte{[]byte{0x41, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x41, 0x31, 0x27}, + output: [][]byte{[]byte{0x41, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x41, 0x31, 0x2c}, + output: [][]byte{[]byte{0x41, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x41, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x41, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x3a, 0x1}, + output: [][]byte{[]byte{0x3a}, []byte{0x1}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x3a, 0xd}, + output: [][]byte{[]byte{0x3a}, []byte{0xd}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x3a, 0xa}, + output: [][]byte{[]byte{0x3a}, []byte{0xa}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x3a, 0xb}, + output: [][]byte{[]byte{0x3a}, []byte{0xb}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x3a, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x3a}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x3a, 0x41}, + output: [][]byte{[]byte{0x3a}, []byte{0x41}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x3a, 0x3a}, + output: [][]byte{[]byte{0x3a}, []byte{0x3a}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x3a, 0x2c}, + output: [][]byte{[]byte{0x3a}, []byte{0x2c}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x3a, 0x2e}, + output: [][]byte{[]byte{0x3a}, []byte{0x2e}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x3a, 0x30}, + output: [][]byte{[]byte{0x3a}, []byte{0x30}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x3a, 0x5f}, + output: [][]byte{[]byte{0x3a}, []byte{0x5f}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x3a, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x3a}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x3a, 0xd7, 0x90}, + output: [][]byte{[]byte{0x3a}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x3a, 0x22}, + output: [][]byte{[]byte{0x3a}, []byte{0x22}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x3a, 0x27}, + output: [][]byte{[]byte{0x3a}, []byte{0x27}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x3a, 0xc2, 0xad}, + output: [][]byte{[]byte{0x3a, 0xc2, 0xad}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x3a, 0xcc, 0x80}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x80}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x3a, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x3a}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x3a, 0x61, 0x3a}, + output: [][]byte{[]byte{0x3a}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x3a, 0x61, 0x27}, + output: [][]byte{[]byte{0x3a}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x3a, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x3a}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x3a, 0x61, 0x2c}, + output: [][]byte{[]byte{0x3a}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x3a, 0x31, 0x3a}, + output: [][]byte{[]byte{0x3a}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x3a, 0x31, 0x27}, + output: [][]byte{[]byte{0x3a}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x3a, 0x31, 0x2c}, + output: [][]byte{[]byte{0x3a}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x3a, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x3a}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x3a, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2c, 0x1}, + output: [][]byte{[]byte{0x2c}, []byte{0x1}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x2c, 0xd}, + output: [][]byte{[]byte{0x2c}, []byte{0xd}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x2c, 0xa}, + output: [][]byte{[]byte{0x2c}, []byte{0xa}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x2c, 0xb}, + output: [][]byte{[]byte{0x2c}, []byte{0xb}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x2c, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x2c}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x2c, 0x41}, + output: [][]byte{[]byte{0x2c}, []byte{0x41}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x2c, 0x3a}, + output: [][]byte{[]byte{0x2c}, []byte{0x3a}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x2c, 0x2c}, + output: [][]byte{[]byte{0x2c}, []byte{0x2c}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x2c, 0x2e}, + output: [][]byte{[]byte{0x2c}, []byte{0x2e}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x2c, 0x30}, + output: [][]byte{[]byte{0x2c}, []byte{0x30}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x2c, 0x5f}, + output: [][]byte{[]byte{0x2c}, []byte{0x5f}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x2c, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x2c}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x2c, 0xd7, 0x90}, + output: [][]byte{[]byte{0x2c}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x2c, 0x22}, + output: [][]byte{[]byte{0x2c}, []byte{0x22}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x2c, 0x27}, + output: [][]byte{[]byte{0x2c}, []byte{0x27}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x2c, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2c, 0xc2, 0xad}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x2c, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x80}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x2c, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2c}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2c, 0x61, 0x3a}, + output: [][]byte{[]byte{0x2c}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x2c, 0x61, 0x27}, + output: [][]byte{[]byte{0x2c}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x2c, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2c}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2c, 0x61, 0x2c}, + output: [][]byte{[]byte{0x2c}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x2c, 0x31, 0x3a}, + output: [][]byte{[]byte{0x2c}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x2c, 0x31, 0x27}, + output: [][]byte{[]byte{0x2c}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x2c, 0x31, 0x2c}, + output: [][]byte{[]byte{0x2c}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x2c, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2c}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2e, 0x1}, + output: [][]byte{[]byte{0x2e}, []byte{0x1}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x2e, 0xd}, + output: [][]byte{[]byte{0x2e}, []byte{0xd}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x2e, 0xa}, + output: [][]byte{[]byte{0x2e}, []byte{0xa}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x2e, 0xb}, + output: [][]byte{[]byte{0x2e}, []byte{0xb}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x2e, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x2e}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x2e, 0x41}, + output: [][]byte{[]byte{0x2e}, []byte{0x41}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x2e, 0x3a}, + output: [][]byte{[]byte{0x2e}, []byte{0x3a}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x2e, 0x2c}, + output: [][]byte{[]byte{0x2e}, []byte{0x2c}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x2e, 0x2e}, + output: [][]byte{[]byte{0x2e}, []byte{0x2e}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x2e, 0x30}, + output: [][]byte{[]byte{0x2e}, []byte{0x30}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x2e, 0x5f}, + output: [][]byte{[]byte{0x2e}, []byte{0x5f}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x2e, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x2e}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x2e, 0xd7, 0x90}, + output: [][]byte{[]byte{0x2e}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x2e, 0x22}, + output: [][]byte{[]byte{0x2e}, []byte{0x22}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x2e, 0x27}, + output: [][]byte{[]byte{0x2e}, []byte{0x27}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x2e, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2e, 0xc2, 0xad}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x2e, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x80}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x2e, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2e}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2e, 0x61, 0x3a}, + output: [][]byte{[]byte{0x2e}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x2e, 0x61, 0x27}, + output: [][]byte{[]byte{0x2e}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x2e, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2e}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2e, 0x61, 0x2c}, + output: [][]byte{[]byte{0x2e}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x2e, 0x31, 0x3a}, + output: [][]byte{[]byte{0x2e}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x2e, 0x31, 0x27}, + output: [][]byte{[]byte{0x2e}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x2e, 0x31, 0x2c}, + output: [][]byte{[]byte{0x2e}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x2e, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2e}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x30, 0x1}, + output: [][]byte{[]byte{0x30}, []byte{0x1}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x30, 0xd}, + output: [][]byte{[]byte{0x30}, []byte{0xd}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x30, 0xa}, + output: [][]byte{[]byte{0x30}, []byte{0xa}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x30, 0xb}, + output: [][]byte{[]byte{0x30}, []byte{0xb}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x30, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x30}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x30, 0x41}, + output: [][]byte{[]byte{0x30, 0x41}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x30, 0x3a}, + output: [][]byte{[]byte{0x30}, []byte{0x3a}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x30, 0x2c}, + output: [][]byte{[]byte{0x30}, []byte{0x2c}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x30, 0x2e}, + output: [][]byte{[]byte{0x30}, []byte{0x2e}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x30, 0x30}, + output: [][]byte{[]byte{0x30, 0x30}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x30, 0x5f}, + output: [][]byte{[]byte{0x30, 0x5f}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x5f}}, + }, + { + input: []byte{0x30, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x30}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x30, 0xd7, 0x90}, + output: [][]byte{[]byte{0x30, 0xd7, 0x90}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x30, 0x22}, + output: [][]byte{[]byte{0x30}, []byte{0x22}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x30, 0x27}, + output: [][]byte{[]byte{0x30}, []byte{0x27}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x30, 0xc2, 0xad}, + output: [][]byte{[]byte{0x30, 0xc2, 0xad}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x30, 0xcc, 0x80}, + output: [][]byte{[]byte{0x30, 0xcc, 0x80}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x30, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x30, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x30, 0x61, 0x3a}, + output: [][]byte{[]byte{0x30, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x30, 0x61, 0x27}, + output: [][]byte{[]byte{0x30, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x30, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x30, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x30, 0x61, 0x2c}, + output: [][]byte{[]byte{0x30, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x30, 0x31, 0x3a}, + output: [][]byte{[]byte{0x30, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x30, 0x31, 0x27}, + output: [][]byte{[]byte{0x30, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x30, 0x31, 0x2c}, + output: [][]byte{[]byte{0x30, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x30, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x30, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x5f, 0x1}, + output: [][]byte{[]byte{0x5f}, []byte{0x1}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x5f, 0xd}, + output: [][]byte{[]byte{0x5f}, []byte{0xd}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x5f, 0xa}, + output: [][]byte{[]byte{0x5f}, []byte{0xa}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x5f, 0xb}, + output: [][]byte{[]byte{0x5f}, []byte{0xb}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x5f, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x5f, 0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x5f, 0x41}, + output: [][]byte{[]byte{0x5f, 0x41}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x5f, 0x3a}, + output: [][]byte{[]byte{0x5f}, []byte{0x3a}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x5f, 0x2c}, + output: [][]byte{[]byte{0x5f}, []byte{0x2c}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x5f, 0x2e}, + output: [][]byte{[]byte{0x5f}, []byte{0x2e}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x5f, 0x30}, + output: [][]byte{[]byte{0x5f, 0x30}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x5f, 0x5f}, + output: [][]byte{[]byte{0x5f, 0x5f}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x5f}}, + }, + { + input: []byte{0x5f, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x5f}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x5f, 0xd7, 0x90}, + output: [][]byte{[]byte{0x5f, 0xd7, 0x90}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x5f, 0x22}, + output: [][]byte{[]byte{0x5f}, []byte{0x22}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x5f, 0x27}, + output: [][]byte{[]byte{0x5f}, []byte{0x27}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x5f, 0xc2, 0xad}, + output: [][]byte{[]byte{0x5f, 0xc2, 0xad}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x5f, 0xcc, 0x80}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x80}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x5f, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x5f, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x5f, 0x61, 0x3a}, + output: [][]byte{[]byte{0x5f, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x5f, 0x61, 0x27}, + output: [][]byte{[]byte{0x5f, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x5f, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x5f, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x5f, 0x61, 0x2c}, + output: [][]byte{[]byte{0x5f, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x5f, 0x31, 0x3a}, + output: [][]byte{[]byte{0x5f, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x5f, 0x31, 0x27}, + output: [][]byte{[]byte{0x5f, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x5f, 0x31, 0x2c}, + output: [][]byte{[]byte{0x5f, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x5f, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x5f, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x5f, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x5f, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x1}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x1}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xd}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xd}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xb}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xb}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x41}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x41}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x3a}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x3a}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x2c}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x2c}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x2e}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x2e}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x30}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x30}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x5f}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x5f}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xd7, 0x90}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x22}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x22}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x27}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x27}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xc2, 0xad}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xc2, 0xad}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x61, 0x3a}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x61, 0x27}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x61, 0x2c}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x31, 0x3a}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x31, 0x27}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x31, 0x2c}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd7, 0x90, 0x1}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0x1}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xd7, 0x90, 0xd}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0xd}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xd7, 0x90, 0xa}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0xa}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xd7, 0x90, 0xb}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0xb}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xd7, 0x90, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xd7, 0x90, 0x41}, + output: [][]byte{[]byte{0xd7, 0x90, 0x41}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xd7, 0x90, 0x3a}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0x3a}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xd7, 0x90, 0x2c}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0x2c}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xd7, 0x90, 0x2e}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0x2e}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xd7, 0x90, 0x30}, + output: [][]byte{[]byte{0xd7, 0x90, 0x30}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xd7, 0x90, 0x5f}, + output: [][]byte{[]byte{0xd7, 0x90, 0x5f}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x5f}}, + }, + { + input: []byte{0xd7, 0x90, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xd7, 0x90, 0xd7, 0x90}, + output: [][]byte{[]byte{0xd7, 0x90, 0xd7, 0x90}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0xd7, 0x90, 0x22}, + output: [][]byte{[]byte{0xd7, 0x90}, []byte{0x22}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xd7, 0x90, 0x27}, + output: [][]byte{[]byte{0xd7, 0x90, 0x27}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x27}}, + }, + { + input: []byte{0xd7, 0x90, 0xc2, 0xad}, + output: [][]byte{[]byte{0xd7, 0x90, 0xc2, 0xad}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x80}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xd7, 0x90, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd7, 0x90, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd7, 0x90, 0x61, 0x3a}, + output: [][]byte{[]byte{0xd7, 0x90, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xd7, 0x90, 0x61, 0x27}, + output: [][]byte{[]byte{0xd7, 0x90, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0xd7, 0x90, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd7, 0x90, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd7, 0x90, 0x61, 0x2c}, + output: [][]byte{[]byte{0xd7, 0x90, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xd7, 0x90, 0x31, 0x3a}, + output: [][]byte{[]byte{0xd7, 0x90, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xd7, 0x90, 0x31, 0x27}, + output: [][]byte{[]byte{0xd7, 0x90, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0xd7, 0x90, 0x31, 0x2c}, + output: [][]byte{[]byte{0xd7, 0x90, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xd7, 0x90, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd7, 0x90, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xd7, 0x90, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xd7, 0x90, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x22, 0x1}, + output: [][]byte{[]byte{0x22}, []byte{0x1}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x22, 0xd}, + output: [][]byte{[]byte{0x22}, []byte{0xd}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x22, 0xa}, + output: [][]byte{[]byte{0x22}, []byte{0xa}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x22, 0xb}, + output: [][]byte{[]byte{0x22}, []byte{0xb}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x22, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x22}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x22, 0x41}, + output: [][]byte{[]byte{0x22}, []byte{0x41}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x22, 0x3a}, + output: [][]byte{[]byte{0x22}, []byte{0x3a}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x22, 0x2c}, + output: [][]byte{[]byte{0x22}, []byte{0x2c}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x22, 0x2e}, + output: [][]byte{[]byte{0x22}, []byte{0x2e}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x22, 0x30}, + output: [][]byte{[]byte{0x22}, []byte{0x30}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x22, 0x5f}, + output: [][]byte{[]byte{0x22}, []byte{0x5f}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x22, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x22}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x22, 0xd7, 0x90}, + output: [][]byte{[]byte{0x22}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x22, 0x22}, + output: [][]byte{[]byte{0x22}, []byte{0x22}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x22, 0x27}, + output: [][]byte{[]byte{0x22}, []byte{0x27}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x22, 0xc2, 0xad}, + output: [][]byte{[]byte{0x22, 0xc2, 0xad}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x22, 0xcc, 0x80}, + output: [][]byte{[]byte{0x22, 0xcc, 0x80}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x22, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x22}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x22, 0x61, 0x3a}, + output: [][]byte{[]byte{0x22}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x22, 0x61, 0x27}, + output: [][]byte{[]byte{0x22}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x22, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x22}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x22, 0x61, 0x2c}, + output: [][]byte{[]byte{0x22}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x22, 0x31, 0x3a}, + output: [][]byte{[]byte{0x22}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x22, 0x31, 0x27}, + output: [][]byte{[]byte{0x22}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x22, 0x31, 0x2c}, + output: [][]byte{[]byte{0x22}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x22, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x22}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x27, 0x1}, + output: [][]byte{[]byte{0x27}, []byte{0x1}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x27, 0xd}, + output: [][]byte{[]byte{0x27}, []byte{0xd}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x27, 0xa}, + output: [][]byte{[]byte{0x27}, []byte{0xa}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x27, 0xb}, + output: [][]byte{[]byte{0x27}, []byte{0xb}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x27, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x27}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x27, 0x41}, + output: [][]byte{[]byte{0x27}, []byte{0x41}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x27, 0x3a}, + output: [][]byte{[]byte{0x27}, []byte{0x3a}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x27, 0x2c}, + output: [][]byte{[]byte{0x27}, []byte{0x2c}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x27, 0x2e}, + output: [][]byte{[]byte{0x27}, []byte{0x2e}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x27, 0x30}, + output: [][]byte{[]byte{0x27}, []byte{0x30}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x27, 0x5f}, + output: [][]byte{[]byte{0x27}, []byte{0x5f}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x27, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x27}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x27, 0xd7, 0x90}, + output: [][]byte{[]byte{0x27}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x27, 0x22}, + output: [][]byte{[]byte{0x27}, []byte{0x22}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x27, 0x27}, + output: [][]byte{[]byte{0x27}, []byte{0x27}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x27, 0xc2, 0xad}, + output: [][]byte{[]byte{0x27, 0xc2, 0xad}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x27, 0xcc, 0x80}, + output: [][]byte{[]byte{0x27, 0xcc, 0x80}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x27, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x27}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x27, 0x61, 0x3a}, + output: [][]byte{[]byte{0x27}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x27, 0x61, 0x27}, + output: [][]byte{[]byte{0x27}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x27, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x27}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x27, 0x61, 0x2c}, + output: [][]byte{[]byte{0x27}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x27, 0x31, 0x3a}, + output: [][]byte{[]byte{0x27}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x27, 0x31, 0x27}, + output: [][]byte{[]byte{0x27}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x27, 0x31, 0x2c}, + output: [][]byte{[]byte{0x27}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x27, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x27}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x27, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xc2, 0xad, 0x1}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x1}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xc2, 0xad, 0xd}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0xd}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xc2, 0xad, 0xa}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0xa}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xc2, 0xad, 0xb}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0xb}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xc2, 0xad, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xc2, 0xad, 0x41}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x41}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xc2, 0xad, 0x3a}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x3a}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xc2, 0xad, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0x2e}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x2e}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xc2, 0xad, 0x30}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x30}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xc2, 0xad, 0x5f}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x5f}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0xc2, 0xad, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xc2, 0xad, 0xd7, 0x90}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xc2, 0xad, 0x22}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x22}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xc2, 0xad, 0x27}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x27}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xc2, 0xad, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc2, 0xad, 0xc2, 0xad}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x80}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xc2, 0xad, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xc2, 0xad, 0x61, 0x3a}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xc2, 0xad, 0x61, 0x27}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xc2, 0xad, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xc2, 0xad, 0x61, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0x31, 0x3a}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xc2, 0xad, 0x31, 0x27}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xc2, 0xad, 0x31, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xc2, 0xad}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0x1}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x1}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0xcc, 0x80, 0xd}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xd}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0xcc, 0x80, 0xa}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xa}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0xcc, 0x80, 0xb}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xb}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0xcc, 0x80, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0xcc, 0x80, 0x41}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x41}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0xcc, 0x80, 0x3a}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x3a}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0xcc, 0x80, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0x2e}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x2e}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0xcc, 0x80, 0x30}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x30}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0xcc, 0x80, 0x5f}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x5f}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0xcc, 0x80, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0xcc, 0x80, 0xd7, 0x90}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0xcc, 0x80, 0x22}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x22}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0xcc, 0x80, 0x27}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x27}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0xcc, 0x80, 0xc2, 0xad}, + output: [][]byte{[]byte{0xcc, 0x80, 0xc2, 0xad}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0x61, 0x3a}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0xcc, 0x80, 0x61, 0x27}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0xcc, 0x80, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0x61, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0x31, 0x3a}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0xcc, 0x80, 0x31, 0x27}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0xcc, 0x80, 0x31, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x1}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xd}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xa}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xb}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x41}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x41}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x3a}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x2c}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x2e}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x30}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x30}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x5f}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x5f}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x5f}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x22}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x27}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x31, 0x27}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x3a, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x3a, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x3a, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x3a, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x3a, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x3a, 0x41}, + output: [][]byte{[]byte{0x61, 0x3a, 0x41}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x61, 0x3a, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x3a, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x3a, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x3a, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x3a, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x3a, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x3a, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0x3a, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x3a, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x3a, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x3a, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x3a, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x3a, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x3a, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0x3a, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x3a, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0x3a, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x3a, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x3a, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x3a, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x3a, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x3a, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x3a, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x3a, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x3a, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x3a, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x3a}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x3a, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x27, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x27, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x27, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x27, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x27, 0x41}, + output: [][]byte{[]byte{0x61, 0x27, 0x41}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x61, 0x27, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x27, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x27, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x27, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x27, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0x27, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x27, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x27, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x27, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0x27, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0x27, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x27, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x27, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x27}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x41}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x41}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x2c, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x61, 0x2c, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x61, 0x2c, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x61, 0x2c, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x61, 0x2c, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x61, 0x2c, 0x41}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x41}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x61, 0x2c, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x2c, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x2c, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x61, 0x2c, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x61, 0x2c, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x61, 0x2c, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x61, 0x2c, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x61, 0x2c, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x61, 0x2c, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x2c, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x2c, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x2c, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x2c, 0x61, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x2c, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x2c, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x2c, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x61, 0x2c, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x61, 0x2c, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x61, 0x2c, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x2c}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0x2c, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x61}, []byte{0x2c, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x3a, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x3a, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x3a, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x3a, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x3a, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x3a, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x3a, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x3a, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x3a, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x3a, 0x30}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x30}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x31, 0x3a, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x3a, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x3a, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x3a, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x3a, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x3a, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x3a, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x3a, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x3a, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x3a, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x3a, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x3a, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x3a, 0x31, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x3a, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x3a, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x3a}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x3a, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x3a, 0xcc, 0x88}, []byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x27, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x27, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x27, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x27, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x27, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x27, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x27, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x27, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x27, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x27, 0x30}, + output: [][]byte{[]byte{0x31, 0x27, 0x30}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x31, 0x27, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x31, 0x27, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x27, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x27, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x27, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x27, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x27, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x27, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x27, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x27, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x27, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x27, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x27}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x27, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x27, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31, 0x27, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31, 0x27, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x27, 0x31, 0x27}, + output: [][]byte{[]byte{0x31, 0x27, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x31, 0x27, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x27, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31, 0x27, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31, 0x27, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x27, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31, 0x27, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x27, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31, 0x27, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2c, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x2c, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x2c, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x2c, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x2c, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x2c, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x2c, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2c, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2c, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x2c, 0x30}, + output: [][]byte{[]byte{0x31, 0x2c, 0x30}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x31, 0x2c, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x31, 0x2c, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x2c, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x2c, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x2c, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x2c, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2c, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x2c, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2c, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2c, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2c, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2c, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2c}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2c, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2c, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31, 0x2c, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31, 0x2c, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2c, 0x31, 0x27}, + output: [][]byte{[]byte{0x31, 0x2c, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x31, 0x2c, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2c, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31, 0x2c, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31, 0x2c, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2c, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31, 0x2c, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2c, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31, 0x2c, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xd}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xa}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xb}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xb}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xe3, 0x80, 0xb1}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xe3, 0x80, 0xb1}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x2e}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x30}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x30}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x5f}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x5f}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xf0, 0x9f, 0x87, 0xa6}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xf0, 0x9f, 0x87, 0xa6}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xd7, 0x90}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0xd7, 0x90}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x22}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x61, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x3a}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x61}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x27}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x61}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x27, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x61}, []byte{0x27, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x61, 0x2c}, + output: [][]byte{[]byte{0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x61}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x3a}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x3a}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31, 0x27}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x27}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x27}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x2c}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x2c}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31, 0x2e, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0x31, 0x2e, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x31}, []byte{0x2e, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x63, 0x61, 0x6e, 0x27, 0x74}, + output: [][]byte{[]byte{0x63, 0x61, 0x6e, 0x27, 0x74}}, + }, + { + input: []byte{0x63, 0x61, 0x6e, 0xe2, 0x80, 0x99, 0x74}, + output: [][]byte{[]byte{0x63, 0x61, 0x6e, 0xe2, 0x80, 0x99, 0x74}}, + }, + { + input: []byte{0x61, 0x62, 0xc2, 0xad, 0x62, 0x79}, + output: [][]byte{[]byte{0x61, 0x62, 0xc2, 0xad, 0x62, 0x79}}, + }, + { + input: []byte{0x61, 0x24, 0x2d, 0x33, 0x34, 0x2c, 0x35, 0x36, 0x37, 0x2e, 0x31, 0x34, 0x25, 0x62}, + output: [][]byte{[]byte{0x61}, []byte{0x24}, []byte{0x2d}, []byte{0x33, 0x34, 0x2c, 0x35, 0x36, 0x37, 0x2e, 0x31, 0x34}, []byte{0x25}, []byte{0x62}}, + }, + { + input: []byte{0x33, 0x61}, + output: [][]byte{[]byte{0x33, 0x61}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x6e, 0xe2, 0x81, 0xa0, 0x27, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0}, []byte{0x63, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x6e, 0xe2, 0x81, 0xa0, 0x27, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x6e, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0}, []byte{0x63, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x6e, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x62, 0xe2, 0x81, 0xa0, 0xc2, 0xad, 0xe2, 0x81, 0xa0, 0x62, 0xe2, 0x81, 0xa0, 0x79, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0}, []byte{0x61, 0xe2, 0x81, 0xa0, 0x62, 0xe2, 0x81, 0xa0, 0xc2, 0xad, 0xe2, 0x81, 0xa0, 0x62, 0xe2, 0x81, 0xa0, 0x79, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x24, 0xe2, 0x81, 0xa0, 0x2d, 0xe2, 0x81, 0xa0, 0x33, 0xe2, 0x81, 0xa0, 0x34, 0xe2, 0x81, 0xa0, 0x2c, 0xe2, 0x81, 0xa0, 0x35, 0xe2, 0x81, 0xa0, 0x36, 0xe2, 0x81, 0xa0, 0x37, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x31, 0xe2, 0x81, 0xa0, 0x34, 0xe2, 0x81, 0xa0, 0x25, 0xe2, 0x81, 0xa0, 0x62, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0}, []byte{0x61, 0xe2, 0x81, 0xa0}, []byte{0x24, 0xe2, 0x81, 0xa0}, []byte{0x2d, 0xe2, 0x81, 0xa0}, []byte{0x33, 0xe2, 0x81, 0xa0, 0x34, 0xe2, 0x81, 0xa0, 0x2c, 0xe2, 0x81, 0xa0, 0x35, 0xe2, 0x81, 0xa0, 0x36, 0xe2, 0x81, 0xa0, 0x37, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x31, 0xe2, 0x81, 0xa0, 0x34, 0xe2, 0x81, 0xa0}, []byte{0x25, 0xe2, 0x81, 0xa0}, []byte{0x62, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x33, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0}, []byte{0x33, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0x61, 0xf0, 0x9f, 0x87, 0xa6, 0x62}, + output: [][]byte{[]byte{0x61}, []byte{0xf0, 0x9f, 0x87, 0xa6}, []byte{0x62}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba, 0xe2, 0x80, 0x8b, 0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xb7, 0xf0, 0x9f, 0x87, 0xba}, []byte{0xe2, 0x80, 0x8b}, []byte{0xf0, 0x9f, 0x87, 0xb8, 0xf0, 0x9f, 0x87, 0xaa}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0x20, 0xe2, 0x80, 0x8d, 0xd9, 0x86}, + output: [][]byte{[]byte{0x20, 0xe2, 0x80, 0x8d}, []byte{0xd9, 0x86}}, + }, + { + input: []byte{0xd9, 0x86, 0xe2, 0x80, 0x8d, 0x20}, + output: [][]byte{[]byte{0xd9, 0x86, 0xe2, 0x80, 0x8d}, []byte{0x20}}, + }, +} +var unicodeSentenceTests = []struct { + input []byte + output [][]byte +}{ + { + input: []byte{0x1, 0x1}, + output: [][]byte{[]byte{0x1, 0x1}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x1, 0xd}, + output: [][]byte{[]byte{0x1, 0xd}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x1, 0xa}, + output: [][]byte{[]byte{0x1, 0xa}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x1, 0xc2, 0x85}, + output: [][]byte{[]byte{0x1, 0xc2, 0x85}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x1, 0x9}, + output: [][]byte{[]byte{0x1, 0x9}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x1, 0x61}, + output: [][]byte{[]byte{0x1, 0x61}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x1, 0x41}, + output: [][]byte{[]byte{0x1, 0x41}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x1, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x1, 0xc6, 0xbb}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x1, 0x30}, + output: [][]byte{[]byte{0x1, 0x30}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x1, 0x2e}, + output: [][]byte{[]byte{0x1, 0x2e}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x1, 0x21}, + output: [][]byte{[]byte{0x1, 0x21}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x1, 0x22}, + output: [][]byte{[]byte{0x1, 0x22}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x1, 0x2c}, + output: [][]byte{[]byte{0x1, 0x2c}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x1, 0xc2, 0xad}, + output: [][]byte{[]byte{0x1, 0xc2, 0xad}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x1, 0xcc, 0x80}, + output: [][]byte{[]byte{0x1, 0xcc, 0x80}}, + }, + { + input: []byte{0x1, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x1, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xd, 0x1}, + output: [][]byte{[]byte{0xd}, []byte{0x1}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0xd, 0xd}, + output: [][]byte{[]byte{0xd}, []byte{0xd}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0xd, 0xa}, + output: [][]byte{[]byte{0xd, 0xa}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0xd, 0xc2, 0x85}, + output: [][]byte{[]byte{0xd}, []byte{0xc2, 0x85}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0xd, 0x9}, + output: [][]byte{[]byte{0xd}, []byte{0x9}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0xd, 0x61}, + output: [][]byte{[]byte{0xd}, []byte{0x61}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0xd, 0x41}, + output: [][]byte{[]byte{0xd}, []byte{0x41}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xd, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xd}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0xd, 0x30}, + output: [][]byte{[]byte{0xd}, []byte{0x30}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xd, 0x2e}, + output: [][]byte{[]byte{0xd}, []byte{0x2e}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0xd, 0x21}, + output: [][]byte{[]byte{0xd}, []byte{0x21}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0xd, 0x22}, + output: [][]byte{[]byte{0xd}, []byte{0x22}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0xd, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0x2c}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0xd, 0xc2, 0xad}, + output: [][]byte{[]byte{0xd}, []byte{0xc2, 0xad}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xd, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xd, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xd}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xa, 0x1}, + output: [][]byte{[]byte{0xa}, []byte{0x1}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0xa, 0xd}, + output: [][]byte{[]byte{0xa}, []byte{0xd}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0xa, 0xa}, + output: [][]byte{[]byte{0xa}, []byte{0xa}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0xa, 0xc2, 0x85}, + output: [][]byte{[]byte{0xa}, []byte{0xc2, 0x85}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0xa, 0x9}, + output: [][]byte{[]byte{0xa}, []byte{0x9}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0xa, 0x61}, + output: [][]byte{[]byte{0xa}, []byte{0x61}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0xa, 0x41}, + output: [][]byte{[]byte{0xa}, []byte{0x41}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xa, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xa}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0xa, 0x30}, + output: [][]byte{[]byte{0xa}, []byte{0x30}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xa, 0x2e}, + output: [][]byte{[]byte{0xa}, []byte{0x2e}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0xa, 0x21}, + output: [][]byte{[]byte{0xa}, []byte{0x21}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0xa, 0x22}, + output: [][]byte{[]byte{0xa}, []byte{0x22}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0xa, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0x2c}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0xa, 0xc2, 0xad}, + output: [][]byte{[]byte{0xa}, []byte{0xc2, 0xad}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xa, 0xcc, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xa, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xa}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xc2, 0x85, 0x1}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x1}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0xc2, 0x85, 0xd}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xd}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0xc2, 0x85, 0xa}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xa}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0xc2, 0x85, 0xc2, 0x85}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xc2, 0x85}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0xc2, 0x85, 0x9}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x9}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0xc2, 0x85, 0x61}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x61}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0xc2, 0x85, 0x41}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x41}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xc2, 0x85, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0xc2, 0x85, 0x30}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x30}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xc2, 0x85, 0x2e}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x2e}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0xc2, 0x85, 0x21}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x21}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0xc2, 0x85, 0x22}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x22}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0xc2, 0x85, 0x2c}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0x2c}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0xc2, 0x85, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xc2, 0xad}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x80}}, + }, + { + input: []byte{0xc2, 0x85, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc2, 0x85}, []byte{0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x9, 0x1}, + output: [][]byte{[]byte{0x9, 0x1}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x9, 0xd}, + output: [][]byte{[]byte{0x9, 0xd}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x9, 0xa}, + output: [][]byte{[]byte{0x9, 0xa}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x9, 0xc2, 0x85}, + output: [][]byte{[]byte{0x9, 0xc2, 0x85}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x9, 0x9}, + output: [][]byte{[]byte{0x9, 0x9}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x9, 0x61}, + output: [][]byte{[]byte{0x9, 0x61}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x9, 0x41}, + output: [][]byte{[]byte{0x9, 0x41}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x9, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x9, 0xc6, 0xbb}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x9, 0x30}, + output: [][]byte{[]byte{0x9, 0x30}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x9, 0x2e}, + output: [][]byte{[]byte{0x9, 0x2e}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x9, 0x21}, + output: [][]byte{[]byte{0x9, 0x21}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x9, 0x22}, + output: [][]byte{[]byte{0x9, 0x22}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x9, 0x2c}, + output: [][]byte{[]byte{0x9, 0x2c}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x9, 0xc2, 0xad}, + output: [][]byte{[]byte{0x9, 0xc2, 0xad}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x9, 0xcc, 0x80}, + output: [][]byte{[]byte{0x9, 0xcc, 0x80}}, + }, + { + input: []byte{0x9, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x9, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0x1}, + output: [][]byte{[]byte{0x61, 0x1}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x61, 0xd}, + output: [][]byte{[]byte{0x61, 0xd}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x61, 0xa}, + output: [][]byte{[]byte{0x61, 0xa}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x61, 0xc2, 0x85}, + output: [][]byte{[]byte{0x61, 0xc2, 0x85}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x61, 0x9}, + output: [][]byte{[]byte{0x61, 0x9}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x61, 0x61}, + output: [][]byte{[]byte{0x61, 0x61}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x61, 0x41}, + output: [][]byte{[]byte{0x61, 0x41}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x61, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x61, 0xc6, 0xbb}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x61, 0x30}, + output: [][]byte{[]byte{0x61, 0x30}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x61, 0x2e}, + output: [][]byte{[]byte{0x61, 0x2e}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x61, 0x21}, + output: [][]byte{[]byte{0x61, 0x21}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x61, 0x22}, + output: [][]byte{[]byte{0x61, 0x22}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x61, 0x2c}, + output: [][]byte{[]byte{0x61, 0x2c}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x61, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x61, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61, 0xcc, 0x80}}, + }, + { + input: []byte{0x61, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x61, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x41, 0x1}, + output: [][]byte{[]byte{0x41, 0x1}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x41, 0xd}, + output: [][]byte{[]byte{0x41, 0xd}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x41, 0xa}, + output: [][]byte{[]byte{0x41, 0xa}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x41, 0xc2, 0x85}, + output: [][]byte{[]byte{0x41, 0xc2, 0x85}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x41, 0x9}, + output: [][]byte{[]byte{0x41, 0x9}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x41, 0x61}, + output: [][]byte{[]byte{0x41, 0x61}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x41, 0x41}, + output: [][]byte{[]byte{0x41, 0x41}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x41, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x41, 0xc6, 0xbb}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x41, 0x30}, + output: [][]byte{[]byte{0x41, 0x30}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x41, 0x2e}, + output: [][]byte{[]byte{0x41, 0x2e}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x41, 0x21}, + output: [][]byte{[]byte{0x41, 0x21}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x41, 0x22}, + output: [][]byte{[]byte{0x41, 0x22}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x41, 0x2c}, + output: [][]byte{[]byte{0x41, 0x2c}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x41, 0xc2, 0xad}, + output: [][]byte{[]byte{0x41, 0xc2, 0xad}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x41, 0xcc, 0x80}, + output: [][]byte{[]byte{0x41, 0xcc, 0x80}}, + }, + { + input: []byte{0x41, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x41, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xc6, 0xbb, 0x1}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x1}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0xc6, 0xbb, 0xd}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xd}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0xc6, 0xbb, 0xa}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xa}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0xc6, 0xbb, 0xc2, 0x85}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xc2, 0x85}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0xc6, 0xbb, 0x9}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x9}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0xc6, 0xbb, 0x61}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x61}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0xc6, 0xbb, 0x41}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x41}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xc6, 0xbb, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xc6, 0xbb}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0xc6, 0xbb, 0x30}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x30}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xc6, 0xbb, 0x2e}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x2e}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0xc6, 0xbb, 0x21}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x21}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0xc6, 0xbb, 0x22}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x22}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0xc6, 0xbb, 0x2c}, + output: [][]byte{[]byte{0xc6, 0xbb, 0x2c}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0xc6, 0xbb, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xc2, 0xad}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x80}}, + }, + { + input: []byte{0xc6, 0xbb, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc6, 0xbb, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x30, 0x1}, + output: [][]byte{[]byte{0x30, 0x1}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x30, 0xd}, + output: [][]byte{[]byte{0x30, 0xd}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x30, 0xa}, + output: [][]byte{[]byte{0x30, 0xa}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x30, 0xc2, 0x85}, + output: [][]byte{[]byte{0x30, 0xc2, 0x85}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x30, 0x9}, + output: [][]byte{[]byte{0x30, 0x9}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x30, 0x61}, + output: [][]byte{[]byte{0x30, 0x61}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x30, 0x41}, + output: [][]byte{[]byte{0x30, 0x41}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x30, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x30, 0xc6, 0xbb}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x30, 0x30}, + output: [][]byte{[]byte{0x30, 0x30}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x30, 0x2e}, + output: [][]byte{[]byte{0x30, 0x2e}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x30, 0x21}, + output: [][]byte{[]byte{0x30, 0x21}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x30, 0x22}, + output: [][]byte{[]byte{0x30, 0x22}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x30, 0x2c}, + output: [][]byte{[]byte{0x30, 0x2c}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x30, 0xc2, 0xad}, + output: [][]byte{[]byte{0x30, 0xc2, 0xad}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x30, 0xcc, 0x80}, + output: [][]byte{[]byte{0x30, 0xcc, 0x80}}, + }, + { + input: []byte{0x30, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x30, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x2e, 0x1}, + output: [][]byte{[]byte{0x2e}, []byte{0x1}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x2e, 0xd}, + output: [][]byte{[]byte{0x2e, 0xd}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x2e, 0xa}, + output: [][]byte{[]byte{0x2e, 0xa}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x2e, 0xc2, 0x85}, + output: [][]byte{[]byte{0x2e, 0xc2, 0x85}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x2e, 0x9}, + output: [][]byte{[]byte{0x2e, 0x9}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x2e, 0x61}, + output: [][]byte{[]byte{0x2e, 0x61}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x2e, 0x41}, + output: [][]byte{[]byte{0x2e}, []byte{0x41}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x2e, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x2e}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0x2e, 0x30}, + output: [][]byte{[]byte{0x2e, 0x30}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x2e, 0x2e}, + output: [][]byte{[]byte{0x2e, 0x2e}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x2e, 0x21}, + output: [][]byte{[]byte{0x2e, 0x21}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x2e, 0x22}, + output: [][]byte{[]byte{0x2e, 0x22}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x2e, 0x2c}, + output: [][]byte{[]byte{0x2e, 0x2c}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x2e, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2e, 0xc2, 0xad}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x2e, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x80}}, + }, + { + input: []byte{0x2e, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2e, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x21, 0x1}, + output: [][]byte{[]byte{0x21}, []byte{0x1}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88}, []byte{0x1}}, + }, + { + input: []byte{0x21, 0xd}, + output: [][]byte{[]byte{0x21, 0xd}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x21, 0xa}, + output: [][]byte{[]byte{0x21, 0xa}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x21, 0xc2, 0x85}, + output: [][]byte{[]byte{0x21, 0xc2, 0x85}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x21, 0x9}, + output: [][]byte{[]byte{0x21, 0x9}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x21, 0x61}, + output: [][]byte{[]byte{0x21}, []byte{0x61}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88}, []byte{0x61}}, + }, + { + input: []byte{0x21, 0x41}, + output: [][]byte{[]byte{0x21}, []byte{0x41}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88}, []byte{0x41}}, + }, + { + input: []byte{0x21, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x21}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88}, []byte{0xc6, 0xbb}}, + }, + { + input: []byte{0x21, 0x30}, + output: [][]byte{[]byte{0x21}, []byte{0x30}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88}, []byte{0x30}}, + }, + { + input: []byte{0x21, 0x2e}, + output: [][]byte{[]byte{0x21, 0x2e}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x21, 0x21}, + output: [][]byte{[]byte{0x21, 0x21}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x21, 0x22}, + output: [][]byte{[]byte{0x21, 0x22}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x21, 0x2c}, + output: [][]byte{[]byte{0x21, 0x2c}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x21, 0xc2, 0xad}, + output: [][]byte{[]byte{0x21, 0xc2, 0xad}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x21, 0xcc, 0x80}, + output: [][]byte{[]byte{0x21, 0xcc, 0x80}}, + }, + { + input: []byte{0x21, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x21, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x22, 0x1}, + output: [][]byte{[]byte{0x22, 0x1}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x22, 0xd}, + output: [][]byte{[]byte{0x22, 0xd}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x22, 0xa}, + output: [][]byte{[]byte{0x22, 0xa}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x22, 0xc2, 0x85}, + output: [][]byte{[]byte{0x22, 0xc2, 0x85}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x22, 0x9}, + output: [][]byte{[]byte{0x22, 0x9}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x22, 0x61}, + output: [][]byte{[]byte{0x22, 0x61}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x22, 0x41}, + output: [][]byte{[]byte{0x22, 0x41}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x22, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x22, 0xc6, 0xbb}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x22, 0x30}, + output: [][]byte{[]byte{0x22, 0x30}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x22, 0x2e}, + output: [][]byte{[]byte{0x22, 0x2e}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x22, 0x21}, + output: [][]byte{[]byte{0x22, 0x21}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x22, 0x22}, + output: [][]byte{[]byte{0x22, 0x22}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x22, 0x2c}, + output: [][]byte{[]byte{0x22, 0x2c}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x22, 0xc2, 0xad}, + output: [][]byte{[]byte{0x22, 0xc2, 0xad}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x22, 0xcc, 0x80}, + output: [][]byte{[]byte{0x22, 0xcc, 0x80}}, + }, + { + input: []byte{0x22, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x22, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x2c, 0x1}, + output: [][]byte{[]byte{0x2c, 0x1}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0x2c, 0xd}, + output: [][]byte{[]byte{0x2c, 0xd}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0x2c, 0xa}, + output: [][]byte{[]byte{0x2c, 0xa}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0x2c, 0xc2, 0x85}, + output: [][]byte{[]byte{0x2c, 0xc2, 0x85}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0x2c, 0x9}, + output: [][]byte{[]byte{0x2c, 0x9}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0x2c, 0x61}, + output: [][]byte{[]byte{0x2c, 0x61}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0x2c, 0x41}, + output: [][]byte{[]byte{0x2c, 0x41}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0x2c, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x2c, 0xc6, 0xbb}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0x2c, 0x30}, + output: [][]byte{[]byte{0x2c, 0x30}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0x2c, 0x2e}, + output: [][]byte{[]byte{0x2c, 0x2e}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0x2c, 0x21}, + output: [][]byte{[]byte{0x2c, 0x21}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0x2c, 0x22}, + output: [][]byte{[]byte{0x2c, 0x22}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0x2c, 0x2c}, + output: [][]byte{[]byte{0x2c, 0x2c}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0x2c, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2c, 0xc2, 0xad}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0x2c, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x80}}, + }, + { + input: []byte{0x2c, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0x2c, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xc2, 0xad, 0x1}, + output: [][]byte{[]byte{0xc2, 0xad, 0x1}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0xc2, 0xad, 0xd}, + output: [][]byte{[]byte{0xc2, 0xad, 0xd}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0xc2, 0xad, 0xa}, + output: [][]byte{[]byte{0xc2, 0xad, 0xa}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0xc2, 0xad, 0xc2, 0x85}, + output: [][]byte{[]byte{0xc2, 0xad, 0xc2, 0x85}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0xc2, 0xad, 0x9}, + output: [][]byte{[]byte{0xc2, 0xad, 0x9}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0xc2, 0xad, 0x61}, + output: [][]byte{[]byte{0xc2, 0xad, 0x61}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0xc2, 0xad, 0x41}, + output: [][]byte{[]byte{0xc2, 0xad, 0x41}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xc2, 0xad, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xc2, 0xad, 0xc6, 0xbb}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0xc2, 0xad, 0x30}, + output: [][]byte{[]byte{0xc2, 0xad, 0x30}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xc2, 0xad, 0x2e}, + output: [][]byte{[]byte{0xc2, 0xad, 0x2e}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0xc2, 0xad, 0x21}, + output: [][]byte{[]byte{0xc2, 0xad, 0x21}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0xc2, 0xad, 0x22}, + output: [][]byte{[]byte{0xc2, 0xad, 0x22}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0xc2, 0xad, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad, 0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0xc2, 0xad, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc2, 0xad, 0xc2, 0xad}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x80}}, + }, + { + input: []byte{0xc2, 0xad, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xc2, 0xad, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0x1}, + output: [][]byte{[]byte{0xcc, 0x80, 0x1}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x1}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x1}}, + }, + { + input: []byte{0xcc, 0x80, 0xd}, + output: [][]byte{[]byte{0xcc, 0x80, 0xd}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xd}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xd}}, + }, + { + input: []byte{0xcc, 0x80, 0xa}, + output: [][]byte{[]byte{0xcc, 0x80, 0xa}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xa}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xa}}, + }, + { + input: []byte{0xcc, 0x80, 0xc2, 0x85}, + output: [][]byte{[]byte{0xcc, 0x80, 0xc2, 0x85}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xc2, 0x85}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xc2, 0x85}}, + }, + { + input: []byte{0xcc, 0x80, 0x9}, + output: [][]byte{[]byte{0xcc, 0x80, 0x9}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x9}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x9}}, + }, + { + input: []byte{0xcc, 0x80, 0x61}, + output: [][]byte{[]byte{0xcc, 0x80, 0x61}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x61}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x61}}, + }, + { + input: []byte{0xcc, 0x80, 0x41}, + output: [][]byte{[]byte{0xcc, 0x80, 0x41}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x41}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x41}}, + }, + { + input: []byte{0xcc, 0x80, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xcc, 0x80, 0xc6, 0xbb}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xc6, 0xbb}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xc6, 0xbb}}, + }, + { + input: []byte{0xcc, 0x80, 0x30}, + output: [][]byte{[]byte{0xcc, 0x80, 0x30}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x30}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x30}}, + }, + { + input: []byte{0xcc, 0x80, 0x2e}, + output: [][]byte{[]byte{0xcc, 0x80, 0x2e}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x2e}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x2e}}, + }, + { + input: []byte{0xcc, 0x80, 0x21}, + output: [][]byte{[]byte{0xcc, 0x80, 0x21}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x21}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x21}}, + }, + { + input: []byte{0xcc, 0x80, 0x22}, + output: [][]byte{[]byte{0xcc, 0x80, 0x22}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x22}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x22}}, + }, + { + input: []byte{0xcc, 0x80, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80, 0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0x2c}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0x2c}}, + }, + { + input: []byte{0xcc, 0x80, 0xc2, 0xad}, + output: [][]byte{[]byte{0xcc, 0x80, 0xc2, 0xad}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xc2, 0xad}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xc2, 0xad}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x80}}, + }, + { + input: []byte{0xcc, 0x80, 0xcc, 0x88, 0xcc, 0x80}, + output: [][]byte{[]byte{0xcc, 0x80, 0xcc, 0x88, 0xcc, 0x80}}, + }, + { + input: []byte{0x28, 0x22, 0x47, 0x6f, 0x2e, 0x22, 0x29, 0x20, 0x28, 0x48, 0x65, 0x20, 0x64, 0x69, 0x64, 0x2e, 0x29}, + output: [][]byte{[]byte{0x28, 0x22, 0x47, 0x6f, 0x2e, 0x22, 0x29, 0x20}, []byte{0x28, 0x48, 0x65, 0x20, 0x64, 0x69, 0x64, 0x2e, 0x29}}, + }, + { + input: []byte{0x28, 0xe2, 0x80, 0x9c, 0x47, 0x6f, 0x3f, 0xe2, 0x80, 0x9d, 0x29, 0x20, 0x28, 0x48, 0x65, 0x20, 0x64, 0x69, 0x64, 0x2e, 0x29}, + output: [][]byte{[]byte{0x28, 0xe2, 0x80, 0x9c, 0x47, 0x6f, 0x3f, 0xe2, 0x80, 0x9d, 0x29, 0x20}, []byte{0x28, 0x48, 0x65, 0x20, 0x64, 0x69, 0x64, 0x2e, 0x29}}, + }, + { + input: []byte{0x55, 0x2e, 0x53, 0x2e, 0x41, 0xcc, 0x80, 0x2e, 0x20, 0x69, 0x73}, + output: [][]byte{[]byte{0x55, 0x2e, 0x53, 0x2e, 0x41, 0xcc, 0x80, 0x2e, 0x20, 0x69, 0x73}}, + }, + { + input: []byte{0x55, 0x2e, 0x53, 0x2e, 0x41, 0xcc, 0x80, 0x3f, 0x20, 0x48, 0x65}, + output: [][]byte{[]byte{0x55, 0x2e, 0x53, 0x2e, 0x41, 0xcc, 0x80, 0x3f, 0x20}, []byte{0x48, 0x65}}, + }, + { + input: []byte{0x55, 0x2e, 0x53, 0x2e, 0x41, 0xcc, 0x80, 0x2e}, + output: [][]byte{[]byte{0x55, 0x2e, 0x53, 0x2e, 0x41, 0xcc, 0x80, 0x2e}}, + }, + { + input: []byte{0x33, 0x2e, 0x34}, + output: [][]byte{[]byte{0x33, 0x2e, 0x34}}, + }, + { + input: []byte{0x63, 0x2e, 0x64}, + output: [][]byte{[]byte{0x63, 0x2e, 0x64}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0x74, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0x74, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0x54, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0}, []byte{0x54, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xe2, 0x80, 0x98, 0x28, 0x74, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xe2, 0x80, 0x98, 0x28, 0x74, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xe2, 0x80, 0x98, 0x28, 0x54, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0}, []byte{0xe2, 0x80, 0x98, 0x28, 0x54, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xcc, 0x88, 0x74, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xcc, 0x88, 0x74, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xcc, 0x88, 0x54, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xc2, 0xa0, 0xcc, 0x88}, []byte{0x54, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xcc, 0x88, 0x54, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xe2, 0x80, 0x99, 0xcc, 0x88}, []byte{0x54, 0x68, 0x65}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xa, 0xcc, 0x88, 0x54, 0x68, 0x65}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0x29, 0xa}, []byte{0xcc, 0x88, 0x54, 0x68, 0x65}}, + }, + { + input: []byte{0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x2e, 0x20, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65}, + output: [][]byte{[]byte{0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x2e, 0x20, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65}}, + }, + { + input: []byte{0xe5, 0xad, 0x97, 0x2e, 0xe5, 0xad, 0x97}, + output: [][]byte{[]byte{0xe5, 0xad, 0x97, 0x2e}, []byte{0xe5, 0xad, 0x97}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0xe5, 0xae, 0x83}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e}, []byte{0xe5, 0xae, 0x83}}, + }, + { + input: []byte{0x65, 0x74, 0x63, 0x2e, 0xe3, 0x80, 0x82}, + output: [][]byte{[]byte{0x65, 0x74, 0x63, 0x2e, 0xe3, 0x80, 0x82}}, + }, + { + input: []byte{0xe5, 0xad, 0x97, 0xe3, 0x80, 0x82, 0xe5, 0xae, 0x83}, + output: [][]byte{[]byte{0xe5, 0xad, 0x97, 0xe3, 0x80, 0x82}, []byte{0xe5, 0xae, 0x83}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x22, 0xe2, 0x81, 0xa0, 0x47, 0xe2, 0x81, 0xa0, 0x6f, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x22, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x48, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x69, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x22, 0xe2, 0x81, 0xa0, 0x47, 0xe2, 0x81, 0xa0, 0x6f, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x22, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0}, []byte{0x28, 0xe2, 0x81, 0xa0, 0x48, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x69, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x9c, 0xe2, 0x81, 0xa0, 0x47, 0xe2, 0x81, 0xa0, 0x6f, 0xe2, 0x81, 0xa0, 0x3f, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x9d, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x48, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x69, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x9c, 0xe2, 0x81, 0xa0, 0x47, 0xe2, 0x81, 0xa0, 0x6f, 0xe2, 0x81, 0xa0, 0x3f, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x9d, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0}, []byte{0x28, 0xe2, 0x81, 0xa0, 0x48, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x69, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x55, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x53, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x41, 0xe2, 0x81, 0xa0, 0xcc, 0x80, 0x2e, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x69, 0xe2, 0x81, 0xa0, 0x73, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x55, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x53, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x41, 0xe2, 0x81, 0xa0, 0xcc, 0x80, 0x2e, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x69, 0xe2, 0x81, 0xa0, 0x73, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x55, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x53, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x41, 0xe2, 0x81, 0xa0, 0xcc, 0x80, 0x3f, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x48, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x55, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x53, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x41, 0xe2, 0x81, 0xa0, 0xcc, 0x80, 0x3f, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0}, []byte{0x48, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x55, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x53, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x41, 0xe2, 0x81, 0xa0, 0xcc, 0x80, 0x2e, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x55, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x53, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x41, 0xe2, 0x81, 0xa0, 0xcc, 0x80, 0x2e, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x33, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x34, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x33, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x34, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0}, []byte{0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x98, 0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x98, 0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x98, 0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0}, []byte{0xe2, 0x80, 0x98, 0xe2, 0x81, 0xa0, 0x28, 0xe2, 0x81, 0xa0, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xc2, 0xa0, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xe2, 0x80, 0x99, 0xe2, 0x81, 0xa0, 0xcc, 0x88}, []byte{0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xa, 0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xe2, 0x81, 0xa0, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x29, 0xe2, 0x81, 0xa0, 0xa}, []byte{0xe2, 0x81, 0xa0, 0xcc, 0x88, 0xe2, 0x81, 0xa0, 0x54, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x72, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x73, 0xe2, 0x81, 0xa0, 0x70, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x6c, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x72, 0xe2, 0x81, 0xa0, 0x73, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x72, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x68, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x72, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x73, 0xe2, 0x81, 0xa0, 0x70, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x6c, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x64, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x72, 0xe2, 0x81, 0xa0, 0x73, 0xe2, 0x81, 0xa0, 0x20, 0xe2, 0x81, 0xa0, 0x61, 0xe2, 0x81, 0xa0, 0x72, 0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0xe5, 0xad, 0x97, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0xe5, 0xad, 0x97, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0xe5, 0xad, 0x97, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0}, []byte{0xe5, 0xad, 0x97, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0xe5, 0xae, 0x83, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0}, []byte{0xe5, 0xae, 0x83, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0x82, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0x65, 0xe2, 0x81, 0xa0, 0x74, 0xe2, 0x81, 0xa0, 0x63, 0xe2, 0x81, 0xa0, 0x2e, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0x82, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xe2, 0x81, 0xa0, 0xe5, 0xad, 0x97, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0x82, 0xe2, 0x81, 0xa0, 0xe5, 0xae, 0x83, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}, + output: [][]byte{[]byte{0xe2, 0x81, 0xa0, 0xe5, 0xad, 0x97, 0xe2, 0x81, 0xa0, 0xe3, 0x80, 0x82, 0xe2, 0x81, 0xa0}, []byte{0xe5, 0xae, 0x83, 0xe2, 0x81, 0xa0, 0xe2, 0x81, 0xa0}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa7, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa8}, + output: [][]byte{[]byte{0xf0, 0x9f, 0x87, 0xa6, 0xf0, 0x9f, 0x87, 0xa7, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x87, 0xa8}}, + }, + { + input: []byte{0x20, 0xe2, 0x80, 0x8d, 0xd9, 0x86}, + output: [][]byte{[]byte{0x20, 0xe2, 0x80, 0x8d, 0xd9, 0x86}}, + }, + { + input: []byte{0xd9, 0x86, 0xe2, 0x80, 0x8d, 0x20}, + output: [][]byte{[]byte{0xd9, 0x86, 0xe2, 0x80, 0x8d, 0x20}}, + }, +} diff --git a/Godeps/_workspace/src/github.com/cznic/b/AUTHORS b/Godeps/_workspace/src/github.com/cznic/b/AUTHORS new file mode 100644 index 00000000..0078f5f5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/AUTHORS @@ -0,0 +1,11 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/b/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/b/CONTRIBUTORS new file mode 100644 index 00000000..094c323e --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/CONTRIBUTORS @@ -0,0 +1,11 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Brian Fallik +Dan Kortschak +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/b/LICENSE b/Godeps/_workspace/src/github.com/cznic/b/LICENSE new file mode 100644 index 00000000..54c6e908 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The b Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/b/Makefile b/Godeps/_workspace/src/github.com/cznic/b/Makefile new file mode 100644 index 00000000..b02c86db --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/Makefile @@ -0,0 +1,53 @@ +# Copyright 2014 The b Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all todo clean cover generic mem nuke cpu + +testbin=b.test + +all: editor + go build + go vet + golint . + go install + make todo + +editor: + gofmt -l -s -w . + go test -i + go test + +clean: + @go clean + rm -f *~ *.out $(testbin) + +cover: + t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t + +cpu: + go test -c + ./$(testbin) -test.cpuprofile cpu.out + go tool pprof --lines $(testbin) cpu.out + +generic: + @# writes to stdout a version where the type of key is KEY and the type + @# of value is VALUE. + @# + @# Intended use is to replace all textual occurrences of KEY or VALUE in + @# the output with your desired types. + @sed -e 's|interface{}[^{]*/\*K\*/|KEY|g' -e 's|interface{}[^{]*/\*V\*/|VALUE|g' btree.go + +mem: + go test -c + ./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1 + go tool pprof --lines --web --alloc_space $(testbin) mem.out + +nuke: clean + rm -f *.test *.out + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true + @grep -n TODO *.go || true + @grep -n BUG *.go || true + @grep -n println *.go || true diff --git a/Godeps/_workspace/src/github.com/cznic/b/README.md b/Godeps/_workspace/src/github.com/cznic/b/README.md new file mode 100644 index 00000000..5a2d8030 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/README.md @@ -0,0 +1,10 @@ +b += + +Package b implements a B+tree. + +Installation: + + $ go get github.com/cznic/b + +Documentation: [godoc.org/github.com/cznic/b](http://godoc.org/github.com/cznic/b) diff --git a/Godeps/_workspace/src/github.com/cznic/b/all_test.go b/Godeps/_workspace/src/github.com/cznic/b/all_test.go new file mode 100644 index 00000000..38c28709 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/all_test.go @@ -0,0 +1,1300 @@ +// Copyright 2014 The b Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import ( + "bytes" + "fmt" + "io" + "math" + "path" + "runtime" + "runtime/debug" + "strings" + "testing" + + "github.com/cznic/mathutil" + "github.com/cznic/strutil" +) + +var caller = func(s string, va ...interface{}) { + _, fn, fl, _ := runtime.Caller(2) + fmt.Printf("%s:%d: ", path.Base(fn), fl) + fmt.Printf(s, va...) + fmt.Println() +} + +func dbg(s string, va ...interface{}) { + if s == "" { + s = strings.Repeat("%v ", len(va)) + } + _, fn, fl, _ := runtime.Caller(1) + fmt.Printf("%s:%d: ", path.Base(fn), fl) + fmt.Printf(s, va...) + fmt.Println() +} + +func TODO(...interface{}) string { + _, fn, fl, _ := runtime.Caller(1) + return fmt.Sprintf("TODO: %s:%d:\n", path.Base(fn), fl) +} + +func use(...interface{}) {} + +// ============================================================================ + +func isNil(p interface{}) bool { + switch x := p.(type) { + case *x: + if x == nil { + return true + } + case *d: + if x == nil { + return true + } + } + return false +} + +func (t *Tree) dump() string { + var buf bytes.Buffer + f := strutil.IndentFormatter(&buf, "\t") + + num := map[interface{}]int{} + visited := map[interface{}]bool{} + + handle := func(p interface{}) int { + if isNil(p) { + return 0 + } + + if n, ok := num[p]; ok { + return n + } + + n := len(num) + 1 + num[p] = n + return n + } + + var pagedump func(interface{}, string) + pagedump = func(p interface{}, pref string) { + if isNil(p) || visited[p] { + return + } + + visited[p] = true + switch x := p.(type) { + case *x: + h := handle(p) + n := 0 + for i, v := range x.x { + if v.ch != nil || v.k != nil { + n = i + 1 + } + } + f.Format("%sX#%d(%p) n %d:%d {", pref, h, x, x.c, n) + a := []interface{}{} + for i, v := range x.x[:n] { + a = append(a, v.ch) + if i != 0 { + f.Format(" ") + } + f.Format("(C#%d K %v)", handle(v.ch), v.k) + } + f.Format("}\n") + for _, p := range a { + pagedump(p, pref+". ") + } + case *d: + h := handle(p) + n := 0 + for i, v := range x.d { + if v.k != nil || v.v != nil { + n = i + 1 + } + } + f.Format("%sD#%d(%p) P#%d N#%d n %d:%d {", pref, h, x, handle(x.p), handle(x.n), x.c, n) + for i, v := range x.d[:n] { + if i != 0 { + f.Format(" ") + } + f.Format("%v:%v", v.k, v.v) + } + f.Format("}\n") + } + } + + pagedump(t.r, "") + s := buf.String() + if s != "" { + s = s[:len(s)-1] + } + return s +} + +func rng() *mathutil.FC32 { + x, err := mathutil.NewFC32(math.MinInt32/4, math.MaxInt32/4, false) + if err != nil { + panic(err) + } + + return x +} + +func cmp(a, b interface{}) int { + return a.(int) - b.(int) +} + +func TestGet0(t *testing.T) { + r := TreeNew(cmp) + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + _, ok := r.Get(42) + if ok { + t.Fatal(ok) + } + +} + +func TestSetGet0(t *testing.T) { + r := TreeNew(cmp) + set := r.Set + set(42, 314) + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + v, ok := r.Get(42) + if !ok { + t.Fatal(ok) + } + + if g, e := v.(int), 314; g != e { + t.Fatal(g, e) + } + + set(42, 278) + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + v, ok = r.Get(42) + if !ok { + t.Fatal(ok) + } + + if g, e := v.(int), 278; g != e { + t.Fatal(g, e) + } + + set(420, 0.5) + if g, e := r.Len(), 2; g != e { + t.Fatal(g, e) + } + + v, ok = r.Get(42) + if !ok { + t.Fatal(ok) + } + + if g, e := v.(int), 278; g != e { + t.Fatal(g, e) + } + + v, ok = r.Get(420) + if !ok { + t.Fatal(ok) + } + + if g, e := v.(float64), 0.5; g != e { + t.Fatal(g, e) + } +} + +func TestSetGet1(t *testing.T) { + const N = 40000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x333333, 0xcccccc, 0x314159} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + for i := range a { + a[i] = (i ^ x) << 1 + } + for i, k := range a { + set(k, k^x) + if g, e := r.Len(), i+1; g != e { + t.Fatal(i, g, e) + } + } + + for i, k := range a { + v, ok := r.Get(k) + if !ok { + t.Fatal(i, k, v, ok) + } + + if g, e := v.(int), k^x; g != e { + t.Fatal(i, g, e) + } + + k |= 1 + _, ok = r.Get(k) + if ok { + t.Fatal(i, k) + } + + } + + for _, k := range a { + r.Set(k, (k^x)+42) + } + + for i, k := range a { + v, ok := r.Get(k) + if !ok { + t.Fatal(i, k, v, ok) + } + + if g, e := v.(int), k^x+42; g != e { + t.Fatal(i, g, e) + } + + k |= 1 + _, ok = r.Get(k) + if ok { + t.Fatal(i, k) + } + } + } +} + +func TestPrealloc(*testing.T) { + const n = 2e6 + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + r := TreeNew(cmp) + for _, v := range a { + r.Set(v, 0) + } + r.Close() +} + +func BenchmarkSetSeq1e3(b *testing.B) { + benchmarkSetSeq(b, 1e3) +} + +func BenchmarkSetSeq1e4(b *testing.B) { + benchmarkSetSeq(b, 1e4) +} + +func BenchmarkSetSeq1e5(b *testing.B) { + benchmarkSetSeq(b, 1e5) +} + +func BenchmarkSetSeq1e6(b *testing.B) { + benchmarkSetSeq(b, 1e6) +} + +func benchmarkSetSeq(b *testing.B, n int) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + debug.FreeOSMemory() + b.StartTimer() + for j := 0; j < n; j++ { + r.Set(j, j) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func BenchmarkGetSeq1e3(b *testing.B) { + benchmarkGetSeq(b, 1e3) +} + +func BenchmarkGetSeq1e4(b *testing.B) { + benchmarkGetSeq(b, 1e4) +} + +func BenchmarkGetSeq1e5(b *testing.B) { + benchmarkGetSeq(b, 1e5) +} + +func BenchmarkGetSeq1e6(b *testing.B) { + benchmarkGetSeq(b, 1e6) +} + +func benchmarkGetSeq(b *testing.B, n int) { + r := TreeNew(cmp) + for i := 0; i < n; i++ { + r.Set(i, i) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < n; j++ { + r.Get(j) + } + } + b.StopTimer() + r.Close() +} + +func BenchmarkSetRnd1e3(b *testing.B) { + benchmarkSetRnd(b, 1e3) +} + +func BenchmarkSetRnd1e4(b *testing.B) { + benchmarkSetRnd(b, 1e4) +} + +func BenchmarkSetRnd1e5(b *testing.B) { + benchmarkSetRnd(b, 1e5) +} + +func BenchmarkSetRnd1e6(b *testing.B) { + benchmarkSetRnd(b, 1e6) +} + +func benchmarkSetRnd(b *testing.B, n int) { + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + debug.FreeOSMemory() + b.StartTimer() + for _, v := range a { + r.Set(v, 0) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func BenchmarkGetRnd1e3(b *testing.B) { + benchmarkGetRnd(b, 1e3) +} + +func BenchmarkGetRnd1e4(b *testing.B) { + benchmarkGetRnd(b, 1e4) +} + +func BenchmarkGetRnd1e5(b *testing.B) { + benchmarkGetRnd(b, 1e5) +} + +func BenchmarkGetRnd1e6(b *testing.B) { + benchmarkGetRnd(b, 1e6) +} + +func benchmarkGetRnd(b *testing.B, n int) { + r := TreeNew(cmp) + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + for _, v := range a { + r.Set(v, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, v := range a { + r.Get(v) + } + } + b.StopTimer() + r.Close() +} + +func TestSetGet2(t *testing.T) { + const N = 40000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x333333, 0xcccccc, 0x314159} { + rng := rng() + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + for i := range a { + a[i] = (rng.Next() ^ x) << 1 + } + for i, k := range a { + set(k, k^x) + if g, e := r.Len(), i+1; g != e { + t.Fatal(i, x, g, e) + } + } + + for i, k := range a { + v, ok := r.Get(k) + if !ok { + t.Fatal(i, k, v, ok) + } + + if g, e := v.(int), k^x; g != e { + t.Fatal(i, g, e) + } + + k |= 1 + _, ok = r.Get(k) + if ok { + t.Fatal(i, k) + } + } + + for _, k := range a { + r.Set(k, (k^x)+42) + } + + for i, k := range a { + v, ok := r.Get(k) + if !ok { + t.Fatal(i, k, v, ok) + } + + if g, e := v.(int), k^x+42; g != e { + t.Fatal(i, g, e) + } + + k |= 1 + _, ok = r.Get(k) + if ok { + t.Fatal(i, k) + } + } + } +} + +func TestSetGet3(t *testing.T) { + r := TreeNew(cmp) + set := r.Set + var i int + for i = 0; ; i++ { + set(i, -i) + if _, ok := r.r.(*x); ok { + break + } + } + for j := 0; j <= i; j++ { + set(j, j) + } + + for j := 0; j <= i; j++ { + v, ok := r.Get(j) + if !ok { + t.Fatal(j) + } + + if g, e := v.(int), j; g != e { + t.Fatal(g, e) + } + } +} + +func TestDelete0(t *testing.T) { + r := TreeNew(cmp) + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + r.Set(0, 0) + if ok := r.Delete(1); ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + r.Set(0, 0) + r.Set(1, 1) + if ok := r.Delete(1); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(1); ok { + t.Fatal(ok) + } + + if ok := r.Delete(0); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + r.Set(0, 0) + r.Set(1, 1) + if ok := r.Delete(0); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + if ok := r.Delete(1); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(1); ok { + t.Fatal(ok) + } +} + +func TestDelete1(t *testing.T) { + const N = 130000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x333333, 0xcccccc, 0x314159} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + for i := range a { + a[i] = (i ^ x) << 1 + } + for _, k := range a { + set(k, 0) + } + + for i, k := range a { + ok := r.Delete(k) + if !ok { + t.Fatal(i, x, k) + } + + if g, e := r.Len(), N-i-1; g != e { + t.Fatal(i, g, e) + } + } + } +} + +func BenchmarkDelSeq1e3(b *testing.B) { + benchmarkDelSeq(b, 1e3) +} + +func BenchmarkDelSeq1e4(b *testing.B) { + benchmarkDelSeq(b, 1e4) +} + +func BenchmarkDelSeq1e5(b *testing.B) { + benchmarkDelSeq(b, 1e5) +} + +func BenchmarkDelSeq1e6(b *testing.B) { + benchmarkDelSeq(b, 1e6) +} + +func benchmarkDelSeq(b *testing.B, n int) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + for i := 0; i < n; i++ { + r.Set(i, i) + } + debug.FreeOSMemory() + b.StartTimer() + for j := 0; j < n; j++ { + r.Delete(j) + } + } + b.StopTimer() +} + +func BenchmarkDelRnd1e3(b *testing.B) { + benchmarkDelRnd(b, 1e3) +} + +func BenchmarkDelRnd1e4(b *testing.B) { + benchmarkDelRnd(b, 1e4) +} + +func BenchmarkDelRnd1e5(b *testing.B) { + benchmarkDelRnd(b, 1e5) +} + +func BenchmarkDelRnd1e6(b *testing.B) { + benchmarkDelRnd(b, 1e6) +} + +func benchmarkDelRnd(b *testing.B, n int) { + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + for _, v := range a { + r.Set(v, 0) + } + debug.FreeOSMemory() + b.StartTimer() + for _, v := range a { + r.Delete(v) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func TestDelete2(t *testing.T) { + const N = 100000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x333333, 0xcccccc, 0x314159} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + rng := rng() + for i := range a { + a[i] = (rng.Next() ^ x) << 1 + } + for _, k := range a { + set(k, 0) + } + + for i, k := range a { + ok := r.Delete(k) + if !ok { + t.Fatal(i, x, k) + } + + if g, e := r.Len(), N-i-1; g != e { + t.Fatal(i, g, e) + } + } + } +} + +func TestEnumeratorNext(t *testing.T) { + // seeking within 3 keys: 10, 20, 30 + table := []struct { + k int + hit bool + keys []int + }{ + {5, false, []int{10, 20, 30}}, + {10, true, []int{10, 20, 30}}, + {15, false, []int{20, 30}}, + {20, true, []int{20, 30}}, + {25, false, []int{30}}, + {30, true, []int{30}}, + {35, false, []int{}}, + } + + for i, test := range table { + up := test.keys + r := TreeNew(cmp) + + r.Set(10, 100) + r.Set(20, 200) + r.Set(30, 300) + + for verChange := 0; verChange < 16; verChange++ { + en, hit := r.Seek(test.k) + + if g, e := hit, test.hit; g != e { + t.Fatal(i, g, e) + } + + j := 0 + for { + if verChange&(1<= len(up) { + t.Fatal(i, j, verChange) + } + + if g, e := k.(int), up[j]; g != e { + t.Fatal(i, j, verChange, g, e) + } + + if g, e := v.(int), 10*up[j]; g != e { + t.Fatal(i, g, e) + } + + j++ + + } + + if g, e := j, len(up); g != e { + t.Fatal(i, j, g, e) + } + } + + } +} + +func TestEnumeratorPrev(t *testing.T) { + // seeking within 3 keys: 10, 20, 30 + table := []struct { + k int + hit bool + keys []int + }{ + {5, false, []int{10}}, + {10, true, []int{10}}, + {15, false, []int{20, 10}}, + {20, true, []int{20, 10}}, + {25, false, []int{30, 20, 10}}, + {30, true, []int{30, 20, 10}}, + {35, false, []int{}}, + } + + for i, test := range table { + dn := test.keys + r := TreeNew(cmp) + + r.Set(10, 100) + r.Set(20, 200) + r.Set(30, 300) + + for verChange := 0; verChange < 16; verChange++ { + en, hit := r.Seek(test.k) + + if g, e := hit, test.hit; g != e { + t.Fatal(i, g, e) + } + + j := 0 + for { + if verChange&(1<= len(dn) { + t.Fatal(i, j, verChange) + } + + if g, e := k.(int), dn[j]; g != e { + t.Fatal(i, j, verChange, g, e) + } + + if g, e := v.(int), 10*dn[j]; g != e { + t.Fatal(i, g, e) + } + + j++ + + } + + if g, e := j, len(dn); g != e { + t.Fatal(i, j, g, e) + } + } + + } +} + +func BenchmarkSeekSeq1e3(b *testing.B) { + benchmarkSeekSeq(b, 1e3) +} + +func BenchmarkSeekSeq1e4(b *testing.B) { + benchmarkSeekSeq(b, 1e4) +} + +func BenchmarkSeekSeq1e5(b *testing.B) { + benchmarkSeekSeq(b, 1e5) +} + +func BenchmarkSeekSeq1e6(b *testing.B) { + benchmarkSeekSeq(b, 1e6) +} + +func benchmarkSeekSeq(b *testing.B, n int) { + for i := 0; i < b.N; i++ { + b.StopTimer() + t := TreeNew(cmp) + for j := 0; j < n; j++ { + t.Set(j, 0) + } + debug.FreeOSMemory() + b.StartTimer() + for j := 0; j < n; j++ { + e, _ := t.Seek(j) + e.Close() + } + b.StopTimer() + t.Close() + } + b.StopTimer() +} + +func BenchmarkSeekRnd1e3(b *testing.B) { + benchmarkSeekRnd(b, 1e3) +} + +func BenchmarkSeekRnd1e4(b *testing.B) { + benchmarkSeekRnd(b, 1e4) +} + +func BenchmarkSeekRnd1e5(b *testing.B) { + benchmarkSeekRnd(b, 1e5) +} + +func BenchmarkSeekRnd1e6(b *testing.B) { + benchmarkSeekRnd(b, 1e6) +} + +func benchmarkSeekRnd(b *testing.B, n int) { + r := TreeNew(cmp) + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + for _, v := range a { + r.Set(v, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, v := range a { + e, _ := r.Seek(v) + e.Close() + } + } + b.StopTimer() + r.Close() +} + +func BenchmarkNext1e3(b *testing.B) { + benchmarkNext(b, 1e3) +} + +func BenchmarkNext1e4(b *testing.B) { + benchmarkNext(b, 1e4) +} + +func BenchmarkNext1e5(b *testing.B) { + benchmarkNext(b, 1e5) +} + +func BenchmarkNext1e6(b *testing.B) { + benchmarkNext(b, 1e6) +} + +func benchmarkNext(b *testing.B, n int) { + t := TreeNew(cmp) + for i := 0; i < n; i++ { + t.Set(i, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + en, err := t.SeekFirst() + if err != nil { + b.Fatal(err) + } + + m := 0 + for { + if _, _, err = en.Next(); err != nil { + break + } + m++ + } + if m != n { + b.Fatal(m) + } + } + b.StopTimer() + t.Close() +} + +func BenchmarkPrev1e3(b *testing.B) { + benchmarkPrev(b, 1e3) +} + +func BenchmarkPrev1e4(b *testing.B) { + benchmarkPrev(b, 1e4) +} + +func BenchmarkPrev1e5(b *testing.B) { + benchmarkPrev(b, 1e5) +} + +func BenchmarkPrev1e6(b *testing.B) { + benchmarkPrev(b, 1e6) +} + +func benchmarkPrev(b *testing.B, n int) { + t := TreeNew(cmp) + for i := 0; i < n; i++ { + t.Set(i, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + en, err := t.SeekLast() + if err != nil { + b.Fatal(err) + } + + m := 0 + for { + if _, _, err = en.Prev(); err != nil { + break + } + m++ + } + if m != n { + b.Fatal(m) + } + } +} + +func TestSeekFirst0(t *testing.T) { + b := TreeNew(cmp) + _, err := b.SeekFirst() + if g, e := err, io.EOF; g != e { + t.Fatal(g, e) + } +} + +func TestSeekFirst1(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + en, err := b.SeekFirst() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekFirst2(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + b.Set(2, 20) + en, err := b.SeekFirst() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekFirst3(t *testing.T) { + b := TreeNew(cmp) + b.Set(2, 20) + b.Set(3, 30) + b.Set(1, 10) + en, err := b.SeekFirst() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if k != 3 || v != 30 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekLast0(t *testing.T) { + b := TreeNew(cmp) + _, err := b.SeekLast() + if g, e := err, io.EOF; g != e { + t.Fatal(g, e) + } +} + +func TestSeekLast1(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + en, err := b.SeekLast() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Prev() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekLast2(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + b.Set(2, 20) + en, err := b.SeekLast() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Prev() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekLast3(t *testing.T) { + b := TreeNew(cmp) + b.Set(2, 20) + b.Set(3, 30) + b.Set(1, 10) + en, err := b.SeekLast() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Prev() + if k != 3 || v != 30 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestPut(t *testing.T) { + tab := []struct { + pre []int // even index: K, odd index: V + newK int // Put(newK, ... + oldV int // Put()->oldV + exists bool // upd(exists) + write bool // upd()->write + post []int // even index: K, odd index: V + }{ + // 0 + { + []int{}, + 1, 0, false, false, + []int{}, + }, + { + []int{}, + 1, 0, false, true, + []int{1, -1}, + }, + { + []int{1, 10}, + 0, 0, false, false, + []int{1, 10}, + }, + { + []int{1, 10}, + 0, 0, false, true, + []int{0, -1, 1, 10}, + }, + { + []int{1, 10}, + 1, 10, true, false, + []int{1, 10}, + }, + + // 5 + { + []int{1, 10}, + 1, 10, true, true, + []int{1, -1}, + }, + { + []int{1, 10}, + 2, 0, false, false, + []int{1, 10}, + }, + { + []int{1, 10}, + 2, 0, false, true, + []int{1, 10, 2, -1}, + }, + } + + for iTest, test := range tab { + tr := TreeNew(cmp) + for i := 0; i < len(test.pre); i += 2 { + k, v := test.pre[i], test.pre[i+1] + tr.Set(k, v) + } + + oldV, written := tr.Put(test.newK, func(old interface{}, exists bool) (newV interface{}, write bool) { + if g, e := exists, test.exists; g != e { + t.Fatal(iTest, g, e) + } + + if exists { + if g, e := old.(int), test.oldV; g != e { + t.Fatal(iTest, g, e) + } + } + return -1, test.write + }) + if test.exists { + if g, e := oldV.(int), test.oldV; g != e { + t.Fatal(iTest, g, e) + } + } + + if g, e := written, test.write; g != e { + t.Fatal(iTest, g, e) + } + + n := len(test.post) + en, err := tr.SeekFirst() + if err != nil { + if n == 0 && err == io.EOF { + continue + } + + t.Fatal(iTest, err) + } + + for i := 0; i < len(test.post); i += 2 { + k, v, err := en.Next() + if err != nil { + t.Fatal(iTest, err) + } + + if g, e := k.(int), test.post[i]; g != e { + t.Fatal(iTest, g, e) + } + + if g, e := v.(int), test.post[i+1]; g != e { + t.Fatal(iTest, g, e) + } + } + + _, _, err = en.Next() + if g, e := err, io.EOF; g != e { + t.Fatal(iTest, g, e) + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/b/btree.go b/Godeps/_workspace/src/github.com/cznic/b/btree.go new file mode 100644 index 00000000..de104339 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/btree.go @@ -0,0 +1,981 @@ +// Copyright 2014 The b Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package b implements a B+tree. +// +// Changelog +// +// 2014-06-26: Lower GC presure by recycling things. +// +// 2014-04-18: Added new method Put. +// +// Generic types +// +// Keys and their associated values are interface{} typed, similar to all of +// the containers in the standard library. +// +// Semiautomatic production of a type specific variant of this package is +// supported via +// +// $ make generic +// +// This command will write to stdout a version of the btree.go file where +// every key type occurrence is replaced by the word 'key' (written in all +// CAPS) and every value type occurrence is replaced by the word 'value' +// (written in all CAPS). Then you have to replace these tokens with your +// desired type(s), using any technique you're comfortable with. +// +// This is how, for example, 'example/int.go' was created: +// +// $ mkdir example +// $ +// $ # Note: the command below must be actually written using the words +// $ # 'key' and 'value' in all CAPS. The proper form is avoided in this +// $ # documentation to not confuse any text replacement mechanism. +// $ +// $ make generic | sed -e 's/key/int/g' -e 's/value/int/g' > example/int.go +// +// No other changes to int.go are necessary, it compiles just fine. +// +// Running the benchmarks for 1000 keys on a machine with Intel i5-4670 CPU @ +// 3.4GHz, Go release 1.3. +// +// $ go test -bench 1e3 example/all_test.go example/int.go +// PASS +// BenchmarkSetSeq1e3 10000 146740 ns/op +// BenchmarkGetSeq1e3 10000 108261 ns/op +// BenchmarkSetRnd1e3 10000 254359 ns/op +// BenchmarkGetRnd1e3 10000 134621 ns/op +// BenchmarkDelRnd1e3 10000 211864 ns/op +// BenchmarkSeekSeq1e3 10000 148628 ns/op +// BenchmarkSeekRnd1e3 10000 215166 ns/op +// BenchmarkNext1e3 200000 9211 ns/op +// BenchmarkPrev1e3 200000 8843 ns/op +// ok command-line-arguments 25.071s +// $ +package b + +import ( + "fmt" + "io" + "sync" +) + +const ( + kx = 32 //TODO benchmark tune this number if using custom key/value type(s). + kd = 32 //TODO benchmark tune this number if using custom key/value type(s). +) + +func init() { + if kd < 1 { + panic(fmt.Errorf("kd %d: out of range", kd)) + } + + if kx < 2 { + panic(fmt.Errorf("kx %d: out of range", kx)) + } +} + +var ( + btDPool = sync.Pool{New: func() interface{} { return &d{} }} + btEPool = btEpool{sync.Pool{New: func() interface{} { return &Enumerator{} }}} + btTPool = btTpool{sync.Pool{New: func() interface{} { return &Tree{} }}} + btXPool = sync.Pool{New: func() interface{} { return &x{} }} +) + +type btTpool struct{ sync.Pool } + +func (p *btTpool) get(cmp Cmp) *Tree { + x := p.Get().(*Tree) + x.cmp = cmp + return x +} + +type btEpool struct{ sync.Pool } + +func (p *btEpool) get(err error, hit bool, i int, k interface{} /*K*/, q *d, t *Tree, ver int64) *Enumerator { + x := p.Get().(*Enumerator) + x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver + return x +} + +type ( + // Cmp compares a and b. Return value is: + // + // < 0 if a < b + // 0 if a == b + // > 0 if a > b + // + Cmp func(a, b interface{} /*K*/) int + + d struct { // data page + c int + d [2*kd + 1]de + n *d + p *d + } + + de struct { // d element + k interface{} /*K*/ + v interface{} /*V*/ + } + + // Enumerator captures the state of enumerating a tree. It is returned + // from the Seek* methods. The enumerator is aware of any mutations + // made to the tree in the process of enumerating it and automatically + // resumes the enumeration at the proper key, if possible. + // + // However, once an Enumerator returns io.EOF to signal "no more + // items", it does no more attempt to "resync" on tree mutation(s). In + // other words, io.EOF from an Enumaretor is "sticky" (idempotent). + Enumerator struct { + err error + hit bool + i int + k interface{} /*K*/ + q *d + t *Tree + ver int64 + } + + // Tree is a B+tree. + Tree struct { + c int + cmp Cmp + first *d + last *d + r interface{} + ver int64 + } + + xe struct { // x element + ch interface{} + k interface{} /*K*/ + } + + x struct { // index page + c int + x [2*kx + 2]xe + } +) + +var ( // R/O zero values + zd d + zde de + ze Enumerator + zk interface{} /*K*/ + zt Tree + zx x + zxe xe +) + +func clr(q interface{}) { + switch x := q.(type) { + case *x: + for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn + clr(x.x[i].ch) + } + *x = zx + btXPool.Put(x) + case *d: + *x = zd + btDPool.Put(x) + } +} + +// -------------------------------------------------------------------------- x + +func newX(ch0 interface{}) *x { + r := btXPool.Get().(*x) + r.x[0].ch = ch0 + return r +} + +func (q *x) extract(i int) { + q.c-- + if i < q.c { + copy(q.x[i:], q.x[i+1:q.c+1]) + q.x[q.c].ch = q.x[q.c+1].ch + q.x[q.c].k = zk // GC + q.x[q.c+1] = zxe // GC + } +} + +func (q *x) insert(i int, k interface{} /*K*/, ch interface{}) *x { + c := q.c + if i < c { + q.x[c+1].ch = q.x[c].ch + copy(q.x[i+2:], q.x[i+1:c]) + q.x[i+1].k = q.x[i].k + } + c++ + q.c = c + q.x[i].k = k + q.x[i+1].ch = ch + return q +} + +func (q *x) siblings(i int) (l, r *d) { + if i >= 0 { + if i > 0 { + l = q.x[i-1].ch.(*d) + } + if i < q.c { + r = q.x[i+1].ch.(*d) + } + } + return +} + +// -------------------------------------------------------------------------- d + +func (l *d) mvL(r *d, c int) { + copy(l.d[l.c:], r.d[:c]) + copy(r.d[:], r.d[c:r.c]) + l.c += c + r.c -= c +} + +func (l *d) mvR(r *d, c int) { + copy(r.d[c:], r.d[:r.c]) + copy(r.d[:c], l.d[l.c-c:]) + r.c += c + l.c -= c +} + +// ----------------------------------------------------------------------- Tree + +// TreeNew returns a newly created, empty Tree. The compare function is used +// for key collation. +func TreeNew(cmp Cmp) *Tree { + return btTPool.get(cmp) +} + +// Clear removes all K/V pairs from the tree. +func (t *Tree) Clear() { + if t.r == nil { + return + } + + clr(t.r) + t.c, t.first, t.last, t.r = 0, nil, nil, nil + t.ver++ +} + +// Close performs Clear and recycles t to a pool for possible later reuse. No +// references to t should exist or such references must not be used afterwards. +func (t *Tree) Close() { + t.Clear() + *t = zt + btTPool.Put(t) +} + +func (t *Tree) cat(p *x, q, r *d, pi int) { + t.ver++ + q.mvL(r, r.c) + if r.n != nil { + r.n.p = q + } else { + t.last = q + } + q.n = r.n + *r = zd + btDPool.Put(r) + if p.c > 1 { + p.extract(pi) + p.x[pi].ch = q + return + } + + switch x := t.r.(type) { + case *x: + *x = zx + btXPool.Put(x) + case *d: + *x = zd + btDPool.Put(x) + } + t.r = q +} + +func (t *Tree) catX(p, q, r *x, pi int) { + t.ver++ + q.x[q.c].k = p.x[pi].k + copy(q.x[q.c+1:], r.x[:r.c]) + q.c += r.c + 1 + q.x[q.c].ch = r.x[r.c].ch + *r = zx + btXPool.Put(r) + if p.c > 1 { + p.c-- + pc := p.c + if pi < pc { + p.x[pi].k = p.x[pi+1].k + copy(p.x[pi+1:], p.x[pi+2:pc+1]) + p.x[pc].ch = p.x[pc+1].ch + p.x[pc].k = zk // GC + p.x[pc+1].ch = nil // GC + } + return + } + + switch x := t.r.(type) { + case *x: + *x = zx + btXPool.Put(x) + case *d: + *x = zd + btDPool.Put(x) + } + t.r = q +} + +// Delete removes the k's KV pair, if it exists, in which case Delete returns +// true. +func (t *Tree) Delete(k interface{} /*K*/) (ok bool) { + pi := -1 + var p *x + q := t.r + if q == nil { + return false + } + + for { + var i int + i, ok = t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + if x.c < kx && q != t.r { + x, i = t.underflowX(p, x, pi, i) + } + pi = i + 1 + p = x + q = x.x[pi].ch + ok = false + continue + case *d: + t.extract(x, i) + if x.c >= kd { + return true + } + + if q != t.r { + t.underflow(p, x, pi) + } else if t.c == 0 { + t.Clear() + } + return true + } + } + + switch x := q.(type) { + case *x: + if x.c < kx && q != t.r { + x, i = t.underflowX(p, x, pi, i) + } + pi = i + p = x + q = x.x[i].ch + case *d: + return false + } + } +} + +func (t *Tree) extract(q *d, i int) { // (r interface{} /*V*/) { + t.ver++ + //r = q.d[i].v // prepared for Extract + q.c-- + if i < q.c { + copy(q.d[i:], q.d[i+1:q.c+1]) + } + q.d[q.c] = zde // GC + t.c-- + return +} + +func (t *Tree) find(q interface{}, k interface{} /*K*/) (i int, ok bool) { + var mk interface{} /*K*/ + l := 0 + switch x := q.(type) { + case *x: + h := x.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = x.x[m].k + switch cmp := t.cmp(k, mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + case *d: + h := x.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = x.d[m].k + switch cmp := t.cmp(k, mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + } + return l, false +} + +// First returns the first item of the tree in the key collating order, or +// (zero-value, zero-value) if the tree is empty. +func (t *Tree) First() (k interface{} /*K*/, v interface{} /*V*/) { + if q := t.first; q != nil { + q := &q.d[0] + k, v = q.k, q.v + } + return +} + +// Get returns the value associated with k and true if it exists. Otherwise Get +// returns (zero-value, false). +func (t *Tree) Get(k interface{} /*K*/) (v interface{} /*V*/, ok bool) { + q := t.r + if q == nil { + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch x := q.(type) { + case *x: + q = x.x[i+1].ch + continue + case *d: + return x.d[i].v, true + } + } + switch x := q.(type) { + case *x: + q = x.x[i].ch + default: + return + } + } +} + +func (t *Tree) insert(q *d, i int, k interface{} /*K*/, v interface{} /*V*/) *d { + t.ver++ + c := q.c + if i < c { + copy(q.d[i+1:], q.d[i:c]) + } + c++ + q.c = c + q.d[i].k, q.d[i].v = k, v + t.c++ + return q +} + +// Last returns the last item of the tree in the key collating order, or +// (zero-value, zero-value) if the tree is empty. +func (t *Tree) Last() (k interface{} /*K*/, v interface{} /*V*/) { + if q := t.last; q != nil { + q := &q.d[q.c-1] + k, v = q.k, q.v + } + return +} + +// Len returns the number of items in the tree. +func (t *Tree) Len() int { + return t.c +} + +func (t *Tree) overflow(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /*V*/) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c < 2*kd { + l.mvL(q, 1) + t.insert(q, i-1, k, v) + p.x[pi-1].k = q.d[0].k + return + } + + if r != nil && r.c < 2*kd { + if i < 2*kd { + q.mvR(r, 1) + t.insert(q, i, k, v) + p.x[pi].k = r.d[0].k + return + } + + t.insert(r, 0, k, v) + p.x[pi].k = k + return + } + + t.split(p, q, pi, i, k, v) +} + +// Seek returns an Enumerator positioned on a an item such that k >= item's +// key. ok reports if k == item.key The Enumerator's position is possibly +// after the last item in the tree. +func (t *Tree) Seek(k interface{} /*K*/) (e *Enumerator, ok bool) { + q := t.r + if q == nil { + e = btEPool.get(nil, false, 0, k, nil, t, t.ver) + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch x := q.(type) { + case *x: + q = x.x[i+1].ch + continue + case *d: + return btEPool.get(nil, ok, i, k, x, t, t.ver), true + } + } + + switch x := q.(type) { + case *x: + q = x.x[i].ch + case *d: + return btEPool.get(nil, ok, i, k, x, t, t.ver), false + } + } +} + +// SeekFirst returns an enumerator positioned on the first KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *Tree) SeekFirst() (e *Enumerator, err error) { + q := t.first + if q == nil { + return nil, io.EOF + } + + return btEPool.get(nil, true, 0, q.d[0].k, q, t, t.ver), nil +} + +// SeekLast returns an enumerator positioned on the last KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *Tree) SeekLast() (e *Enumerator, err error) { + q := t.last + if q == nil { + return nil, io.EOF + } + + return btEPool.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, t.ver), nil +} + +// Set sets the value associated with k. +func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) { + //dbg("--- PRE Set(%v, %v)\n%s", k, v, t.dump()) + //defer func() { + // dbg("--- POST\n%s\n====\n", t.dump()) + //}() + + pi := -1 + var p *x + q := t.r + if q == nil { + z := t.insert(btDPool.Get().(*d), 0, k, v) + t.r, t.first, t.last = z, z, z + return + } + + for { + i, ok := t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + 1 + p = x + q = x.x[i+1].ch + continue + case *d: + x.d[i].v = v + } + return + } + + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + p = x + q = x.x[i].ch + case *d: + switch { + case x.c < 2*kd: + t.insert(x, i, k, v) + default: + t.overflow(p, x, pi, i, k, v) + } + return + } + } +} + +// Put combines Get and Set in a more efficient way where the tree is walked +// only once. The upd(ater) receives (old-value, true) if a KV pair for k +// exists or (zero-value, false) otherwise. It can then return a (new-value, +// true) to create or overwrite the existing value in the KV pair, or +// (whatever, false) if it decides not to create or not to update the value of +// the KV pair. +// +// tree.Set(k, v) call conceptually equals calling +// +// tree.Put(k, func(interface{} /*K*/, bool){ return v, true }) +// +// modulo the differing return values. +func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists bool) (newV interface{} /*V*/, write bool)) (oldV interface{} /*V*/, written bool) { + pi := -1 + var p *x + q := t.r + var newV interface{} /*V*/ + if q == nil { + // new KV pair in empty tree + newV, written = upd(newV, false) + if !written { + return + } + + z := t.insert(btDPool.Get().(*d), 0, k, newV) + t.r, t.first, t.last = z, z, z + return + } + + for { + i, ok := t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + 1 + p = x + q = x.x[i+1].ch + continue + case *d: + oldV = x.d[i].v + newV, written = upd(oldV, true) + if !written { + return + } + + x.d[i].v = newV + } + return + } + + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + p = x + q = x.x[i].ch + case *d: // new KV pair + newV, written = upd(newV, false) + if !written { + return + } + + switch { + case x.c < 2*kd: + t.insert(x, i, k, newV) + default: + t.overflow(p, x, pi, i, k, newV) + } + return + } + } +} + +func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /*V*/) { + t.ver++ + r := btDPool.Get().(*d) + if q.n != nil { + r.n = q.n + r.n.p = r + } else { + t.last = r + } + q.n = r + r.p = q + + copy(r.d[:], q.d[kd:2*kd]) + for i := range q.d[kd:] { + q.d[kd+i] = zde + } + q.c = kd + r.c = kd + var done bool + if i > kd { + done = true + t.insert(r, i-kd, k, v) + } + if pi >= 0 { + p.insert(pi, r.d[0].k, r) + } else { + t.r = newX(q).insert(0, r.d[0].k, r) + } + if done { + return + } + + t.insert(q, i, k, v) +} + +func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) { + t.ver++ + r := btXPool.Get().(*x) + copy(r.x[:], q.x[kx+1:]) + q.c = kx + r.c = kx + if pi >= 0 { + p.insert(pi, q.x[kx].k, r) + q.x[kx].k = zk + for i := range q.x[kx+1:] { + q.x[kx+i+1] = zxe + } + + switch { + case i < kx: + return q, i + case i == kx: + return p, pi + default: // i > kx + return r, i - kx - 1 + } + } + + nr := newX(q).insert(0, q.x[kx].k, r) + t.r = nr + q.x[kx].k = zk + for i := range q.x[kx+1:] { + q.x[kx+i+1] = zxe + } + + switch { + case i < kx: + return q, i + case i == kx: + return nr, 0 + default: // i > kx + return r, i - kx - 1 + } +} + +func (t *Tree) underflow(p *x, q *d, pi int) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c+q.c >= 2*kd { + l.mvR(q, 1) + p.x[pi-1].k = q.d[0].k + return + } + + if r != nil && q.c+r.c >= 2*kd { + q.mvL(r, 1) + p.x[pi].k = r.d[0].k + r.d[r.c] = zde // GC + return + } + + if l != nil { + t.cat(p, l, q, pi-1) + return + } + + t.cat(p, q, r, pi) +} + +func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { + t.ver++ + var l, r *x + + if pi >= 0 { + if pi > 0 { + l = p.x[pi-1].ch.(*x) + } + if pi < p.c { + r = p.x[pi+1].ch.(*x) + } + } + + if l != nil && l.c > kx { + q.x[q.c+1].ch = q.x[q.c].ch + copy(q.x[1:], q.x[:q.c]) + q.x[0].ch = l.x[l.c].ch + q.x[0].k = p.x[pi-1].k + q.c++ + i++ + l.c-- + p.x[pi-1].k = l.x[l.c].k + return q, i + } + + if r != nil && r.c > kx { + q.x[q.c].k = p.x[pi].k + q.c++ + q.x[q.c].ch = r.x[0].ch + p.x[pi].k = r.x[0].k + copy(r.x[:], r.x[1:r.c]) + r.c-- + rc := r.c + r.x[rc].ch = r.x[rc+1].ch + r.x[rc].k = zk + r.x[rc+1].ch = nil + return q, i + } + + if l != nil { + i += l.c + 1 + t.catX(p, l, q, pi-1) + q = l + return q, i + } + + t.catX(p, q, r, pi) + return q, i +} + +// ----------------------------------------------------------------- Enumerator + +// Close recycles e to a pool for possible later reuse. No references to e +// should exist or such references must not be used afterwards. +func (e *Enumerator) Close() { + *e = ze + btEPool.Put(e) +} + +// Next returns the currently enumerated item, if it exists and moves to the +// next item in the key collation order. If there is no item to return, err == +// io.EOF is returned. +func (e *Enumerator) Next() (k interface{} /*K*/, v interface{} /*V*/, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.next(); err != nil { + return + } + } + + *e = *f + f.Close() + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.d[e.i] + k, v = i.k, i.v + e.k, e.hit = k, false + e.next() + return +} + +func (e *Enumerator) next() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i < e.q.c-1: + e.i++ + default: + if e.q, e.i = e.q.n, 0; e.q == nil { + e.err = io.EOF + } + } + return e.err +} + +// Prev returns the currently enumerated item, if it exists and moves to the +// previous item in the key collation order. If there is no item to return, err +// == io.EOF is returned. +func (e *Enumerator) Prev() (k interface{} /*K*/, v interface{} /*V*/, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.prev(); err != nil { + return + } + } + + *e = *f + f.Close() + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.d[e.i] + k, v = i.k, i.v + e.k, e.hit = k, false + e.prev() + return +} + +func (e *Enumerator) prev() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i > 0: + e.i-- + default: + if e.q = e.q.p; e.q == nil { + e.err = io.EOF + break + } + + e.i = e.q.c - 1 + } + return e.err +} diff --git a/Godeps/_workspace/src/github.com/cznic/b/example/Makefile b/Godeps/_workspace/src/github.com/cznic/b/example/Makefile new file mode 100644 index 00000000..6c0f1856 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/example/Makefile @@ -0,0 +1,35 @@ +# Copyright 2014 The b Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all todo clean cover mem + +testbin=b.test + +all: editor + go build + go vet + make todo + +editor: + go fmt + go test -i + go test + +mem: + go test -c + ./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1 + go tool pprof --lines --web --alloc_space $(testbin) mem.out + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true + @grep -n TODO *.go || true + @grep -n BUG *.go || true + @grep -n println *.go || true + +clean: + @go clean + rm -f *~ + +cover: + t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t diff --git a/Godeps/_workspace/src/github.com/cznic/b/example/all_test.go b/Godeps/_workspace/src/github.com/cznic/b/example/all_test.go new file mode 100644 index 00000000..cfc7848c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/example/all_test.go @@ -0,0 +1,1126 @@ +// Copyright 2014 The b Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import ( + "io" + "math" + "runtime/debug" + "testing" + + "github.com/cznic/fileutil" + "github.com/cznic/mathutil" +) + +func rng() *mathutil.FC32 { + x, err := mathutil.NewFC32(math.MinInt32/4, math.MaxInt32/4, false) + if err != nil { + panic(err) + } + + return x +} + +func cmp(a, b int) int { + return a - b +} + +func TestGet0(t *testing.T) { + r := TreeNew(cmp) + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + _, ok := r.Get(42) + if ok { + t.Fatal(ok) + } + +} + +func TestSetGet0(t *testing.T) { + r := TreeNew(cmp) + set := r.Set + set(42, 314) + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + v, ok := r.Get(42) + if !ok { + t.Fatal(ok) + } + + if g, e := v, 314; g != e { + t.Fatal(g, e) + } + + set(42, 278) + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + v, ok = r.Get(42) + if !ok { + t.Fatal(ok) + } + + if g, e := v, 278; g != e { + t.Fatal(g, e) + } + + set(420, 50) + if g, e := r.Len(), 2; g != e { + t.Fatal(g, e) + } + + v, ok = r.Get(42) + if !ok { + t.Fatal(ok) + } + + if g, e := v, 278; g != e { + t.Fatal(g, e) + } + + v, ok = r.Get(420) + if !ok { + t.Fatal(ok) + } + + if g, e := v, 50; g != e { + t.Fatal(g, e) + } +} + +func TestSetGet1(t *testing.T) { + const N = 90000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + for i := range a { + a[i] = (i ^ x) << 1 + } + for i, k := range a { + set(k, k^x) + if g, e := r.Len(), i+1; g != e { + t.Fatal(i, g, e) + } + } + + for i, k := range a { + v, ok := r.Get(k) + if !ok { + t.Fatal(i, k, v, ok) + } + + if g, e := v, k^x; g != e { + t.Fatal(i, g, e) + } + + k |= 1 + _, ok = r.Get(k) + if ok { + t.Fatal(i, k) + } + + } + } +} + +func BenchmarkSetSeq1e3(b *testing.B) { + benchmarkSetSeq(b, 1e3) +} + +func BenchmarkSetSeq1e4(b *testing.B) { + benchmarkSetSeq(b, 1e4) +} + +func BenchmarkSetSeq1e5(b *testing.B) { + benchmarkSetSeq(b, 1e5) +} + +func BenchmarkSetSeq1e6(b *testing.B) { + benchmarkSetSeq(b, 1e6) +} + +func benchmarkSetSeq(b *testing.B, n int) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + debug.FreeOSMemory() + b.StartTimer() + for j := 0; j < n; j++ { + r.Set(j, j) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func BenchmarkGetSeq1e3(b *testing.B) { + benchmarkGetSeq(b, 1e3) +} + +func BenchmarkGetSeq1e4(b *testing.B) { + benchmarkGetSeq(b, 1e4) +} + +func BenchmarkGetSeq1e5(b *testing.B) { + benchmarkGetSeq(b, 1e5) +} + +func BenchmarkGetSeq1e6(b *testing.B) { + benchmarkGetSeq(b, 1e6) +} + +func benchmarkGetSeq(b *testing.B, n int) { + r := TreeNew(cmp) + for i := 0; i < n; i++ { + r.Set(i, i) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < n; j++ { + r.Get(j) + } + } + b.StopTimer() + r.Close() +} + +func BenchmarkSetRnd1e3(b *testing.B) { + benchmarkSetRnd(b, 1e3) +} + +func BenchmarkSetRnd1e4(b *testing.B) { + benchmarkSetRnd(b, 1e4) +} + +func BenchmarkSetRnd1e5(b *testing.B) { + benchmarkSetRnd(b, 1e5) +} + +func BenchmarkSetRnd1e6(b *testing.B) { + benchmarkSetRnd(b, 1e6) +} + +func benchmarkSetRnd(b *testing.B, n int) { + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + debug.FreeOSMemory() + b.StartTimer() + for _, v := range a { + r.Set(v, 0) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func BenchmarkGetRnd1e3(b *testing.B) { + benchmarkGetRnd(b, 1e3) +} + +func BenchmarkGetRnd1e4(b *testing.B) { + benchmarkGetRnd(b, 1e4) +} + +func BenchmarkGetRnd1e5(b *testing.B) { + benchmarkGetRnd(b, 1e5) +} + +func BenchmarkGetRnd1e6(b *testing.B) { + benchmarkGetRnd(b, 1e6) +} + +func benchmarkGetRnd(b *testing.B, n int) { + r := TreeNew(cmp) + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + for _, v := range a { + r.Set(v, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, v := range a { + r.Get(v) + } + } + b.StopTimer() + r.Close() +} + +func TestSetGet2(t *testing.T) { + const N = 70000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + rng := rng() + for i := range a { + a[i] = (rng.Next() ^ x) << 1 + } + for i, k := range a { + set(k, k^x) + if g, e := r.Len(), i+1; g != e { + t.Fatal(i, x, g, e) + } + } + + for i, k := range a { + v, ok := r.Get(k) + if !ok { + t.Fatal(i, k, v, ok) + } + + if g, e := v, k^x; g != e { + t.Fatal(i, g, e) + } + + k |= 1 + _, ok = r.Get(k) + if ok { + t.Fatal(i, k) + } + } + } +} + +func TestSetGet3(t *testing.T) { + r := TreeNew(cmp) + set := r.Set + var i int + for i = 0; ; i++ { + set(i, -i) + if _, ok := r.r.(*x); ok { + break + } + } + for j := 0; j <= i; j++ { + set(j, j) + } + + for j := 0; j <= i; j++ { + v, ok := r.Get(j) + if !ok { + t.Fatal(j) + } + + if g, e := v, j; g != e { + t.Fatal(g, e) + } + } +} + +func TestDelete0(t *testing.T) { + r := TreeNew(cmp) + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + r.Set(0, 0) + if ok := r.Delete(1); ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + r.Set(0, 0) + r.Set(1, 1) + if ok := r.Delete(1); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(1); ok { + t.Fatal(ok) + } + + if ok := r.Delete(0); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + r.Set(0, 0) + r.Set(1, 1) + if ok := r.Delete(0); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 1; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(0); ok { + t.Fatal(ok) + } + + if ok := r.Delete(1); !ok { + t.Fatal(ok) + } + + if g, e := r.Len(), 0; g != e { + t.Fatal(g, e) + } + + if ok := r.Delete(1); ok { + t.Fatal(ok) + } +} + +func TestDelete1(t *testing.T) { + const N = 100000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + for i := range a { + a[i] = (i ^ x) << 1 + } + for _, k := range a { + set(k, 0) + } + + for i, k := range a { + ok := r.Delete(k) + if !ok { + t.Fatal(i, x, k) + } + + if g, e := r.Len(), N-i-1; g != e { + t.Fatal(i, g, e) + } + } + } +} + +func BenchmarkDelSeq1e3(b *testing.B) { + benchmarkDelSeq(b, 1e3) +} + +func BenchmarkDelSeq1e4(b *testing.B) { + benchmarkDelSeq(b, 1e4) +} + +func BenchmarkDelSeq1e5(b *testing.B) { + benchmarkDelSeq(b, 1e5) +} + +func BenchmarkDelSeq1e6(b *testing.B) { + benchmarkDelSeq(b, 1e6) +} + +func benchmarkDelSeq(b *testing.B, n int) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + for i := 0; i < n; i++ { + r.Set(i, i) + } + debug.FreeOSMemory() + b.StartTimer() + for j := 0; j < n; j++ { + r.Delete(j) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func BenchmarkDelRnd1e3(b *testing.B) { + benchmarkDelRnd(b, 1e3) +} + +func BenchmarkDelRnd1e4(b *testing.B) { + benchmarkDelRnd(b, 1e4) +} + +func BenchmarkDelRnd1e5(b *testing.B) { + benchmarkDelRnd(b, 1e5) +} + +func BenchmarkDelRnd1e6(b *testing.B) { + benchmarkDelRnd(b, 1e6) +} + +func benchmarkDelRnd(b *testing.B, n int) { + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + r := TreeNew(cmp) + for _, v := range a { + r.Set(v, 0) + } + debug.FreeOSMemory() + b.StartTimer() + for _, v := range a { + r.Delete(v) + } + b.StopTimer() + r.Close() + } + b.StopTimer() +} + +func TestDelete2(t *testing.T) { + const N = 80000 + for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} { + r := TreeNew(cmp) + set := r.Set + a := make([]int, N) + rng := rng() + for i := range a { + a[i] = (rng.Next() ^ x) << 1 + } + for _, k := range a { + set(k, 0) + } + + for i, k := range a { + ok := r.Delete(k) + if !ok { + t.Fatal(i, x, k) + } + + if g, e := r.Len(), N-i-1; g != e { + t.Fatal(i, g, e) + } + } + } +} + +func TestEnumeratorNext(t *testing.T) { + // seeking within 3 keys: 10, 20, 30 + table := []struct { + k int + hit bool + keys []int + }{ + {5, false, []int{10, 20, 30}}, + {10, true, []int{10, 20, 30}}, + {15, false, []int{20, 30}}, + {20, true, []int{20, 30}}, + {25, false, []int{30}}, + {30, true, []int{30}}, + {35, false, []int{}}, + } + + for i, test := range table { + up := test.keys + r := TreeNew(cmp) + + r.Set(10, 100) + r.Set(20, 200) + r.Set(30, 300) + + for verChange := 0; verChange < 16; verChange++ { + en, hit := r.Seek(test.k) + + if g, e := hit, test.hit; g != e { + t.Fatal(i, g, e) + } + + j := 0 + for { + if verChange&(1<= len(up) { + t.Fatal(i, j, verChange) + } + + if g, e := k, up[j]; g != e { + t.Fatal(i, j, verChange, g, e) + } + + if g, e := v, 10*up[j]; g != e { + t.Fatal(i, g, e) + } + + j++ + + } + + if g, e := j, len(up); g != e { + t.Fatal(i, j, g, e) + } + } + + } +} + +func TestEnumeratorPrev(t *testing.T) { + // seeking within 3 keys: 10, 20, 30 + table := []struct { + k int + hit bool + keys []int + }{ + {5, false, []int{10}}, + {10, true, []int{10}}, + {15, false, []int{20, 10}}, + {20, true, []int{20, 10}}, + {25, false, []int{30, 20, 10}}, + {30, true, []int{30, 20, 10}}, + {35, false, []int{}}, + } + + for i, test := range table { + dn := test.keys + r := TreeNew(cmp) + + r.Set(10, 100) + r.Set(20, 200) + r.Set(30, 300) + + for verChange := 0; verChange < 16; verChange++ { + en, hit := r.Seek(test.k) + + if g, e := hit, test.hit; g != e { + t.Fatal(i, g, e) + } + + j := 0 + for { + if verChange&(1<= len(dn) { + t.Fatal(i, j, verChange) + } + + if g, e := k, dn[j]; g != e { + t.Fatal(i, j, verChange, g, e) + } + + if g, e := v, 10*dn[j]; g != e { + t.Fatal(i, g, e) + } + + j++ + + } + + if g, e := j, len(dn); g != e { + t.Fatal(i, j, g, e) + } + } + + } +} + +func BenchmarkSeekSeq1e3(b *testing.B) { + benchmarkSeekSeq(b, 1e3) +} + +func BenchmarkSeekSeq1e4(b *testing.B) { + benchmarkSeekSeq(b, 1e4) +} + +func BenchmarkSeekSeq1e5(b *testing.B) { + benchmarkSeekSeq(b, 1e5) +} + +func BenchmarkSeekSeq1e6(b *testing.B) { + benchmarkSeekSeq(b, 1e6) +} + +func benchmarkSeekSeq(b *testing.B, n int) { + for i := 0; i < b.N; i++ { + b.StopTimer() + t := TreeNew(cmp) + for j := 0; j < n; j++ { + t.Set(j, 0) + } + debug.FreeOSMemory() + b.StartTimer() + for j := 0; j < n; j++ { + e, _ := t.Seek(j) + e.Close() + } + b.StopTimer() + t.Close() + } + b.StopTimer() +} + +func BenchmarkSeekRnd1e3(b *testing.B) { + benchmarkSeekRnd(b, 1e3) +} + +func BenchmarkSeekRnd1e4(b *testing.B) { + benchmarkSeekRnd(b, 1e4) +} + +func BenchmarkSeekRnd1e5(b *testing.B) { + benchmarkSeekRnd(b, 1e5) +} + +func BenchmarkSeekRnd1e6(b *testing.B) { + benchmarkSeekRnd(b, 1e6) +} + +func benchmarkSeekRnd(b *testing.B, n int) { + r := TreeNew(cmp) + rng := rng() + a := make([]int, n) + for i := range a { + a[i] = rng.Next() + } + for _, v := range a { + r.Set(v, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, v := range a { + e, _ := r.Seek(v) + e.Close() + } + } + b.StopTimer() + r.Close() +} + +func BenchmarkNext1e3(b *testing.B) { + benchmarkNext(b, 1e3) +} + +func BenchmarkNext1e4(b *testing.B) { + benchmarkNext(b, 1e4) +} + +func BenchmarkNext1e5(b *testing.B) { + benchmarkNext(b, 1e5) +} + +func BenchmarkNext1e6(b *testing.B) { + benchmarkNext(b, 1e6) +} + +func benchmarkNext(b *testing.B, n int) { + t := TreeNew(cmp) + for i := 0; i < n; i++ { + t.Set(i, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + en, err := t.SeekFirst() + if err != nil { + b.Fatal(err) + } + + m := 0 + for { + if _, _, err = en.Next(); err != nil { + break + } + m++ + } + if m != n { + b.Fatal(m) + } + } + b.StopTimer() + t.Close() +} + +func BenchmarkPrev1e3(b *testing.B) { + benchmarkPrev(b, 1e3) +} + +func BenchmarkPrev1e4(b *testing.B) { + benchmarkPrev(b, 1e4) +} + +func BenchmarkPrev1e5(b *testing.B) { + benchmarkPrev(b, 1e5) +} + +func BenchmarkPrev1e6(b *testing.B) { + benchmarkPrev(b, 1e6) +} + +func benchmarkPrev(b *testing.B, n int) { + t := TreeNew(cmp) + for i := 0; i < n; i++ { + t.Set(i, 0) + } + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + en, err := t.SeekLast() + if err != nil { + b.Fatal(err) + } + + m := 0 + for { + if _, _, err = en.Prev(); err != nil { + break + } + m++ + } + if m != n { + b.Fatal(m) + } + } + b.StopTimer() + t.Close() +} + +func TestSeekFirst0(t *testing.T) { + b := TreeNew(cmp) + _, err := b.SeekFirst() + if g, e := err, io.EOF; g != e { + t.Fatal(g, e) + } +} + +func TestSeekFirst1(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + en, err := b.SeekFirst() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekFirst2(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + b.Set(2, 20) + en, err := b.SeekFirst() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekFirst3(t *testing.T) { + b := TreeNew(cmp) + b.Set(2, 20) + b.Set(3, 30) + b.Set(1, 10) + en, err := b.SeekFirst() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if k != 3 || v != 30 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Next() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekLast0(t *testing.T) { + b := TreeNew(cmp) + _, err := b.SeekLast() + if g, e := err, io.EOF; g != e { + t.Fatal(g, e) + } +} + +func TestSeekLast1(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + en, err := b.SeekLast() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Prev() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekLast2(t *testing.T) { + b := TreeNew(cmp) + b.Set(1, 10) + b.Set(2, 20) + en, err := b.SeekLast() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Prev() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestSeekLast3(t *testing.T) { + b := TreeNew(cmp) + b.Set(2, 20) + b.Set(3, 30) + b.Set(1, 10) + en, err := b.SeekLast() + if err != nil { + t.Fatal(err) + } + + k, v, err := en.Prev() + if k != 3 || v != 30 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if k != 2 || v != 20 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if k != 1 || v != 10 || err != nil { + t.Fatal(k, v, err) + } + + k, v, err = en.Prev() + if err == nil { + t.Fatal(k, v, err) + } +} + +func TestPut(t *testing.T) { + tab := []struct { + pre []int // even index: K, odd index: V + newK int // Put(newK, ... + oldV int // Put()->oldV + exists bool // upd(exists) + write bool // upd()->write + post []int // even index: K, odd index: V + }{ + // 0 + { + []int{}, + 1, 0, false, false, + []int{}, + }, + { + []int{}, + 1, 0, false, true, + []int{1, -1}, + }, + { + []int{1, 10}, + 0, 0, false, false, + []int{1, 10}, + }, + { + []int{1, 10}, + 0, 0, false, true, + []int{0, -1, 1, 10}, + }, + { + []int{1, 10}, + 1, 10, true, false, + []int{1, 10}, + }, + + // 5 + { + []int{1, 10}, + 1, 10, true, true, + []int{1, -1}, + }, + { + []int{1, 10}, + 2, 0, false, false, + []int{1, 10}, + }, + { + []int{1, 10}, + 2, 0, false, true, + []int{1, 10, 2, -1}, + }, + } + + for iTest, test := range tab { + tr := TreeNew(cmp) + for i := 0; i < len(test.pre); i += 2 { + k, v := test.pre[i], test.pre[i+1] + tr.Set(k, v) + } + + oldV, written := tr.Put(test.newK, func(old int, exists bool) (newV int, write bool) { + if g, e := exists, test.exists; g != e { + t.Fatal(iTest, g, e) + } + + if exists { + if g, e := old, test.oldV; g != e { + t.Fatal(iTest, g, e) + } + } + return -1, test.write + }) + if test.exists { + if g, e := oldV, test.oldV; g != e { + t.Fatal(iTest, g, e) + } + } + + if g, e := written, test.write; g != e { + t.Fatal(iTest, g, e) + } + + n := len(test.post) + en, err := tr.SeekFirst() + if err != nil { + if n == 0 && err == io.EOF { + continue + } + + t.Fatal(iTest, err) + } + + for i := 0; i < len(test.post); i += 2 { + k, v, err := en.Next() + if err != nil { + t.Fatal(iTest, err) + } + + if g, e := k, test.post[i]; g != e { + t.Fatal(iTest, g, e) + } + + if g, e := v, test.post[i+1]; g != e { + t.Fatal(iTest, g, e) + } + } + + _, _, err = en.Next() + if g, e := err, io.EOF; g != e { + t.Fatal(iTest, g, e) + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/b/example/int.go b/Godeps/_workspace/src/github.com/cznic/b/example/int.go new file mode 100644 index 00000000..c7cabff2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/b/example/int.go @@ -0,0 +1,921 @@ +// Copyright 2014 The b Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package b implements a int->int B+tree. +package b + +import ( + "fmt" + "io" + "sync" +) + +const ( + kx = 32 //TODO benchmark tune this number if using custom key/value type(s). + kd = 32 //TODO benchmark tune this number if using custom key/value type(s). +) + +func init() { + if kd < 1 { + panic(fmt.Errorf("kd %d: out of range", kd)) + } + + if kx < 2 { + panic(fmt.Errorf("kx %d: out of range", kx)) + } +} + +var ( + btDPool = sync.Pool{New: func() interface{} { return &d{} }} + btEPool = btEpool{sync.Pool{New: func() interface{} { return &Enumerator{} }}} + btTPool = btTpool{sync.Pool{New: func() interface{} { return &Tree{} }}} + btXPool = sync.Pool{New: func() interface{} { return &x{} }} +) + +type btTpool struct{ sync.Pool } + +func (p *btTpool) get(cmp Cmp) *Tree { + x := p.Get().(*Tree) + x.cmp = cmp + return x +} + +type btEpool struct{ sync.Pool } + +func (p *btEpool) get(err error, hit bool, i int, k int, q *d, t *Tree, ver int64) *Enumerator { + x := p.Get().(*Enumerator) + x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver + return x +} + +type ( + // Cmp compares a and b. Return value is: + // + // < 0 if a < b + // 0 if a == b + // > 0 if a > b + // + Cmp func(a, b int) int + + d struct { // data page + c int + d [2*kd + 1]de + n *d + p *d + } + + de struct { // d element + k int + v int + } + + // Enumerator captures the state of enumerating a tree. It is returned + // from the Seek* methods. The enumerator is aware of any mutations + // made to the tree in the process of enumerating it and automatically + // resumes the enumeration at the proper key, if possible. + // + // However, once an Enumerator returns io.EOF to signal "no more + // items", it does no more attempt to "resync" on tree mutation(s). In + // other words, io.EOF from an Enumaretor is "sticky" (idempotent). + Enumerator struct { + err error + hit bool + i int + k int + q *d + t *Tree + ver int64 + } + + // Tree is a B+tree. + Tree struct { + c int + cmp Cmp + first *d + last *d + r interface{} + ver int64 + } + + xe struct { // x element + ch interface{} + k int + } + + x struct { // index page + c int + x [2*kx + 2]xe + } +) + +var ( // R/O zero values + zd d + zde de + ze Enumerator + zk int + zt Tree + zx x + zxe xe +) + +func clr(q interface{}) { + switch x := q.(type) { + case *x: + for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn + clr(x.x[i].ch) + } + *x = zx + btXPool.Put(x) + case *d: + *x = zd + btDPool.Put(x) + } +} + +// -------------------------------------------------------------------------- x + +func newX(ch0 interface{}) *x { + r := btXPool.Get().(*x) + r.x[0].ch = ch0 + return r +} + +func (q *x) extract(i int) { + q.c-- + if i < q.c { + copy(q.x[i:], q.x[i+1:q.c+1]) + q.x[q.c].ch = q.x[q.c+1].ch + q.x[q.c].k = zk // GC + q.x[q.c+1] = zxe // GC + } +} + +func (q *x) insert(i int, k int, ch interface{}) *x { + c := q.c + if i < c { + q.x[c+1].ch = q.x[c].ch + copy(q.x[i+2:], q.x[i+1:c]) + q.x[i+1].k = q.x[i].k + } + c++ + q.c = c + q.x[i].k = k + q.x[i+1].ch = ch + return q +} + +func (q *x) siblings(i int) (l, r *d) { + if i >= 0 { + if i > 0 { + l = q.x[i-1].ch.(*d) + } + if i < q.c { + r = q.x[i+1].ch.(*d) + } + } + return +} + +// -------------------------------------------------------------------------- d + +func (l *d) mvL(r *d, c int) { + copy(l.d[l.c:], r.d[:c]) + copy(r.d[:], r.d[c:r.c]) + l.c += c + r.c -= c +} + +func (l *d) mvR(r *d, c int) { + copy(r.d[c:], r.d[:r.c]) + copy(r.d[:c], l.d[l.c-c:]) + r.c += c + l.c -= c +} + +// ----------------------------------------------------------------------- Tree + +// TreeNew returns a newly created, empty Tree. The compare function is used +// for key collation. +func TreeNew(cmp Cmp) *Tree { + return btTPool.get(cmp) +} + +// Clear removes all K/V pairs from the tree. +func (t *Tree) Clear() { + if t.r == nil { + return + } + + clr(t.r) + t.c, t.first, t.last, t.r = 0, nil, nil, nil + t.ver++ +} + +// Close performs Clear and recycles t to a pool for possible later reuse. No +// references to t should exist or such references must not be used afterwards. +func (t *Tree) Close() { + t.Clear() + *t = zt + btTPool.Put(t) +} + +func (t *Tree) cat(p *x, q, r *d, pi int) { + t.ver++ + q.mvL(r, r.c) + if r.n != nil { + r.n.p = q + } else { + t.last = q + } + q.n = r.n + *r = zd + btDPool.Put(r) + if p.c > 1 { + p.extract(pi) + p.x[pi].ch = q + } else { + switch x := t.r.(type) { + case *x: + *x = zx + btXPool.Put(x) + case *d: + *x = zd + btDPool.Put(x) + } + t.r = q + } +} + +func (t *Tree) catX(p, q, r *x, pi int) { + t.ver++ + q.x[q.c].k = p.x[pi].k + copy(q.x[q.c+1:], r.x[:r.c]) + q.c += r.c + 1 + q.x[q.c].ch = r.x[r.c].ch + *r = zx + btXPool.Put(r) + if p.c > 1 { + p.c-- + pc := p.c + if pi < pc { + p.x[pi].k = p.x[pi+1].k + copy(p.x[pi+1:], p.x[pi+2:pc+1]) + p.x[pc].ch = p.x[pc+1].ch + p.x[pc].k = zk // GC + p.x[pc+1].ch = nil // GC + } + return + } + + switch x := t.r.(type) { + case *x: + *x = zx + btXPool.Put(x) + case *d: + *x = zd + btDPool.Put(x) + } + t.r = q +} + +// Delete removes the k's KV pair, if it exists, in which case Delete returns +// true. +func (t *Tree) Delete(k int) (ok bool) { + pi := -1 + var p *x + q := t.r + if q == nil { + return false + } + + for { + var i int + i, ok = t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + if x.c < kx && q != t.r { + x, i = t.underflowX(p, x, pi, i) + } + pi = i + 1 + p = x + q = x.x[pi].ch + ok = false + continue + case *d: + t.extract(x, i) + if x.c >= kd { + return true + } + + if q != t.r { + t.underflow(p, x, pi) + } else if t.c == 0 { + t.Clear() + } + return true + } + } + + switch x := q.(type) { + case *x: + if x.c < kx && q != t.r { + x, i = t.underflowX(p, x, pi, i) + } + pi = i + p = x + q = x.x[i].ch + case *d: + return false + } + } +} + +func (t *Tree) extract(q *d, i int) { // (r int) { + t.ver++ + //r = q.d[i].v // prepared for Extract + q.c-- + if i < q.c { + copy(q.d[i:], q.d[i+1:q.c+1]) + } + q.d[q.c] = zde // GC + t.c-- + return +} + +func (t *Tree) find(q interface{}, k int) (i int, ok bool) { + var mk int + l := 0 + switch x := q.(type) { + case *x: + h := x.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = x.x[m].k + switch cmp := t.cmp(k, mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + case *d: + h := x.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = x.d[m].k + switch cmp := t.cmp(k, mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + } + return l, false +} + +// First returns the first item of the tree in the key collating order, or +// (zero-value, zero-value) if the tree is empty. +func (t *Tree) First() (k int, v int) { + if q := t.first; q != nil { + q := &q.d[0] + k, v = q.k, q.v + } + return +} + +// Get returns the value associated with k and true if it exists. Otherwise Get +// returns (zero-value, false). +func (t *Tree) Get(k int) (v int, ok bool) { + q := t.r + if q == nil { + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch x := q.(type) { + case *x: + q = x.x[i+1].ch + continue + case *d: + return x.d[i].v, true + } + } + switch x := q.(type) { + case *x: + q = x.x[i].ch + default: + return + } + } +} + +func (t *Tree) insert(q *d, i int, k int, v int) *d { + t.ver++ + c := q.c + if i < c { + copy(q.d[i+1:], q.d[i:c]) + } + c++ + q.c = c + q.d[i].k, q.d[i].v = k, v + t.c++ + return q +} + +// Last returns the last item of the tree in the key collating order, or +// (zero-value, zero-value) if the tree is empty. +func (t *Tree) Last() (k int, v int) { + if q := t.last; q != nil { + q := &q.d[q.c-1] + k, v = q.k, q.v + } + return +} + +// Len returns the number of items in the tree. +func (t *Tree) Len() int { + return t.c +} + +func (t *Tree) overflow(p *x, q *d, pi, i int, k int, v int) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c < 2*kd { + l.mvL(q, 1) + t.insert(q, i-1, k, v) + p.x[pi-1].k = q.d[0].k + return + } + + if r != nil && r.c < 2*kd { + if i < 2*kd { + q.mvR(r, 1) + t.insert(q, i, k, v) + p.x[pi].k = r.d[0].k + } else { + t.insert(r, 0, k, v) + p.x[pi].k = k + } + return + } + + t.split(p, q, pi, i, k, v) +} + +// Seek returns an Enumerator positioned on a an item such that k >= item's +// key. ok reports if k == item.key The Enumerator's position is possibly +// after the last item in the tree. +func (t *Tree) Seek(k int) (e *Enumerator, ok bool) { + q := t.r + if q == nil { + e = btEPool.get(nil, false, 0, k, nil, t, t.ver) + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch x := q.(type) { + case *x: + q = x.x[i+1].ch + continue + case *d: + return btEPool.get(nil, ok, i, k, x, t, t.ver), true + } + } + + switch x := q.(type) { + case *x: + q = x.x[i].ch + case *d: + return btEPool.get(nil, ok, i, k, x, t, t.ver), false + } + } +} + +// SeekFirst returns an enumerator positioned on the first KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *Tree) SeekFirst() (e *Enumerator, err error) { + q := t.first + if q == nil { + return nil, io.EOF + } + + return btEPool.get(nil, true, 0, q.d[0].k, q, t, t.ver), nil +} + +// SeekLast returns an enumerator positioned on the last KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *Tree) SeekLast() (e *Enumerator, err error) { + q := t.last + if q == nil { + return nil, io.EOF + } + + return btEPool.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, t.ver), nil +} + +// Set sets the value associated with k. +func (t *Tree) Set(k int, v int) { + //dbg("--- PRE Set(%v, %v)\n%s", k, v, t.dump()) + //defer func() { + // dbg("--- POST\n%s\n====\n", t.dump()) + //}() + + pi := -1 + var p *x + q := t.r + if q == nil { + z := t.insert(btDPool.Get().(*d), 0, k, v) + t.r, t.first, t.last = z, z, z + return + } + + for { + i, ok := t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + 1 + p = x + q = x.x[i+1].ch + continue + case *d: + x.d[i].v = v + } + return + } + + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + p = x + q = x.x[i].ch + case *d: + switch { + case x.c < 2*kd: + t.insert(x, i, k, v) + default: + t.overflow(p, x, pi, i, k, v) + } + return + } + } +} + +// Put combines Get and Set in a more efficient way where the tree is walked +// only once. The upd(ater) receives (old-value, true) if a KV pair for k +// exists or (zero-value, false) otherwise. It can then return a (new-value, +// true) to create or overwrite the existing value in the KV pair, or +// (whatever, false) if it decides not to create or not to update the value of +// the KV pair. +// +// tree.Set(k, v) conceptually equals +// +// tree.Put(k, func(k, v []byte){ return v, true }([]byte, bool)) +// +// modulo the differing return values. +func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)) (oldV int, written bool) { + pi := -1 + var p *x + q := t.r + var newV int + if q == nil { + // new KV pair in empty tree + newV, written = upd(newV, false) + if !written { + return + } + + z := t.insert(btDPool.Get().(*d), 0, k, newV) + t.r, t.first, t.last = z, z, z + return + } + + for { + i, ok := t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + 1 + p = x + q = x.x[i+1].ch + continue + case *d: + oldV = x.d[i].v + newV, written = upd(oldV, true) + if !written { + return + } + + x.d[i].v = newV + } + return + } + + switch x := q.(type) { + case *x: + if x.c > 2*kx { + x, i = t.splitX(p, x, pi, i) + } + pi = i + p = x + q = x.x[i].ch + case *d: // new KV pair + newV, written = upd(newV, false) + if !written { + return + } + + switch { + case x.c < 2*kd: + t.insert(x, i, k, newV) + default: + t.overflow(p, x, pi, i, k, newV) + } + return + } + } +} + +func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) { + t.ver++ + r := btDPool.Get().(*d) + if q.n != nil { + r.n = q.n + r.n.p = r + } else { + t.last = r + } + q.n = r + r.p = q + + copy(r.d[:], q.d[kd:2*kd]) + for i := range q.d[kd:] { + q.d[kd+i] = zde + } + q.c = kd + r.c = kd + var done bool + if i > kd { + done = true + t.insert(r, i-kd, k, v) + } + if pi >= 0 { + p.insert(pi, r.d[0].k, r) + } else { + t.r = newX(q).insert(0, r.d[0].k, r) + } + if done { + return + } + + t.insert(q, i, k, v) +} + +func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) { + t.ver++ + r := btXPool.Get().(*x) + copy(r.x[:], q.x[kx+1:]) + q.c = kx + r.c = kx + if pi >= 0 { + p.insert(pi, q.x[kx].k, r) + q.x[kx].k = zk + for i := range q.x[kx+1:] { + q.x[kx+i+1] = zxe + } + + switch { + case i < kx: + return q, i + case i == kx: + return p, pi + default: // i > kx + return r, i - kx - 1 + } + } + + nr := newX(q).insert(0, q.x[kx].k, r) + t.r = nr + q.x[kx].k = zk + for i := range q.x[kx+1:] { + q.x[kx+i+1] = zxe + } + + switch { + case i < kx: + return q, i + case i == kx: + return nr, 0 + default: // i > kx + return r, i - kx - 1 + } +} + +func (t *Tree) underflow(p *x, q *d, pi int) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c+q.c >= 2*kd { + l.mvR(q, 1) + p.x[pi-1].k = q.d[0].k + } else if r != nil && q.c+r.c >= 2*kd { + q.mvL(r, 1) + p.x[pi].k = r.d[0].k + r.d[r.c] = zde // GC + } else if l != nil { + t.cat(p, l, q, pi-1) + } else { + t.cat(p, q, r, pi) + } +} + +func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { + t.ver++ + var l, r *x + + if pi >= 0 { + if pi > 0 { + l = p.x[pi-1].ch.(*x) + } + if pi < p.c { + r = p.x[pi+1].ch.(*x) + } + } + + if l != nil && l.c > kx { + q.x[q.c+1].ch = q.x[q.c].ch + copy(q.x[1:], q.x[:q.c]) + q.x[0].ch = l.x[l.c].ch + q.x[0].k = p.x[pi-1].k + q.c++ + i++ + l.c-- + p.x[pi-1].k = l.x[l.c].k + return q, i + } + + if r != nil && r.c > kx { + q.x[q.c].k = p.x[pi].k + q.c++ + q.x[q.c].ch = r.x[0].ch + p.x[pi].k = r.x[0].k + copy(r.x[:], r.x[1:r.c]) + r.c-- + rc := r.c + r.x[rc].ch = r.x[rc+1].ch + r.x[rc].k = zk + r.x[rc+1].ch = nil + return q, i + } + + if l != nil { + i += l.c + 1 + t.catX(p, l, q, pi-1) + q = l + return q, i + } + + t.catX(p, q, r, pi) + return q, i +} + +// ----------------------------------------------------------------- Enumerator + +// Close recycles e to a pool for possible later reuse. No references to e +// should exist or such references must not be used afterwards. +func (e *Enumerator) Close() { + *e = ze + btEPool.Put(e) +} + +// Next returns the currently enumerated item, if it exists and moves to the +// next item in the key collation order. If there is no item to return, err == +// io.EOF is returned. +func (e *Enumerator) Next() (k int, v int, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.next(); err != nil { + return + } + } + + *e = *f + f.Close() + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.d[e.i] + k, v = i.k, i.v + e.k, e.hit = k, false + e.next() + return +} + +func (e *Enumerator) next() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i < e.q.c-1: + e.i++ + default: + if e.q, e.i = e.q.n, 0; e.q == nil { + e.err = io.EOF + } + } + return e.err +} + +// Prev returns the currently enumerated item, if it exists and moves to the +// previous item in the key collation order. If there is no item to return, err +// == io.EOF is returned. +func (e *Enumerator) Prev() (k int, v int, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.prev(); err != nil { + return + } + } + + *e = *f + f.Close() + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.d[e.i] + k, v = i.k, i.v + e.k, e.hit = k, false + e.prev() + return +} + +func (e *Enumerator) prev() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i > 0: + e.i-- + default: + if e.q = e.q.p; e.q == nil { + e.err = io.EOF + break + } + + e.i = e.q.c - 1 + } + return e.err +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile b/Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile new file mode 100644 index 00000000..f1f06564 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C testdata + protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata:. proto3_proto/proto3.proto + make diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go new file mode 100644 index 00000000..6e044dff --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/all_test.go @@ -0,0 +1,2071 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "math" + "math/rand" + "reflect" + "runtime/debug" + "strings" + "testing" + "time" + + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +var globalO *Buffer + +func old() *Buffer { + if globalO == nil { + globalO = NewBuffer(nil) + } + globalO.Reset() + return globalO +} + +func equalbytes(b1, b2 []byte, t *testing.T) { + if len(b1) != len(b2) { + t.Errorf("wrong lengths: 2*%d != %d", len(b1), len(b2)) + return + } + for i := 0; i < len(b1); i++ { + if b1[i] != b2[i] { + t.Errorf("bad byte[%d]:%x %x: %s %s", i, b1[i], b2[i], b1, b2) + } + } +} + +func initGoTestField() *GoTestField { + f := new(GoTestField) + f.Label = String("label") + f.Type = String("type") + return f +} + +// These are all structurally equivalent but the tag numbers differ. +// (It's remarkable that required, optional, and repeated all have +// 8 letters.) +func initGoTest_RequiredGroup() *GoTest_RequiredGroup { + return &GoTest_RequiredGroup{ + RequiredField: String("required"), + } +} + +func initGoTest_OptionalGroup() *GoTest_OptionalGroup { + return &GoTest_OptionalGroup{ + RequiredField: String("optional"), + } +} + +func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup { + return &GoTest_RepeatedGroup{ + RequiredField: String("repeated"), + } +} + +func initGoTest(setdefaults bool) *GoTest { + pb := new(GoTest) + if setdefaults { + pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted) + pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted) + pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted) + pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted) + pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted) + pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted) + pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted) + pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted) + pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted) + pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted) + pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted + pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) + pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) + } + + pb.Kind = GoTest_TIME.Enum() + pb.RequiredField = initGoTestField() + pb.F_BoolRequired = Bool(true) + pb.F_Int32Required = Int32(3) + pb.F_Int64Required = Int64(6) + pb.F_Fixed32Required = Uint32(32) + pb.F_Fixed64Required = Uint64(64) + pb.F_Uint32Required = Uint32(3232) + pb.F_Uint64Required = Uint64(6464) + pb.F_FloatRequired = Float32(3232) + pb.F_DoubleRequired = Float64(6464) + pb.F_StringRequired = String("string") + pb.F_BytesRequired = []byte("bytes") + pb.F_Sint32Required = Int32(-32) + pb.F_Sint64Required = Int64(-64) + pb.Requiredgroup = initGoTest_RequiredGroup() + + return pb +} + +func fail(msg string, b *bytes.Buffer, s string, t *testing.T) { + data := b.Bytes() + ld := len(data) + ls := len(s) / 2 + + fmt.Printf("fail %s ld=%d ls=%d\n", msg, ld, ls) + + // find the interesting spot - n + n := ls + if ld < ls { + n = ld + } + j := 0 + for i := 0; i < n; i++ { + bs := hex(s[j])*16 + hex(s[j+1]) + j += 2 + if data[i] == bs { + continue + } + n = i + break + } + l := n - 10 + if l < 0 { + l = 0 + } + h := n + 10 + + // find the interesting spot - n + fmt.Printf("is[%d]:", l) + for i := l; i < h; i++ { + if i >= ld { + fmt.Printf(" --") + continue + } + fmt.Printf(" %.2x", data[i]) + } + fmt.Printf("\n") + + fmt.Printf("sb[%d]:", l) + for i := l; i < h; i++ { + if i >= ls { + fmt.Printf(" --") + continue + } + bs := hex(s[j])*16 + hex(s[j+1]) + j += 2 + fmt.Printf(" %.2x", bs) + } + fmt.Printf("\n") + + t.Fail() + + // t.Errorf("%s: \ngood: %s\nbad: %x", msg, s, b.Bytes()) + // Print the output in a partially-decoded format; can + // be helpful when updating the test. It produces the output + // that is pasted, with minor edits, into the argument to verify(). + // data := b.Bytes() + // nesting := 0 + // for b.Len() > 0 { + // start := len(data) - b.Len() + // var u uint64 + // u, err := DecodeVarint(b) + // if err != nil { + // fmt.Printf("decode error on varint:", err) + // return + // } + // wire := u & 0x7 + // tag := u >> 3 + // switch wire { + // case WireVarint: + // v, err := DecodeVarint(b) + // if err != nil { + // fmt.Printf("decode error on varint:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", + // data[start:len(data)-b.Len()], tag, wire, v) + // case WireFixed32: + // v, err := DecodeFixed32(b) + // if err != nil { + // fmt.Printf("decode error on fixed32:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", + // data[start:len(data)-b.Len()], tag, wire, v) + // case WireFixed64: + // v, err := DecodeFixed64(b) + // if err != nil { + // fmt.Printf("decode error on fixed64:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", + // data[start:len(data)-b.Len()], tag, wire, v) + // case WireBytes: + // nb, err := DecodeVarint(b) + // if err != nil { + // fmt.Printf("decode error on bytes:", err) + // return + // } + // after_tag := len(data) - b.Len() + // str := make([]byte, nb) + // _, err = b.Read(str) + // if err != nil { + // fmt.Printf("decode error on bytes:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" \"%x\" // field %d, encoding %d (FIELD)\n", + // data[start:after_tag], str, tag, wire) + // case WireStartGroup: + // nesting++ + // fmt.Printf("\t\t\"%x\"\t\t// start group field %d level %d\n", + // data[start:len(data)-b.Len()], tag, nesting) + // case WireEndGroup: + // fmt.Printf("\t\t\"%x\"\t\t// end group field %d level %d\n", + // data[start:len(data)-b.Len()], tag, nesting) + // nesting-- + // default: + // fmt.Printf("unrecognized wire type %d\n", wire) + // return + // } + // } +} + +func hex(c uint8) uint8 { + if '0' <= c && c <= '9' { + return c - '0' + } + if 'a' <= c && c <= 'f' { + return 10 + c - 'a' + } + if 'A' <= c && c <= 'F' { + return 10 + c - 'A' + } + return 0 +} + +func equal(b []byte, s string, t *testing.T) bool { + if 2*len(b) != len(s) { + // fail(fmt.Sprintf("wrong lengths: 2*%d != %d", len(b), len(s)), b, s, t) + fmt.Printf("wrong lengths: 2*%d != %d\n", len(b), len(s)) + return false + } + for i, j := 0, 0; i < len(b); i, j = i+1, j+2 { + x := hex(s[j])*16 + hex(s[j+1]) + if b[i] != x { + // fail(fmt.Sprintf("bad byte[%d]:%x %x", i, b[i], x), b, s, t) + fmt.Printf("bad byte[%d]:%x %x", i, b[i], x) + return false + } + } + return true +} + +func overify(t *testing.T, pb *GoTest, expected string) { + o := old() + err := o.Marshal(pb) + if err != nil { + fmt.Printf("overify marshal-1 err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("expected = %s", expected) + } + if !equal(o.Bytes(), expected, t) { + o.DebugPrint("overify neq 1", o.Bytes()) + t.Fatalf("expected = %s", expected) + } + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + err = o.Unmarshal(pbd) + if err != nil { + t.Fatalf("overify unmarshal err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("string = %s", expected) + } + o.Reset() + err = o.Marshal(pbd) + if err != nil { + t.Errorf("overify marshal-2 err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("string = %s", expected) + } + if !equal(o.Bytes(), expected, t) { + o.DebugPrint("overify neq 2", o.Bytes()) + t.Fatalf("string = %s", expected) + } +} + +// Simple tests for numeric encode/decode primitives (varint, etc.) +func TestNumericPrimitives(t *testing.T) { + for i := uint64(0); i < 1e6; i += 111 { + o := old() + if o.EncodeVarint(i) != nil { + t.Error("EncodeVarint") + break + } + x, e := o.DecodeVarint() + if e != nil { + t.Fatal("DecodeVarint") + } + if x != i { + t.Fatal("varint decode fail:", i, x) + } + + o = old() + if o.EncodeFixed32(i) != nil { + t.Fatal("encFixed32") + } + x, e = o.DecodeFixed32() + if e != nil { + t.Fatal("decFixed32") + } + if x != i { + t.Fatal("fixed32 decode fail:", i, x) + } + + o = old() + if o.EncodeFixed64(i*1234567) != nil { + t.Error("encFixed64") + break + } + x, e = o.DecodeFixed64() + if e != nil { + t.Error("decFixed64") + break + } + if x != i*1234567 { + t.Error("fixed64 decode fail:", i*1234567, x) + break + } + + o = old() + i32 := int32(i - 12345) + if o.EncodeZigzag32(uint64(i32)) != nil { + t.Fatal("EncodeZigzag32") + } + x, e = o.DecodeZigzag32() + if e != nil { + t.Fatal("DecodeZigzag32") + } + if x != uint64(uint32(i32)) { + t.Fatal("zigzag32 decode fail:", i32, x) + } + + o = old() + i64 := int64(i - 12345) + if o.EncodeZigzag64(uint64(i64)) != nil { + t.Fatal("EncodeZigzag64") + } + x, e = o.DecodeZigzag64() + if e != nil { + t.Fatal("DecodeZigzag64") + } + if x != uint64(i64) { + t.Fatal("zigzag64 decode fail:", i64, x) + } + } +} + +// fakeMarshaler is a simple struct implementing Marshaler and Message interfaces. +type fakeMarshaler struct { + b []byte + err error +} + +func (f fakeMarshaler) Marshal() ([]byte, error) { + return f.b, f.err +} + +func (f fakeMarshaler) String() string { + return fmt.Sprintf("Bytes: %v Error: %v", f.b, f.err) +} + +func (f fakeMarshaler) ProtoMessage() {} + +func (f fakeMarshaler) Reset() {} + +// Simple tests for proto messages that implement the Marshaler interface. +func TestMarshalerEncoding(t *testing.T) { + tests := []struct { + name string + m Message + want []byte + wantErr error + }{ + { + name: "Marshaler that fails", + m: fakeMarshaler{ + err: errors.New("some marshal err"), + b: []byte{5, 6, 7}, + }, + // Since there's an error, nothing should be written to buffer. + want: nil, + wantErr: errors.New("some marshal err"), + }, + { + name: "Marshaler that succeeds", + m: fakeMarshaler{ + b: []byte{0, 1, 2, 3, 4, 127, 255}, + }, + want: []byte{0, 1, 2, 3, 4, 127, 255}, + wantErr: nil, + }, + } + for _, test := range tests { + b := NewBuffer(nil) + err := b.Marshal(test.m) + if !reflect.DeepEqual(test.wantErr, err) { + t.Errorf("%s: got err %v wanted %v", test.name, err, test.wantErr) + } + if !reflect.DeepEqual(test.want, b.Bytes()) { + t.Errorf("%s: got bytes %v wanted %v", test.name, b.Bytes(), test.want) + } + } +} + +// Simple tests for bytes +func TestBytesPrimitives(t *testing.T) { + o := old() + bytes := []byte{'n', 'o', 'w', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 't', 'i', 'm', 'e'} + if o.EncodeRawBytes(bytes) != nil { + t.Error("EncodeRawBytes") + } + decb, e := o.DecodeRawBytes(false) + if e != nil { + t.Error("DecodeRawBytes") + } + equalbytes(bytes, decb, t) +} + +// Simple tests for strings +func TestStringPrimitives(t *testing.T) { + o := old() + s := "now is the time" + if o.EncodeStringBytes(s) != nil { + t.Error("enc_string") + } + decs, e := o.DecodeStringBytes() + if e != nil { + t.Error("dec_string") + } + if s != decs { + t.Error("string encode/decode fail:", s, decs) + } +} + +// Do we catch the "required bit not set" case? +func TestRequiredBit(t *testing.T) { + o := old() + pb := new(GoTest) + err := o.Marshal(pb) + if err == nil { + t.Error("did not catch missing required fields") + } else if strings.Index(err.Error(), "Kind") < 0 { + t.Error("wrong error type:", err) + } +} + +// Check that all fields are nil. +// Clearly silly, and a residue from a more interesting test with an earlier, +// different initialization property, but it once caught a compiler bug so +// it lives. +func checkInitialized(pb *GoTest, t *testing.T) { + if pb.F_BoolDefaulted != nil { + t.Error("New or Reset did not set boolean:", *pb.F_BoolDefaulted) + } + if pb.F_Int32Defaulted != nil { + t.Error("New or Reset did not set int32:", *pb.F_Int32Defaulted) + } + if pb.F_Int64Defaulted != nil { + t.Error("New or Reset did not set int64:", *pb.F_Int64Defaulted) + } + if pb.F_Fixed32Defaulted != nil { + t.Error("New or Reset did not set fixed32:", *pb.F_Fixed32Defaulted) + } + if pb.F_Fixed64Defaulted != nil { + t.Error("New or Reset did not set fixed64:", *pb.F_Fixed64Defaulted) + } + if pb.F_Uint32Defaulted != nil { + t.Error("New or Reset did not set uint32:", *pb.F_Uint32Defaulted) + } + if pb.F_Uint64Defaulted != nil { + t.Error("New or Reset did not set uint64:", *pb.F_Uint64Defaulted) + } + if pb.F_FloatDefaulted != nil { + t.Error("New or Reset did not set float:", *pb.F_FloatDefaulted) + } + if pb.F_DoubleDefaulted != nil { + t.Error("New or Reset did not set double:", *pb.F_DoubleDefaulted) + } + if pb.F_StringDefaulted != nil { + t.Error("New or Reset did not set string:", *pb.F_StringDefaulted) + } + if pb.F_BytesDefaulted != nil { + t.Error("New or Reset did not set bytes:", string(pb.F_BytesDefaulted)) + } + if pb.F_Sint32Defaulted != nil { + t.Error("New or Reset did not set int32:", *pb.F_Sint32Defaulted) + } + if pb.F_Sint64Defaulted != nil { + t.Error("New or Reset did not set int64:", *pb.F_Sint64Defaulted) + } +} + +// Does Reset() reset? +func TestReset(t *testing.T) { + pb := initGoTest(true) + // muck with some values + pb.F_BoolDefaulted = Bool(false) + pb.F_Int32Defaulted = Int32(237) + pb.F_Int64Defaulted = Int64(12346) + pb.F_Fixed32Defaulted = Uint32(32000) + pb.F_Fixed64Defaulted = Uint64(666) + pb.F_Uint32Defaulted = Uint32(323232) + pb.F_Uint64Defaulted = nil + pb.F_FloatDefaulted = nil + pb.F_DoubleDefaulted = Float64(0) + pb.F_StringDefaulted = String("gotcha") + pb.F_BytesDefaulted = []byte("asdfasdf") + pb.F_Sint32Defaulted = Int32(123) + pb.F_Sint64Defaulted = Int64(789) + pb.Reset() + checkInitialized(pb, t) +} + +// All required fields set, no defaults provided. +func TestEncodeDecode1(t *testing.T) { + pb := initGoTest(false) + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 0x20 + "714000000000000000"+ // field 14, encoding 1, value 0x40 + "78a019"+ // field 15, encoding 0, value 0xca0 = 3232 + "8001c032"+ // field 16, encoding 0, value 0x1940 = 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2, string "string" + "b304"+ // field 70, encoding 3, start group + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // field 70, encoding 4, end group + "aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f") // field 103, encoding 0, 0x7f zigzag64 +} + +// All required fields set, defaults provided. +func TestEncodeDecode2(t *testing.T) { + pb := initGoTest(true) + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All default fields set to their default value by hand +func TestEncodeDecode3(t *testing.T) { + pb := initGoTest(false) + pb.F_BoolDefaulted = Bool(true) + pb.F_Int32Defaulted = Int32(32) + pb.F_Int64Defaulted = Int64(64) + pb.F_Fixed32Defaulted = Uint32(320) + pb.F_Fixed64Defaulted = Uint64(640) + pb.F_Uint32Defaulted = Uint32(3200) + pb.F_Uint64Defaulted = Uint64(6400) + pb.F_FloatDefaulted = Float32(314159) + pb.F_DoubleDefaulted = Float64(271828) + pb.F_StringDefaulted = String("hello, \"world!\"\n") + pb.F_BytesDefaulted = []byte("Bignose") + pb.F_Sint32Defaulted = Int32(-32) + pb.F_Sint64Defaulted = Int64(-64) + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All required fields set, defaults provided, all non-defaulted optional fields have values. +func TestEncodeDecode4(t *testing.T) { + pb := initGoTest(true) + pb.Table = String("hello") + pb.Param = Int32(7) + pb.OptionalField = initGoTestField() + pb.F_BoolOptional = Bool(true) + pb.F_Int32Optional = Int32(32) + pb.F_Int64Optional = Int64(64) + pb.F_Fixed32Optional = Uint32(3232) + pb.F_Fixed64Optional = Uint64(6464) + pb.F_Uint32Optional = Uint32(323232) + pb.F_Uint64Optional = Uint64(646464) + pb.F_FloatOptional = Float32(32.) + pb.F_DoubleOptional = Float64(64.) + pb.F_StringOptional = String("hello") + pb.F_BytesOptional = []byte("Bignose") + pb.F_Sint32Optional = Int32(-32) + pb.F_Sint64Optional = Int64(-64) + pb.Optionalgroup = initGoTest_OptionalGroup() + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "1205"+"68656c6c6f"+ // field 2, encoding 2, string "hello" + "1807"+ // field 3, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "320d"+"0a056c6162656c120474797065"+ // field 6, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "f00101"+ // field 30, encoding 0, value 1 + "f80120"+ // field 31, encoding 0, value 32 + "800240"+ // field 32, encoding 0, value 64 + "8d02a00c0000"+ // field 33, encoding 5, value 3232 + "91024019000000000000"+ // field 34, encoding 1, value 6464 + "9802a0dd13"+ // field 35, encoding 0, value 323232 + "a002c0ba27"+ // field 36, encoding 0, value 646464 + "ad0200000042"+ // field 37, encoding 5, value 32.0 + "b1020000000000005040"+ // field 38, encoding 1, value 64.0 + "ba0205"+"68656c6c6f"+ // field 39, encoding 2, string "hello" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "d305"+ // start group field 90 level 1 + "da0508"+"6f7074696f6e616c"+ // field 91, encoding 2, string "optional" + "d405"+ // end group field 90 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose" + "f0123f"+ // field 302, encoding 0, value 63 + "f8127f"+ // field 303, encoding 0, value 127 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All required fields set, defaults provided, all repeated fields given two values. +func TestEncodeDecode5(t *testing.T) { + pb := initGoTest(true) + pb.RepeatedField = []*GoTestField{initGoTestField(), initGoTestField()} + pb.F_BoolRepeated = []bool{false, true} + pb.F_Int32Repeated = []int32{32, 33} + pb.F_Int64Repeated = []int64{64, 65} + pb.F_Fixed32Repeated = []uint32{3232, 3333} + pb.F_Fixed64Repeated = []uint64{6464, 6565} + pb.F_Uint32Repeated = []uint32{323232, 333333} + pb.F_Uint64Repeated = []uint64{646464, 656565} + pb.F_FloatRepeated = []float32{32., 33.} + pb.F_DoubleRepeated = []float64{64., 65.} + pb.F_StringRepeated = []string{"hello", "sailor"} + pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")} + pb.F_Sint32Repeated = []int32{32, -32} + pb.F_Sint64Repeated = []int64{64, -64} + pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()} + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) + "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "a00100"+ // field 20, encoding 0, value 0 + "a00101"+ // field 20, encoding 0, value 1 + "a80120"+ // field 21, encoding 0, value 32 + "a80121"+ // field 21, encoding 0, value 33 + "b00140"+ // field 22, encoding 0, value 64 + "b00141"+ // field 22, encoding 0, value 65 + "bd01a00c0000"+ // field 23, encoding 5, value 3232 + "bd01050d0000"+ // field 23, encoding 5, value 3333 + "c1014019000000000000"+ // field 24, encoding 1, value 6464 + "c101a519000000000000"+ // field 24, encoding 1, value 6565 + "c801a0dd13"+ // field 25, encoding 0, value 323232 + "c80195ac14"+ // field 25, encoding 0, value 333333 + "d001c0ba27"+ // field 26, encoding 0, value 646464 + "d001b58928"+ // field 26, encoding 0, value 656565 + "dd0100000042"+ // field 27, encoding 5, value 32.0 + "dd0100000442"+ // field 27, encoding 5, value 33.0 + "e1010000000000005040"+ // field 28, encoding 1, value 64.0 + "e1010000000000405040"+ // field 28, encoding 1, value 65.0 + "ea0105"+"68656c6c6f"+ // field 29, encoding 2, string "hello" + "ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "8305"+ // start group field 80 level 1 + "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" + "8405"+ // end group field 80 level 1 + "8305"+ // start group field 80 level 1 + "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" + "8405"+ // end group field 80 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "ca0c03"+"626967"+ // field 201, encoding 2, string "big" + "ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose" + "d00c40"+ // field 202, encoding 0, value 32 + "d00c3f"+ // field 202, encoding 0, value -32 + "d80c8001"+ // field 203, encoding 0, value 64 + "d80c7f"+ // field 203, encoding 0, value -64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All required fields set, all packed repeated fields given two values. +func TestEncodeDecode6(t *testing.T) { + pb := initGoTest(false) + pb.F_BoolRepeatedPacked = []bool{false, true} + pb.F_Int32RepeatedPacked = []int32{32, 33} + pb.F_Int64RepeatedPacked = []int64{64, 65} + pb.F_Fixed32RepeatedPacked = []uint32{3232, 3333} + pb.F_Fixed64RepeatedPacked = []uint64{6464, 6565} + pb.F_Uint32RepeatedPacked = []uint32{323232, 333333} + pb.F_Uint64RepeatedPacked = []uint64{646464, 656565} + pb.F_FloatRepeatedPacked = []float32{32., 33.} + pb.F_DoubleRepeatedPacked = []float64{64., 65.} + pb.F_Sint32RepeatedPacked = []int32{32, -32} + pb.F_Sint64RepeatedPacked = []int64{64, -64} + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "9203020001"+ // field 50, encoding 2, 2 bytes, value 0, value 1 + "9a03022021"+ // field 51, encoding 2, 2 bytes, value 32, value 33 + "a203024041"+ // field 52, encoding 2, 2 bytes, value 64, value 65 + "aa0308"+ // field 53, encoding 2, 8 bytes + "a00c0000050d0000"+ // value 3232, value 3333 + "b20310"+ // field 54, encoding 2, 16 bytes + "4019000000000000a519000000000000"+ // value 6464, value 6565 + "ba0306"+ // field 55, encoding 2, 6 bytes + "a0dd1395ac14"+ // value 323232, value 333333 + "c20306"+ // field 56, encoding 2, 6 bytes + "c0ba27b58928"+ // value 646464, value 656565 + "ca0308"+ // field 57, encoding 2, 8 bytes + "0000004200000442"+ // value 32.0, value 33.0 + "d20310"+ // field 58, encoding 2, 16 bytes + "00000000000050400000000000405040"+ // value 64.0, value 65.0 + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "b21f02"+ // field 502, encoding 2, 2 bytes + "403f"+ // value 32, value -32 + "ba1f03"+ // field 503, encoding 2, 3 bytes + "80017f") // value 64, value -64 +} + +// Test that we can encode empty bytes fields. +func TestEncodeDecodeBytes1(t *testing.T) { + pb := initGoTest(false) + + // Create our bytes + pb.F_BytesRequired = []byte{} + pb.F_BytesRepeated = [][]byte{{}} + pb.F_BytesOptional = []byte{} + + d, err := Marshal(pb) + if err != nil { + t.Error(err) + } + + pbd := new(GoTest) + if err := Unmarshal(d, pbd); err != nil { + t.Error(err) + } + + if pbd.F_BytesRequired == nil || len(pbd.F_BytesRequired) != 0 { + t.Error("required empty bytes field is incorrect") + } + if pbd.F_BytesRepeated == nil || len(pbd.F_BytesRepeated) == 1 && pbd.F_BytesRepeated[0] == nil { + t.Error("repeated empty bytes field is incorrect") + } + if pbd.F_BytesOptional == nil || len(pbd.F_BytesOptional) != 0 { + t.Error("optional empty bytes field is incorrect") + } +} + +// Test that we encode nil-valued fields of a repeated bytes field correctly. +// Since entries in a repeated field cannot be nil, nil must mean empty value. +func TestEncodeDecodeBytes2(t *testing.T) { + pb := initGoTest(false) + + // Create our bytes + pb.F_BytesRepeated = [][]byte{nil} + + d, err := Marshal(pb) + if err != nil { + t.Error(err) + } + + pbd := new(GoTest) + if err := Unmarshal(d, pbd); err != nil { + t.Error(err) + } + + if len(pbd.F_BytesRepeated) != 1 || pbd.F_BytesRepeated[0] == nil { + t.Error("Unexpected value for repeated bytes field") + } +} + +// All required fields set, defaults provided, all repeated fields given two values. +func TestSkippingUnrecognizedFields(t *testing.T) { + o := old() + pb := initGoTestField() + + // Marshal it normally. + o.Marshal(pb) + + // Now new a GoSkipTest record. + skip := &GoSkipTest{ + SkipInt32: Int32(32), + SkipFixed32: Uint32(3232), + SkipFixed64: Uint64(6464), + SkipString: String("skipper"), + Skipgroup: &GoSkipTest_SkipGroup{ + GroupInt32: Int32(75), + GroupString: String("wxyz"), + }, + } + + // Marshal it into same buffer. + o.Marshal(skip) + + pbd := new(GoTestField) + o.Unmarshal(pbd) + + // The __unrecognized field should be a marshaling of GoSkipTest + skipd := new(GoSkipTest) + + o.SetBuf(pbd.XXX_unrecognized) + o.Unmarshal(skipd) + + if *skipd.SkipInt32 != *skip.SkipInt32 { + t.Error("skip int32", skipd.SkipInt32) + } + if *skipd.SkipFixed32 != *skip.SkipFixed32 { + t.Error("skip fixed32", skipd.SkipFixed32) + } + if *skipd.SkipFixed64 != *skip.SkipFixed64 { + t.Error("skip fixed64", skipd.SkipFixed64) + } + if *skipd.SkipString != *skip.SkipString { + t.Error("skip string", *skipd.SkipString) + } + if *skipd.Skipgroup.GroupInt32 != *skip.Skipgroup.GroupInt32 { + t.Error("skip group int32", skipd.Skipgroup.GroupInt32) + } + if *skipd.Skipgroup.GroupString != *skip.Skipgroup.GroupString { + t.Error("skip group string", *skipd.Skipgroup.GroupString) + } +} + +// Check that unrecognized fields of a submessage are preserved. +func TestSubmessageUnrecognizedFields(t *testing.T) { + nm := &NewMessage{ + Nested: &NewMessage_Nested{ + Name: String("Nigel"), + FoodGroup: String("carbs"), + }, + } + b, err := Marshal(nm) + if err != nil { + t.Fatalf("Marshal of NewMessage: %v", err) + } + + // Unmarshal into an OldMessage. + om := new(OldMessage) + if err := Unmarshal(b, om); err != nil { + t.Fatalf("Unmarshal to OldMessage: %v", err) + } + exp := &OldMessage{ + Nested: &OldMessage_Nested{ + Name: String("Nigel"), + // normal protocol buffer users should not do this + XXX_unrecognized: []byte("\x12\x05carbs"), + }, + } + if !Equal(om, exp) { + t.Errorf("om = %v, want %v", om, exp) + } + + // Clone the OldMessage. + om = Clone(om).(*OldMessage) + if !Equal(om, exp) { + t.Errorf("Clone(om) = %v, want %v", om, exp) + } + + // Marshal the OldMessage, then unmarshal it into an empty NewMessage. + if b, err = Marshal(om); err != nil { + t.Fatalf("Marshal of OldMessage: %v", err) + } + t.Logf("Marshal(%v) -> %q", om, b) + nm2 := new(NewMessage) + if err := Unmarshal(b, nm2); err != nil { + t.Fatalf("Unmarshal to NewMessage: %v", err) + } + if !Equal(nm, nm2) { + t.Errorf("NewMessage round-trip: %v => %v", nm, nm2) + } +} + +// Check that an int32 field can be upgraded to an int64 field. +func TestNegativeInt32(t *testing.T) { + om := &OldMessage{ + Num: Int32(-1), + } + b, err := Marshal(om) + if err != nil { + t.Fatalf("Marshal of OldMessage: %v", err) + } + + // Check the size. It should be 11 bytes; + // 1 for the field/wire type, and 10 for the negative number. + if len(b) != 11 { + t.Errorf("%v marshaled as %q, wanted 11 bytes", om, b) + } + + // Unmarshal into a NewMessage. + nm := new(NewMessage) + if err := Unmarshal(b, nm); err != nil { + t.Fatalf("Unmarshal to NewMessage: %v", err) + } + want := &NewMessage{ + Num: Int64(-1), + } + if !Equal(nm, want) { + t.Errorf("nm = %v, want %v", nm, want) + } +} + +// Check that we can grow an array (repeated field) to have many elements. +// This test doesn't depend only on our encoding; for variety, it makes sure +// we create, encode, and decode the correct contents explicitly. It's therefore +// a bit messier. +// This test also uses (and hence tests) the Marshal/Unmarshal functions +// instead of the methods. +func TestBigRepeated(t *testing.T) { + pb := initGoTest(true) + + // Create the arrays + const N = 50 // Internally the library starts much smaller. + pb.Repeatedgroup = make([]*GoTest_RepeatedGroup, N) + pb.F_Sint64Repeated = make([]int64, N) + pb.F_Sint32Repeated = make([]int32, N) + pb.F_BytesRepeated = make([][]byte, N) + pb.F_StringRepeated = make([]string, N) + pb.F_DoubleRepeated = make([]float64, N) + pb.F_FloatRepeated = make([]float32, N) + pb.F_Uint64Repeated = make([]uint64, N) + pb.F_Uint32Repeated = make([]uint32, N) + pb.F_Fixed64Repeated = make([]uint64, N) + pb.F_Fixed32Repeated = make([]uint32, N) + pb.F_Int64Repeated = make([]int64, N) + pb.F_Int32Repeated = make([]int32, N) + pb.F_BoolRepeated = make([]bool, N) + pb.RepeatedField = make([]*GoTestField, N) + + // Fill in the arrays with checkable values. + igtf := initGoTestField() + igtrg := initGoTest_RepeatedGroup() + for i := 0; i < N; i++ { + pb.Repeatedgroup[i] = igtrg + pb.F_Sint64Repeated[i] = int64(i) + pb.F_Sint32Repeated[i] = int32(i) + s := fmt.Sprint(i) + pb.F_BytesRepeated[i] = []byte(s) + pb.F_StringRepeated[i] = s + pb.F_DoubleRepeated[i] = float64(i) + pb.F_FloatRepeated[i] = float32(i) + pb.F_Uint64Repeated[i] = uint64(i) + pb.F_Uint32Repeated[i] = uint32(i) + pb.F_Fixed64Repeated[i] = uint64(i) + pb.F_Fixed32Repeated[i] = uint32(i) + pb.F_Int64Repeated[i] = int64(i) + pb.F_Int32Repeated[i] = int32(i) + pb.F_BoolRepeated[i] = i%2 == 0 + pb.RepeatedField[i] = igtf + } + + // Marshal. + buf, _ := Marshal(pb) + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + Unmarshal(buf, pbd) + + // Check the checkable values + for i := uint64(0); i < N; i++ { + if pbd.Repeatedgroup[i] == nil { // TODO: more checking? + t.Error("pbd.Repeatedgroup bad") + } + var x uint64 + x = uint64(pbd.F_Sint64Repeated[i]) + if x != i { + t.Error("pbd.F_Sint64Repeated bad", x, i) + } + x = uint64(pbd.F_Sint32Repeated[i]) + if x != i { + t.Error("pbd.F_Sint32Repeated bad", x, i) + } + s := fmt.Sprint(i) + equalbytes(pbd.F_BytesRepeated[i], []byte(s), t) + if pbd.F_StringRepeated[i] != s { + t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i) + } + x = uint64(pbd.F_DoubleRepeated[i]) + if x != i { + t.Error("pbd.F_DoubleRepeated bad", x, i) + } + x = uint64(pbd.F_FloatRepeated[i]) + if x != i { + t.Error("pbd.F_FloatRepeated bad", x, i) + } + x = pbd.F_Uint64Repeated[i] + if x != i { + t.Error("pbd.F_Uint64Repeated bad", x, i) + } + x = uint64(pbd.F_Uint32Repeated[i]) + if x != i { + t.Error("pbd.F_Uint32Repeated bad", x, i) + } + x = pbd.F_Fixed64Repeated[i] + if x != i { + t.Error("pbd.F_Fixed64Repeated bad", x, i) + } + x = uint64(pbd.F_Fixed32Repeated[i]) + if x != i { + t.Error("pbd.F_Fixed32Repeated bad", x, i) + } + x = uint64(pbd.F_Int64Repeated[i]) + if x != i { + t.Error("pbd.F_Int64Repeated bad", x, i) + } + x = uint64(pbd.F_Int32Repeated[i]) + if x != i { + t.Error("pbd.F_Int32Repeated bad", x, i) + } + if pbd.F_BoolRepeated[i] != (i%2 == 0) { + t.Error("pbd.F_BoolRepeated bad", x, i) + } + if pbd.RepeatedField[i] == nil { // TODO: more checking? + t.Error("pbd.RepeatedField bad") + } + } +} + +// Verify we give a useful message when decoding to the wrong structure type. +func TestTypeMismatch(t *testing.T) { + pb1 := initGoTest(true) + + // Marshal + o := old() + o.Marshal(pb1) + + // Now Unmarshal it to the wrong type. + pb2 := initGoTestField() + err := o.Unmarshal(pb2) + if err == nil { + t.Error("expected error, got no error") + } else if !strings.Contains(err.Error(), "bad wiretype") { + t.Error("expected bad wiretype error, got", err) + } +} + +func encodeDecode(t *testing.T, in, out Message, msg string) { + buf, err := Marshal(in) + if err != nil { + t.Fatalf("failed marshaling %v: %v", msg, err) + } + if err := Unmarshal(buf, out); err != nil { + t.Fatalf("failed unmarshaling %v: %v", msg, err) + } +} + +func TestPackedNonPackedDecoderSwitching(t *testing.T) { + np, p := new(NonPackedTest), new(PackedTest) + + // non-packed -> packed + np.A = []int32{0, 1, 1, 2, 3, 5} + encodeDecode(t, np, p, "non-packed -> packed") + if !reflect.DeepEqual(np.A, p.B) { + t.Errorf("failed non-packed -> packed; np.A=%+v, p.B=%+v", np.A, p.B) + } + + // packed -> non-packed + np.Reset() + p.B = []int32{3, 1, 4, 1, 5, 9} + encodeDecode(t, p, np, "packed -> non-packed") + if !reflect.DeepEqual(p.B, np.A) { + t.Errorf("failed packed -> non-packed; p.B=%+v, np.A=%+v", p.B, np.A) + } +} + +func TestProto1RepeatedGroup(t *testing.T) { + pb := &MessageList{ + Message: []*MessageList_Message{ + { + Name: String("blah"), + Count: Int32(7), + }, + // NOTE: pb.Message[1] is a nil + nil, + }, + } + + o := old() + err := o.Marshal(pb) + if err == nil || !strings.Contains(err.Error(), "repeated field Message has nil") { + t.Fatalf("unexpected or no error when marshaling: %v", err) + } +} + +// Test that enums work. Checks for a bug introduced by making enums +// named types instead of int32: newInt32FromUint64 would crash with +// a type mismatch in reflect.PointTo. +func TestEnum(t *testing.T) { + pb := new(GoEnum) + pb.Foo = FOO_FOO1.Enum() + o := old() + if err := o.Marshal(pb); err != nil { + t.Fatal("error encoding enum:", err) + } + pb1 := new(GoEnum) + if err := o.Unmarshal(pb1); err != nil { + t.Fatal("error decoding enum:", err) + } + if *pb1.Foo != FOO_FOO1 { + t.Error("expected 7 but got ", *pb1.Foo) + } +} + +// Enum types have String methods. Check that enum fields can be printed. +// We don't care what the value actually is, just as long as it doesn't crash. +func TestPrintingNilEnumFields(t *testing.T) { + pb := new(GoEnum) + fmt.Sprintf("%+v", pb) +} + +// Verify that absent required fields cause Marshal/Unmarshal to return errors. +func TestRequiredFieldEnforcement(t *testing.T) { + pb := new(GoTestField) + _, err := Marshal(pb) + if err == nil { + t.Error("marshal: expected error, got nil") + } else if strings.Index(err.Error(), "Label") < 0 { + t.Errorf("marshal: bad error type: %v", err) + } + + // A slightly sneaky, yet valid, proto. It encodes the same required field twice, + // so simply counting the required fields is insufficient. + // field 1, encoding 2, value "hi" + buf := []byte("\x0A\x02hi\x0A\x02hi") + err = Unmarshal(buf, pb) + if err == nil { + t.Error("unmarshal: expected error, got nil") + } else if strings.Index(err.Error(), "{Unknown}") < 0 { + t.Errorf("unmarshal: bad error type: %v", err) + } +} + +func TestTypedNilMarshal(t *testing.T) { + // A typed nil should return ErrNil and not crash. + _, err := Marshal((*GoEnum)(nil)) + if err != ErrNil { + t.Errorf("Marshal: got err %v, want ErrNil", err) + } +} + +// A type that implements the Marshaler interface, but is not nillable. +type nonNillableInt uint64 + +func (nni nonNillableInt) Marshal() ([]byte, error) { + return EncodeVarint(uint64(nni)), nil +} + +type NNIMessage struct { + nni nonNillableInt +} + +func (*NNIMessage) Reset() {} +func (*NNIMessage) String() string { return "" } +func (*NNIMessage) ProtoMessage() {} + +// A type that implements the Marshaler interface and is nillable. +type nillableMessage struct { + x uint64 +} + +func (nm *nillableMessage) Marshal() ([]byte, error) { + return EncodeVarint(nm.x), nil +} + +type NMMessage struct { + nm *nillableMessage +} + +func (*NMMessage) Reset() {} +func (*NMMessage) String() string { return "" } +func (*NMMessage) ProtoMessage() {} + +// Verify a type that uses the Marshaler interface, but has a nil pointer. +func TestNilMarshaler(t *testing.T) { + // Try a struct with a Marshaler field that is nil. + // It should be directly marshable. + nmm := new(NMMessage) + if _, err := Marshal(nmm); err != nil { + t.Error("unexpected error marshaling nmm: ", err) + } + + // Try a struct with a Marshaler field that is not nillable. + nnim := new(NNIMessage) + nnim.nni = 7 + var _ Marshaler = nnim.nni // verify it is truly a Marshaler + if _, err := Marshal(nnim); err != nil { + t.Error("unexpected error marshaling nnim: ", err) + } +} + +func TestAllSetDefaults(t *testing.T) { + // Exercise SetDefaults with all scalar field types. + m := &Defaults{ + // NaN != NaN, so override that here. + F_Nan: Float32(1.7), + } + expected := &Defaults{ + F_Bool: Bool(true), + F_Int32: Int32(32), + F_Int64: Int64(64), + F_Fixed32: Uint32(320), + F_Fixed64: Uint64(640), + F_Uint32: Uint32(3200), + F_Uint64: Uint64(6400), + F_Float: Float32(314159), + F_Double: Float64(271828), + F_String: String(`hello, "world!"` + "\n"), + F_Bytes: []byte("Bignose"), + F_Sint32: Int32(-32), + F_Sint64: Int64(-64), + F_Enum: Defaults_GREEN.Enum(), + F_Pinf: Float32(float32(math.Inf(1))), + F_Ninf: Float32(float32(math.Inf(-1))), + F_Nan: Float32(1.7), + StrZero: String(""), + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("SetDefaults failed\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultsWithSetField(t *testing.T) { + // Check that a set value is not overridden. + m := &Defaults{ + F_Int32: Int32(12), + } + SetDefaults(m) + if v := m.GetF_Int32(); v != 12 { + t.Errorf("m.FInt32 = %v, want 12", v) + } +} + +func TestSetDefaultsWithSubMessage(t *testing.T) { + m := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("gopher"), + }, + } + expected := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("gopher"), + Port: Int32(4000), + }, + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultsWithRepeatedSubMessage(t *testing.T) { + m := &MyMessage{ + RepInner: []*InnerMessage{{}}, + } + expected := &MyMessage{ + RepInner: []*InnerMessage{{ + Port: Int32(4000), + }}, + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultWithRepeatedNonMessage(t *testing.T) { + m := &MyMessage{ + Pet: []string{"turtle", "wombat"}, + } + expected := Clone(m) + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestMaximumTagNumber(t *testing.T) { + m := &MaxTag{ + LastField: String("natural goat essence"), + } + buf, err := Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal failed: %v", err) + } + m2 := new(MaxTag) + if err := Unmarshal(buf, m2); err != nil { + t.Fatalf("proto.Unmarshal failed: %v", err) + } + if got, want := m2.GetLastField(), *m.LastField; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func TestJSON(t *testing.T) { + m := &MyMessage{ + Count: Int32(4), + Pet: []string{"bunny", "kitty"}, + Inner: &InnerMessage{ + Host: String("cauchy"), + }, + Bikeshed: MyMessage_GREEN.Enum(), + } + const expected = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":1}` + + b, err := json.Marshal(m) + if err != nil { + t.Fatalf("json.Marshal failed: %v", err) + } + s := string(b) + if s != expected { + t.Errorf("got %s\nwant %s", s, expected) + } + + received := new(MyMessage) + if err := json.Unmarshal(b, received); err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + if !Equal(received, m) { + t.Fatalf("got %s, want %s", received, m) + } + + // Test unmarshalling of JSON with symbolic enum name. + const old = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":"GREEN"}` + received.Reset() + if err := json.Unmarshal([]byte(old), received); err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + if !Equal(received, m) { + t.Fatalf("got %s, want %s", received, m) + } +} + +func TestBadWireType(t *testing.T) { + b := []byte{7<<3 | 6} // field 7, wire type 6 + pb := new(OtherMessage) + if err := Unmarshal(b, pb); err == nil { + t.Errorf("Unmarshal did not fail") + } else if !strings.Contains(err.Error(), "unknown wire type") { + t.Errorf("wrong error: %v", err) + } +} + +func TestBytesWithInvalidLength(t *testing.T) { + // If a byte sequence has an invalid (negative) length, Unmarshal should not panic. + b := []byte{2<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0} + Unmarshal(b, new(MyMessage)) +} + +func TestLengthOverflow(t *testing.T) { + // Overflowing a length should not panic. + b := []byte{2<<3 | WireBytes, 1, 1, 3<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01} + Unmarshal(b, new(MyMessage)) +} + +func TestVarintOverflow(t *testing.T) { + // Overflowing a 64-bit length should not be allowed. + b := []byte{1<<3 | WireVarint, 0x01, 3<<3 | WireBytes, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01} + if err := Unmarshal(b, new(MyMessage)); err == nil { + t.Fatalf("Overflowed uint64 length without error") + } +} + +func TestUnmarshalFuzz(t *testing.T) { + const N = 1000 + seed := time.Now().UnixNano() + t.Logf("RNG seed is %d", seed) + rng := rand.New(rand.NewSource(seed)) + buf := make([]byte, 20) + for i := 0; i < N; i++ { + for j := range buf { + buf[j] = byte(rng.Intn(256)) + } + fuzzUnmarshal(t, buf) + } +} + +func TestMergeMessages(t *testing.T) { + pb := &MessageList{Message: []*MessageList_Message{{Name: String("x"), Count: Int32(1)}}} + data, err := Marshal(pb) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + pb1 := new(MessageList) + if err := Unmarshal(data, pb1); err != nil { + t.Fatalf("first Unmarshal: %v", err) + } + if err := Unmarshal(data, pb1); err != nil { + t.Fatalf("second Unmarshal: %v", err) + } + if len(pb1.Message) != 1 { + t.Errorf("two Unmarshals produced %d Messages, want 1", len(pb1.Message)) + } + + pb2 := new(MessageList) + if err := UnmarshalMerge(data, pb2); err != nil { + t.Fatalf("first UnmarshalMerge: %v", err) + } + if err := UnmarshalMerge(data, pb2); err != nil { + t.Fatalf("second UnmarshalMerge: %v", err) + } + if len(pb2.Message) != 2 { + t.Errorf("two UnmarshalMerges produced %d Messages, want 2", len(pb2.Message)) + } +} + +func TestExtensionMarshalOrder(t *testing.T) { + m := &MyMessage{Count: Int(123)} + if err := SetExtension(m, E_Ext_More, &Ext{Data: String("alpha")}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + if err := SetExtension(m, E_Ext_Text, String("aleph")); err != nil { + t.Fatalf("SetExtension: %v", err) + } + if err := SetExtension(m, E_Ext_Number, Int32(1)); err != nil { + t.Fatalf("SetExtension: %v", err) + } + + // Serialize m several times, and check we get the same bytes each time. + var orig []byte + for i := 0; i < 100; i++ { + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if i == 0 { + orig = b + continue + } + if !bytes.Equal(b, orig) { + t.Errorf("Bytes differ on attempt #%d", i) + } + } +} + +// Many extensions, because small maps might not iterate differently on each iteration. +var exts = []*ExtensionDesc{ + E_X201, + E_X202, + E_X203, + E_X204, + E_X205, + E_X206, + E_X207, + E_X208, + E_X209, + E_X210, + E_X211, + E_X212, + E_X213, + E_X214, + E_X215, + E_X216, + E_X217, + E_X218, + E_X219, + E_X220, + E_X221, + E_X222, + E_X223, + E_X224, + E_X225, + E_X226, + E_X227, + E_X228, + E_X229, + E_X230, + E_X231, + E_X232, + E_X233, + E_X234, + E_X235, + E_X236, + E_X237, + E_X238, + E_X239, + E_X240, + E_X241, + E_X242, + E_X243, + E_X244, + E_X245, + E_X246, + E_X247, + E_X248, + E_X249, + E_X250, +} + +func TestMessageSetMarshalOrder(t *testing.T) { + m := &MyMessageSet{} + for _, x := range exts { + if err := SetExtension(m, x, &Empty{}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + } + + buf, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + // Serialize m several times, and check we get the same bytes each time. + for i := 0; i < 10; i++ { + b1, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if !bytes.Equal(b1, buf) { + t.Errorf("Bytes differ on re-Marshal #%d", i) + } + + m2 := &MyMessageSet{} + if err := Unmarshal(buf, m2); err != nil { + t.Errorf("Unmarshal: %v", err) + } + b2, err := Marshal(m2) + if err != nil { + t.Errorf("re-Marshal: %v", err) + } + if !bytes.Equal(b2, buf) { + t.Errorf("Bytes differ on round-trip #%d", i) + } + } +} + +func TestUnmarshalMergesMessages(t *testing.T) { + // If a nested message occurs twice in the input, + // the fields should be merged when decoding. + a := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("polhode"), + Port: Int32(1234), + }, + } + aData, err := Marshal(a) + if err != nil { + t.Fatalf("Marshal(a): %v", err) + } + b := &OtherMessage{ + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Connected: Bool(true), + }, + } + bData, err := Marshal(b) + if err != nil { + t.Fatalf("Marshal(b): %v", err) + } + want := &OtherMessage{ + Key: Int64(123), + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Port: Int32(1234), + Connected: Bool(true), + }, + } + got := new(OtherMessage) + if err := Unmarshal(append(aData, bData...), got); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + +func TestEncodingSizes(t *testing.T) { + tests := []struct { + m Message + n int + }{ + {&Defaults{F_Int32: Int32(math.MaxInt32)}, 6}, + {&Defaults{F_Int32: Int32(math.MinInt32)}, 11}, + {&Defaults{F_Uint32: Uint32(uint32(math.MaxInt32) + 1)}, 6}, + {&Defaults{F_Uint32: Uint32(math.MaxUint32)}, 6}, + } + for _, test := range tests { + b, err := Marshal(test.m) + if err != nil { + t.Errorf("Marshal(%v): %v", test.m, err) + continue + } + if len(b) != test.n { + t.Errorf("Marshal(%v) yielded %d bytes, want %d bytes", test.m, len(b), test.n) + } + } +} + +func TestRequiredNotSetError(t *testing.T) { + pb := initGoTest(false) + pb.RequiredField.Label = nil + pb.F_Int32Required = nil + pb.F_Int64Required = nil + + expected := "0807" + // field 1, encoding 0, value 7 + "2206" + "120474797065" + // field 4, encoding 2 (GoTestField) + "5001" + // field 10, encoding 0, value 1 + "6d20000000" + // field 13, encoding 5, value 0x20 + "714000000000000000" + // field 14, encoding 1, value 0x40 + "78a019" + // field 15, encoding 0, value 0xca0 = 3232 + "8001c032" + // field 16, encoding 0, value 0x1940 = 6464 + "8d0100004a45" + // field 17, encoding 5, value 3232.0 + "9101000000000040b940" + // field 18, encoding 1, value 6464.0 + "9a0106" + "737472696e67" + // field 19, encoding 2, string "string" + "b304" + // field 70, encoding 3, start group + "ba0408" + "7265717569726564" + // field 71, encoding 2, string "required" + "b404" + // field 70, encoding 4, end group + "aa0605" + "6279746573" + // field 101, encoding 2, string "bytes" + "b0063f" + // field 102, encoding 0, 0x3f zigzag32 + "b8067f" // field 103, encoding 0, 0x7f zigzag64 + + o := old() + bytes, err := Marshal(pb) + if _, ok := err.(*RequiredNotSetError); !ok { + fmt.Printf("marshal-1 err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", bytes) + t.Fatalf("expected = %s", expected) + } + if strings.Index(err.Error(), "RequiredField.Label") < 0 { + t.Errorf("marshal-1 wrong err msg: %v", err) + } + if !equal(bytes, expected, t) { + o.DebugPrint("neq 1", bytes) + t.Fatalf("expected = %s", expected) + } + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + err = Unmarshal(bytes, pbd) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Fatalf("unmarshal err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", bytes) + t.Fatalf("string = %s", expected) + } + if strings.Index(err.Error(), "RequiredField.{Unknown}") < 0 { + t.Errorf("unmarshal wrong err msg: %v", err) + } + bytes, err = Marshal(pbd) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Errorf("marshal-2 err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", bytes) + t.Fatalf("string = %s", expected) + } + if strings.Index(err.Error(), "RequiredField.Label") < 0 { + t.Errorf("marshal-2 wrong err msg: %v", err) + } + if !equal(bytes, expected, t) { + o.DebugPrint("neq 2", bytes) + t.Fatalf("string = %s", expected) + } +} + +func fuzzUnmarshal(t *testing.T, data []byte) { + defer func() { + if e := recover(); e != nil { + t.Errorf("These bytes caused a panic: %+v", data) + t.Logf("Stack:\n%s", debug.Stack()) + t.FailNow() + } + }() + + pb := new(MyMessage) + Unmarshal(data, pb) +} + +func TestMapFieldMarshal(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + } + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + // b should be the concatenation of these three byte sequences in some order. + parts := []string{ + "\n\a\b\x01\x12\x03Rob", + "\n\a\b\x04\x12\x03Ian", + "\n\b\b\x08\x12\x04Dave", + } + ok := false + for i := range parts { + for j := range parts { + if j == i { + continue + } + for k := range parts { + if k == i || k == j { + continue + } + try := parts[i] + parts[j] + parts[k] + if bytes.Equal(b, []byte(try)) { + ok = true + break + } + } + } + } + if !ok { + t.Fatalf("Incorrect Marshal output.\n got %q\nwant %q (or a permutation of that)", b, parts[0]+parts[1]+parts[2]) + } + t.Logf("FYI b: %q", b) + + (new(Buffer)).DebugPrint("Dump of b", b) +} + +func TestMapFieldRoundTrips(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + MsgMapping: map[int64]*FloatingPoint{ + 0x7001: &FloatingPoint{F: Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{ + false: []byte("that's not right!"), + true: []byte("aye, 'tis true!"), + }, + } + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + t.Logf("FYI b: %q", b) + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + for _, pair := range [][2]interface{}{ + {m.NameMapping, m2.NameMapping}, + {m.MsgMapping, m2.MsgMapping}, + {m.ByteMapping, m2.ByteMapping}, + } { + if !reflect.DeepEqual(pair[0], pair[1]) { + t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", pair[0], pair[1]) + } + } +} + +// Benchmarks + +func testMsg() *GoTest { + pb := initGoTest(true) + const N = 1000 // Internally the library starts much smaller. + pb.F_Int32Repeated = make([]int32, N) + pb.F_DoubleRepeated = make([]float64, N) + for i := 0; i < N; i++ { + pb.F_Int32Repeated[i] = int32(i) + pb.F_DoubleRepeated[i] = float64(i) + } + return pb +} + +func bytesMsg() *GoTest { + pb := initGoTest(true) + buf := make([]byte, 4000) + for i := range buf { + buf[i] = byte(i) + } + pb.F_BytesDefaulted = buf + return pb +} + +func benchmarkMarshal(b *testing.B, pb Message, marshal func(Message) ([]byte, error)) { + d, _ := marshal(pb) + b.SetBytes(int64(len(d))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + marshal(pb) + } +} + +func benchmarkBufferMarshal(b *testing.B, pb Message) { + p := NewBuffer(nil) + benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { + p.Reset() + err := p.Marshal(pb0) + return p.Bytes(), err + }) +} + +func benchmarkSize(b *testing.B, pb Message) { + benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { + Size(pb) + return nil, nil + }) +} + +func newOf(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + return reflect.New(in.Type().Elem()).Interface().(Message) +} + +func benchmarkUnmarshal(b *testing.B, pb Message, unmarshal func([]byte, Message) error) { + d, _ := Marshal(pb) + b.SetBytes(int64(len(d))) + pbd := newOf(pb) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + unmarshal(d, pbd) + } +} + +func benchmarkBufferUnmarshal(b *testing.B, pb Message) { + p := NewBuffer(nil) + benchmarkUnmarshal(b, pb, func(d []byte, pb0 Message) error { + p.SetBuf(d) + return p.Unmarshal(pb0) + }) +} + +// Benchmark{Marshal,BufferMarshal,Size,Unmarshal,BufferUnmarshal}{,Bytes} + +func BenchmarkMarshal(b *testing.B) { + benchmarkMarshal(b, testMsg(), Marshal) +} + +func BenchmarkBufferMarshal(b *testing.B) { + benchmarkBufferMarshal(b, testMsg()) +} + +func BenchmarkSize(b *testing.B) { + benchmarkSize(b, testMsg()) +} + +func BenchmarkUnmarshal(b *testing.B) { + benchmarkUnmarshal(b, testMsg(), Unmarshal) +} + +func BenchmarkBufferUnmarshal(b *testing.B) { + benchmarkBufferUnmarshal(b, testMsg()) +} + +func BenchmarkMarshalBytes(b *testing.B) { + benchmarkMarshal(b, bytesMsg(), Marshal) +} + +func BenchmarkBufferMarshalBytes(b *testing.B) { + benchmarkBufferMarshal(b, bytesMsg()) +} + +func BenchmarkSizeBytes(b *testing.B) { + benchmarkSize(b, bytesMsg()) +} + +func BenchmarkUnmarshalBytes(b *testing.B) { + benchmarkUnmarshal(b, bytesMsg(), Unmarshal) +} + +func BenchmarkBufferUnmarshalBytes(b *testing.B) { + benchmarkBufferUnmarshal(b, bytesMsg()) +} + +func BenchmarkUnmarshalUnrecognizedFields(b *testing.B) { + b.StopTimer() + pb := initGoTestField() + skip := &GoSkipTest{ + SkipInt32: Int32(32), + SkipFixed32: Uint32(3232), + SkipFixed64: Uint64(6464), + SkipString: String("skipper"), + Skipgroup: &GoSkipTest_SkipGroup{ + GroupInt32: Int32(75), + GroupString: String("wxyz"), + }, + } + + pbd := new(GoTestField) + p := NewBuffer(nil) + p.Marshal(pb) + p.Marshal(skip) + p2 := NewBuffer(nil) + + b.StartTimer() + for i := 0; i < b.N; i++ { + p2.SetBuf(p.Bytes()) + p2.Unmarshal(pbd) + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go new file mode 100644 index 00000000..6c6a7d95 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go @@ -0,0 +1,197 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer deep copy and merge. +// TODO: MessageSet and RawMessage. + +package proto + +import ( + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + + out := reflect.New(in.Type().Elem()) + // out is empty so a merge is a deep copy. + mergeStruct(out.Elem(), in.Elem()) + return out.Interface().(Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + // Explicit test prior to mergeStruct so that mistyped nils will fail + panic("proto: type mismatch") + } + if in.IsNil() { + // Merging nil into non-nil is a quiet no-op + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i)) + } + + if emIn, ok := in.Addr().Interface().(extendableProto); ok { + emOut := out.Addr().Interface().(extendableProto) + mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap()) + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +func mergeAny(out, in reflect.Value) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(in) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key)) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem()) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i)) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value)) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go new file mode 100644 index 00000000..fa5b792a --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone_test.go @@ -0,0 +1,226 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +var cloneTestMessage = &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &pb.InnerMessage{ + Host: proto.String("niles"), + Port: proto.Int32(9099), + Connected: proto.Bool(true), + }, + Others: []*pb.OtherMessage{ + { + Value: []byte("some bytes"), + }, + }, + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, +} + +func init() { + ext := &pb.Ext{ + Data: proto.String("extension"), + } + if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil { + panic("SetExtension: " + err.Error()) + } +} + +func TestClone(t *testing.T) { + m := proto.Clone(cloneTestMessage).(*pb.MyMessage) + if !proto.Equal(m, cloneTestMessage) { + t.Errorf("Clone(%v) = %v", cloneTestMessage, m) + } + + // Verify it was a deep copy. + *m.Inner.Port++ + if proto.Equal(m, cloneTestMessage) { + t.Error("Mutating clone changed the original") + } + // Byte fields and repeated fields should be copied. + if &m.Pet[0] == &cloneTestMessage.Pet[0] { + t.Error("Pet: repeated field not copied") + } + if &m.Others[0] == &cloneTestMessage.Others[0] { + t.Error("Others: repeated field not copied") + } + if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { + t.Error("Others[0].Value: bytes field not copied") + } + if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { + t.Error("RepBytes: repeated field not copied") + } + if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { + t.Error("RepBytes[0]: bytes field not copied") + } +} + +func TestCloneNil(t *testing.T) { + var m *pb.MyMessage + if c := proto.Clone(m); !proto.Equal(m, c) { + t.Errorf("Clone(%v) = %v", m, c) + } +} + +var mergeTests = []struct { + src, dst, want proto.Message +}{ + { + src: &pb.MyMessage{ + Count: proto.Int32(42), + }, + dst: &pb.MyMessage{ + Name: proto.String("Dave"), + }, + want: &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + }, + }, + { + src: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("hey"), + Connected: proto.Bool(true), + }, + Pet: []string{"horsey"}, + Others: []*pb.OtherMessage{ + { + Value: []byte("some bytes"), + }, + }, + }, + dst: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("niles"), + Port: proto.Int32(9099), + }, + Pet: []string{"bunny", "kitty"}, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(31415926535), + }, + { + // Explicitly test a src=nil field + Inner: nil, + }, + }, + }, + want: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("hey"), + Connected: proto.Bool(true), + Port: proto.Int32(9099), + }, + Pet: []string{"bunny", "kitty", "horsey"}, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(31415926535), + }, + {}, + { + Value: []byte("some bytes"), + }, + }, + }, + }, + { + src: &pb.MyMessage{ + RepBytes: [][]byte{[]byte("wow")}, + }, + dst: &pb.MyMessage{ + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham")}, + }, + want: &pb.MyMessage{ + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, + }, + }, + // Check that a scalar bytes field replaces rather than appends. + { + src: &pb.OtherMessage{Value: []byte("foo")}, + dst: &pb.OtherMessage{Value: []byte("bar")}, + want: &pb.OtherMessage{Value: []byte("foo")}, + }, + { + src: &pb.MessageWithMap{ + NameMapping: map[int32]string{6: "Nigel"}, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + dst: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Bruce", // should be overwritten + 7: "Andrew", + }, + }, + want: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Nigel", + 7: "Andrew", + }, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + }, +} + +func TestMerge(t *testing.T) { + for _, m := range mergeTests { + got := proto.Clone(m.dst) + proto.Merge(got, m.src) + if !proto.Equal(got, m.want) { + t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want) + } + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go new file mode 100644 index 00000000..129792ed --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go @@ -0,0 +1,821 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" + "os" + "reflect" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// The fundamental decoders that interpret bytes on the wire. +// Those that take integer types all return uint64 and are +// therefore of type valueDecoder. + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + // x, n already 0 + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + // x, err already 0 + + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// These are not ValueDecoders: they produce an array of bytes or a string. +// bytes, embedded messages + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +// If the protocol buffer has extensions, and the field matches, add it as an extension. +// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. +func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { + oi := o.index + + err := o.skip(t, tag, wire) + if err != nil { + return err + } + + if !unrecField.IsValid() { + return nil + } + + ptr := structPointer_Bytes(base, unrecField) + + // Add the skipped field to struct field + obuf := o.buf + + o.buf = *ptr + o.EncodeVarint(uint64(tag<<3 | wire)) + *ptr = append(o.buf, obuf[oi:o.index]...) + + o.buf = obuf + + return nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +func (o *Buffer) skip(t reflect.Type, tag, wire int) error { + + var u uint64 + var err error + + switch wire { + case WireVarint: + _, err = o.DecodeVarint() + case WireFixed64: + _, err = o.DecodeFixed64() + case WireBytes: + _, err = o.DecodeRawBytes(false) + case WireFixed32: + _, err = o.DecodeFixed32() + case WireStartGroup: + for { + u, err = o.DecodeVarint() + if err != nil { + break + } + fwire := int(u & 0x7) + if fwire == WireEndGroup { + break + } + ftag := int(u >> 3) + err = o.skip(t, ftag, fwire) + if err != nil { + break + } + } + default: + err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) + } + return err +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The method should reset the receiver before +// decoding starts. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + return UnmarshalMerge(buf, pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + typ, base, err := getbase(pb) + if err != nil { + return err + } + + err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) + + if collectStats { + stats.Decode++ + } + + return err +} + +// unmarshalType does the work of unmarshaling a structure. +func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { + var state errorState + required, reqFields := prop.reqCount, uint64(0) + + var err error + for err == nil && o.index < len(o.buf) { + oi := o.index + var u uint64 + u, err = o.DecodeVarint() + if err != nil { + break + } + wire := int(u & 0x7) + if wire == WireEndGroup { + if is_group { + return nil // input is satisfied + } + return fmt.Errorf("proto: %s: wiretype end group for non-group", st) + } + tag := int(u >> 3) + if tag <= 0 { + return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) + } + fieldnum, ok := prop.decoderTags.get(tag) + if !ok { + // Maybe it's an extension? + if prop.extendable { + if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + ext := e.ExtensionMap()[int32(tag)] // may be missing + ext.enc = append(ext.enc, o.buf[oi:o.index]...) + e.ExtensionMap()[int32(tag)] = ext + } + continue + } + } + err = o.skipAndSave(st, tag, wire, base, prop.unrecField) + continue + } + p := prop.Prop[fieldnum] + + if p.dec == nil { + fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) + continue + } + dec := p.dec + if wire != WireStartGroup && wire != p.WireType { + if wire == WireBytes && p.packedDec != nil { + // a packable field + dec = p.packedDec + } else { + err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) + continue + } + } + decErr := dec(o, p, base) + if decErr != nil && !state.shouldContinue(decErr, p) { + err = decErr + } + if err == nil && p.Required { + // Successfully decoded a required field. + if tag <= 64 { + // use bitmap for fields 1-64 to catch field reuse. + var mask uint64 = 1 << uint64(tag-1) + if reqFields&mask == 0 { + // new required field + reqFields |= mask + required-- + } + } else { + // This is imprecise. It can be fooled by a required field + // with a tag > 64 that is encoded twice; that's very rare. + // A fully correct implementation would require allocating + // a data structure, which we would like to avoid. + required-- + } + } + } + if err == nil { + if is_group { + return io.ErrUnexpectedEOF + } + if state.err != nil { + return state.err + } + if required > 0 { + // Not enough information to determine the exact field. If we use extra + // CPU, we could determine the field only if the missing required field + // has a tag <= 64 and we check reqFields. + return &RequiredNotSetError{"{Unknown}"} + } + } + return err +} + +// Individual type decoders +// For each, +// u is the decoded value, +// v is a pointer to the field (pointer) in the struct + +// Sizes of the pools to allocate inside the Buffer. +// The goal is modest amortization and allocation +// on at least 16-byte boundaries. +const ( + boolPoolSize = 16 + uint32PoolSize = 8 + uint64PoolSize = 4 +) + +// Decode a bool. +func (o *Buffer) dec_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + if len(o.bools) == 0 { + o.bools = make([]bool, boolPoolSize) + } + o.bools[0] = u != 0 + *structPointer_Bool(base, p.field) = &o.bools[0] + o.bools = o.bools[1:] + return nil +} + +func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + *structPointer_BoolVal(base, p.field) = u != 0 + return nil +} + +// Decode an int32. +func (o *Buffer) dec_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) + return nil +} + +func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) + return nil +} + +// Decode an int64. +func (o *Buffer) dec_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, u) + return nil +} + +func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, u) + return nil +} + +// Decode a string. +func (o *Buffer) dec_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_String(base, p.field) = &s + return nil +} + +func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_StringVal(base, p.field) = s + return nil +} + +// Decode a slice of bytes ([]byte). +func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + *structPointer_Bytes(base, p.field) = b + return nil +} + +// Decode a slice of bools ([]bool). +func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + v := structPointer_BoolSlice(base, p.field) + *v = append(*v, u != 0) + return nil +} + +// Decode a slice of bools ([]bool) in packed format. +func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { + v := structPointer_BoolSlice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded bools + + y := *v + for i := 0; i < nb; i++ { + u, err := p.valDec(o) + if err != nil { + return err + } + y = append(y, u != 0) + } + + *v = y + return nil +} + +// Decode a slice of int32s ([]int32). +func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + structPointer_Word32Slice(base, p.field).Append(uint32(u)) + return nil +} + +// Decode a slice of int32s ([]int32) in packed format. +func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int32s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(uint32(u)) + } + return nil +} + +// Decode a slice of int64s ([]int64). +func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + + structPointer_Word64Slice(base, p.field).Append(u) + return nil +} + +// Decode a slice of int64s ([]int64) in packed format. +func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int64s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(u) + } + return nil +} + +// Decode a slice of strings ([]string). +func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + v := structPointer_StringSlice(base, p.field) + *v = append(*v, s) + return nil +} + +// Decode a slice of slice of bytes ([][]byte). +func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + v := structPointer_BytesSlice(base, p.field) + *v = append(*v, b) + return nil +} + +// Decode a map field. +func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + oi := o.index // index at the end of this map entry + o.index -= len(raw) // move buffer back to start of map entry + + mptr := structPointer_Map(base, p.field, p.mtype) // *map[K]V + if mptr.Elem().IsNil() { + mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) + } + v := mptr.Elem() // map[K]V + + // Prepare addressable doubly-indirect placeholders for the key and value types. + // See enc_new_map for why. + keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K + keybase := toStructPointer(keyptr.Addr()) // **K + + var valbase structPointer + var valptr reflect.Value + switch p.mtype.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valptr = reflect.ValueOf(&dummy) // *[]byte + valbase = toStructPointer(valptr) // *[]byte + case reflect.Ptr: + // message; valptr is **Msg; need to allocate the intermediate pointer + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valptr.Set(reflect.New(valptr.Type().Elem())) + valbase = toStructPointer(valptr) + default: + // everything else + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valbase = toStructPointer(valptr.Addr()) // **V + } + + // Decode. + // This parses a restricted wire format, namely the encoding of a message + // with two fields. See enc_new_map for the format. + for o.index < oi { + // tagcode for key and value properties are always a single byte + // because they have tags 1 and 2. + tagcode := o.buf[o.index] + o.index++ + switch tagcode { + case p.mkeyprop.tagcode[0]: + if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { + return err + } + case p.mvalprop.tagcode[0]: + if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { + return err + } + default: + // TODO: Should we silently skip this instead? + return fmt.Errorf("proto: bad map data tag %d", raw[0]) + } + } + + v.SetMapIndex(keyptr.Elem(), valptr.Elem()) + return nil +} + +// Decode a group. +func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + return o.unmarshalType(p.stype, p.sprop, true, bas) +} + +// Decode an embedded message. +func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := structPointer_Interface(bas, p.stype) + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of embedded messages. +func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, false, base) +} + +// Decode a slice of embedded groups. +func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, true, base) +} + +// Decode a slice of structs ([]*struct). +func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { + v := reflect.New(p.stype) + bas := toStructPointer(v) + structPointer_StructPointerSlice(base, p.field).Append(bas) + + if is_group { + err := o.unmarshalType(p.stype, p.sprop, is_group, bas) + return err + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := v.Interface() + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, bas) + + o.buf = obuf + o.index = oi + + return err +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go new file mode 100644 index 00000000..d1abc332 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go @@ -0,0 +1,1288 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "fmt" + "reflect" + "sort" +) + +// RequiredNotSetError is the error returned if Marshal is called with +// a protocol buffer struct whose required fields have not +// all been initialized. It is also the error returned if Unmarshal is +// called with an encoded protocol buffer that does not include all the +// required fields. +// +// When printed, RequiredNotSetError reports the first unset required field in a +// message. If the field cannot be precisely determined, it is reported as +// "{Unknown}". +type RequiredNotSetError struct { + field string +} + +func (e *RequiredNotSetError) Error() string { + return fmt.Sprintf("proto: required field %q not set", e.field) +} + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +func sizeVarint(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +func sizeFixed64(x uint64) int { + return 8 +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +func sizeFixed32(x uint64) int { + return 4 +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +func sizeZigzag64(x uint64) int { + return sizeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +func sizeZigzag32(x uint64) int { + return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +func sizeRawBytes(b []byte) int { + return sizeVarint(uint64(len(b))) + + len(b) +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +func sizeStringBytes(s string) int { + return sizeVarint(uint64(len(s))) + + len(s) +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, returning the data. +func Marshal(pb Message) ([]byte, error) { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + return m.Marshal() + } + p := NewBuffer(nil) + err := p.Marshal(pb) + var state errorState + if err != nil && !state.shouldContinue(err, nil) { + return nil, err + } + if p.buf == nil && err == nil { + // Return a non-nil slice on success. + return []byte{}, nil + } + return p.buf, err +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, writing the result to the +// Buffer. +func (p *Buffer) Marshal(pb Message) error { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + data, err := m.Marshal() + if err != nil { + return err + } + p.buf = append(p.buf, data...) + return nil + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + err = p.enc_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + stats.Encode++ + } + + return err +} + +// Size returns the encoded size of a protocol buffer. +func Size(pb Message) (n int) { + // Can the object marshal itself? If so, Size is slow. + // TODO: add Size to Marshaler, or add a Sizer interface. + if m, ok := pb.(Marshaler); ok { + b, _ := m.Marshal() + return len(b) + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return 0 + } + if err == nil { + n = size_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + stats.Size++ + } + + return +} + +// Individual type encoders. + +// Encode a bool. +func (o *Buffer) enc_bool(p *Properties, base structPointer) error { + v := *structPointer_Bool(base, p.field) + if v == nil { + return ErrNil + } + x := 0 + if *v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + if !v { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, 1) + return nil +} + +func size_bool(p *Properties, base structPointer) int { + v := *structPointer_Bool(base, p.field) + if v == nil { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +func size_proto3_bool(p *Properties, base structPointer) int { + v := *structPointer_BoolVal(base, p.field) + if !v { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode an int32. +func (o *Buffer) enc_int32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a uint32. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := word32_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := word32_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode an int64. +func (o *Buffer) enc_int64(p *Properties, base structPointer) error { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return ErrNil + } + x := word64_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return 0 + } + x := word64_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +func size_proto3_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return 0 + } + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a string. +func (o *Buffer) enc_string(p *Properties, base structPointer) error { + v := *structPointer_String(base, p.field) + if v == nil { + return ErrNil + } + x := *v + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(x) + return nil +} + +func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_string(p *Properties, base structPointer) (n int) { + v := *structPointer_String(base, p.field) + if v == nil { + return 0 + } + x := *v + n += len(p.tagcode) + n += sizeStringBytes(x) + return +} + +func size_proto3_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return 0 + } + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} + +// Encode a message struct. +func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return nil + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +func size_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a group struct. +func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { + var state errorState + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return ErrNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + err := o.enc_struct(p.sprop, b) + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return state.err +} + +func size_struct_group(p *Properties, base structPointer) (n int) { + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return 0 + } + + n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) + n += size_struct(p.sprop, b) + n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return +} + +// Encode a slice of bools ([]bool). +func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + for _, x := range s { + o.buf = append(o.buf, p.tagcode...) + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_bool(p *Properties, base structPointer) int { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + return l * (len(p.tagcode) + 1) // each bool takes exactly one byte +} + +// Encode a slice of bools ([]bool) in packed format. +func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(l)) // each bool takes exactly one byte + for _, x := range s { + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_packed_bool(p *Properties, base structPointer) (n int) { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + n += len(p.tagcode) + n += sizeVarint(uint64(l)) + n += l // each bool takes exactly one byte + return +} + +// Encode a slice of bytes ([]byte). +func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func size_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +// Encode a slice of int32s ([]int32). +func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of int32s ([]int32) in packed format. +func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(buf, uint64(x)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + bufSize += p.valSize(uint64(x)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of uint32s ([]uint32). +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := s.Index(i) + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := s.Index(i) + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of uint32s ([]uint32) in packed format. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, uint64(s.Index(i))) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(uint64(s.Index(i))) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of int64s ([]int64). +func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, s.Index(i)) + } + return nil +} + +func size_slice_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + n += p.valSize(s.Index(i)) + } + return +} + +// Encode a slice of int64s ([]int64) in packed format. +func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, s.Index(i)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(s.Index(i)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of slice of bytes ([][]byte). +func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(ss[i]) + } + return nil +} + +func size_slice_slice_byte(p *Properties, base structPointer) (n int) { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return 0 + } + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeRawBytes(ss[i]) + } + return +} + +// Encode a slice of strings ([]string). +func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(ss[i]) + } + return nil +} + +func size_slice_string(p *Properties, base structPointer) (n int) { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeStringBytes(ss[i]) + } + return +} + +// Encode a slice of message structs ([]*struct). +func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + } + return state.err +} + +func size_slice_struct_message(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += len(p.tagcode) + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +// Encode a slice of group structs ([]*struct). +func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return errRepeatedHasNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + + err := o.enc_struct(p.sprop, b) + + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + } + return state.err +} + +func size_slice_struct_group(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) + n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return // return size up to this point + } + + n += size_struct(p.sprop, b) + } + return +} + +// Encode an extension map. +func (o *Buffer) enc_map(p *Properties, base structPointer) error { + v := *structPointer_ExtMap(base, p.field) + if err := encodeExtensionMap(v); err != nil { + return err + } + // Fast-path for common cases: zero or one extensions. + if len(v) <= 1 { + for _, e := range v { + o.buf = append(o.buf, e.enc...) + } + return nil + } + + // Sort keys to provide a deterministic encoding. + keys := make([]int, 0, len(v)) + for k := range v { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + o.buf = append(o.buf, v[int32(k)].enc...) + } + return nil +} + +func size_map(p *Properties, base structPointer) int { + v := *structPointer_ExtMap(base, p.field) + return sizeExtensionMap(v) +} + +// Encode a map field. +func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { + var state errorState // XXX: or do we need to plumb this through? + + /* + A map defined as + map map_field = N; + is encoded in the same way as + message MapFieldEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapFieldEntry map_field = N; + */ + + v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V + if v.Len() == 0 { + return nil + } + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + enc := func() error { + if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { + return err + } + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil { + return err + } + return nil + } + + keys := v.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := v.MapIndex(key) + + keycopy.Set(key) + valcopy.Set(val) + + o.buf = append(o.buf, p.tagcode...) + if err := o.enc_len_thing(enc, &state); err != nil { + return err + } + } + return nil +} + +func size_new_map(p *Properties, base structPointer) int { + v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + n := 0 + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + keycopy.Set(key) + valcopy.Set(val) + + // Tag codes for key and val are the responsibility of the sub-sizer. + keysize := p.mkeyprop.size(p.mkeyprop, keybase) + valsize := p.mvalprop.size(p.mvalprop, valbase) + entry := keysize + valsize + // Add on tag code and length of map entry itself. + n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry + } + return n +} + +// mapEncodeScratch returns a new reflect.Value matching the map's value type, +// and a structPointer suitable for passing to an encoder or sizer. +func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { + // Prepare addressable doubly-indirect placeholders for the key and value types. + // This is needed because the element-type encoders expect **T, but the map iteration produces T. + + keycopy = reflect.New(mapType.Key()).Elem() // addressable K + keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K + keyptr.Set(keycopy.Addr()) // + keybase = toStructPointer(keyptr.Addr()) // **K + + // Value types are more varied and require special handling. + switch mapType.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte + valbase = toStructPointer(valcopy.Addr()) + case reflect.Ptr: + // message; the generated field type is map[K]*Msg (so V is *Msg), + // so we only need one level of indirection. + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valbase = toStructPointer(valcopy.Addr()) + default: + // everything else + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V + valptr.Set(valcopy.Addr()) // + valbase = toStructPointer(valptr.Addr()) // **V + } + return +} + +// Encode a struct. +func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { + var state errorState + // Encode fields in tag order so that decoders may use optimizations + // that depend on the ordering. + // https://developers.google.com/protocol-buffers/docs/encoding#order + for _, i := range prop.order { + p := prop.Prop[i] + if p.enc != nil { + err := p.enc(o, p, base) + if err != nil { + if err == ErrNil { + if p.Required && state.err == nil { + state.err = &RequiredNotSetError{p.Name} + } + } else if err == errRepeatedHasNil { + // Give more context to nil values in repeated fields. + return errors.New("repeated field " + p.OrigName + " has nil element") + } else if !state.shouldContinue(err, p) { + return err + } + } + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + if len(v) > 0 { + o.buf = append(o.buf, v...) + } + } + + return state.err +} + +func size_struct(prop *StructProperties, base structPointer) (n int) { + for _, i := range prop.order { + p := prop.Prop[i] + if p.size != nil { + n += p.size(p, base) + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + n += len(v) + } + + return +} + +var zeroes [20]byte // longer than any conceivable sizeVarint + +// Encode a struct, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { + return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) +} + +// Encode something, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { + iLen := len(o.buf) + o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length + iMsg := len(o.buf) + err := enc() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + lMsg := len(o.buf) - iMsg + lLen := sizeVarint(uint64(lMsg)) + switch x := lLen - (iMsg - iLen); { + case x > 0: // actual length is x bytes larger than the space we reserved + // Move msg x bytes right. + o.buf = append(o.buf, zeroes[:x]...) + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + case x < 0: // actual length is x bytes smaller than the space we reserved + // Move msg x bytes left. + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + o.buf = o.buf[:len(o.buf)+x] // x is negative + } + // Encode the length in the reserved space. + o.buf = o.buf[:iLen] + o.EncodeVarint(uint64(lMsg)) + o.buf = o.buf[:len(o.buf)+lMsg] + return state.err +} + +// errorState maintains the first error that occurs and updates that error +// with additional context. +type errorState struct { + err error +} + +// shouldContinue reports whether encoding should continue upon encountering the +// given error. If the error is RequiredNotSetError, shouldContinue returns true +// and, if this is the first appearance of that error, remembers it for future +// reporting. +// +// If prop is not nil, it may update any error with additional context about the +// field with the error. +func (s *errorState) shouldContinue(err error, prop *Properties) bool { + // Ignore unset required fields. + reqNotSet, ok := err.(*RequiredNotSetError) + if !ok { + return false + } + if s.err == nil { + if prop != nil { + err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} + } + s.err = err + } + return true +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go new file mode 100644 index 00000000..d8673a3e --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go @@ -0,0 +1,256 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer comparison. +// TODO: MessageSet. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal (a "bytes" field, + although represented by []byte, is not a repeated field) + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + b1, ok := f1.Interface().(raw) + if ok { + b2 := f2.Interface().(raw) + // RawMessage + if !bytes.Equal(b1.Bytes(), b2.Bytes()) { + return false + } + continue + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + if !bytes.Equal(u1, u2) { + return false + } + + return true +} + +// v1 and v2 are known to have the same type. +func equalAny(v1, v2 reflect.Value) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2) { + return false + } + } + return true + case reflect.Ptr: + return equalAny(v1.Elem(), v2.Elem()) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i)) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// em1 and em2 are extension maps. +func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + continue + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) { + return false + } + } + + return true +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go new file mode 100644 index 00000000..b09684ff --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal_test.go @@ -0,0 +1,191 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +// Four identical base messages. +// The init function adds extensions to some of them. +var messageWithoutExtension = &pb.MyMessage{Count: Int32(7)} +var messageWithExtension1a = &pb.MyMessage{Count: Int32(7)} +var messageWithExtension1b = &pb.MyMessage{Count: Int32(7)} +var messageWithExtension2 = &pb.MyMessage{Count: Int32(7)} + +// Two messages with non-message extensions. +var messageWithInt32Extension1 = &pb.MyMessage{Count: Int32(8)} +var messageWithInt32Extension2 = &pb.MyMessage{Count: Int32(8)} + +func init() { + ext1 := &pb.Ext{Data: String("Kirk")} + ext2 := &pb.Ext{Data: String("Picard")} + + // messageWithExtension1a has ext1, but never marshals it. + if err := SetExtension(messageWithExtension1a, pb.E_Ext_More, ext1); err != nil { + panic("SetExtension on 1a failed: " + err.Error()) + } + + // messageWithExtension1b is the unmarshaled form of messageWithExtension1a. + if err := SetExtension(messageWithExtension1b, pb.E_Ext_More, ext1); err != nil { + panic("SetExtension on 1b failed: " + err.Error()) + } + buf, err := Marshal(messageWithExtension1b) + if err != nil { + panic("Marshal of 1b failed: " + err.Error()) + } + messageWithExtension1b.Reset() + if err := Unmarshal(buf, messageWithExtension1b); err != nil { + panic("Unmarshal of 1b failed: " + err.Error()) + } + + // messageWithExtension2 has ext2. + if err := SetExtension(messageWithExtension2, pb.E_Ext_More, ext2); err != nil { + panic("SetExtension on 2 failed: " + err.Error()) + } + + if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(23)); err != nil { + panic("SetExtension on Int32-1 failed: " + err.Error()) + } + if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(24)); err != nil { + panic("SetExtension on Int32-2 failed: " + err.Error()) + } +} + +var EqualTests = []struct { + desc string + a, b Message + exp bool +}{ + {"different types", &pb.GoEnum{}, &pb.GoTestField{}, false}, + {"equal empty", &pb.GoEnum{}, &pb.GoEnum{}, true}, + {"nil vs nil", nil, nil, true}, + {"typed nil vs typed nil", (*pb.GoEnum)(nil), (*pb.GoEnum)(nil), true}, + {"typed nil vs empty", (*pb.GoEnum)(nil), &pb.GoEnum{}, false}, + {"different typed nil", (*pb.GoEnum)(nil), (*pb.GoTestField)(nil), false}, + + {"one set field, one unset field", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{}, false}, + {"one set field zero, one unset field", &pb.GoTest{Param: Int32(0)}, &pb.GoTest{}, false}, + {"different set fields", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("bar")}, false}, + {"equal set", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("foo")}, true}, + + {"repeated, one set", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{}, false}, + {"repeated, different length", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{F_Int32Repeated: []int32{2}}, false}, + {"repeated, different value", &pb.GoTest{F_Int32Repeated: []int32{2}}, &pb.GoTest{F_Int32Repeated: []int32{3}}, false}, + {"repeated, equal", &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, true}, + {"repeated, nil equal nil", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: nil}, true}, + {"repeated, nil equal empty", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: []int32{}}, true}, + {"repeated, empty equal nil", &pb.GoTest{F_Int32Repeated: []int32{}}, &pb.GoTest{F_Int32Repeated: nil}, true}, + + { + "nested, different", + &pb.GoTest{RequiredField: &pb.GoTestField{Label: String("foo")}}, + &pb.GoTest{RequiredField: &pb.GoTestField{Label: String("bar")}}, + false, + }, + { + "nested, equal", + &pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}}, + &pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}}, + true, + }, + + {"bytes", &pb.OtherMessage{Value: []byte("foo")}, &pb.OtherMessage{Value: []byte("foo")}, true}, + {"bytes, empty", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: []byte{}}, true}, + {"bytes, empty vs nil", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: nil}, false}, + { + "repeated bytes", + &pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}}, + &pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}}, + true, + }, + + {"extension vs. no extension", messageWithoutExtension, messageWithExtension1a, false}, + {"extension vs. same extension", messageWithExtension1a, messageWithExtension1b, true}, + {"extension vs. different extension", messageWithExtension1a, messageWithExtension2, false}, + + {"int32 extension vs. itself", messageWithInt32Extension1, messageWithInt32Extension1, true}, + {"int32 extension vs. a different int32", messageWithInt32Extension1, messageWithInt32Extension2, false}, + + { + "message with group", + &pb.MyMessage{ + Count: Int32(1), + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: Int32(5), + }, + }, + &pb.MyMessage{ + Count: Int32(1), + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: Int32(5), + }, + }, + true, + }, + + { + "map same", + &pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, + &pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, + true, + }, + { + "map different entry", + &pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, + &pb.MessageWithMap{NameMapping: map[int32]string{2: "Rob"}}, + false, + }, + { + "map different key only", + &pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, + &pb.MessageWithMap{NameMapping: map[int32]string{2: "Ken"}}, + false, + }, + { + "map different value only", + &pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, + &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob"}}, + false, + }, +} + +func TestEqual(t *testing.T) { + for _, tc := range EqualTests { + if res := Equal(tc.a, tc.b); res != tc.exp { + t.Errorf("%v: Equal(%v, %v) = %v, want %v", tc.desc, tc.a, tc.b, res, tc.exp) + } + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go new file mode 100644 index 00000000..5f62dff2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go @@ -0,0 +1,362 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base extendableProto, id int32, b []byte) { + base.ExtensionMap()[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extendableProto, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + // Check the extended type. + if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b { + return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m. +func encodeExtensionMap(m map[int32]Extension) error { + for k, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + m[k] = e + } + return nil +} + +func sizeExtensionMap(m map[int32]Extension) (n int) { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + n += props.size(props, toStructPointer(x)) + } + return +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { + // TODO: Check types, field numbers, etc.? + _, ok := pb.ExtensionMap()[extension.Field] + return ok +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb extendableProto, extension *ExtensionDesc) { + // TODO: Check types, field numbers, etc.? + delete(pb.ExtensionMap(), extension.Field) +} + +// GetExtension parses and returns the given extension of pb. +// If the extension is not present it returns ErrMissingExtension. +func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) { + if err := checkExtensionTypes(pb, extension); err != nil { + return nil, err + } + + emap := pb.ExtensionMap() + e, ok := emap[extension.Field] + if !ok { + return nil, ErrMissingExtension + } + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + o := NewBuffer(b) + + t := reflect.TypeOf(extension.ExtensionType) + rep := extension.repeated() + + props := extensionProperties(extension) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate a "field" to store the pointer/slice itself; the + // pointer/slice will be stored here. We pass + // the address of this field to props.dec. + // This passes a zero field and a *t and lets props.dec + // interpret it as a *struct{ x t }. + value := reflect.New(t).Elem() + + for { + // Discard wire type and field number varint. It isn't needed. + if _, err := o.DecodeVarint(); err != nil { + return nil, err + } + + if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { + return nil, err + } + + if !rep || o.index >= len(o.buf) { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + epb, ok := pb.(extendableProto) + if !ok { + err = errors.New("proto: not an extendable proto") + return + } + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(epb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error { + if err := checkExtensionTypes(pb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return errors.New("proto: bad extension value type") + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go new file mode 100644 index 00000000..ea7542a0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions_test.go @@ -0,0 +1,153 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +func TestGetExtensionsWithMissingExtensions(t *testing.T) { + msg := &pb.MyMessage{} + ext1 := &pb.Ext{} + if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil { + t.Fatalf("Could not set ext1: %s", ext1) + } + exts, err := proto.GetExtensions(msg, []*proto.ExtensionDesc{ + pb.E_Ext_More, + pb.E_Ext_Text, + }) + if err != nil { + t.Fatalf("GetExtensions() failed: %s", err) + } + if exts[0] != ext1 { + t.Errorf("ext1 not in returned extensions: %T %v", exts[0], exts[0]) + } + if exts[1] != nil { + t.Errorf("ext2 in returned extensions: %T %v", exts[1], exts[1]) + } +} + +func TestGetExtensionStability(t *testing.T) { + check := func(m *pb.MyMessage) bool { + ext1, err := proto.GetExtension(m, pb.E_Ext_More) + if err != nil { + t.Fatalf("GetExtension() failed: %s", err) + } + ext2, err := proto.GetExtension(m, pb.E_Ext_More) + if err != nil { + t.Fatalf("GetExtension() failed: %s", err) + } + return ext1 == ext2 + } + msg := &pb.MyMessage{Count: proto.Int32(4)} + ext0 := &pb.Ext{} + if err := proto.SetExtension(msg, pb.E_Ext_More, ext0); err != nil { + t.Fatalf("Could not set ext1: %s", ext0) + } + if !check(msg) { + t.Errorf("GetExtension() not stable before marshaling") + } + bb, err := proto.Marshal(msg) + if err != nil { + t.Fatalf("Marshal() failed: %s", err) + } + msg1 := &pb.MyMessage{} + err = proto.Unmarshal(bb, msg1) + if err != nil { + t.Fatalf("Unmarshal() failed: %s", err) + } + if !check(msg1) { + t.Errorf("GetExtension() not stable after unmarshaling") + } +} + +func TestExtensionsRoundTrip(t *testing.T) { + msg := &pb.MyMessage{} + ext1 := &pb.Ext{ + Data: proto.String("hi"), + } + ext2 := &pb.Ext{ + Data: proto.String("there"), + } + exists := proto.HasExtension(msg, pb.E_Ext_More) + if exists { + t.Error("Extension More present unexpectedly") + } + if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil { + t.Error(err) + } + if err := proto.SetExtension(msg, pb.E_Ext_More, ext2); err != nil { + t.Error(err) + } + e, err := proto.GetExtension(msg, pb.E_Ext_More) + if err != nil { + t.Error(err) + } + x, ok := e.(*pb.Ext) + if !ok { + t.Errorf("e has type %T, expected testdata.Ext", e) + } else if *x.Data != "there" { + t.Errorf("SetExtension failed to overwrite, got %+v, not 'there'", x) + } + proto.ClearExtension(msg, pb.E_Ext_More) + if _, err = proto.GetExtension(msg, pb.E_Ext_More); err != proto.ErrMissingExtension { + t.Errorf("got %v, expected ErrMissingExtension", e) + } + if _, err := proto.GetExtension(msg, pb.E_X215); err == nil { + t.Error("expected bad extension error, got nil") + } + if err := proto.SetExtension(msg, pb.E_X215, 12); err == nil { + t.Error("expected extension err") + } + if err := proto.SetExtension(msg, pb.E_Ext_More, 12); err == nil { + t.Error("expected some sort of type mismatch error, got nil") + } +} + +func TestNilExtension(t *testing.T) { + msg := &pb.MyMessage{ + Count: proto.Int32(1), + } + if err := proto.SetExtension(msg, pb.E_Ext_Text, proto.String("hello")); err != nil { + t.Fatal(err) + } + if err := proto.SetExtension(msg, pb.E_Ext_More, (*pb.Ext)(nil)); err == nil { + t.Error("expected SetExtension to fail due to a nil extension") + } else if want := "proto: SetExtension called with nil value of type *testdata.Ext"; err.Error() != want { + t.Errorf("expected error %v, got %v", want, err) + } + // Note: if the behavior of Marshal is ever changed to ignore nil extensions, update + // this test to verify that E_Ext_Text is properly propagated through marshal->unmarshal. +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go new file mode 100644 index 00000000..fb139f6b --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go @@ -0,0 +1,790 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* + Package proto converts data structures to and from the wire format of + protocol buffers. It works in concert with the Go source code generated + for .proto files by the protocol compiler. + + A summary of the properties of the protocol buffer interface + for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Marshal and Unmarshal are functions to encode and decode the wire format. + + The simplest way to describe this is to see an example. + Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + } + + The resulting file, test.pb.go, is: + + package example + + import proto "github.com/golang/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + + To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/golang/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "strconv" + "sync" +) + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// Stats records allocation details about the protocol buffer encoders +// and decoders. Useful for tuning the library itself. +type Stats struct { + Emalloc uint64 // mallocs in encode + Dmalloc uint64 // mallocs in decode + Encode uint64 // number of encodes + Decode uint64 // number of decodes + Chit uint64 // number of cache hits + Cmiss uint64 // number of cache misses + Size uint64 // number of sizes +} + +// Set to true to enable stats collection. +const collectStats = false + +var stats Stats + +// GetStats returns a copy of the global Stats structure. +func GetStats() Stats { return stats } + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // write point + + // pools of basic types to amortize allocation. + bools []bool + uint32s []uint32 + uint64s []uint64 + + // extra pools, only used with pointer_reflect.go + int32s []int32 + int64s []int64 + float32s []float32 + float64s []float64 +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (o *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := o.buf + index := o.index + o.buf = b + o.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := o.index + if index == len(o.buf) { + break + } + + op, err := o.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = o.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = o.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = o.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + break + + case WireVarint: + u, err = o.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + if err != nil { + fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + if err != nil { + fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth) + } + fmt.Printf("\n") + + o.buf = obuf + o.index = index +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a pointer to a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + v = v.Elem() + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + var canHaveDefault, nestedMessage bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + dm.nested = append(dm.nested, fi) + } + continue + } + + sf := scalarField{ + index: fi, + kind: ft.Elem().Kind(), + } + + // scalar fields without defaults + if !prop.HasDefault { + dm.scalars = append(dm.scalars, sf) + continue + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + log.Printf("proto: bad default bool %q: %v", prop.Default, err) + continue + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + log.Printf("proto: bad default float32 %q: %v", prop.Default, err) + continue + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + log.Printf("proto: bad default float64 %q: %v", prop.Default, err) + continue + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + log.Printf("proto: bad default int32 %q: %v", prop.Default, err) + continue + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + log.Printf("proto: bad default int64 %q: %v", prop.Default, err) + continue + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + log.Printf("proto: bad default uint32 %q: %v", prop.Default, err) + continue + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + log.Printf("proto: bad default uint64 %q: %v", prop.Default, err) + continue + } + sf.value = x + default: + log.Printf("proto: unhandled def kind %v", ft.Elem().Kind()) + continue + } + + dm.scalars = append(dm.scalars, sf) + } + + return dm +} + +// Map fields may have key types of non-float scalars, strings and enums. +// The easiest way to sort them in some deterministic order is to use fmt. +// If this turns out to be inefficient we can always consider other options, +// such as doing a Schwartzian transform. + +type mapKeys []reflect.Value + +func (s mapKeys) Len() int { return len(s) } +func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s mapKeys) Less(i, j int) bool { + return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface()) +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go new file mode 100644 index 00000000..9d912bce --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go @@ -0,0 +1,287 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Support for message sets. + */ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" +) + +// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var ErrNoMessageTypeId = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and MessageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. +// +// When a proto1 proto has a field that looks like: +// optional message info = 3; +// the protocol compiler produces a field in the generated struct that looks like: +// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"` +// The package is automatically inserted so there is no need for that proto file to +// import this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type MessageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure MessageSet is a Message. +var _ Message = (*MessageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *MessageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *MessageSet) Has(pb Message) bool { + if ms.find(pb) != nil { + return true + } + return false +} + +func (ms *MessageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return ErrNoMessageTypeId + } + return nil // TODO: return error instead? +} + +func (ms *MessageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return ErrNoMessageTypeId + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *MessageSet) Reset() { *ms = MessageSet{} } +func (ms *MessageSet) String() string { return CompactTextString(ms) } +func (*MessageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// MarshalMessageSet encodes the extension map represented by m in the message set wire format. +// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { + if err := encodeExtensionMap(m); err != nil { + return nil, err + } + + // Sort extension IDs to provide a deterministic encoding. + // See also enc_map in encode.go. + ids := make([]int, 0, len(m)) + for id := range m { + ids = append(ids, int(id)) + } + sort.Ints(ids) + + ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))} + for _, id := range ids { + e := m[int32(id)] + // Remove the wire type and field number varint, as well as the length varint. + msg := skipVarint(skipVarint(e.enc)) + + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: Int32(int32(id)), + Message: msg, + }) + } + return Marshal(ms) +} + +// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { + ms := new(MessageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} + +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + if i > 0 { + b.WriteByte(',') + } + + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + +// A global registry of types that can be used in a MessageSet. + +var messageSetMap = make(map[int32]messageSetDesc) + +type messageSetDesc struct { + t reflect.Type // pointer to struct + name string +} + +// RegisterMessageSetType is called from the generated code. +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), + name: name, + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go new file mode 100644 index 00000000..7c29bccf --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set_test.go @@ -0,0 +1,66 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "bytes" + "testing" +) + +func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { + // Check that a repeated message set entry will be concatenated. + in := &MessageSet{ + Item: []*_MessageSet_Item{ + {TypeId: Int32(12345), Message: []byte("hoo")}, + {TypeId: Int32(12345), Message: []byte("hah")}, + }, + } + b, err := Marshal(in) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + t.Logf("Marshaled bytes: %q", b) + + m := make(map[int32]Extension) + if err := UnmarshalMessageSet(b, m); err != nil { + t.Fatalf("UnmarshalMessageSet: %v", err) + } + ext, ok := m[12345] + if !ok { + t.Fatalf("Didn't retrieve extension 12345; map is %v", m) + } + // Skip wire type/field number and length varints. + got := skipVarint(skipVarint(ext.enc)) + if want := []byte("hoohah"); !bytes.Equal(got, want) { + t.Errorf("Combined extension is %q, want %q", got, want) + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go new file mode 100644 index 00000000..c68b1252 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go @@ -0,0 +1,479 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build appengine + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "math" + "reflect" +) + +// A structPointer is a pointer to a struct. +type structPointer struct { + v reflect.Value +} + +// toStructPointer returns a structPointer equivalent to the given reflect value. +// The reflect value must itself be a pointer to a struct. +func toStructPointer(v reflect.Value) structPointer { + return structPointer{v} +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p.v.IsNil() +} + +// Interface returns the struct pointer as an interface value. +func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { + return p.v.Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// field returns the given field in the struct as a reflect value. +func structPointer_field(p structPointer, f field) reflect.Value { + // Special case: an extension map entry with a value of type T + // passes a *T to the struct-handling code with a zero field, + // expecting that it will be treated as equivalent to *struct{ X T }, + // which has the same memory layout. We have to handle that case + // specially, because reflect will panic if we call FieldByIndex on a + // non-struct. + if f == nil { + return p.v.Elem() + } + + return p.v.Elem().FieldByIndex(f) +} + +// ifield returns the given field in the struct as an interface value. +func structPointer_ifield(p structPointer, f field) interface{} { + return structPointer_field(p, f).Addr().Interface() +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return structPointer_ifield(p, f).(*[]byte) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return structPointer_ifield(p, f).(*[][]byte) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return structPointer_ifield(p, f).(**bool) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return structPointer_ifield(p, f).(*bool) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return structPointer_ifield(p, f).(*[]bool) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return structPointer_ifield(p, f).(**string) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return structPointer_ifield(p, f).(*string) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return structPointer_ifield(p, f).(*[]string) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return structPointer_ifield(p, f).(*map[int32]Extension) +} + +// Map returns the reflect.Value for the address of a map field in the struct. +func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { + return structPointer_field(p, f).Addr() +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + structPointer_field(p, f).Set(q.v) +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return structPointer{structPointer_field(p, f)} +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { + return structPointerSlice{structPointer_field(p, f)} +} + +// A structPointerSlice represents the address of a slice of pointers to structs +// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. +type structPointerSlice struct { + v reflect.Value +} + +func (p structPointerSlice) Len() int { return p.v.Len() } +func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } +func (p structPointerSlice) Append(q structPointer) { + p.v.Set(reflect.Append(p.v, q.v)) +} + +var ( + int32Type = reflect.TypeOf(int32(0)) + uint32Type = reflect.TypeOf(uint32(0)) + float32Type = reflect.TypeOf(float32(0)) + int64Type = reflect.TypeOf(int64(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float64Type = reflect.TypeOf(float64(0)) +) + +// A word32 represents a field of type *int32, *uint32, *float32, or *enum. +// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. +type word32 struct { + v reflect.Value +} + +// IsNil reports whether p is nil. +func word32_IsNil(p word32) bool { + return p.v.IsNil() +} + +// Set sets p to point at a newly allocated word with bits set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + t := p.v.Type().Elem() + switch t { + case int32Type: + if len(o.int32s) == 0 { + o.int32s = make([]int32, uint32PoolSize) + } + o.int32s[0] = int32(x) + p.v.Set(reflect.ValueOf(&o.int32s[0])) + o.int32s = o.int32s[1:] + return + case uint32Type: + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + p.v.Set(reflect.ValueOf(&o.uint32s[0])) + o.uint32s = o.uint32s[1:] + return + case float32Type: + if len(o.float32s) == 0 { + o.float32s = make([]float32, uint32PoolSize) + } + o.float32s[0] = math.Float32frombits(x) + p.v.Set(reflect.ValueOf(&o.float32s[0])) + o.float32s = o.float32s[1:] + return + } + + // must be enum + p.v.Set(reflect.New(t)) + p.v.Elem().SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32_Get(p word32) uint32 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32{structPointer_field(p, f)} +} + +// A word32Val represents a field of type int32, uint32, float32, or enum. +// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. +type word32Val struct { + v reflect.Value +} + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + switch p.v.Type() { + case int32Type: + p.v.SetInt(int64(x)) + return + case uint32Type: + p.v.SetUint(uint64(x)) + return + case float32Type: + p.v.SetFloat(float64(math.Float32frombits(x))) + return + } + + // must be enum + p.v.SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32Val_Get(p word32Val) uint32 { + elem := p.v + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val{structPointer_field(p, f)} +} + +// A word32Slice is a slice of 32-bit values. +// That is, v.Type() is []int32, []uint32, []float32, or []enum. +type word32Slice struct { + v reflect.Value +} + +func (p word32Slice) Append(x uint32) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int32: + elem.SetInt(int64(int32(x))) + case reflect.Uint32: + elem.SetUint(uint64(x)) + case reflect.Float32: + elem.SetFloat(float64(math.Float32frombits(x))) + } +} + +func (p word32Slice) Len() int { + return p.v.Len() +} + +func (p word32Slice) Index(i int) uint32 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) word32Slice { + return word32Slice{structPointer_field(p, f)} +} + +// word64 is like word32 but for 64-bit values. +type word64 struct { + v reflect.Value +} + +func word64_Set(p word64, o *Buffer, x uint64) { + t := p.v.Type().Elem() + switch t { + case int64Type: + if len(o.int64s) == 0 { + o.int64s = make([]int64, uint64PoolSize) + } + o.int64s[0] = int64(x) + p.v.Set(reflect.ValueOf(&o.int64s[0])) + o.int64s = o.int64s[1:] + return + case uint64Type: + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + p.v.Set(reflect.ValueOf(&o.uint64s[0])) + o.uint64s = o.uint64s[1:] + return + case float64Type: + if len(o.float64s) == 0 { + o.float64s = make([]float64, uint64PoolSize) + } + o.float64s[0] = math.Float64frombits(x) + p.v.Set(reflect.ValueOf(&o.float64s[0])) + o.float64s = o.float64s[1:] + return + } + panic("unreachable") +} + +func word64_IsNil(p word64) bool { + return p.v.IsNil() +} + +func word64_Get(p word64) uint64 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64{structPointer_field(p, f)} +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val struct { + v reflect.Value +} + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + switch p.v.Type() { + case int64Type: + p.v.SetInt(int64(x)) + return + case uint64Type: + p.v.SetUint(x) + return + case float64Type: + p.v.SetFloat(math.Float64frombits(x)) + return + } + panic("unreachable") +} + +func word64Val_Get(p word64Val) uint64 { + elem := p.v + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val{structPointer_field(p, f)} +} + +type word64Slice struct { + v reflect.Value +} + +func (p word64Slice) Append(x uint64) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int64: + elem.SetInt(int64(int64(x))) + case reflect.Uint64: + elem.SetUint(uint64(x)) + case reflect.Float64: + elem.SetFloat(float64(math.Float64frombits(x))) + } +} + +func (p word64Slice) Len() int { + return p.v.Len() +} + +func (p word64Slice) Index(i int) uint64 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return uint64(elem.Uint()) + case reflect.Float64: + return math.Float64bits(float64(elem.Float())) + } + panic("unreachable") +} + +func structPointer_Word64Slice(p structPointer, f field) word64Slice { + return word64Slice{structPointer_field(p, f)} +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go new file mode 100644 index 00000000..48bc0fa4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,266 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !appengine + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +// NOTE: These type_Foo functions would more idiomatically be methods, +// but Go does not allow methods on pointer types, and we must preserve +// some pointer type for the garbage collector. We use these +// funcs with clunky names as our poor approximation to methods. +// +// An alternative would be +// type structPointer struct { p unsafe.Pointer } +// but that does not registerize as well. + +// A structPointer is a pointer to a struct. +type structPointer unsafe.Pointer + +// toStructPointer returns a structPointer equivalent to the given reflect value. +func toStructPointer(v reflect.Value) structPointer { + return structPointer(unsafe.Pointer(v.Pointer())) +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p == nil +} + +// Interface returns the struct pointer, assumed to have element type t, +// as an interface value. +func structPointer_Interface(p structPointer, t reflect.Type) interface{} { + return reflect.NewAt(t, unsafe.Pointer(p)).Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != ^field(0) +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// Map returns the reflect.Value for the address of a map field in the struct. +func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { + return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { + return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). +type structPointerSlice []structPointer + +func (v *structPointerSlice) Len() int { return len(*v) } +func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } +func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } + +// A word32 is the address of a "pointer to 32-bit value" field. +type word32 **uint32 + +// IsNil reports whether *v is nil. +func word32_IsNil(p word32) bool { + return *p == nil +} + +// Set sets *v to point at a newly allocated word set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + *p = &o.uint32s[0] + o.uint32s = o.uint32s[1:] +} + +// Get gets the value pointed at by *v. +func word32_Get(p word32) uint32 { + return **p +} + +// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Val is the address of a 32-bit value field. +type word32Val *uint32 + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + *p = x +} + +// Get gets the value pointed at by p. +func word32Val_Get(p word32Val) uint32 { + return *p +} + +// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Slice is a slice of 32-bit values. +type word32Slice []uint32 + +func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } +func (v *word32Slice) Len() int { return len(*v) } +func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } + +// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) *word32Slice { + return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// word64 is like word32 but for 64-bit values. +type word64 **uint64 + +func word64_Set(p word64, o *Buffer, x uint64) { + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + *p = &o.uint64s[0] + o.uint64s = o.uint64s[1:] +} + +func word64_IsNil(p word64) bool { + return *p == nil +} + +func word64_Get(p word64) uint64 { + return **p +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val *uint64 + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + *p = x +} + +func word64Val_Get(p word64Val) uint64 { + return *p +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Slice is like word32Slice but for 64-bit values. +type word64Slice []uint64 + +func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } +func (v *word64Slice) Len() int { return len(*v) } +func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } + +func structPointer_Word64Slice(p structPointer, f field) *word64Slice { + return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go new file mode 100644 index 00000000..d74844ab --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go @@ -0,0 +1,742 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "os" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +const startSize = 10 // initial slice/string sizes + +// Encoders are defined in encode.go +// An encoder outputs the full representation of a field, including its +// tag and encoder type. +type encoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueEncoder encodes a single integer in a particular encoding. +type valueEncoder func(o *Buffer, x uint64) error + +// Sizers are defined in encode.go +// A sizer returns the encoded size of a field, including its tag and encoder +// type. +type sizer func(prop *Properties, base structPointer) int + +// A valueSizer returns the encoded size of a single integer in a particular +// encoding. +type valueSizer func(x uint64) int + +// Decoders are defined in decode.go +// A decoder creates a value from its wire representation. +// Unrecognized subelements are saved in unrec. +type decoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueDecoder decodes a single integer in a particular encoding. +type valueDecoder func(o *Buffer) (x uint64, err error) + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + unrecField field // field id of the XXX_unrecognized []byte field + extendable bool // is this an extendable proto +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only + + Default string // default value + HasDefault bool // whether an explicit default was provided + def_uint64 uint64 + + enc encoder + valEnc valueEncoder // set for bool and numeric types only + field field + tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) + tagbuf [8]byte + stype reflect.Type // set for struct types only + sprop *StructProperties // set for struct types only + isMarshaler bool + isUnmarshaler bool + + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only + + size sizer + valSize valueSizer // set for bool and numeric types only + + dec decoder + valDec valueDecoder // set for bool and numeric types only + + // If this is a packable field, this will be the decoder for the packed version of the field. + packedDec decoder +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s = "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + if p.OrigName != p.Name { + s += ",name=" + p.OrigName + } + if p.proto3 { + s += ",proto3" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeVarint + p.valDec = (*Buffer).DecodeVarint + p.valSize = sizeVarint + case "fixed32": + p.WireType = WireFixed32 + p.valEnc = (*Buffer).EncodeFixed32 + p.valDec = (*Buffer).DecodeFixed32 + p.valSize = sizeFixed32 + case "fixed64": + p.WireType = WireFixed64 + p.valEnc = (*Buffer).EncodeFixed64 + p.valDec = (*Buffer).DecodeFixed64 + p.valSize = sizeFixed64 + case "zigzag32": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag32 + p.valDec = (*Buffer).DecodeZigzag32 + p.valSize = sizeZigzag32 + case "zigzag64": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag64 + p.valDec = (*Buffer).DecodeZigzag64 + p.valSize = sizeZigzag64 + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break + } + } + } +} + +func logNoSliceEnc(t1, t2 reflect.Type) { + fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// Initialize the fields for encoding and decoding. +func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + p.enc = nil + p.dec = nil + p.size = nil + + switch t1 := typ; t1.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) + + // proto3 scalar types + + case reflect.Bool: + p.enc = (*Buffer).enc_proto3_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_proto3_bool + case reflect.Int32: + p.enc = (*Buffer).enc_proto3_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_proto3_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_proto3_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_proto3_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + case reflect.String: + p.enc = (*Buffer).enc_proto3_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_proto3_string + + case reflect.Ptr: + switch t2 := t1.Elem(); t2.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) + break + case reflect.Bool: + p.enc = (*Buffer).enc_bool + p.dec = (*Buffer).dec_bool + p.size = size_bool + case reflect.Int32: + p.enc = (*Buffer).enc_int32 + p.dec = (*Buffer).dec_int32 + p.size = size_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_uint32 + p.dec = (*Buffer).dec_int32 // can reuse + p.size = size_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_int64 + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_int32 + p.size = size_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_int64 // can just treat them as bits + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.String: + p.enc = (*Buffer).enc_string + p.dec = (*Buffer).dec_string + p.size = size_string + case reflect.Struct: + p.stype = t1.Elem() + p.isMarshaler = isMarshaler(t1) + p.isUnmarshaler = isUnmarshaler(t1) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_struct_message + p.dec = (*Buffer).dec_struct_message + p.size = size_struct_message + } else { + p.enc = (*Buffer).enc_struct_group + p.dec = (*Buffer).dec_struct_group + p.size = size_struct_group + } + } + + case reflect.Slice: + switch t2 := t1.Elem(); t2.Kind() { + default: + logNoSliceEnc(t1, t2) + break + case reflect.Bool: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_bool + p.size = size_slice_packed_bool + } else { + p.enc = (*Buffer).enc_slice_bool + p.size = size_slice_bool + } + p.dec = (*Buffer).dec_slice_bool + p.packedDec = (*Buffer).dec_slice_packed_bool + case reflect.Int32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int32 + p.size = size_slice_packed_int32 + } else { + p.enc = (*Buffer).enc_slice_int32 + p.size = size_slice_int32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Uint32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Int64, reflect.Uint64: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + case reflect.Uint8: + p.enc = (*Buffer).enc_slice_byte + p.dec = (*Buffer).dec_slice_byte + p.size = size_slice_byte + // This is a []byte, which is either a bytes field, + // or the value of a map field. In the latter case, + // we always encode an empty []byte, so we should not + // use the proto3 enc/size funcs. + // f == nil iff this is the key/value of a map field. + if p.proto3 && f != nil { + p.enc = (*Buffer).enc_proto3_slice_byte + p.size = size_proto3_slice_byte + } + case reflect.Float32, reflect.Float64: + switch t2.Bits() { + case 32: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case 64: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + default: + logNoSliceEnc(t1, t2) + break + } + case reflect.String: + p.enc = (*Buffer).enc_slice_string + p.dec = (*Buffer).dec_slice_string + p.size = size_slice_string + case reflect.Ptr: + switch t3 := t2.Elem(); t3.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) + break + case reflect.Struct: + p.stype = t2.Elem() + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_slice_struct_message + p.dec = (*Buffer).dec_slice_struct_message + p.size = size_slice_struct_message + } else { + p.enc = (*Buffer).enc_slice_struct_group + p.dec = (*Buffer).dec_slice_struct_group + p.size = size_slice_struct_group + } + } + case reflect.Slice: + switch t2.Elem().Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) + break + case reflect.Uint8: + p.enc = (*Buffer).enc_slice_slice_byte + p.dec = (*Buffer).dec_slice_slice_byte + p.size = size_slice_slice_byte + } + } + + case reflect.Map: + p.enc = (*Buffer).enc_new_map + p.dec = (*Buffer).dec_new_map + p.size = size_new_map + + p.mtype = t1 + p.mkeyprop = &Properties{} + p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.mvalprop = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + + // precalculate tag code + wire := p.WireType + if p.Packed { + wire = WireBytes + } + x := uint32(p.Tag)<<3 | uint32(wire) + i := 0 + for i = 0; x > 127; i++ { + p.tagbuf[i] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + p.tagbuf[i] = uint8(x) + p.tagcode = p.tagbuf[0 : i+1] + + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +// isMarshaler reports whether type t implements Marshaler. +func isMarshaler(t reflect.Type) bool { + // We're checking for (likely) pointer-receiver methods + // so if t is not a pointer, something is very wrong. + // The calls above only invoke isMarshaler on pointer types. + if t.Kind() != reflect.Ptr { + panic("proto: misuse of isMarshaler") + } + return t.Implements(marshalerType) +} + +// isUnmarshaler reports whether type t implements Unmarshaler. +func isUnmarshaler(t reflect.Type) bool { + // We're checking for (likely) pointer-receiver methods + // so if t is not a pointer, something is very wrong. + // The calls above only invoke isUnmarshaler on pointer types. + if t.Kind() != reflect.Ptr { + panic("proto: misuse of isUnmarshaler") + } + return t.Implements(unmarshalerType) +} + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if f != nil { + p.field = toField(f) + } + if tag == "" { + return + } + p.Parse(tag) + p.setEncAndDec(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + if collectStats { + stats.Chit++ + } + return prop + } + if collectStats { + stats.Cmiss++ + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) + prop.unrecField = invalidField + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + if f.Name == "XXX_extensions" { // special case + p.enc = (*Buffer).enc_map + p.dec = nil // not needed + p.size = size_map + } + if f.Name == "XXX_unrecognized" { // special case + prop.unrecField = toField(&f) + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") { + fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// Return the Properties object for the x[0]'th field of the structure. +func propByIndex(t reflect.Type, x []int) *Properties { + if len(x) != 1 { + fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) + return nil + } + prop := GetProperties(t) + return prop.Prop[x[0]] +} + +// Get the address and type of a pointer to a struct from an interface. +func getbase(pb Message) (t reflect.Type, b structPointer, err error) { + if pb == nil { + err = ErrNil + return + } + // get the reflect type of the pointer to the struct. + t = reflect.TypeOf(pb) + // get the address of the struct. + value := reflect.ValueOf(pb) + b = toStructPointer(value) + return +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto new file mode 100644 index 00000000..e2311d92 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto/proto3.proto @@ -0,0 +1,68 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +import "testdata/test.proto"; + +package proto3_proto; + +message Message { + enum Humour { + UNKNOWN = 0; + PUNS = 1; + SLAPSTICK = 2; + BILL_BAILEY = 3; + } + + string name = 1; + Humour hilarity = 2; + uint32 height_in_cm = 3; + bytes data = 4; + int64 result_count = 7; + bool true_scotsman = 8; + float score = 9; + + repeated uint64 key = 5; + Nested nested = 6; + + map terrain = 10; + testdata.SubDefaults proto2_field = 11; + map proto2_value = 13; +} + +message Nested { + string bunny = 1; +} + +message MessageWithMap { + map byte_mapping = 1; +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go new file mode 100644 index 00000000..10453925 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_test.go @@ -0,0 +1,125 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto" + tpb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +func TestProto3ZeroValues(t *testing.T) { + tests := []struct { + desc string + m proto.Message + }{ + {"zero message", &pb.Message{}}, + {"empty bytes field", &pb.Message{Data: []byte{}}}, + } + for _, test := range tests { + b, err := proto.Marshal(test.m) + if err != nil { + t.Errorf("%s: proto.Marshal: %v", test.desc, err) + continue + } + if len(b) > 0 { + t.Errorf("%s: Encoding is non-empty: %q", test.desc, b) + } + } +} + +func TestRoundTripProto3(t *testing.T) { + m := &pb.Message{ + Name: "David", // (2 | 1<<3): 0x0a 0x05 "David" + Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01 + HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01 + Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto" + ResultCount: 47, // (0 | 7<<3): 0x38 0x2f + TrueScotsman: true, // (0 | 8<<3): 0x40 0x01 + Score: 8.1, // (5 | 9<<3): 0x4d <8.1> + + Key: []uint64{1, 0xdeadbeef}, + Nested: &pb.Nested{ + Bunny: "Monty", + }, + } + t.Logf(" m: %v", m) + + b, err := proto.Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal: %v", err) + } + t.Logf(" b: %q", b) + + m2 := new(pb.Message) + if err := proto.Unmarshal(b, m2); err != nil { + t.Fatalf("proto.Unmarshal: %v", err) + } + t.Logf("m2: %v", m2) + + if !proto.Equal(m, m2) { + t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2) + } +} + +func TestProto3SetDefaults(t *testing.T) { + in := &pb.Message{ + Terrain: map[string]*pb.Nested{ + "meadow": new(pb.Nested), + }, + Proto2Field: new(tpb.SubDefaults), + Proto2Value: map[string]*tpb.SubDefaults{ + "badlands": new(tpb.SubDefaults), + }, + } + + got := proto.Clone(in).(*pb.Message) + proto.SetDefaults(got) + + // There are no defaults in proto3. Everything should be the zero value, but + // we need to remember to set defaults for nested proto2 messages. + want := &pb.Message{ + Terrain: map[string]*pb.Nested{ + "meadow": new(pb.Nested), + }, + Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, + Proto2Value: map[string]*tpb.SubDefaults{ + "badlands": &tpb.SubDefaults{N: proto.Int64(7)}, + }, + } + + if !proto.Equal(got, want) { + t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go new file mode 100644 index 00000000..a2729c39 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size2_test.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "testing" +) + +// This is a separate file and package from size_test.go because that one uses +// generated messages and thus may not be in package proto without having a circular +// dependency, whereas this file tests unexported details of size.go. + +func TestVarintSize(t *testing.T) { + // Check the edge cases carefully. + testCases := []struct { + n uint64 + size int + }{ + {0, 1}, + {1, 1}, + {127, 1}, + {128, 2}, + {16383, 2}, + {16384, 3}, + {1<<63 - 1, 9}, + {1 << 63, 10}, + } + for _, tc := range testCases { + size := sizeVarint(tc.n) + if size != tc.size { + t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) + } + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go new file mode 100644 index 00000000..308aafb4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/size_test.go @@ -0,0 +1,142 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "log" + "strings" + "testing" + + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + proto3pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto" + pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} + +// messageWithExtension2 is in equal_test.go. +var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)} + +func init() { + if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil { + log.Panicf("SetExtension: %v", err) + } + if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil { + log.Panicf("SetExtension: %v", err) + } + + // Force messageWithExtension3 to have the extension encoded. + Marshal(messageWithExtension3) + +} + +var SizeTests = []struct { + desc string + pb Message +}{ + {"empty", &pb.OtherMessage{}}, + // Basic types. + {"bool", &pb.Defaults{F_Bool: Bool(true)}}, + {"int32", &pb.Defaults{F_Int32: Int32(12)}}, + {"negative int32", &pb.Defaults{F_Int32: Int32(-1)}}, + {"small int64", &pb.Defaults{F_Int64: Int64(1)}}, + {"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}}, + {"negative int64", &pb.Defaults{F_Int64: Int64(-1)}}, + {"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}}, + {"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}}, + {"uint32", &pb.Defaults{F_Uint32: Uint32(123)}}, + {"uint64", &pb.Defaults{F_Uint64: Uint64(124)}}, + {"float", &pb.Defaults{F_Float: Float32(12.6)}}, + {"double", &pb.Defaults{F_Double: Float64(13.9)}}, + {"string", &pb.Defaults{F_String: String("niles")}}, + {"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}}, + {"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}}, + {"sint32", &pb.Defaults{F_Sint32: Int32(65)}}, + {"sint64", &pb.Defaults{F_Sint64: Int64(67)}}, + {"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}}, + // Repeated. + {"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}}, + {"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}}, + {"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}}, + {"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}}, + {"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}}, + {"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{ + // Need enough large numbers to verify that the header is counting the number of bytes + // for the field, not the number of elements. + 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, + 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, + }}}, + {"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}}, + {"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}}, + // Nested. + {"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}}, + {"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}}, + // Other things. + {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, + {"extension (unencoded)", messageWithExtension1}, + {"extension (encoded)", messageWithExtension3}, + // proto3 message + {"proto3 empty", &proto3pb.Message{}}, + {"proto3 bool", &proto3pb.Message{TrueScotsman: true}}, + {"proto3 int64", &proto3pb.Message{ResultCount: 1}}, + {"proto3 uint32", &proto3pb.Message{HeightInCm: 123}}, + {"proto3 float", &proto3pb.Message{Score: 12.6}}, + {"proto3 string", &proto3pb.Message{Name: "Snezana"}}, + {"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}}, + {"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}}, + {"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}}, + {"proto3 map field with empty bytes", &proto3pb.MessageWithMap{ByteMapping: map[bool][]byte{false: []byte{}}}}, + + {"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}}, + {"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}}, + {"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}}, + {"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte{}}}}, + + {"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}}, + {"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}}, + {"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}}, +} + +func TestSize(t *testing.T) { + for _, tc := range SizeTests { + size := Size(tc.pb) + b, err := Marshal(tc.pb) + if err != nil { + t.Errorf("%v: Marshal failed: %v", tc.desc, err) + continue + } + if size != len(b) { + t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b)) + t.Logf("%v: bytes: %#v", tc.desc, b) + } + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile new file mode 100644 index 00000000..fc288628 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/Makefile @@ -0,0 +1,50 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +include ../../Make.protobuf + +all: regenerate + +regenerate: + rm -f test.pb.go + make test.pb.go + +# The following rules are just aids to development. Not needed for typical testing. + +diff: regenerate + git diff test.pb.go + +restore: + cp test.pb.go.golden test.pb.go + +preserve: + cp test.pb.go test.pb.go.golden diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go new file mode 100644 index 00000000..7172d0e9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/golden_test.go @@ -0,0 +1,86 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Verify that the compiler output for test.proto is unchanged. + +package testdata + +import ( + "crypto/sha1" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "testing" +) + +// sum returns in string form (for easy comparison) the SHA-1 hash of the named file. +func sum(t *testing.T, name string) string { + data, err := ioutil.ReadFile(name) + if err != nil { + t.Fatal(err) + } + t.Logf("sum(%q): length is %d", name, len(data)) + hash := sha1.New() + _, err = hash.Write(data) + if err != nil { + t.Fatal(err) + } + return fmt.Sprintf("% x", hash.Sum(nil)) +} + +func run(t *testing.T, name string, args ...string) { + cmd := exec.Command(name, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + t.Fatal(err) + } +} + +func TestGolden(t *testing.T) { + // Compute the original checksum. + goldenSum := sum(t, "test.pb.go") + // Run the proto compiler. + run(t, "protoc", "--go_out="+os.TempDir(), "test.proto") + newFile := filepath.Join(os.TempDir(), "test.pb.go") + defer os.Remove(newFile) + // Compute the new checksum. + newSum := sum(t, newFile) + // Verify + if newSum != goldenSum { + run(t, "diff", "-u", "test.pb.go", newFile) + t.Fatal("Code generated by protoc-gen-go has changed; update test.pb.go") + } +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go new file mode 100644 index 00000000..74426c81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.pb.go @@ -0,0 +1,2397 @@ +// Code generated by protoc-gen-go. +// source: test.proto +// DO NOT EDIT! + +/* +Package testdata is a generated protocol buffer package. + +It is generated from these files: + test.proto + +It has these top-level messages: + GoEnum + GoTestField + GoTest + GoSkipTest + NonPackedTest + PackedTest + MaxTag + OldMessage + NewMessage + InnerMessage + OtherMessage + MyMessage + Ext + MyMessageSet + Empty + MessageList + Strings + Defaults + SubDefaults + RepeatedEnum + MoreRepeated + GroupOld + GroupNew + FloatingPoint + MessageWithMap +*/ +package testdata + +import proto "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = math.Inf + +type FOO int32 + +const ( + FOO_FOO1 FOO = 1 +) + +var FOO_name = map[int32]string{ + 1: "FOO1", +} +var FOO_value = map[string]int32{ + "FOO1": 1, +} + +func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p +} +func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) +} +func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO") + if err != nil { + return err + } + *x = FOO(value) + return nil +} + +// An enum, for completeness. +type GoTest_KIND int32 + +const ( + GoTest_VOID GoTest_KIND = 0 + // Basic types + GoTest_BOOL GoTest_KIND = 1 + GoTest_BYTES GoTest_KIND = 2 + GoTest_FINGERPRINT GoTest_KIND = 3 + GoTest_FLOAT GoTest_KIND = 4 + GoTest_INT GoTest_KIND = 5 + GoTest_STRING GoTest_KIND = 6 + GoTest_TIME GoTest_KIND = 7 + // Groupings + GoTest_TUPLE GoTest_KIND = 8 + GoTest_ARRAY GoTest_KIND = 9 + GoTest_MAP GoTest_KIND = 10 + // Table types + GoTest_TABLE GoTest_KIND = 11 + // Functions + GoTest_FUNCTION GoTest_KIND = 12 +) + +var GoTest_KIND_name = map[int32]string{ + 0: "VOID", + 1: "BOOL", + 2: "BYTES", + 3: "FINGERPRINT", + 4: "FLOAT", + 5: "INT", + 6: "STRING", + 7: "TIME", + 8: "TUPLE", + 9: "ARRAY", + 10: "MAP", + 11: "TABLE", + 12: "FUNCTION", +} +var GoTest_KIND_value = map[string]int32{ + "VOID": 0, + "BOOL": 1, + "BYTES": 2, + "FINGERPRINT": 3, + "FLOAT": 4, + "INT": 5, + "STRING": 6, + "TIME": 7, + "TUPLE": 8, + "ARRAY": 9, + "MAP": 10, + "TABLE": 11, + "FUNCTION": 12, +} + +func (x GoTest_KIND) Enum() *GoTest_KIND { + p := new(GoTest_KIND) + *p = x + return p +} +func (x GoTest_KIND) String() string { + return proto.EnumName(GoTest_KIND_name, int32(x)) +} +func (x *GoTest_KIND) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(GoTest_KIND_value, data, "GoTest_KIND") + if err != nil { + return err + } + *x = GoTest_KIND(value) + return nil +} + +type MyMessage_Color int32 + +const ( + MyMessage_RED MyMessage_Color = 0 + MyMessage_GREEN MyMessage_Color = 1 + MyMessage_BLUE MyMessage_Color = 2 +) + +var MyMessage_Color_name = map[int32]string{ + 0: "RED", + 1: "GREEN", + 2: "BLUE", +} +var MyMessage_Color_value = map[string]int32{ + "RED": 0, + "GREEN": 1, + "BLUE": 2, +} + +func (x MyMessage_Color) Enum() *MyMessage_Color { + p := new(MyMessage_Color) + *p = x + return p +} +func (x MyMessage_Color) String() string { + return proto.EnumName(MyMessage_Color_name, int32(x)) +} +func (x *MyMessage_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(MyMessage_Color_value, data, "MyMessage_Color") + if err != nil { + return err + } + *x = MyMessage_Color(value) + return nil +} + +type Defaults_Color int32 + +const ( + Defaults_RED Defaults_Color = 0 + Defaults_GREEN Defaults_Color = 1 + Defaults_BLUE Defaults_Color = 2 +) + +var Defaults_Color_name = map[int32]string{ + 0: "RED", + 1: "GREEN", + 2: "BLUE", +} +var Defaults_Color_value = map[string]int32{ + "RED": 0, + "GREEN": 1, + "BLUE": 2, +} + +func (x Defaults_Color) Enum() *Defaults_Color { + p := new(Defaults_Color) + *p = x + return p +} +func (x Defaults_Color) String() string { + return proto.EnumName(Defaults_Color_name, int32(x)) +} +func (x *Defaults_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Defaults_Color_value, data, "Defaults_Color") + if err != nil { + return err + } + *x = Defaults_Color(value) + return nil +} + +type RepeatedEnum_Color int32 + +const ( + RepeatedEnum_RED RepeatedEnum_Color = 1 +) + +var RepeatedEnum_Color_name = map[int32]string{ + 1: "RED", +} +var RepeatedEnum_Color_value = map[string]int32{ + "RED": 1, +} + +func (x RepeatedEnum_Color) Enum() *RepeatedEnum_Color { + p := new(RepeatedEnum_Color) + *p = x + return p +} +func (x RepeatedEnum_Color) String() string { + return proto.EnumName(RepeatedEnum_Color_name, int32(x)) +} +func (x *RepeatedEnum_Color) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(RepeatedEnum_Color_value, data, "RepeatedEnum_Color") + if err != nil { + return err + } + *x = RepeatedEnum_Color(value) + return nil +} + +type GoEnum struct { + Foo *FOO `protobuf:"varint,1,req,name=foo,enum=testdata.FOO" json:"foo,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoEnum) Reset() { *m = GoEnum{} } +func (m *GoEnum) String() string { return proto.CompactTextString(m) } +func (*GoEnum) ProtoMessage() {} + +func (m *GoEnum) GetFoo() FOO { + if m != nil && m.Foo != nil { + return *m.Foo + } + return FOO_FOO1 +} + +type GoTestField struct { + Label *string `protobuf:"bytes,1,req" json:"Label,omitempty"` + Type *string `protobuf:"bytes,2,req" json:"Type,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoTestField) Reset() { *m = GoTestField{} } +func (m *GoTestField) String() string { return proto.CompactTextString(m) } +func (*GoTestField) ProtoMessage() {} + +func (m *GoTestField) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *GoTestField) GetType() string { + if m != nil && m.Type != nil { + return *m.Type + } + return "" +} + +type GoTest struct { + // Some typical parameters + Kind *GoTest_KIND `protobuf:"varint,1,req,enum=testdata.GoTest_KIND" json:"Kind,omitempty"` + Table *string `protobuf:"bytes,2,opt" json:"Table,omitempty"` + Param *int32 `protobuf:"varint,3,opt" json:"Param,omitempty"` + // Required, repeated and optional foreign fields. + RequiredField *GoTestField `protobuf:"bytes,4,req" json:"RequiredField,omitempty"` + RepeatedField []*GoTestField `protobuf:"bytes,5,rep" json:"RepeatedField,omitempty"` + OptionalField *GoTestField `protobuf:"bytes,6,opt" json:"OptionalField,omitempty"` + // Required fields of all basic types + F_BoolRequired *bool `protobuf:"varint,10,req,name=F_Bool_required" json:"F_Bool_required,omitempty"` + F_Int32Required *int32 `protobuf:"varint,11,req,name=F_Int32_required" json:"F_Int32_required,omitempty"` + F_Int64Required *int64 `protobuf:"varint,12,req,name=F_Int64_required" json:"F_Int64_required,omitempty"` + F_Fixed32Required *uint32 `protobuf:"fixed32,13,req,name=F_Fixed32_required" json:"F_Fixed32_required,omitempty"` + F_Fixed64Required *uint64 `protobuf:"fixed64,14,req,name=F_Fixed64_required" json:"F_Fixed64_required,omitempty"` + F_Uint32Required *uint32 `protobuf:"varint,15,req,name=F_Uint32_required" json:"F_Uint32_required,omitempty"` + F_Uint64Required *uint64 `protobuf:"varint,16,req,name=F_Uint64_required" json:"F_Uint64_required,omitempty"` + F_FloatRequired *float32 `protobuf:"fixed32,17,req,name=F_Float_required" json:"F_Float_required,omitempty"` + F_DoubleRequired *float64 `protobuf:"fixed64,18,req,name=F_Double_required" json:"F_Double_required,omitempty"` + F_StringRequired *string `protobuf:"bytes,19,req,name=F_String_required" json:"F_String_required,omitempty"` + F_BytesRequired []byte `protobuf:"bytes,101,req,name=F_Bytes_required" json:"F_Bytes_required,omitempty"` + F_Sint32Required *int32 `protobuf:"zigzag32,102,req,name=F_Sint32_required" json:"F_Sint32_required,omitempty"` + F_Sint64Required *int64 `protobuf:"zigzag64,103,req,name=F_Sint64_required" json:"F_Sint64_required,omitempty"` + // Repeated fields of all basic types + F_BoolRepeated []bool `protobuf:"varint,20,rep,name=F_Bool_repeated" json:"F_Bool_repeated,omitempty"` + F_Int32Repeated []int32 `protobuf:"varint,21,rep,name=F_Int32_repeated" json:"F_Int32_repeated,omitempty"` + F_Int64Repeated []int64 `protobuf:"varint,22,rep,name=F_Int64_repeated" json:"F_Int64_repeated,omitempty"` + F_Fixed32Repeated []uint32 `protobuf:"fixed32,23,rep,name=F_Fixed32_repeated" json:"F_Fixed32_repeated,omitempty"` + F_Fixed64Repeated []uint64 `protobuf:"fixed64,24,rep,name=F_Fixed64_repeated" json:"F_Fixed64_repeated,omitempty"` + F_Uint32Repeated []uint32 `protobuf:"varint,25,rep,name=F_Uint32_repeated" json:"F_Uint32_repeated,omitempty"` + F_Uint64Repeated []uint64 `protobuf:"varint,26,rep,name=F_Uint64_repeated" json:"F_Uint64_repeated,omitempty"` + F_FloatRepeated []float32 `protobuf:"fixed32,27,rep,name=F_Float_repeated" json:"F_Float_repeated,omitempty"` + F_DoubleRepeated []float64 `protobuf:"fixed64,28,rep,name=F_Double_repeated" json:"F_Double_repeated,omitempty"` + F_StringRepeated []string `protobuf:"bytes,29,rep,name=F_String_repeated" json:"F_String_repeated,omitempty"` + F_BytesRepeated [][]byte `protobuf:"bytes,201,rep,name=F_Bytes_repeated" json:"F_Bytes_repeated,omitempty"` + F_Sint32Repeated []int32 `protobuf:"zigzag32,202,rep,name=F_Sint32_repeated" json:"F_Sint32_repeated,omitempty"` + F_Sint64Repeated []int64 `protobuf:"zigzag64,203,rep,name=F_Sint64_repeated" json:"F_Sint64_repeated,omitempty"` + // Optional fields of all basic types + F_BoolOptional *bool `protobuf:"varint,30,opt,name=F_Bool_optional" json:"F_Bool_optional,omitempty"` + F_Int32Optional *int32 `protobuf:"varint,31,opt,name=F_Int32_optional" json:"F_Int32_optional,omitempty"` + F_Int64Optional *int64 `protobuf:"varint,32,opt,name=F_Int64_optional" json:"F_Int64_optional,omitempty"` + F_Fixed32Optional *uint32 `protobuf:"fixed32,33,opt,name=F_Fixed32_optional" json:"F_Fixed32_optional,omitempty"` + F_Fixed64Optional *uint64 `protobuf:"fixed64,34,opt,name=F_Fixed64_optional" json:"F_Fixed64_optional,omitempty"` + F_Uint32Optional *uint32 `protobuf:"varint,35,opt,name=F_Uint32_optional" json:"F_Uint32_optional,omitempty"` + F_Uint64Optional *uint64 `protobuf:"varint,36,opt,name=F_Uint64_optional" json:"F_Uint64_optional,omitempty"` + F_FloatOptional *float32 `protobuf:"fixed32,37,opt,name=F_Float_optional" json:"F_Float_optional,omitempty"` + F_DoubleOptional *float64 `protobuf:"fixed64,38,opt,name=F_Double_optional" json:"F_Double_optional,omitempty"` + F_StringOptional *string `protobuf:"bytes,39,opt,name=F_String_optional" json:"F_String_optional,omitempty"` + F_BytesOptional []byte `protobuf:"bytes,301,opt,name=F_Bytes_optional" json:"F_Bytes_optional,omitempty"` + F_Sint32Optional *int32 `protobuf:"zigzag32,302,opt,name=F_Sint32_optional" json:"F_Sint32_optional,omitempty"` + F_Sint64Optional *int64 `protobuf:"zigzag64,303,opt,name=F_Sint64_optional" json:"F_Sint64_optional,omitempty"` + // Default-valued fields of all basic types + F_BoolDefaulted *bool `protobuf:"varint,40,opt,name=F_Bool_defaulted,def=1" json:"F_Bool_defaulted,omitempty"` + F_Int32Defaulted *int32 `protobuf:"varint,41,opt,name=F_Int32_defaulted,def=32" json:"F_Int32_defaulted,omitempty"` + F_Int64Defaulted *int64 `protobuf:"varint,42,opt,name=F_Int64_defaulted,def=64" json:"F_Int64_defaulted,omitempty"` + F_Fixed32Defaulted *uint32 `protobuf:"fixed32,43,opt,name=F_Fixed32_defaulted,def=320" json:"F_Fixed32_defaulted,omitempty"` + F_Fixed64Defaulted *uint64 `protobuf:"fixed64,44,opt,name=F_Fixed64_defaulted,def=640" json:"F_Fixed64_defaulted,omitempty"` + F_Uint32Defaulted *uint32 `protobuf:"varint,45,opt,name=F_Uint32_defaulted,def=3200" json:"F_Uint32_defaulted,omitempty"` + F_Uint64Defaulted *uint64 `protobuf:"varint,46,opt,name=F_Uint64_defaulted,def=6400" json:"F_Uint64_defaulted,omitempty"` + F_FloatDefaulted *float32 `protobuf:"fixed32,47,opt,name=F_Float_defaulted,def=314159" json:"F_Float_defaulted,omitempty"` + F_DoubleDefaulted *float64 `protobuf:"fixed64,48,opt,name=F_Double_defaulted,def=271828" json:"F_Double_defaulted,omitempty"` + F_StringDefaulted *string `protobuf:"bytes,49,opt,name=F_String_defaulted,def=hello, \"world!\"\n" json:"F_String_defaulted,omitempty"` + F_BytesDefaulted []byte `protobuf:"bytes,401,opt,name=F_Bytes_defaulted,def=Bignose" json:"F_Bytes_defaulted,omitempty"` + F_Sint32Defaulted *int32 `protobuf:"zigzag32,402,opt,name=F_Sint32_defaulted,def=-32" json:"F_Sint32_defaulted,omitempty"` + F_Sint64Defaulted *int64 `protobuf:"zigzag64,403,opt,name=F_Sint64_defaulted,def=-64" json:"F_Sint64_defaulted,omitempty"` + // Packed repeated fields (no string or bytes). + F_BoolRepeatedPacked []bool `protobuf:"varint,50,rep,packed,name=F_Bool_repeated_packed" json:"F_Bool_repeated_packed,omitempty"` + F_Int32RepeatedPacked []int32 `protobuf:"varint,51,rep,packed,name=F_Int32_repeated_packed" json:"F_Int32_repeated_packed,omitempty"` + F_Int64RepeatedPacked []int64 `protobuf:"varint,52,rep,packed,name=F_Int64_repeated_packed" json:"F_Int64_repeated_packed,omitempty"` + F_Fixed32RepeatedPacked []uint32 `protobuf:"fixed32,53,rep,packed,name=F_Fixed32_repeated_packed" json:"F_Fixed32_repeated_packed,omitempty"` + F_Fixed64RepeatedPacked []uint64 `protobuf:"fixed64,54,rep,packed,name=F_Fixed64_repeated_packed" json:"F_Fixed64_repeated_packed,omitempty"` + F_Uint32RepeatedPacked []uint32 `protobuf:"varint,55,rep,packed,name=F_Uint32_repeated_packed" json:"F_Uint32_repeated_packed,omitempty"` + F_Uint64RepeatedPacked []uint64 `protobuf:"varint,56,rep,packed,name=F_Uint64_repeated_packed" json:"F_Uint64_repeated_packed,omitempty"` + F_FloatRepeatedPacked []float32 `protobuf:"fixed32,57,rep,packed,name=F_Float_repeated_packed" json:"F_Float_repeated_packed,omitempty"` + F_DoubleRepeatedPacked []float64 `protobuf:"fixed64,58,rep,packed,name=F_Double_repeated_packed" json:"F_Double_repeated_packed,omitempty"` + F_Sint32RepeatedPacked []int32 `protobuf:"zigzag32,502,rep,packed,name=F_Sint32_repeated_packed" json:"F_Sint32_repeated_packed,omitempty"` + F_Sint64RepeatedPacked []int64 `protobuf:"zigzag64,503,rep,packed,name=F_Sint64_repeated_packed" json:"F_Sint64_repeated_packed,omitempty"` + Requiredgroup *GoTest_RequiredGroup `protobuf:"group,70,req,name=RequiredGroup" json:"requiredgroup,omitempty"` + Repeatedgroup []*GoTest_RepeatedGroup `protobuf:"group,80,rep,name=RepeatedGroup" json:"repeatedgroup,omitempty"` + Optionalgroup *GoTest_OptionalGroup `protobuf:"group,90,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoTest) Reset() { *m = GoTest{} } +func (m *GoTest) String() string { return proto.CompactTextString(m) } +func (*GoTest) ProtoMessage() {} + +const Default_GoTest_F_BoolDefaulted bool = true +const Default_GoTest_F_Int32Defaulted int32 = 32 +const Default_GoTest_F_Int64Defaulted int64 = 64 +const Default_GoTest_F_Fixed32Defaulted uint32 = 320 +const Default_GoTest_F_Fixed64Defaulted uint64 = 640 +const Default_GoTest_F_Uint32Defaulted uint32 = 3200 +const Default_GoTest_F_Uint64Defaulted uint64 = 6400 +const Default_GoTest_F_FloatDefaulted float32 = 314159 +const Default_GoTest_F_DoubleDefaulted float64 = 271828 +const Default_GoTest_F_StringDefaulted string = "hello, \"world!\"\n" + +var Default_GoTest_F_BytesDefaulted []byte = []byte("Bignose") + +const Default_GoTest_F_Sint32Defaulted int32 = -32 +const Default_GoTest_F_Sint64Defaulted int64 = -64 + +func (m *GoTest) GetKind() GoTest_KIND { + if m != nil && m.Kind != nil { + return *m.Kind + } + return GoTest_VOID +} + +func (m *GoTest) GetTable() string { + if m != nil && m.Table != nil { + return *m.Table + } + return "" +} + +func (m *GoTest) GetParam() int32 { + if m != nil && m.Param != nil { + return *m.Param + } + return 0 +} + +func (m *GoTest) GetRequiredField() *GoTestField { + if m != nil { + return m.RequiredField + } + return nil +} + +func (m *GoTest) GetRepeatedField() []*GoTestField { + if m != nil { + return m.RepeatedField + } + return nil +} + +func (m *GoTest) GetOptionalField() *GoTestField { + if m != nil { + return m.OptionalField + } + return nil +} + +func (m *GoTest) GetF_BoolRequired() bool { + if m != nil && m.F_BoolRequired != nil { + return *m.F_BoolRequired + } + return false +} + +func (m *GoTest) GetF_Int32Required() int32 { + if m != nil && m.F_Int32Required != nil { + return *m.F_Int32Required + } + return 0 +} + +func (m *GoTest) GetF_Int64Required() int64 { + if m != nil && m.F_Int64Required != nil { + return *m.F_Int64Required + } + return 0 +} + +func (m *GoTest) GetF_Fixed32Required() uint32 { + if m != nil && m.F_Fixed32Required != nil { + return *m.F_Fixed32Required + } + return 0 +} + +func (m *GoTest) GetF_Fixed64Required() uint64 { + if m != nil && m.F_Fixed64Required != nil { + return *m.F_Fixed64Required + } + return 0 +} + +func (m *GoTest) GetF_Uint32Required() uint32 { + if m != nil && m.F_Uint32Required != nil { + return *m.F_Uint32Required + } + return 0 +} + +func (m *GoTest) GetF_Uint64Required() uint64 { + if m != nil && m.F_Uint64Required != nil { + return *m.F_Uint64Required + } + return 0 +} + +func (m *GoTest) GetF_FloatRequired() float32 { + if m != nil && m.F_FloatRequired != nil { + return *m.F_FloatRequired + } + return 0 +} + +func (m *GoTest) GetF_DoubleRequired() float64 { + if m != nil && m.F_DoubleRequired != nil { + return *m.F_DoubleRequired + } + return 0 +} + +func (m *GoTest) GetF_StringRequired() string { + if m != nil && m.F_StringRequired != nil { + return *m.F_StringRequired + } + return "" +} + +func (m *GoTest) GetF_BytesRequired() []byte { + if m != nil { + return m.F_BytesRequired + } + return nil +} + +func (m *GoTest) GetF_Sint32Required() int32 { + if m != nil && m.F_Sint32Required != nil { + return *m.F_Sint32Required + } + return 0 +} + +func (m *GoTest) GetF_Sint64Required() int64 { + if m != nil && m.F_Sint64Required != nil { + return *m.F_Sint64Required + } + return 0 +} + +func (m *GoTest) GetF_BoolRepeated() []bool { + if m != nil { + return m.F_BoolRepeated + } + return nil +} + +func (m *GoTest) GetF_Int32Repeated() []int32 { + if m != nil { + return m.F_Int32Repeated + } + return nil +} + +func (m *GoTest) GetF_Int64Repeated() []int64 { + if m != nil { + return m.F_Int64Repeated + } + return nil +} + +func (m *GoTest) GetF_Fixed32Repeated() []uint32 { + if m != nil { + return m.F_Fixed32Repeated + } + return nil +} + +func (m *GoTest) GetF_Fixed64Repeated() []uint64 { + if m != nil { + return m.F_Fixed64Repeated + } + return nil +} + +func (m *GoTest) GetF_Uint32Repeated() []uint32 { + if m != nil { + return m.F_Uint32Repeated + } + return nil +} + +func (m *GoTest) GetF_Uint64Repeated() []uint64 { + if m != nil { + return m.F_Uint64Repeated + } + return nil +} + +func (m *GoTest) GetF_FloatRepeated() []float32 { + if m != nil { + return m.F_FloatRepeated + } + return nil +} + +func (m *GoTest) GetF_DoubleRepeated() []float64 { + if m != nil { + return m.F_DoubleRepeated + } + return nil +} + +func (m *GoTest) GetF_StringRepeated() []string { + if m != nil { + return m.F_StringRepeated + } + return nil +} + +func (m *GoTest) GetF_BytesRepeated() [][]byte { + if m != nil { + return m.F_BytesRepeated + } + return nil +} + +func (m *GoTest) GetF_Sint32Repeated() []int32 { + if m != nil { + return m.F_Sint32Repeated + } + return nil +} + +func (m *GoTest) GetF_Sint64Repeated() []int64 { + if m != nil { + return m.F_Sint64Repeated + } + return nil +} + +func (m *GoTest) GetF_BoolOptional() bool { + if m != nil && m.F_BoolOptional != nil { + return *m.F_BoolOptional + } + return false +} + +func (m *GoTest) GetF_Int32Optional() int32 { + if m != nil && m.F_Int32Optional != nil { + return *m.F_Int32Optional + } + return 0 +} + +func (m *GoTest) GetF_Int64Optional() int64 { + if m != nil && m.F_Int64Optional != nil { + return *m.F_Int64Optional + } + return 0 +} + +func (m *GoTest) GetF_Fixed32Optional() uint32 { + if m != nil && m.F_Fixed32Optional != nil { + return *m.F_Fixed32Optional + } + return 0 +} + +func (m *GoTest) GetF_Fixed64Optional() uint64 { + if m != nil && m.F_Fixed64Optional != nil { + return *m.F_Fixed64Optional + } + return 0 +} + +func (m *GoTest) GetF_Uint32Optional() uint32 { + if m != nil && m.F_Uint32Optional != nil { + return *m.F_Uint32Optional + } + return 0 +} + +func (m *GoTest) GetF_Uint64Optional() uint64 { + if m != nil && m.F_Uint64Optional != nil { + return *m.F_Uint64Optional + } + return 0 +} + +func (m *GoTest) GetF_FloatOptional() float32 { + if m != nil && m.F_FloatOptional != nil { + return *m.F_FloatOptional + } + return 0 +} + +func (m *GoTest) GetF_DoubleOptional() float64 { + if m != nil && m.F_DoubleOptional != nil { + return *m.F_DoubleOptional + } + return 0 +} + +func (m *GoTest) GetF_StringOptional() string { + if m != nil && m.F_StringOptional != nil { + return *m.F_StringOptional + } + return "" +} + +func (m *GoTest) GetF_BytesOptional() []byte { + if m != nil { + return m.F_BytesOptional + } + return nil +} + +func (m *GoTest) GetF_Sint32Optional() int32 { + if m != nil && m.F_Sint32Optional != nil { + return *m.F_Sint32Optional + } + return 0 +} + +func (m *GoTest) GetF_Sint64Optional() int64 { + if m != nil && m.F_Sint64Optional != nil { + return *m.F_Sint64Optional + } + return 0 +} + +func (m *GoTest) GetF_BoolDefaulted() bool { + if m != nil && m.F_BoolDefaulted != nil { + return *m.F_BoolDefaulted + } + return Default_GoTest_F_BoolDefaulted +} + +func (m *GoTest) GetF_Int32Defaulted() int32 { + if m != nil && m.F_Int32Defaulted != nil { + return *m.F_Int32Defaulted + } + return Default_GoTest_F_Int32Defaulted +} + +func (m *GoTest) GetF_Int64Defaulted() int64 { + if m != nil && m.F_Int64Defaulted != nil { + return *m.F_Int64Defaulted + } + return Default_GoTest_F_Int64Defaulted +} + +func (m *GoTest) GetF_Fixed32Defaulted() uint32 { + if m != nil && m.F_Fixed32Defaulted != nil { + return *m.F_Fixed32Defaulted + } + return Default_GoTest_F_Fixed32Defaulted +} + +func (m *GoTest) GetF_Fixed64Defaulted() uint64 { + if m != nil && m.F_Fixed64Defaulted != nil { + return *m.F_Fixed64Defaulted + } + return Default_GoTest_F_Fixed64Defaulted +} + +func (m *GoTest) GetF_Uint32Defaulted() uint32 { + if m != nil && m.F_Uint32Defaulted != nil { + return *m.F_Uint32Defaulted + } + return Default_GoTest_F_Uint32Defaulted +} + +func (m *GoTest) GetF_Uint64Defaulted() uint64 { + if m != nil && m.F_Uint64Defaulted != nil { + return *m.F_Uint64Defaulted + } + return Default_GoTest_F_Uint64Defaulted +} + +func (m *GoTest) GetF_FloatDefaulted() float32 { + if m != nil && m.F_FloatDefaulted != nil { + return *m.F_FloatDefaulted + } + return Default_GoTest_F_FloatDefaulted +} + +func (m *GoTest) GetF_DoubleDefaulted() float64 { + if m != nil && m.F_DoubleDefaulted != nil { + return *m.F_DoubleDefaulted + } + return Default_GoTest_F_DoubleDefaulted +} + +func (m *GoTest) GetF_StringDefaulted() string { + if m != nil && m.F_StringDefaulted != nil { + return *m.F_StringDefaulted + } + return Default_GoTest_F_StringDefaulted +} + +func (m *GoTest) GetF_BytesDefaulted() []byte { + if m != nil && m.F_BytesDefaulted != nil { + return m.F_BytesDefaulted + } + return append([]byte(nil), Default_GoTest_F_BytesDefaulted...) +} + +func (m *GoTest) GetF_Sint32Defaulted() int32 { + if m != nil && m.F_Sint32Defaulted != nil { + return *m.F_Sint32Defaulted + } + return Default_GoTest_F_Sint32Defaulted +} + +func (m *GoTest) GetF_Sint64Defaulted() int64 { + if m != nil && m.F_Sint64Defaulted != nil { + return *m.F_Sint64Defaulted + } + return Default_GoTest_F_Sint64Defaulted +} + +func (m *GoTest) GetF_BoolRepeatedPacked() []bool { + if m != nil { + return m.F_BoolRepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Int32RepeatedPacked() []int32 { + if m != nil { + return m.F_Int32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Int64RepeatedPacked() []int64 { + if m != nil { + return m.F_Int64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Fixed32RepeatedPacked() []uint32 { + if m != nil { + return m.F_Fixed32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Fixed64RepeatedPacked() []uint64 { + if m != nil { + return m.F_Fixed64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Uint32RepeatedPacked() []uint32 { + if m != nil { + return m.F_Uint32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Uint64RepeatedPacked() []uint64 { + if m != nil { + return m.F_Uint64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_FloatRepeatedPacked() []float32 { + if m != nil { + return m.F_FloatRepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_DoubleRepeatedPacked() []float64 { + if m != nil { + return m.F_DoubleRepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Sint32RepeatedPacked() []int32 { + if m != nil { + return m.F_Sint32RepeatedPacked + } + return nil +} + +func (m *GoTest) GetF_Sint64RepeatedPacked() []int64 { + if m != nil { + return m.F_Sint64RepeatedPacked + } + return nil +} + +func (m *GoTest) GetRequiredgroup() *GoTest_RequiredGroup { + if m != nil { + return m.Requiredgroup + } + return nil +} + +func (m *GoTest) GetRepeatedgroup() []*GoTest_RepeatedGroup { + if m != nil { + return m.Repeatedgroup + } + return nil +} + +func (m *GoTest) GetOptionalgroup() *GoTest_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil +} + +// Required, repeated, and optional groups. +type GoTest_RequiredGroup struct { + RequiredField *string `protobuf:"bytes,71,req" json:"RequiredField,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoTest_RequiredGroup) Reset() { *m = GoTest_RequiredGroup{} } +func (m *GoTest_RequiredGroup) String() string { return proto.CompactTextString(m) } +func (*GoTest_RequiredGroup) ProtoMessage() {} + +func (m *GoTest_RequiredGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" +} + +type GoTest_RepeatedGroup struct { + RequiredField *string `protobuf:"bytes,81,req" json:"RequiredField,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoTest_RepeatedGroup) Reset() { *m = GoTest_RepeatedGroup{} } +func (m *GoTest_RepeatedGroup) String() string { return proto.CompactTextString(m) } +func (*GoTest_RepeatedGroup) ProtoMessage() {} + +func (m *GoTest_RepeatedGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" +} + +type GoTest_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,91,req" json:"RequiredField,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoTest_OptionalGroup) Reset() { *m = GoTest_OptionalGroup{} } +func (m *GoTest_OptionalGroup) String() string { return proto.CompactTextString(m) } +func (*GoTest_OptionalGroup) ProtoMessage() {} + +func (m *GoTest_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" +} + +// For testing skipping of unrecognized fields. +// Numbers are all big, larger than tag numbers in GoTestField, +// the message used in the corresponding test. +type GoSkipTest struct { + SkipInt32 *int32 `protobuf:"varint,11,req,name=skip_int32" json:"skip_int32,omitempty"` + SkipFixed32 *uint32 `protobuf:"fixed32,12,req,name=skip_fixed32" json:"skip_fixed32,omitempty"` + SkipFixed64 *uint64 `protobuf:"fixed64,13,req,name=skip_fixed64" json:"skip_fixed64,omitempty"` + SkipString *string `protobuf:"bytes,14,req,name=skip_string" json:"skip_string,omitempty"` + Skipgroup *GoSkipTest_SkipGroup `protobuf:"group,15,req,name=SkipGroup" json:"skipgroup,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoSkipTest) Reset() { *m = GoSkipTest{} } +func (m *GoSkipTest) String() string { return proto.CompactTextString(m) } +func (*GoSkipTest) ProtoMessage() {} + +func (m *GoSkipTest) GetSkipInt32() int32 { + if m != nil && m.SkipInt32 != nil { + return *m.SkipInt32 + } + return 0 +} + +func (m *GoSkipTest) GetSkipFixed32() uint32 { + if m != nil && m.SkipFixed32 != nil { + return *m.SkipFixed32 + } + return 0 +} + +func (m *GoSkipTest) GetSkipFixed64() uint64 { + if m != nil && m.SkipFixed64 != nil { + return *m.SkipFixed64 + } + return 0 +} + +func (m *GoSkipTest) GetSkipString() string { + if m != nil && m.SkipString != nil { + return *m.SkipString + } + return "" +} + +func (m *GoSkipTest) GetSkipgroup() *GoSkipTest_SkipGroup { + if m != nil { + return m.Skipgroup + } + return nil +} + +type GoSkipTest_SkipGroup struct { + GroupInt32 *int32 `protobuf:"varint,16,req,name=group_int32" json:"group_int32,omitempty"` + GroupString *string `protobuf:"bytes,17,req,name=group_string" json:"group_string,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GoSkipTest_SkipGroup) Reset() { *m = GoSkipTest_SkipGroup{} } +func (m *GoSkipTest_SkipGroup) String() string { return proto.CompactTextString(m) } +func (*GoSkipTest_SkipGroup) ProtoMessage() {} + +func (m *GoSkipTest_SkipGroup) GetGroupInt32() int32 { + if m != nil && m.GroupInt32 != nil { + return *m.GroupInt32 + } + return 0 +} + +func (m *GoSkipTest_SkipGroup) GetGroupString() string { + if m != nil && m.GroupString != nil { + return *m.GroupString + } + return "" +} + +// For testing packed/non-packed decoder switching. +// A serialized instance of one should be deserializable as the other. +type NonPackedTest struct { + A []int32 `protobuf:"varint,1,rep,name=a" json:"a,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *NonPackedTest) Reset() { *m = NonPackedTest{} } +func (m *NonPackedTest) String() string { return proto.CompactTextString(m) } +func (*NonPackedTest) ProtoMessage() {} + +func (m *NonPackedTest) GetA() []int32 { + if m != nil { + return m.A + } + return nil +} + +type PackedTest struct { + B []int32 `protobuf:"varint,1,rep,packed,name=b" json:"b,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *PackedTest) Reset() { *m = PackedTest{} } +func (m *PackedTest) String() string { return proto.CompactTextString(m) } +func (*PackedTest) ProtoMessage() {} + +func (m *PackedTest) GetB() []int32 { + if m != nil { + return m.B + } + return nil +} + +type MaxTag struct { + // Maximum possible tag number. + LastField *string `protobuf:"bytes,536870911,opt,name=last_field" json:"last_field,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MaxTag) Reset() { *m = MaxTag{} } +func (m *MaxTag) String() string { return proto.CompactTextString(m) } +func (*MaxTag) ProtoMessage() {} + +func (m *MaxTag) GetLastField() string { + if m != nil && m.LastField != nil { + return *m.LastField + } + return "" +} + +type OldMessage struct { + Nested *OldMessage_Nested `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` + Num *int32 `protobuf:"varint,2,opt,name=num" json:"num,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *OldMessage) Reset() { *m = OldMessage{} } +func (m *OldMessage) String() string { return proto.CompactTextString(m) } +func (*OldMessage) ProtoMessage() {} + +func (m *OldMessage) GetNested() *OldMessage_Nested { + if m != nil { + return m.Nested + } + return nil +} + +func (m *OldMessage) GetNum() int32 { + if m != nil && m.Num != nil { + return *m.Num + } + return 0 +} + +type OldMessage_Nested struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *OldMessage_Nested) Reset() { *m = OldMessage_Nested{} } +func (m *OldMessage_Nested) String() string { return proto.CompactTextString(m) } +func (*OldMessage_Nested) ProtoMessage() {} + +func (m *OldMessage_Nested) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +// NewMessage is wire compatible with OldMessage; +// imagine it as a future version. +type NewMessage struct { + Nested *NewMessage_Nested `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"` + // This is an int32 in OldMessage. + Num *int64 `protobuf:"varint,2,opt,name=num" json:"num,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *NewMessage) Reset() { *m = NewMessage{} } +func (m *NewMessage) String() string { return proto.CompactTextString(m) } +func (*NewMessage) ProtoMessage() {} + +func (m *NewMessage) GetNested() *NewMessage_Nested { + if m != nil { + return m.Nested + } + return nil +} + +func (m *NewMessage) GetNum() int64 { + if m != nil && m.Num != nil { + return *m.Num + } + return 0 +} + +type NewMessage_Nested struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + FoodGroup *string `protobuf:"bytes,2,opt,name=food_group" json:"food_group,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *NewMessage_Nested) Reset() { *m = NewMessage_Nested{} } +func (m *NewMessage_Nested) String() string { return proto.CompactTextString(m) } +func (*NewMessage_Nested) ProtoMessage() {} + +func (m *NewMessage_Nested) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *NewMessage_Nested) GetFoodGroup() string { + if m != nil && m.FoodGroup != nil { + return *m.FoodGroup + } + return "" +} + +type InnerMessage struct { + Host *string `protobuf:"bytes,1,req,name=host" json:"host,omitempty"` + Port *int32 `protobuf:"varint,2,opt,name=port,def=4000" json:"port,omitempty"` + Connected *bool `protobuf:"varint,3,opt,name=connected" json:"connected,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *InnerMessage) Reset() { *m = InnerMessage{} } +func (m *InnerMessage) String() string { return proto.CompactTextString(m) } +func (*InnerMessage) ProtoMessage() {} + +const Default_InnerMessage_Port int32 = 4000 + +func (m *InnerMessage) GetHost() string { + if m != nil && m.Host != nil { + return *m.Host + } + return "" +} + +func (m *InnerMessage) GetPort() int32 { + if m != nil && m.Port != nil { + return *m.Port + } + return Default_InnerMessage_Port +} + +func (m *InnerMessage) GetConnected() bool { + if m != nil && m.Connected != nil { + return *m.Connected + } + return false +} + +type OtherMessage struct { + Key *int64 `protobuf:"varint,1,opt,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` + Weight *float32 `protobuf:"fixed32,3,opt,name=weight" json:"weight,omitempty"` + Inner *InnerMessage `protobuf:"bytes,4,opt,name=inner" json:"inner,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *OtherMessage) Reset() { *m = OtherMessage{} } +func (m *OtherMessage) String() string { return proto.CompactTextString(m) } +func (*OtherMessage) ProtoMessage() {} + +func (m *OtherMessage) GetKey() int64 { + if m != nil && m.Key != nil { + return *m.Key + } + return 0 +} + +func (m *OtherMessage) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *OtherMessage) GetWeight() float32 { + if m != nil && m.Weight != nil { + return *m.Weight + } + return 0 +} + +func (m *OtherMessage) GetInner() *InnerMessage { + if m != nil { + return m.Inner + } + return nil +} + +type MyMessage struct { + Count *int32 `protobuf:"varint,1,req,name=count" json:"count,omitempty"` + Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Quote *string `protobuf:"bytes,3,opt,name=quote" json:"quote,omitempty"` + Pet []string `protobuf:"bytes,4,rep,name=pet" json:"pet,omitempty"` + Inner *InnerMessage `protobuf:"bytes,5,opt,name=inner" json:"inner,omitempty"` + Others []*OtherMessage `protobuf:"bytes,6,rep,name=others" json:"others,omitempty"` + RepInner []*InnerMessage `protobuf:"bytes,12,rep,name=rep_inner" json:"rep_inner,omitempty"` + Bikeshed *MyMessage_Color `protobuf:"varint,7,opt,name=bikeshed,enum=testdata.MyMessage_Color" json:"bikeshed,omitempty"` + Somegroup *MyMessage_SomeGroup `protobuf:"group,8,opt,name=SomeGroup" json:"somegroup,omitempty"` + // This field becomes [][]byte in the generated code. + RepBytes [][]byte `protobuf:"bytes,10,rep,name=rep_bytes" json:"rep_bytes,omitempty"` + Bigfloat *float64 `protobuf:"fixed64,11,opt,name=bigfloat" json:"bigfloat,omitempty"` + XXX_extensions map[int32]proto.Extension `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MyMessage) Reset() { *m = MyMessage{} } +func (m *MyMessage) String() string { return proto.CompactTextString(m) } +func (*MyMessage) ProtoMessage() {} + +var extRange_MyMessage = []proto.ExtensionRange{ + {100, 536870911}, +} + +func (*MyMessage) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_MyMessage +} +func (m *MyMessage) ExtensionMap() map[int32]proto.Extension { + if m.XXX_extensions == nil { + m.XXX_extensions = make(map[int32]proto.Extension) + } + return m.XXX_extensions +} + +func (m *MyMessage) GetCount() int32 { + if m != nil && m.Count != nil { + return *m.Count + } + return 0 +} + +func (m *MyMessage) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *MyMessage) GetQuote() string { + if m != nil && m.Quote != nil { + return *m.Quote + } + return "" +} + +func (m *MyMessage) GetPet() []string { + if m != nil { + return m.Pet + } + return nil +} + +func (m *MyMessage) GetInner() *InnerMessage { + if m != nil { + return m.Inner + } + return nil +} + +func (m *MyMessage) GetOthers() []*OtherMessage { + if m != nil { + return m.Others + } + return nil +} + +func (m *MyMessage) GetRepInner() []*InnerMessage { + if m != nil { + return m.RepInner + } + return nil +} + +func (m *MyMessage) GetBikeshed() MyMessage_Color { + if m != nil && m.Bikeshed != nil { + return *m.Bikeshed + } + return MyMessage_RED +} + +func (m *MyMessage) GetSomegroup() *MyMessage_SomeGroup { + if m != nil { + return m.Somegroup + } + return nil +} + +func (m *MyMessage) GetRepBytes() [][]byte { + if m != nil { + return m.RepBytes + } + return nil +} + +func (m *MyMessage) GetBigfloat() float64 { + if m != nil && m.Bigfloat != nil { + return *m.Bigfloat + } + return 0 +} + +type MyMessage_SomeGroup struct { + GroupField *int32 `protobuf:"varint,9,opt,name=group_field" json:"group_field,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MyMessage_SomeGroup) Reset() { *m = MyMessage_SomeGroup{} } +func (m *MyMessage_SomeGroup) String() string { return proto.CompactTextString(m) } +func (*MyMessage_SomeGroup) ProtoMessage() {} + +func (m *MyMessage_SomeGroup) GetGroupField() int32 { + if m != nil && m.GroupField != nil { + return *m.GroupField + } + return 0 +} + +type Ext struct { + Data *string `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Ext) Reset() { *m = Ext{} } +func (m *Ext) String() string { return proto.CompactTextString(m) } +func (*Ext) ProtoMessage() {} + +func (m *Ext) GetData() string { + if m != nil && m.Data != nil { + return *m.Data + } + return "" +} + +var E_Ext_More = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: (*Ext)(nil), + Field: 103, + Name: "testdata.Ext.more", + Tag: "bytes,103,opt,name=more", +} + +var E_Ext_Text = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: (*string)(nil), + Field: 104, + Name: "testdata.Ext.text", + Tag: "bytes,104,opt,name=text", +} + +var E_Ext_Number = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: (*int32)(nil), + Field: 105, + Name: "testdata.Ext.number", + Tag: "varint,105,opt,name=number", +} + +type MyMessageSet struct { + XXX_extensions map[int32]proto.Extension `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MyMessageSet) Reset() { *m = MyMessageSet{} } +func (m *MyMessageSet) String() string { return proto.CompactTextString(m) } +func (*MyMessageSet) ProtoMessage() {} + +func (m *MyMessageSet) Marshal() ([]byte, error) { + return proto.MarshalMessageSet(m.ExtensionMap()) +} +func (m *MyMessageSet) Unmarshal(buf []byte) error { + return proto.UnmarshalMessageSet(buf, m.ExtensionMap()) +} +func (m *MyMessageSet) MarshalJSON() ([]byte, error) { + return proto.MarshalMessageSetJSON(m.XXX_extensions) +} +func (m *MyMessageSet) UnmarshalJSON(buf []byte) error { + return proto.UnmarshalMessageSetJSON(buf, m.XXX_extensions) +} + +// ensure MyMessageSet satisfies proto.Marshaler and proto.Unmarshaler +var _ proto.Marshaler = (*MyMessageSet)(nil) +var _ proto.Unmarshaler = (*MyMessageSet)(nil) + +var extRange_MyMessageSet = []proto.ExtensionRange{ + {100, 2147483646}, +} + +func (*MyMessageSet) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_MyMessageSet +} +func (m *MyMessageSet) ExtensionMap() map[int32]proto.Extension { + if m.XXX_extensions == nil { + m.XXX_extensions = make(map[int32]proto.Extension) + } + return m.XXX_extensions +} + +type Empty struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} + +type MessageList struct { + Message []*MessageList_Message `protobuf:"group,1,rep" json:"message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MessageList) Reset() { *m = MessageList{} } +func (m *MessageList) String() string { return proto.CompactTextString(m) } +func (*MessageList) ProtoMessage() {} + +func (m *MessageList) GetMessage() []*MessageList_Message { + if m != nil { + return m.Message + } + return nil +} + +type MessageList_Message struct { + Name *string `protobuf:"bytes,2,req,name=name" json:"name,omitempty"` + Count *int32 `protobuf:"varint,3,req,name=count" json:"count,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MessageList_Message) Reset() { *m = MessageList_Message{} } +func (m *MessageList_Message) String() string { return proto.CompactTextString(m) } +func (*MessageList_Message) ProtoMessage() {} + +func (m *MessageList_Message) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *MessageList_Message) GetCount() int32 { + if m != nil && m.Count != nil { + return *m.Count + } + return 0 +} + +type Strings struct { + StringField *string `protobuf:"bytes,1,opt,name=string_field" json:"string_field,omitempty"` + BytesField []byte `protobuf:"bytes,2,opt,name=bytes_field" json:"bytes_field,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Strings) Reset() { *m = Strings{} } +func (m *Strings) String() string { return proto.CompactTextString(m) } +func (*Strings) ProtoMessage() {} + +func (m *Strings) GetStringField() string { + if m != nil && m.StringField != nil { + return *m.StringField + } + return "" +} + +func (m *Strings) GetBytesField() []byte { + if m != nil { + return m.BytesField + } + return nil +} + +type Defaults struct { + // Default-valued fields of all basic types. + // Same as GoTest, but copied here to make testing easier. + F_Bool *bool `protobuf:"varint,1,opt,def=1" json:"F_Bool,omitempty"` + F_Int32 *int32 `protobuf:"varint,2,opt,def=32" json:"F_Int32,omitempty"` + F_Int64 *int64 `protobuf:"varint,3,opt,def=64" json:"F_Int64,omitempty"` + F_Fixed32 *uint32 `protobuf:"fixed32,4,opt,def=320" json:"F_Fixed32,omitempty"` + F_Fixed64 *uint64 `protobuf:"fixed64,5,opt,def=640" json:"F_Fixed64,omitempty"` + F_Uint32 *uint32 `protobuf:"varint,6,opt,def=3200" json:"F_Uint32,omitempty"` + F_Uint64 *uint64 `protobuf:"varint,7,opt,def=6400" json:"F_Uint64,omitempty"` + F_Float *float32 `protobuf:"fixed32,8,opt,def=314159" json:"F_Float,omitempty"` + F_Double *float64 `protobuf:"fixed64,9,opt,def=271828" json:"F_Double,omitempty"` + F_String *string `protobuf:"bytes,10,opt,def=hello, \"world!\"\n" json:"F_String,omitempty"` + F_Bytes []byte `protobuf:"bytes,11,opt,def=Bignose" json:"F_Bytes,omitempty"` + F_Sint32 *int32 `protobuf:"zigzag32,12,opt,def=-32" json:"F_Sint32,omitempty"` + F_Sint64 *int64 `protobuf:"zigzag64,13,opt,def=-64" json:"F_Sint64,omitempty"` + F_Enum *Defaults_Color `protobuf:"varint,14,opt,enum=testdata.Defaults_Color,def=1" json:"F_Enum,omitempty"` + // More fields with crazy defaults. + F_Pinf *float32 `protobuf:"fixed32,15,opt,def=inf" json:"F_Pinf,omitempty"` + F_Ninf *float32 `protobuf:"fixed32,16,opt,def=-inf" json:"F_Ninf,omitempty"` + F_Nan *float32 `protobuf:"fixed32,17,opt,def=nan" json:"F_Nan,omitempty"` + // Sub-message. + Sub *SubDefaults `protobuf:"bytes,18,opt,name=sub" json:"sub,omitempty"` + // Redundant but explicit defaults. + StrZero *string `protobuf:"bytes,19,opt,name=str_zero,def=" json:"str_zero,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Defaults) Reset() { *m = Defaults{} } +func (m *Defaults) String() string { return proto.CompactTextString(m) } +func (*Defaults) ProtoMessage() {} + +const Default_Defaults_F_Bool bool = true +const Default_Defaults_F_Int32 int32 = 32 +const Default_Defaults_F_Int64 int64 = 64 +const Default_Defaults_F_Fixed32 uint32 = 320 +const Default_Defaults_F_Fixed64 uint64 = 640 +const Default_Defaults_F_Uint32 uint32 = 3200 +const Default_Defaults_F_Uint64 uint64 = 6400 +const Default_Defaults_F_Float float32 = 314159 +const Default_Defaults_F_Double float64 = 271828 +const Default_Defaults_F_String string = "hello, \"world!\"\n" + +var Default_Defaults_F_Bytes []byte = []byte("Bignose") + +const Default_Defaults_F_Sint32 int32 = -32 +const Default_Defaults_F_Sint64 int64 = -64 +const Default_Defaults_F_Enum Defaults_Color = Defaults_GREEN + +var Default_Defaults_F_Pinf float32 = float32(math.Inf(1)) +var Default_Defaults_F_Ninf float32 = float32(math.Inf(-1)) +var Default_Defaults_F_Nan float32 = float32(math.NaN()) + +func (m *Defaults) GetF_Bool() bool { + if m != nil && m.F_Bool != nil { + return *m.F_Bool + } + return Default_Defaults_F_Bool +} + +func (m *Defaults) GetF_Int32() int32 { + if m != nil && m.F_Int32 != nil { + return *m.F_Int32 + } + return Default_Defaults_F_Int32 +} + +func (m *Defaults) GetF_Int64() int64 { + if m != nil && m.F_Int64 != nil { + return *m.F_Int64 + } + return Default_Defaults_F_Int64 +} + +func (m *Defaults) GetF_Fixed32() uint32 { + if m != nil && m.F_Fixed32 != nil { + return *m.F_Fixed32 + } + return Default_Defaults_F_Fixed32 +} + +func (m *Defaults) GetF_Fixed64() uint64 { + if m != nil && m.F_Fixed64 != nil { + return *m.F_Fixed64 + } + return Default_Defaults_F_Fixed64 +} + +func (m *Defaults) GetF_Uint32() uint32 { + if m != nil && m.F_Uint32 != nil { + return *m.F_Uint32 + } + return Default_Defaults_F_Uint32 +} + +func (m *Defaults) GetF_Uint64() uint64 { + if m != nil && m.F_Uint64 != nil { + return *m.F_Uint64 + } + return Default_Defaults_F_Uint64 +} + +func (m *Defaults) GetF_Float() float32 { + if m != nil && m.F_Float != nil { + return *m.F_Float + } + return Default_Defaults_F_Float +} + +func (m *Defaults) GetF_Double() float64 { + if m != nil && m.F_Double != nil { + return *m.F_Double + } + return Default_Defaults_F_Double +} + +func (m *Defaults) GetF_String() string { + if m != nil && m.F_String != nil { + return *m.F_String + } + return Default_Defaults_F_String +} + +func (m *Defaults) GetF_Bytes() []byte { + if m != nil && m.F_Bytes != nil { + return m.F_Bytes + } + return append([]byte(nil), Default_Defaults_F_Bytes...) +} + +func (m *Defaults) GetF_Sint32() int32 { + if m != nil && m.F_Sint32 != nil { + return *m.F_Sint32 + } + return Default_Defaults_F_Sint32 +} + +func (m *Defaults) GetF_Sint64() int64 { + if m != nil && m.F_Sint64 != nil { + return *m.F_Sint64 + } + return Default_Defaults_F_Sint64 +} + +func (m *Defaults) GetF_Enum() Defaults_Color { + if m != nil && m.F_Enum != nil { + return *m.F_Enum + } + return Default_Defaults_F_Enum +} + +func (m *Defaults) GetF_Pinf() float32 { + if m != nil && m.F_Pinf != nil { + return *m.F_Pinf + } + return Default_Defaults_F_Pinf +} + +func (m *Defaults) GetF_Ninf() float32 { + if m != nil && m.F_Ninf != nil { + return *m.F_Ninf + } + return Default_Defaults_F_Ninf +} + +func (m *Defaults) GetF_Nan() float32 { + if m != nil && m.F_Nan != nil { + return *m.F_Nan + } + return Default_Defaults_F_Nan +} + +func (m *Defaults) GetSub() *SubDefaults { + if m != nil { + return m.Sub + } + return nil +} + +func (m *Defaults) GetStrZero() string { + if m != nil && m.StrZero != nil { + return *m.StrZero + } + return "" +} + +type SubDefaults struct { + N *int64 `protobuf:"varint,1,opt,name=n,def=7" json:"n,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SubDefaults) Reset() { *m = SubDefaults{} } +func (m *SubDefaults) String() string { return proto.CompactTextString(m) } +func (*SubDefaults) ProtoMessage() {} + +const Default_SubDefaults_N int64 = 7 + +func (m *SubDefaults) GetN() int64 { + if m != nil && m.N != nil { + return *m.N + } + return Default_SubDefaults_N +} + +type RepeatedEnum struct { + Color []RepeatedEnum_Color `protobuf:"varint,1,rep,name=color,enum=testdata.RepeatedEnum_Color" json:"color,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *RepeatedEnum) Reset() { *m = RepeatedEnum{} } +func (m *RepeatedEnum) String() string { return proto.CompactTextString(m) } +func (*RepeatedEnum) ProtoMessage() {} + +func (m *RepeatedEnum) GetColor() []RepeatedEnum_Color { + if m != nil { + return m.Color + } + return nil +} + +type MoreRepeated struct { + Bools []bool `protobuf:"varint,1,rep,name=bools" json:"bools,omitempty"` + BoolsPacked []bool `protobuf:"varint,2,rep,packed,name=bools_packed" json:"bools_packed,omitempty"` + Ints []int32 `protobuf:"varint,3,rep,name=ints" json:"ints,omitempty"` + IntsPacked []int32 `protobuf:"varint,4,rep,packed,name=ints_packed" json:"ints_packed,omitempty"` + Int64SPacked []int64 `protobuf:"varint,7,rep,packed,name=int64s_packed" json:"int64s_packed,omitempty"` + Strings []string `protobuf:"bytes,5,rep,name=strings" json:"strings,omitempty"` + Fixeds []uint32 `protobuf:"fixed32,6,rep,name=fixeds" json:"fixeds,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MoreRepeated) Reset() { *m = MoreRepeated{} } +func (m *MoreRepeated) String() string { return proto.CompactTextString(m) } +func (*MoreRepeated) ProtoMessage() {} + +func (m *MoreRepeated) GetBools() []bool { + if m != nil { + return m.Bools + } + return nil +} + +func (m *MoreRepeated) GetBoolsPacked() []bool { + if m != nil { + return m.BoolsPacked + } + return nil +} + +func (m *MoreRepeated) GetInts() []int32 { + if m != nil { + return m.Ints + } + return nil +} + +func (m *MoreRepeated) GetIntsPacked() []int32 { + if m != nil { + return m.IntsPacked + } + return nil +} + +func (m *MoreRepeated) GetInt64SPacked() []int64 { + if m != nil { + return m.Int64SPacked + } + return nil +} + +func (m *MoreRepeated) GetStrings() []string { + if m != nil { + return m.Strings + } + return nil +} + +func (m *MoreRepeated) GetFixeds() []uint32 { + if m != nil { + return m.Fixeds + } + return nil +} + +type GroupOld struct { + G *GroupOld_G `protobuf:"group,101,opt" json:"g,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GroupOld) Reset() { *m = GroupOld{} } +func (m *GroupOld) String() string { return proto.CompactTextString(m) } +func (*GroupOld) ProtoMessage() {} + +func (m *GroupOld) GetG() *GroupOld_G { + if m != nil { + return m.G + } + return nil +} + +type GroupOld_G struct { + X *int32 `protobuf:"varint,2,opt,name=x" json:"x,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GroupOld_G) Reset() { *m = GroupOld_G{} } +func (m *GroupOld_G) String() string { return proto.CompactTextString(m) } +func (*GroupOld_G) ProtoMessage() {} + +func (m *GroupOld_G) GetX() int32 { + if m != nil && m.X != nil { + return *m.X + } + return 0 +} + +type GroupNew struct { + G *GroupNew_G `protobuf:"group,101,opt" json:"g,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GroupNew) Reset() { *m = GroupNew{} } +func (m *GroupNew) String() string { return proto.CompactTextString(m) } +func (*GroupNew) ProtoMessage() {} + +func (m *GroupNew) GetG() *GroupNew_G { + if m != nil { + return m.G + } + return nil +} + +type GroupNew_G struct { + X *int32 `protobuf:"varint,2,opt,name=x" json:"x,omitempty"` + Y *int32 `protobuf:"varint,3,opt,name=y" json:"y,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GroupNew_G) Reset() { *m = GroupNew_G{} } +func (m *GroupNew_G) String() string { return proto.CompactTextString(m) } +func (*GroupNew_G) ProtoMessage() {} + +func (m *GroupNew_G) GetX() int32 { + if m != nil && m.X != nil { + return *m.X + } + return 0 +} + +func (m *GroupNew_G) GetY() int32 { + if m != nil && m.Y != nil { + return *m.Y + } + return 0 +} + +type FloatingPoint struct { + F *float64 `protobuf:"fixed64,1,req,name=f" json:"f,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FloatingPoint) Reset() { *m = FloatingPoint{} } +func (m *FloatingPoint) String() string { return proto.CompactTextString(m) } +func (*FloatingPoint) ProtoMessage() {} + +func (m *FloatingPoint) GetF() float64 { + if m != nil && m.F != nil { + return *m.F + } + return 0 +} + +type MessageWithMap struct { + NameMapping map[int32]string `protobuf:"bytes,1,rep,name=name_mapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + MsgMapping map[int64]*FloatingPoint `protobuf:"bytes,2,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + ByteMapping map[bool][]byte `protobuf:"bytes,3,rep,name=byte_mapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + StrToStr map[string]string `protobuf:"bytes,4,rep,name=str_to_str" json:"str_to_str,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MessageWithMap) Reset() { *m = MessageWithMap{} } +func (m *MessageWithMap) String() string { return proto.CompactTextString(m) } +func (*MessageWithMap) ProtoMessage() {} + +func (m *MessageWithMap) GetNameMapping() map[int32]string { + if m != nil { + return m.NameMapping + } + return nil +} + +func (m *MessageWithMap) GetMsgMapping() map[int64]*FloatingPoint { + if m != nil { + return m.MsgMapping + } + return nil +} + +func (m *MessageWithMap) GetByteMapping() map[bool][]byte { + if m != nil { + return m.ByteMapping + } + return nil +} + +func (m *MessageWithMap) GetStrToStr() map[string]string { + if m != nil { + return m.StrToStr + } + return nil +} + +var E_Greeting = &proto.ExtensionDesc{ + ExtendedType: (*MyMessage)(nil), + ExtensionType: ([]string)(nil), + Field: 106, + Name: "testdata.greeting", + Tag: "bytes,106,rep,name=greeting", +} + +var E_X201 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 201, + Name: "testdata.x201", + Tag: "bytes,201,opt,name=x201", +} + +var E_X202 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 202, + Name: "testdata.x202", + Tag: "bytes,202,opt,name=x202", +} + +var E_X203 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 203, + Name: "testdata.x203", + Tag: "bytes,203,opt,name=x203", +} + +var E_X204 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 204, + Name: "testdata.x204", + Tag: "bytes,204,opt,name=x204", +} + +var E_X205 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 205, + Name: "testdata.x205", + Tag: "bytes,205,opt,name=x205", +} + +var E_X206 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 206, + Name: "testdata.x206", + Tag: "bytes,206,opt,name=x206", +} + +var E_X207 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 207, + Name: "testdata.x207", + Tag: "bytes,207,opt,name=x207", +} + +var E_X208 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 208, + Name: "testdata.x208", + Tag: "bytes,208,opt,name=x208", +} + +var E_X209 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 209, + Name: "testdata.x209", + Tag: "bytes,209,opt,name=x209", +} + +var E_X210 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 210, + Name: "testdata.x210", + Tag: "bytes,210,opt,name=x210", +} + +var E_X211 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 211, + Name: "testdata.x211", + Tag: "bytes,211,opt,name=x211", +} + +var E_X212 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 212, + Name: "testdata.x212", + Tag: "bytes,212,opt,name=x212", +} + +var E_X213 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 213, + Name: "testdata.x213", + Tag: "bytes,213,opt,name=x213", +} + +var E_X214 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 214, + Name: "testdata.x214", + Tag: "bytes,214,opt,name=x214", +} + +var E_X215 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 215, + Name: "testdata.x215", + Tag: "bytes,215,opt,name=x215", +} + +var E_X216 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 216, + Name: "testdata.x216", + Tag: "bytes,216,opt,name=x216", +} + +var E_X217 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 217, + Name: "testdata.x217", + Tag: "bytes,217,opt,name=x217", +} + +var E_X218 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 218, + Name: "testdata.x218", + Tag: "bytes,218,opt,name=x218", +} + +var E_X219 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 219, + Name: "testdata.x219", + Tag: "bytes,219,opt,name=x219", +} + +var E_X220 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 220, + Name: "testdata.x220", + Tag: "bytes,220,opt,name=x220", +} + +var E_X221 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 221, + Name: "testdata.x221", + Tag: "bytes,221,opt,name=x221", +} + +var E_X222 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 222, + Name: "testdata.x222", + Tag: "bytes,222,opt,name=x222", +} + +var E_X223 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 223, + Name: "testdata.x223", + Tag: "bytes,223,opt,name=x223", +} + +var E_X224 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 224, + Name: "testdata.x224", + Tag: "bytes,224,opt,name=x224", +} + +var E_X225 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 225, + Name: "testdata.x225", + Tag: "bytes,225,opt,name=x225", +} + +var E_X226 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 226, + Name: "testdata.x226", + Tag: "bytes,226,opt,name=x226", +} + +var E_X227 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 227, + Name: "testdata.x227", + Tag: "bytes,227,opt,name=x227", +} + +var E_X228 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 228, + Name: "testdata.x228", + Tag: "bytes,228,opt,name=x228", +} + +var E_X229 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 229, + Name: "testdata.x229", + Tag: "bytes,229,opt,name=x229", +} + +var E_X230 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 230, + Name: "testdata.x230", + Tag: "bytes,230,opt,name=x230", +} + +var E_X231 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 231, + Name: "testdata.x231", + Tag: "bytes,231,opt,name=x231", +} + +var E_X232 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 232, + Name: "testdata.x232", + Tag: "bytes,232,opt,name=x232", +} + +var E_X233 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 233, + Name: "testdata.x233", + Tag: "bytes,233,opt,name=x233", +} + +var E_X234 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 234, + Name: "testdata.x234", + Tag: "bytes,234,opt,name=x234", +} + +var E_X235 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 235, + Name: "testdata.x235", + Tag: "bytes,235,opt,name=x235", +} + +var E_X236 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 236, + Name: "testdata.x236", + Tag: "bytes,236,opt,name=x236", +} + +var E_X237 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 237, + Name: "testdata.x237", + Tag: "bytes,237,opt,name=x237", +} + +var E_X238 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 238, + Name: "testdata.x238", + Tag: "bytes,238,opt,name=x238", +} + +var E_X239 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 239, + Name: "testdata.x239", + Tag: "bytes,239,opt,name=x239", +} + +var E_X240 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 240, + Name: "testdata.x240", + Tag: "bytes,240,opt,name=x240", +} + +var E_X241 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 241, + Name: "testdata.x241", + Tag: "bytes,241,opt,name=x241", +} + +var E_X242 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 242, + Name: "testdata.x242", + Tag: "bytes,242,opt,name=x242", +} + +var E_X243 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 243, + Name: "testdata.x243", + Tag: "bytes,243,opt,name=x243", +} + +var E_X244 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 244, + Name: "testdata.x244", + Tag: "bytes,244,opt,name=x244", +} + +var E_X245 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 245, + Name: "testdata.x245", + Tag: "bytes,245,opt,name=x245", +} + +var E_X246 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 246, + Name: "testdata.x246", + Tag: "bytes,246,opt,name=x246", +} + +var E_X247 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 247, + Name: "testdata.x247", + Tag: "bytes,247,opt,name=x247", +} + +var E_X248 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 248, + Name: "testdata.x248", + Tag: "bytes,248,opt,name=x248", +} + +var E_X249 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 249, + Name: "testdata.x249", + Tag: "bytes,249,opt,name=x249", +} + +var E_X250 = &proto.ExtensionDesc{ + ExtendedType: (*MyMessageSet)(nil), + ExtensionType: (*Empty)(nil), + Field: 250, + Name: "testdata.x250", + Tag: "bytes,250,opt,name=x250", +} + +func init() { + proto.RegisterEnum("testdata.FOO", FOO_name, FOO_value) + proto.RegisterEnum("testdata.GoTest_KIND", GoTest_KIND_name, GoTest_KIND_value) + proto.RegisterEnum("testdata.MyMessage_Color", MyMessage_Color_name, MyMessage_Color_value) + proto.RegisterEnum("testdata.Defaults_Color", Defaults_Color_name, Defaults_Color_value) + proto.RegisterEnum("testdata.RepeatedEnum_Color", RepeatedEnum_Color_name, RepeatedEnum_Color_value) + proto.RegisterExtension(E_Ext_More) + proto.RegisterExtension(E_Ext_Text) + proto.RegisterExtension(E_Ext_Number) + proto.RegisterExtension(E_Greeting) + proto.RegisterExtension(E_X201) + proto.RegisterExtension(E_X202) + proto.RegisterExtension(E_X203) + proto.RegisterExtension(E_X204) + proto.RegisterExtension(E_X205) + proto.RegisterExtension(E_X206) + proto.RegisterExtension(E_X207) + proto.RegisterExtension(E_X208) + proto.RegisterExtension(E_X209) + proto.RegisterExtension(E_X210) + proto.RegisterExtension(E_X211) + proto.RegisterExtension(E_X212) + proto.RegisterExtension(E_X213) + proto.RegisterExtension(E_X214) + proto.RegisterExtension(E_X215) + proto.RegisterExtension(E_X216) + proto.RegisterExtension(E_X217) + proto.RegisterExtension(E_X218) + proto.RegisterExtension(E_X219) + proto.RegisterExtension(E_X220) + proto.RegisterExtension(E_X221) + proto.RegisterExtension(E_X222) + proto.RegisterExtension(E_X223) + proto.RegisterExtension(E_X224) + proto.RegisterExtension(E_X225) + proto.RegisterExtension(E_X226) + proto.RegisterExtension(E_X227) + proto.RegisterExtension(E_X228) + proto.RegisterExtension(E_X229) + proto.RegisterExtension(E_X230) + proto.RegisterExtension(E_X231) + proto.RegisterExtension(E_X232) + proto.RegisterExtension(E_X233) + proto.RegisterExtension(E_X234) + proto.RegisterExtension(E_X235) + proto.RegisterExtension(E_X236) + proto.RegisterExtension(E_X237) + proto.RegisterExtension(E_X238) + proto.RegisterExtension(E_X239) + proto.RegisterExtension(E_X240) + proto.RegisterExtension(E_X241) + proto.RegisterExtension(E_X242) + proto.RegisterExtension(E_X243) + proto.RegisterExtension(E_X244) + proto.RegisterExtension(E_X245) + proto.RegisterExtension(E_X246) + proto.RegisterExtension(E_X247) + proto.RegisterExtension(E_X248) + proto.RegisterExtension(E_X249) + proto.RegisterExtension(E_X250) +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto new file mode 100644 index 00000000..411634d8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata/test.proto @@ -0,0 +1,435 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A feature-rich test file for the protocol compiler and libraries. + +syntax = "proto2"; + +package testdata; + +enum FOO { FOO1 = 1; }; + +message GoEnum { + required FOO foo = 1; +} + +message GoTestField { + required string Label = 1; + required string Type = 2; +} + +message GoTest { + // An enum, for completeness. + enum KIND { + VOID = 0; + + // Basic types + BOOL = 1; + BYTES = 2; + FINGERPRINT = 3; + FLOAT = 4; + INT = 5; + STRING = 6; + TIME = 7; + + // Groupings + TUPLE = 8; + ARRAY = 9; + MAP = 10; + + // Table types + TABLE = 11; + + // Functions + FUNCTION = 12; // last tag + }; + + // Some typical parameters + required KIND Kind = 1; + optional string Table = 2; + optional int32 Param = 3; + + // Required, repeated and optional foreign fields. + required GoTestField RequiredField = 4; + repeated GoTestField RepeatedField = 5; + optional GoTestField OptionalField = 6; + + // Required fields of all basic types + required bool F_Bool_required = 10; + required int32 F_Int32_required = 11; + required int64 F_Int64_required = 12; + required fixed32 F_Fixed32_required = 13; + required fixed64 F_Fixed64_required = 14; + required uint32 F_Uint32_required = 15; + required uint64 F_Uint64_required = 16; + required float F_Float_required = 17; + required double F_Double_required = 18; + required string F_String_required = 19; + required bytes F_Bytes_required = 101; + required sint32 F_Sint32_required = 102; + required sint64 F_Sint64_required = 103; + + // Repeated fields of all basic types + repeated bool F_Bool_repeated = 20; + repeated int32 F_Int32_repeated = 21; + repeated int64 F_Int64_repeated = 22; + repeated fixed32 F_Fixed32_repeated = 23; + repeated fixed64 F_Fixed64_repeated = 24; + repeated uint32 F_Uint32_repeated = 25; + repeated uint64 F_Uint64_repeated = 26; + repeated float F_Float_repeated = 27; + repeated double F_Double_repeated = 28; + repeated string F_String_repeated = 29; + repeated bytes F_Bytes_repeated = 201; + repeated sint32 F_Sint32_repeated = 202; + repeated sint64 F_Sint64_repeated = 203; + + // Optional fields of all basic types + optional bool F_Bool_optional = 30; + optional int32 F_Int32_optional = 31; + optional int64 F_Int64_optional = 32; + optional fixed32 F_Fixed32_optional = 33; + optional fixed64 F_Fixed64_optional = 34; + optional uint32 F_Uint32_optional = 35; + optional uint64 F_Uint64_optional = 36; + optional float F_Float_optional = 37; + optional double F_Double_optional = 38; + optional string F_String_optional = 39; + optional bytes F_Bytes_optional = 301; + optional sint32 F_Sint32_optional = 302; + optional sint64 F_Sint64_optional = 303; + + // Default-valued fields of all basic types + optional bool F_Bool_defaulted = 40 [default=true]; + optional int32 F_Int32_defaulted = 41 [default=32]; + optional int64 F_Int64_defaulted = 42 [default=64]; + optional fixed32 F_Fixed32_defaulted = 43 [default=320]; + optional fixed64 F_Fixed64_defaulted = 44 [default=640]; + optional uint32 F_Uint32_defaulted = 45 [default=3200]; + optional uint64 F_Uint64_defaulted = 46 [default=6400]; + optional float F_Float_defaulted = 47 [default=314159.]; + optional double F_Double_defaulted = 48 [default=271828.]; + optional string F_String_defaulted = 49 [default="hello, \"world!\"\n"]; + optional bytes F_Bytes_defaulted = 401 [default="Bignose"]; + optional sint32 F_Sint32_defaulted = 402 [default = -32]; + optional sint64 F_Sint64_defaulted = 403 [default = -64]; + + // Packed repeated fields (no string or bytes). + repeated bool F_Bool_repeated_packed = 50 [packed=true]; + repeated int32 F_Int32_repeated_packed = 51 [packed=true]; + repeated int64 F_Int64_repeated_packed = 52 [packed=true]; + repeated fixed32 F_Fixed32_repeated_packed = 53 [packed=true]; + repeated fixed64 F_Fixed64_repeated_packed = 54 [packed=true]; + repeated uint32 F_Uint32_repeated_packed = 55 [packed=true]; + repeated uint64 F_Uint64_repeated_packed = 56 [packed=true]; + repeated float F_Float_repeated_packed = 57 [packed=true]; + repeated double F_Double_repeated_packed = 58 [packed=true]; + repeated sint32 F_Sint32_repeated_packed = 502 [packed=true]; + repeated sint64 F_Sint64_repeated_packed = 503 [packed=true]; + + // Required, repeated, and optional groups. + required group RequiredGroup = 70 { + required string RequiredField = 71; + }; + + repeated group RepeatedGroup = 80 { + required string RequiredField = 81; + }; + + optional group OptionalGroup = 90 { + required string RequiredField = 91; + }; +} + +// For testing skipping of unrecognized fields. +// Numbers are all big, larger than tag numbers in GoTestField, +// the message used in the corresponding test. +message GoSkipTest { + required int32 skip_int32 = 11; + required fixed32 skip_fixed32 = 12; + required fixed64 skip_fixed64 = 13; + required string skip_string = 14; + required group SkipGroup = 15 { + required int32 group_int32 = 16; + required string group_string = 17; + } +} + +// For testing packed/non-packed decoder switching. +// A serialized instance of one should be deserializable as the other. +message NonPackedTest { + repeated int32 a = 1; +} + +message PackedTest { + repeated int32 b = 1 [packed=true]; +} + +message MaxTag { + // Maximum possible tag number. + optional string last_field = 536870911; +} + +message OldMessage { + message Nested { + optional string name = 1; + } + optional Nested nested = 1; + + optional int32 num = 2; +} + +// NewMessage is wire compatible with OldMessage; +// imagine it as a future version. +message NewMessage { + message Nested { + optional string name = 1; + optional string food_group = 2; + } + optional Nested nested = 1; + + // This is an int32 in OldMessage. + optional int64 num = 2; +} + +// Smaller tests for ASCII formatting. + +message InnerMessage { + required string host = 1; + optional int32 port = 2 [default=4000]; + optional bool connected = 3; +} + +message OtherMessage { + optional int64 key = 1; + optional bytes value = 2; + optional float weight = 3; + optional InnerMessage inner = 4; +} + +message MyMessage { + required int32 count = 1; + optional string name = 2; + optional string quote = 3; + repeated string pet = 4; + optional InnerMessage inner = 5; + repeated OtherMessage others = 6; + repeated InnerMessage rep_inner = 12; + + enum Color { + RED = 0; + GREEN = 1; + BLUE = 2; + }; + optional Color bikeshed = 7; + + optional group SomeGroup = 8 { + optional int32 group_field = 9; + } + + // This field becomes [][]byte in the generated code. + repeated bytes rep_bytes = 10; + + optional double bigfloat = 11; + + extensions 100 to max; +} + +message Ext { + extend MyMessage { + optional Ext more = 103; + optional string text = 104; + optional int32 number = 105; + } + + optional string data = 1; +} + +extend MyMessage { + repeated string greeting = 106; +} + +message MyMessageSet { + option message_set_wire_format = true; + extensions 100 to max; +} + +message Empty { +} + +extend MyMessageSet { + optional Empty x201 = 201; + optional Empty x202 = 202; + optional Empty x203 = 203; + optional Empty x204 = 204; + optional Empty x205 = 205; + optional Empty x206 = 206; + optional Empty x207 = 207; + optional Empty x208 = 208; + optional Empty x209 = 209; + optional Empty x210 = 210; + optional Empty x211 = 211; + optional Empty x212 = 212; + optional Empty x213 = 213; + optional Empty x214 = 214; + optional Empty x215 = 215; + optional Empty x216 = 216; + optional Empty x217 = 217; + optional Empty x218 = 218; + optional Empty x219 = 219; + optional Empty x220 = 220; + optional Empty x221 = 221; + optional Empty x222 = 222; + optional Empty x223 = 223; + optional Empty x224 = 224; + optional Empty x225 = 225; + optional Empty x226 = 226; + optional Empty x227 = 227; + optional Empty x228 = 228; + optional Empty x229 = 229; + optional Empty x230 = 230; + optional Empty x231 = 231; + optional Empty x232 = 232; + optional Empty x233 = 233; + optional Empty x234 = 234; + optional Empty x235 = 235; + optional Empty x236 = 236; + optional Empty x237 = 237; + optional Empty x238 = 238; + optional Empty x239 = 239; + optional Empty x240 = 240; + optional Empty x241 = 241; + optional Empty x242 = 242; + optional Empty x243 = 243; + optional Empty x244 = 244; + optional Empty x245 = 245; + optional Empty x246 = 246; + optional Empty x247 = 247; + optional Empty x248 = 248; + optional Empty x249 = 249; + optional Empty x250 = 250; +} + +message MessageList { + repeated group Message = 1 { + required string name = 2; + required int32 count = 3; + } +} + +message Strings { + optional string string_field = 1; + optional bytes bytes_field = 2; +} + +message Defaults { + enum Color { + RED = 0; + GREEN = 1; + BLUE = 2; + } + + // Default-valued fields of all basic types. + // Same as GoTest, but copied here to make testing easier. + optional bool F_Bool = 1 [default=true]; + optional int32 F_Int32 = 2 [default=32]; + optional int64 F_Int64 = 3 [default=64]; + optional fixed32 F_Fixed32 = 4 [default=320]; + optional fixed64 F_Fixed64 = 5 [default=640]; + optional uint32 F_Uint32 = 6 [default=3200]; + optional uint64 F_Uint64 = 7 [default=6400]; + optional float F_Float = 8 [default=314159.]; + optional double F_Double = 9 [default=271828.]; + optional string F_String = 10 [default="hello, \"world!\"\n"]; + optional bytes F_Bytes = 11 [default="Bignose"]; + optional sint32 F_Sint32 = 12 [default=-32]; + optional sint64 F_Sint64 = 13 [default=-64]; + optional Color F_Enum = 14 [default=GREEN]; + + // More fields with crazy defaults. + optional float F_Pinf = 15 [default=inf]; + optional float F_Ninf = 16 [default=-inf]; + optional float F_Nan = 17 [default=nan]; + + // Sub-message. + optional SubDefaults sub = 18; + + // Redundant but explicit defaults. + optional string str_zero = 19 [default=""]; +} + +message SubDefaults { + optional int64 n = 1 [default=7]; +} + +message RepeatedEnum { + enum Color { + RED = 1; + } + repeated Color color = 1; +} + +message MoreRepeated { + repeated bool bools = 1; + repeated bool bools_packed = 2 [packed=true]; + repeated int32 ints = 3; + repeated int32 ints_packed = 4 [packed=true]; + repeated int64 int64s_packed = 7 [packed=true]; + repeated string strings = 5; + repeated fixed32 fixeds = 6; +} + +// GroupOld and GroupNew have the same wire format. +// GroupNew has a new field inside a group. + +message GroupOld { + optional group G = 101 { + optional int32 x = 2; + } +} + +message GroupNew { + optional group G = 101 { + optional int32 x = 2; + optional int32 y = 3; + } +} + +message FloatingPoint { + required double f = 1; +} + +message MessageWithMap { + map name_mapping = 1; + map msg_mapping = 2; + map byte_mapping = 3; + map str_to_str = 4; +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go new file mode 100644 index 00000000..720eac47 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go @@ -0,0 +1,789 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "fmt" + "io" + "log" + "math" + "os" + "reflect" + "sort" + "strings" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + gtNewline = []byte(">\n") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Printf("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +var ( + messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem() +) + +// raw is the interface satisfied by RawMessage. +type raw interface { + Bytes() []byte +} + +func writeStruct(w *textWriter, sv reflect.Value) error { + if sv.Type() == messageSetType { + return writeMessageSet(w, sv.Addr().Interface().(*MessageSet)) + } + + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + continue + } + if err := writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() // TODO: should we sort these for deterministic output? + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + switch fv.Kind() { + case reflect.Bool: + if !fv.Bool() { + continue + } + case reflect.Int32, reflect.Int64: + if fv.Int() == 0 { + continue + } + case reflect.Uint32, reflect.Uint64: + if fv.Uint() == 0 { + continue + } + case reflect.Float32, reflect.Float64: + if fv.Float() == 0 { + continue + } + case reflect.String: + if fv.String() == "" { + continue + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if b, ok := fv.Interface().(raw); ok { + if err := writeRaw(w, b.Bytes()); err != nil { + return err + } + continue + } + + // Enums have a String method, so writeAny will work fine. + if err := writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv.Addr() + if pv.Type().Implements(extendableProtoType) { + if err := writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +// writeRaw writes an uninterpreted raw message. +func writeRaw(w *textWriter, b []byte) error { + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if err := writeUnknownStruct(w, b); err != nil { + return err + } + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + return nil +} + +// writeAny writes an arbitrary field. +func writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Interface().([]byte))); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if tm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := tm.MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else if err := writeStruct(w, v); err != nil { + return err + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeMessageSet(w *textWriter, ms *MessageSet) error { + for _, item := range ms.Item { + id := *item.TypeId + if msd, ok := messageSetMap[id]; ok { + // Known message set type. + if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil { + return err + } + w.indent() + + pb := reflect.New(msd.t.Elem()) + if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil { + if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil { + return err + } + } else { + if err := writeStruct(w, pb.Elem()); err != nil { + return err + } + } + } else { + // Unknown type. + if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil { + return err + } + w.indent() + if err := writeUnknownStruct(w, item.Message); err != nil { + return err + } + } + w.unindent() + if _, err := w.Write(gtNewline); err != nil { + return err + } + } + return nil +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, err := fmt.Fprintf(w, "/* %v */\n", err) + return err + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, err := w.Write(endBraceNewline); err != nil { + return err + } + continue + } + if _, err := fmt.Fprint(w, tag); err != nil { + return err + } + if wire != WireStartGroup { + if err := w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err := w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err = w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + ep := pv.Interface().(extendableProto) + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + m := ep.ExtensionMap() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(ep, desc) + if err != nil { + if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil { + return err + } + continue + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +func marshalText(w io.Writer, pb Message, compact bool) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: compact, + } + + if tm, ok := pb.(encoding.TextMarshaler); ok { + text, err := tm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { + return marshalText(w, pb, false) +} + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { + var buf bytes.Buffer + marshalText(&buf, pb, false) + return buf.String() +} + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { + var buf bytes.Buffer + marshalText(&buf, pb, true) + return buf.String() +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go new file mode 100644 index 00000000..d1caeff5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go @@ -0,0 +1,757 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "unicode/utf8" +) + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %v", p.s[0:i+1]) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") + errBadHex = errors.New("proto: bad hexadecimal") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + base := 8 + ss := s[:2] + s = s[2:] + if r == 'x' || r == 'X' { + base = 16 + } else { + ss = string(r) + ss + } + i, err := strconv.ParseUint(ss, base, 8) + if err != nil { + return "", "", err + } + return string([]byte{byte(i)}), s, nil + case 'u', 'U': + n := 4 + if r == 'U' { + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) + } + + bs := make([]byte, n/2) + for i := 0; i < n; i += 2 { + a, ok1 := unhex(s[i]) + b, ok2 := unhex(s[i+1]) + if !ok1 || !ok2 { + return "", "", errBadHex + } + bs[i/2] = a<<4 | b + } + s = s[n:] + return string(bs), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Adapted from src/pkg/strconv/quote.go. +func unhex(b byte) (v byte, ok bool) { + switch { + case '0' <= b && b <= '9': + return b - '0', true + case 'a' <= b && b <= 'f': + return b - 'a' + 10, true + case 'A' <= b && b <= 'F': + return b - 'A' + 10, true + } + return 0, false +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && p.cur.value[0] == '"' { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || p.s[0] != '"' { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) { + sprops := GetProperties(st) + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + reqCount := GetProperties(st).reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]". + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + tok = p.next() + if tok.err != nil { + return tok.err + } + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == tok.value { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", tok.value) + } + // Check the extension terminator. + tok = p.next() + if tok.err != nil { + return tok.err + } + if tok.value != "]" { + return p.errorf("unrecognized extension terminator %q", tok.value) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(extendableProto) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + } else { + // This is a normal, non-extension field. + name := tok.value + fi, props, ok := structFieldByName(st, name) + if !ok { + return p.errorf("unknown field name %q in %v", name, st) + } + + dst := sv.Field(fi) + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // Technically the "key" and "value" could come in any order, + // but in practice they won't. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + if err := p.consumeToken("key"); err != nil { + return err + } + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeToken("value"); err != nil { + return err + } + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeToken(terminator); err != nil { + return err + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, st.Field(fi).Type); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } else if props.Required { + reqCount-- + } + } + + // For backward compatibility, permit a semicolon or comma after a field. + tok = p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. May already exist. + flen := fv.Len() + if flen == fv.Cap() { + nav := reflect.MakeSlice(at, flen, 2*flen+1) + reflect.Copy(nav, fv) + fv.Set(nav) + } + fv.SetLen(flen + 1) + + // Read one. + p.back() + return p.readAny(fv.Index(flen), props) + case reflect.Bool: + // Either "true", "false", 1 or 0. + switch tok.value { + case "true", "1": + fv.SetBool(true) + return nil + case "false", "0": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(uint64(x)) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + err := um.UnmarshalText([]byte(s)) + return err + } + pb.Reset() + v := reflect.ValueOf(pb) + if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { + return pe + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go new file mode 100644 index 00000000..8aeca60c --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser_test.go @@ -0,0 +1,511 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "math" + "reflect" + "testing" + + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + proto3pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto" + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +type UnmarshalTextTest struct { + in string + err string // if "", no error expected + out *MyMessage +} + +func buildExtStructTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + SetExtension(msg, E_Ext_More, &Ext{ + Data: String("Hello, world!"), + }) + return UnmarshalTextTest{in: text, out: msg} +} + +func buildExtDataTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + SetExtension(msg, E_Ext_Text, String("Hello, world!")) + SetExtension(msg, E_Ext_Number, Int32(1729)) + return UnmarshalTextTest{in: text, out: msg} +} + +func buildExtRepStringTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil { + panic(err) + } + return UnmarshalTextTest{in: text, out: msg} +} + +var unMarshalTextTests = []UnmarshalTextTest{ + // Basic + { + in: " count:42\n name:\"Dave\" ", + out: &MyMessage{ + Count: Int32(42), + Name: String("Dave"), + }, + }, + + // Empty quoted string + { + in: `count:42 name:""`, + out: &MyMessage{ + Count: Int32(42), + Name: String(""), + }, + }, + + // Quoted string concatenation + { + in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string with escaped apostrophe + { + in: `count:42 name: "HOLIDAY - New Year\'s Day"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("HOLIDAY - New Year's Day"), + }, + }, + + // Quoted string with single quote + { + in: `count:42 name: 'Roger "The Ramster" Ramjet'`, + out: &MyMessage{ + Count: Int32(42), + Name: String(`Roger "The Ramster" Ramjet`), + }, + }, + + // Quoted string with all the accepted special characters from the C++ test + { + in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"", + out: &MyMessage{ + Count: Int32(42), + Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"), + }, + }, + + // Quoted string with quoted backslash + { + in: `count:42 name: "\\'xyz"`, + out: &MyMessage{ + Count: Int32(42), + Name: String(`\'xyz`), + }, + }, + + // Quoted string with UTF-8 bytes. + { + in: "count:42 name: '\303\277\302\201\xAB'", + out: &MyMessage{ + Count: Int32(42), + Name: String("\303\277\302\201\xAB"), + }, + }, + + // Bad quoted string + { + in: `inner: < host: "\0" >` + "\n", + err: `line 1.15: invalid quoted string "\0"`, + }, + + // Number too large for int64 + { + in: "count: 1 others { key: 123456789012345678901 }", + err: "line 1.23: invalid int64: 123456789012345678901", + }, + + // Number too large for int32 + { + in: "count: 1234567890123", + err: "line 1.7: invalid int32: 1234567890123", + }, + + // Number in hexadecimal + { + in: "count: 0x2beef", + out: &MyMessage{ + Count: Int32(0x2beef), + }, + }, + + // Number in octal + { + in: "count: 024601", + out: &MyMessage{ + Count: Int32(024601), + }, + }, + + // Floating point number with "f" suffix + { + in: "count: 4 others:< weight: 17.0f >", + out: &MyMessage{ + Count: Int32(4), + Others: []*OtherMessage{ + { + Weight: Float32(17), + }, + }, + }, + }, + + // Floating point positive infinity + { + in: "count: 4 bigfloat: inf", + out: &MyMessage{ + Count: Int32(4), + Bigfloat: Float64(math.Inf(1)), + }, + }, + + // Floating point negative infinity + { + in: "count: 4 bigfloat: -inf", + out: &MyMessage{ + Count: Int32(4), + Bigfloat: Float64(math.Inf(-1)), + }, + }, + + // Number too large for float32 + { + in: "others:< weight: 12345678901234567890123456789012345678901234567890 >", + err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890", + }, + + // Number posing as a quoted string + { + in: `inner: < host: 12 >` + "\n", + err: `line 1.15: invalid string: 12`, + }, + + // Quoted string posing as int32 + { + in: `count: "12"`, + err: `line 1.7: invalid int32: "12"`, + }, + + // Quoted string posing a float32 + { + in: `others:< weight: "17.4" >`, + err: `line 1.17: invalid float32: "17.4"`, + }, + + // Enum + { + in: `count:42 bikeshed: BLUE`, + out: &MyMessage{ + Count: Int32(42), + Bikeshed: MyMessage_BLUE.Enum(), + }, + }, + + // Repeated field + { + in: `count:42 pet: "horsey" pet:"bunny"`, + out: &MyMessage{ + Count: Int32(42), + Pet: []string{"horsey", "bunny"}, + }, + }, + + // Repeated message with/without colon and <>/{} + { + in: `count:42 others:{} others{} others:<> others:{}`, + out: &MyMessage{ + Count: Int32(42), + Others: []*OtherMessage{ + {}, + {}, + {}, + {}, + }, + }, + }, + + // Missing colon for inner message + { + in: `count:42 inner < host: "cauchy.syd" >`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("cauchy.syd"), + }, + }, + }, + + // Missing colon for string field + { + in: `name "Dave"`, + err: `line 1.5: expected ':', found "\"Dave\""`, + }, + + // Missing colon for int32 field + { + in: `count 42`, + err: `line 1.6: expected ':', found "42"`, + }, + + // Missing required field + { + in: `name: "Pawel"`, + err: `proto: required field "testdata.MyMessage.count" not set`, + out: &MyMessage{ + Name: String("Pawel"), + }, + }, + + // Repeated non-repeated field + { + in: `name: "Rob" name: "Russ"`, + err: `line 1.12: non-repeated field "name" was repeated`, + }, + + // Group + { + in: `count: 17 SomeGroup { group_field: 12 }`, + out: &MyMessage{ + Count: Int32(17), + Somegroup: &MyMessage_SomeGroup{ + GroupField: Int32(12), + }, + }, + }, + + // Semicolon between fields + { + in: `count:3;name:"Calvin"`, + out: &MyMessage{ + Count: Int32(3), + Name: String("Calvin"), + }, + }, + // Comma between fields + { + in: `count:4,name:"Ezekiel"`, + out: &MyMessage{ + Count: Int32(4), + Name: String("Ezekiel"), + }, + }, + + // Extension + buildExtStructTest(`count: 42 [testdata.Ext.more]:`), + buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`), + buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`), + buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`), + + // Big all-in-one + { + in: "count:42 # Meaning\n" + + `name:"Dave" ` + + `quote:"\"I didn't want to go.\"" ` + + `pet:"bunny" ` + + `pet:"kitty" ` + + `pet:"horsey" ` + + `inner:<` + + ` host:"footrest.syd" ` + + ` port:7001 ` + + ` connected:true ` + + `> ` + + `others:<` + + ` key:3735928559 ` + + ` value:"\x01A\a\f" ` + + `> ` + + `others:<` + + " weight:58.9 # Atomic weight of Co\n" + + ` inner:<` + + ` host:"lesha.mtv" ` + + ` port:8002 ` + + ` >` + + `>`, + out: &MyMessage{ + Count: Int32(42), + Name: String("Dave"), + Quote: String(`"I didn't want to go."`), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &InnerMessage{ + Host: String("footrest.syd"), + Port: Int32(7001), + Connected: Bool(true), + }, + Others: []*OtherMessage{ + { + Key: Int64(3735928559), + Value: []byte{0x1, 'A', '\a', '\f'}, + }, + { + Weight: Float32(58.9), + Inner: &InnerMessage{ + Host: String("lesha.mtv"), + Port: Int32(8002), + }, + }, + }, + }, + }, +} + +func TestUnmarshalText(t *testing.T) { + for i, test := range unMarshalTextTests { + pb := new(MyMessage) + err := UnmarshalText(test.in, pb) + if test.err == "" { + // We don't expect failure. + if err != nil { + t.Errorf("Test %d: Unexpected error: %v", i, err) + } else if !reflect.DeepEqual(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) + } + } else { + // We do expect failure. + if err == nil { + t.Errorf("Test %d: Didn't get expected error: %v", i, test.err) + } else if err.Error() != test.err { + t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", + i, err.Error(), test.err) + } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) + } + } + } +} + +func TestUnmarshalTextCustomMessage(t *testing.T) { + msg := &textMessage{} + if err := UnmarshalText("custom", msg); err != nil { + t.Errorf("Unexpected error from custom unmarshal: %v", err) + } + if UnmarshalText("not custom", msg) == nil { + t.Errorf("Didn't get expected error from custom unmarshal") + } +} + +// Regression test; this caused a panic. +func TestRepeatedEnum(t *testing.T) { + pb := new(RepeatedEnum) + if err := UnmarshalText("color: RED", pb); err != nil { + t.Fatal(err) + } + exp := &RepeatedEnum{ + Color: []RepeatedEnum_Color{RepeatedEnum_RED}, + } + if !Equal(pb, exp) { + t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp) + } +} + +func TestProto3TextParsing(t *testing.T) { + m := new(proto3pb.Message) + const in = `name: "Wallace" true_scotsman: true` + want := &proto3pb.Message{ + Name: "Wallace", + TrueScotsman: true, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + +func TestMapParsing(t *testing.T) { + m := new(MessageWithMap) + const in = `name_mapping: name_mapping:` + + `msg_mapping:>` + + `msg_mapping>` + // no colon after "value" + `byte_mapping:` + want := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Beatles", + 1234: "Feist", + }, + MsgMapping: map[int64]*FloatingPoint{ + -4: {F: Float64(2.0)}, + -2: {F: Float64(4.0)}, + }, + ByteMapping: map[bool][]byte{ + true: []byte("so be it"), + }, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + +var benchInput string + +func init() { + benchInput = "count: 4\n" + for i := 0; i < 1000; i++ { + benchInput += "pet: \"fido\"\n" + } + + // Check it is valid input. + pb := new(MyMessage) + err := UnmarshalText(benchInput, pb) + if err != nil { + panic("Bad benchmark input: " + err.Error()) + } +} + +func BenchmarkUnmarshalText(b *testing.B) { + pb := new(MyMessage) + for i := 0; i < b.N; i++ { + UnmarshalText(benchInput, pb) + } + b.SetBytes(int64(len(benchInput))) +} diff --git a/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go new file mode 100644 index 00000000..3e73fb81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_test.go @@ -0,0 +1,435 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "errors" + "io/ioutil" + "math" + "strings" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto" + proto3pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/proto3_proto" + pb "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/golang/protobuf/proto/testdata" +) + +// textMessage implements the methods that allow it to marshal and unmarshal +// itself as text. +type textMessage struct { +} + +func (*textMessage) MarshalText() ([]byte, error) { + return []byte("custom"), nil +} + +func (*textMessage) UnmarshalText(bytes []byte) error { + if string(bytes) != "custom" { + return errors.New("expected 'custom'") + } + return nil +} + +func (*textMessage) Reset() {} +func (*textMessage) String() string { return "" } +func (*textMessage) ProtoMessage() {} + +func newTestMessage() *pb.MyMessage { + msg := &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + Quote: proto.String(`"I didn't want to go."`), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &pb.InnerMessage{ + Host: proto.String("footrest.syd"), + Port: proto.Int32(7001), + Connected: proto.Bool(true), + }, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(0xdeadbeef), + Value: []byte{1, 65, 7, 12}, + }, + { + Weight: proto.Float32(6.022), + Inner: &pb.InnerMessage{ + Host: proto.String("lesha.mtv"), + Port: proto.Int32(8002), + }, + }, + }, + Bikeshed: pb.MyMessage_BLUE.Enum(), + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(8), + }, + // One normally wouldn't do this. + // This is an undeclared tag 13, as a varint (wire type 0) with value 4. + XXX_unrecognized: []byte{13<<3 | 0, 4}, + } + ext := &pb.Ext{ + Data: proto.String("Big gobs for big rats"), + } + if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil { + panic(err) + } + greetings := []string{"adg", "easy", "cow"} + if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil { + panic(err) + } + + // Add an unknown extension. We marshal a pb.Ext, and fake the ID. + b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")}) + if err != nil { + panic(err) + } + b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...) + proto.SetRawExtension(msg, 201, b) + + // Extensions can be plain fields, too, so let's test that. + b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19) + proto.SetRawExtension(msg, 202, b) + + return msg +} + +const text = `count: 42 +name: "Dave" +quote: "\"I didn't want to go.\"" +pet: "bunny" +pet: "kitty" +pet: "horsey" +inner: < + host: "footrest.syd" + port: 7001 + connected: true +> +others: < + key: 3735928559 + value: "\001A\007\014" +> +others: < + weight: 6.022 + inner: < + host: "lesha.mtv" + port: 8002 + > +> +bikeshed: BLUE +SomeGroup { + group_field: 8 +} +/* 2 unknown bytes */ +13: 4 +[testdata.Ext.more]: < + data: "Big gobs for big rats" +> +[testdata.greeting]: "adg" +[testdata.greeting]: "easy" +[testdata.greeting]: "cow" +/* 13 unknown bytes */ +201: "\t3G skiing" +/* 3 unknown bytes */ +202: 19 +` + +func TestMarshalText(t *testing.T) { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, newTestMessage()); err != nil { + t.Fatalf("proto.MarshalText: %v", err) + } + s := buf.String() + if s != text { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text) + } +} + +func TestMarshalTextCustomMessage(t *testing.T) { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, &textMessage{}); err != nil { + t.Fatalf("proto.MarshalText: %v", err) + } + s := buf.String() + if s != "custom" { + t.Errorf("Got %q, expected %q", s, "custom") + } +} +func TestMarshalTextNil(t *testing.T) { + want := "" + tests := []proto.Message{nil, (*pb.MyMessage)(nil)} + for i, test := range tests { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, test); err != nil { + t.Fatal(err) + } + if got := buf.String(); got != want { + t.Errorf("%d: got %q want %q", i, got, want) + } + } +} + +func TestMarshalTextUnknownEnum(t *testing.T) { + // The Color enum only specifies values 0-2. + m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()} + got := m.String() + const want = `bikeshed:3 ` + if got != want { + t.Errorf("\n got %q\nwant %q", got, want) + } +} + +func BenchmarkMarshalTextBuffered(b *testing.B) { + buf := new(bytes.Buffer) + m := newTestMessage() + for i := 0; i < b.N; i++ { + buf.Reset() + proto.MarshalText(buf, m) + } +} + +func BenchmarkMarshalTextUnbuffered(b *testing.B) { + w := ioutil.Discard + m := newTestMessage() + for i := 0; i < b.N; i++ { + proto.MarshalText(w, m) + } +} + +func compact(src string) string { + // s/[ \n]+/ /g; s/ $//; + dst := make([]byte, len(src)) + space, comment := false, false + j := 0 + for i := 0; i < len(src); i++ { + if strings.HasPrefix(src[i:], "/*") { + comment = true + i++ + continue + } + if comment && strings.HasPrefix(src[i:], "*/") { + comment = false + i++ + continue + } + if comment { + continue + } + c := src[i] + if c == ' ' || c == '\n' { + space = true + continue + } + if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') { + space = false + } + if c == '{' { + space = false + } + if space { + dst[j] = ' ' + j++ + space = false + } + dst[j] = c + j++ + } + if space { + dst[j] = ' ' + j++ + } + return string(dst[0:j]) +} + +var compactText = compact(text) + +func TestCompactText(t *testing.T) { + s := proto.CompactTextString(newTestMessage()) + if s != compactText { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText) + } +} + +func TestStringEscaping(t *testing.T) { + testCases := []struct { + in *pb.Strings + out string + }{ + { + // Test data from C++ test (TextFormatTest.StringEscape). + // Single divergence: we don't escape apostrophes. + &pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")}, + "string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n", + }, + { + // Test data from the same C++ test. + &pb.Strings{StringField: proto.String("\350\260\267\346\255\214")}, + "string_field: \"\\350\\260\\267\\346\\255\\214\"\n", + }, + { + // Some UTF-8. + &pb.Strings{StringField: proto.String("\x00\x01\xff\x81")}, + `string_field: "\000\001\377\201"` + "\n", + }, + } + + for i, tc := range testCases { + var buf bytes.Buffer + if err := proto.MarshalText(&buf, tc.in); err != nil { + t.Errorf("proto.MarsalText: %v", err) + continue + } + s := buf.String() + if s != tc.out { + t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out) + continue + } + + // Check round-trip. + pb := new(pb.Strings) + if err := proto.UnmarshalText(s, pb); err != nil { + t.Errorf("#%d: UnmarshalText: %v", i, err) + continue + } + if !proto.Equal(pb, tc.in) { + t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb) + } + } +} + +// A limitedWriter accepts some output before it fails. +// This is a proxy for something like a nearly-full or imminently-failing disk, +// or a network connection that is about to die. +type limitedWriter struct { + b bytes.Buffer + limit int +} + +var outOfSpace = errors.New("proto: insufficient space") + +func (w *limitedWriter) Write(p []byte) (n int, err error) { + var avail = w.limit - w.b.Len() + if avail <= 0 { + return 0, outOfSpace + } + if len(p) <= avail { + return w.b.Write(p) + } + n, _ = w.b.Write(p[:avail]) + return n, outOfSpace +} + +func TestMarshalTextFailing(t *testing.T) { + // Try lots of different sizes to exercise more error code-paths. + for lim := 0; lim < len(text); lim++ { + buf := new(limitedWriter) + buf.limit = lim + err := proto.MarshalText(buf, newTestMessage()) + // We expect a certain error, but also some partial results in the buffer. + if err != outOfSpace { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace) + } + s := buf.b.String() + x := text[:buf.limit] + if s != x { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x) + } + } +} + +func TestFloats(t *testing.T) { + tests := []struct { + f float64 + want string + }{ + {0, "0"}, + {4.7, "4.7"}, + {math.Inf(1), "inf"}, + {math.Inf(-1), "-inf"}, + {math.NaN(), "nan"}, + } + for _, test := range tests { + msg := &pb.FloatingPoint{F: &test.f} + got := strings.TrimSpace(msg.String()) + want := `f:` + test.want + if got != want { + t.Errorf("f=%f: got %q, want %q", test.f, got, want) + } + } +} + +func TestRepeatedNilText(t *testing.T) { + m := &pb.MessageList{ + Message: []*pb.MessageList_Message{ + nil, + &pb.MessageList_Message{ + Name: proto.String("Horse"), + }, + nil, + }, + } + want := `Message +Message { + name: "Horse" +} +Message +` + if s := proto.MarshalTextString(m); s != want { + t.Errorf(" got: %s\nwant: %s", s, want) + } +} + +func TestProto3Text(t *testing.T) { + tests := []struct { + m proto.Message + want string + }{ + // zero message + {&proto3pb.Message{}, ``}, + // zero message except for an empty byte slice + {&proto3pb.Message{Data: []byte{}}, ``}, + // trivial case + {&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`}, + // empty map + {&pb.MessageWithMap{}, ``}, + // non-empty map; current map format is the same as a repeated struct + { + &pb.MessageWithMap{NameMapping: map[int32]string{1234: "Feist"}}, + `name_mapping:`, + }, + } + for _, test := range tests { + got := strings.TrimSpace(test.m.String()) + if got != test.want { + t.Errorf("\n got %s\nwant %s", got, test.want) + } + } +} diff --git a/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist.go b/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist.go new file mode 100644 index 00000000..6aa932ef --- /dev/null +++ b/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist.go @@ -0,0 +1,635 @@ +// Copyright 2012 Google Inc. All rights reserved. +// Author: Ric Szopa (Ryszard) + +// Package skiplist implements skip list based maps and sets. +// +// Skip lists are a data structure that can be used in place of +// balanced trees. Skip lists use probabilistic balancing rather than +// strictly enforced balancing and as a result the algorithms for +// insertion and deletion in skip lists are much simpler and +// significantly faster than equivalent algorithms for balanced trees. +// +// Skip lists were first described in Pugh, William (June 1990). "Skip +// lists: a probabilistic alternative to balanced +// trees". Communications of the ACM 33 (6): 668–676 +package skiplist + +import ( + "math/rand" +) + +// TODO(ryszard): +// - A separately seeded source of randomness + +// p is the fraction of nodes with level i pointers that also have +// level i+1 pointers. p equal to 1/4 is a good value from the point +// of view of speed and space requirements. If variability of running +// times is a concern, 1/2 is a better value for p. +const p = 0.25 + +const DefaultMaxLevel = 32 + +// A node is a container for key-value pairs that are stored in a skip +// list. +type node struct { + forward []*node + backward *node + key, value interface{} +} + +// next returns the next node in the skip list containing n. +func (n *node) next() *node { + if len(n.forward) == 0 { + return nil + } + return n.forward[0] +} + +// previous returns the previous node in the skip list containing n. +func (n *node) previous() *node { + return n.backward +} + +// hasNext returns true if n has a next node. +func (n *node) hasNext() bool { + return n.next() != nil +} + +// hasPrevious returns true if n has a previous node. +func (n *node) hasPrevious() bool { + return n.previous() != nil +} + +// A SkipList is a map-like data structure that maintains an ordered +// collection of key-value pairs. Insertion, lookup, and deletion are +// all O(log n) operations. A SkipList can efficiently store up to +// 2^MaxLevel items. +// +// To iterate over a skip list (where s is a +// *SkipList): +// +// for i := s.Iterator(); i.Next(); { +// // do something with i.Key() and i.Value() +// } +type SkipList struct { + lessThan func(l, r interface{}) bool + header *node + footer *node + length int + // MaxLevel determines how many items the SkipList can store + // efficiently (2^MaxLevel). + // + // It is safe to increase MaxLevel to accomodate more + // elements. If you decrease MaxLevel and the skip list + // already contains nodes on higer levels, the effective + // MaxLevel will be the greater of the new MaxLevel and the + // level of the highest node. + // + // A SkipList with MaxLevel equal to 0 is equivalent to a + // standard linked list and will not have any of the nice + // properties of skip lists (probably not what you want). + MaxLevel int +} + +// Len returns the length of s. +func (s *SkipList) Len() int { + return s.length +} + +// Iterator is an interface that you can use to iterate through the +// skip list (in its entirety or fragments). For an use example, see +// the documentation of SkipList. +// +// Key and Value return the key and the value of the current node. +type Iterator interface { + // Next returns true if the iterator contains subsequent elements + // and advances its state to the next element if that is possible. + Next() (ok bool) + // Previous returns true if the iterator contains previous elements + // and rewinds its state to the previous element if that is possible. + Previous() (ok bool) + // Key returns the current key. + Key() interface{} + // Value returns the current value. + Value() interface{} + // Seek reduces iterative seek costs for searching forward into the Skip List + // by remarking the range of keys over which it has scanned before. If the + // requested key occurs prior to the point, the Skip List will start searching + // as a safeguard. It returns true if the key is within the known range of + // the list. + Seek(key interface{}) (ok bool) + // Close this iterator to reap resources associated with it. While not + // strictly required, it will provide extra hints for the garbage collector. + Close() +} + +type iter struct { + current *node + key interface{} + list *SkipList + value interface{} +} + +func (i iter) Key() interface{} { + return i.key +} + +func (i iter) Value() interface{} { + return i.value +} + +func (i *iter) Next() bool { + if !i.current.hasNext() { + return false + } + + i.current = i.current.next() + i.key = i.current.key + i.value = i.current.value + + return true +} + +func (i *iter) Previous() bool { + if !i.current.hasPrevious() { + return false + } + + i.current = i.current.previous() + i.key = i.current.key + i.value = i.current.value + + return true +} + +func (i *iter) Seek(key interface{}) (ok bool) { + current := i.current + list := i.list + + // If the existing iterator outside of the known key range, we should set the + // position back to the beginning of the list. + if current == nil { + current = list.header + } + + // If the target key occurs before the current key, we cannot take advantage + // of the heretofore spent traversal cost to find it; resetting back to the + // beginning is the safest choice. + if current.key != nil && list.lessThan(key, current.key) { + current = list.header + } + + // We should back up to the so that we can seek to our present value if that + // is requested for whatever reason. + if current.backward == nil { + current = list.header + } else { + current = current.backward + } + + current = list.getPath(current, nil, key) + + if current == nil { + return + } + + i.current = current + i.key = current.key + i.value = current.value + + return true +} + +func (i *iter) Close() { + i.key = nil + i.value = nil + i.current = nil + i.list = nil +} + +type rangeIterator struct { + iter + upperLimit interface{} + lowerLimit interface{} +} + +func (i *rangeIterator) Next() bool { + if !i.current.hasNext() { + return false + } + + next := i.current.next() + + if !i.list.lessThan(next.key, i.upperLimit) { + return false + } + + i.current = i.current.next() + i.key = i.current.key + i.value = i.current.value + return true +} + +func (i *rangeIterator) Previous() bool { + if !i.current.hasPrevious() { + return false + } + + previous := i.current.previous() + + if i.list.lessThan(previous.key, i.lowerLimit) { + return false + } + + i.current = i.current.previous() + i.key = i.current.key + i.value = i.current.value + return true +} + +func (i *rangeIterator) Seek(key interface{}) (ok bool) { + if i.list.lessThan(key, i.lowerLimit) { + return + } else if !i.list.lessThan(key, i.upperLimit) { + return + } + + return i.iter.Seek(key) +} + +func (i *rangeIterator) Close() { + i.iter.Close() + i.upperLimit = nil + i.lowerLimit = nil +} + +// Iterator returns an Iterator that will go through all elements s. +func (s *SkipList) Iterator() Iterator { + return &iter{ + current: s.header, + list: s, + } +} + +// Seek returns a bidirectional iterator starting with the first element whose +// key is greater or equal to key; otherwise, a nil iterator is returned. +func (s *SkipList) Seek(key interface{}) Iterator { + current := s.getPath(s.header, nil, key) + if current == nil { + return nil + } + + return &iter{ + current: current, + key: current.key, + list: s, + value: current.value, + } +} + +// SeekToFirst returns a bidirectional iterator starting from the first element +// in the list if the list is populated; otherwise, a nil iterator is returned. +func (s *SkipList) SeekToFirst() Iterator { + if s.length == 0 { + return nil + } + + current := s.header.next() + + return &iter{ + current: current, + key: current.key, + list: s, + value: current.value, + } +} + +// SeekToLast returns a bidirectional iterator starting from the last element +// in the list if the list is populated; otherwise, a nil iterator is returned. +func (s *SkipList) SeekToLast() Iterator { + current := s.footer + if current == nil { + return nil + } + + return &iter{ + current: current, + key: current.key, + list: s, + value: current.value, + } +} + +// Range returns an iterator that will go through all the +// elements of the skip list that are greater or equal than from, but +// less than to. +func (s *SkipList) Range(from, to interface{}) Iterator { + start := s.getPath(s.header, nil, from) + return &rangeIterator{ + iter: iter{ + current: &node{ + forward: []*node{start}, + backward: start, + }, + list: s, + }, + upperLimit: to, + lowerLimit: from, + } +} + +func (s *SkipList) level() int { + return len(s.header.forward) - 1 +} + +func maxInt(x, y int) int { + if x > y { + return x + } + return y +} + +func (s *SkipList) effectiveMaxLevel() int { + return maxInt(s.level(), s.MaxLevel) +} + +// Returns a new random level. +func (s SkipList) randomLevel() (n int) { + for n = 0; n < s.effectiveMaxLevel() && rand.Float64() < p; n++ { + } + return +} + +// Get returns the value associated with key from s (nil if the key is +// not present in s). The second return value is true when the key is +// present. +func (s *SkipList) Get(key interface{}) (value interface{}, ok bool) { + candidate := s.getPath(s.header, nil, key) + + if candidate == nil || candidate.key != key { + return nil, false + } + + return candidate.value, true +} + +// GetGreaterOrEqual finds the node whose key is greater than or equal +// to min. It returns its value, its actual key, and whether such a +// node is present in the skip list. +func (s *SkipList) GetGreaterOrEqual(min interface{}) (actualKey, value interface{}, ok bool) { + candidate := s.getPath(s.header, nil, min) + + if candidate != nil { + return candidate.key, candidate.value, true + } + return nil, nil, false +} + +// getPath populates update with nodes that constitute the path to the +// node that may contain key. The candidate node will be returned. If +// update is nil, it will be left alone (the candidate node will still +// be returned). If update is not nil, but it doesn't have enough +// slots for all the nodes in the path, getPath will panic. +func (s *SkipList) getPath(current *node, update []*node, key interface{}) *node { + depth := len(current.forward) - 1 + + for i := depth; i >= 0; i-- { + for current.forward[i] != nil && s.lessThan(current.forward[i].key, key) { + current = current.forward[i] + } + if update != nil { + update[i] = current + } + } + return current.next() +} + +// Sets set the value associated with key in s. +func (s *SkipList) Set(key, value interface{}) { + if key == nil { + panic("goskiplist: nil keys are not supported") + } + // s.level starts from 0, so we need to allocate one. + update := make([]*node, s.level()+1, s.effectiveMaxLevel()+1) + candidate := s.getPath(s.header, update, key) + + if candidate != nil && candidate.key == key { + candidate.value = value + return + } + + newLevel := s.randomLevel() + + if currentLevel := s.level(); newLevel > currentLevel { + // there are no pointers for the higher levels in + // update. Header should be there. Also add higher + // level links to the header. + for i := currentLevel + 1; i <= newLevel; i++ { + update = append(update, s.header) + s.header.forward = append(s.header.forward, nil) + } + } + + newNode := &node{ + forward: make([]*node, newLevel+1, s.effectiveMaxLevel()+1), + key: key, + value: value, + } + + if previous := update[0]; previous.key != nil { + newNode.backward = previous + } + + for i := 0; i <= newLevel; i++ { + newNode.forward[i] = update[i].forward[i] + update[i].forward[i] = newNode + } + + s.length++ + + if newNode.forward[0] != nil { + if newNode.forward[0].backward != newNode { + newNode.forward[0].backward = newNode + } + } + + if s.footer == nil || s.lessThan(s.footer.key, key) { + s.footer = newNode + } +} + +// Delete removes the node with the given key. +// +// It returns the old value and whether the node was present. +func (s *SkipList) Delete(key interface{}) (value interface{}, ok bool) { + if key == nil { + panic("goskiplist: nil keys are not supported") + } + update := make([]*node, s.level()+1, s.effectiveMaxLevel()) + candidate := s.getPath(s.header, update, key) + + if candidate == nil || candidate.key != key { + return nil, false + } + + previous := candidate.backward + if s.footer == candidate { + s.footer = previous + } + + next := candidate.next() + if next != nil { + next.backward = previous + } + + for i := 0; i <= s.level() && update[i].forward[i] == candidate; i++ { + update[i].forward[i] = candidate.forward[i] + } + + for s.level() > 0 && s.header.forward[s.level()] == nil { + s.header.forward = s.header.forward[:s.level()] + } + s.length-- + + return candidate.value, true +} + +// NewCustomMap returns a new SkipList that will use lessThan as the +// comparison function. lessThan should define a linear order on keys +// you intend to use with the SkipList. +func NewCustomMap(lessThan func(l, r interface{}) bool) *SkipList { + return &SkipList{ + lessThan: lessThan, + header: &node{ + forward: []*node{nil}, + }, + MaxLevel: DefaultMaxLevel, + } +} + +// Ordered is an interface which can be linearly ordered by the +// LessThan method, whereby this instance is deemed to be less than +// other. Additionally, Ordered instances should behave properly when +// compared using == and !=. +type Ordered interface { + LessThan(other Ordered) bool +} + +// New returns a new SkipList. +// +// Its keys must implement the Ordered interface. +func New() *SkipList { + comparator := func(left, right interface{}) bool { + return left.(Ordered).LessThan(right.(Ordered)) + } + return NewCustomMap(comparator) + +} + +// NewIntKey returns a SkipList that accepts int keys. +func NewIntMap() *SkipList { + return NewCustomMap(func(l, r interface{}) bool { + return l.(int) < r.(int) + }) +} + +// NewStringMap returns a SkipList that accepts string keys. +func NewStringMap() *SkipList { + return NewCustomMap(func(l, r interface{}) bool { + return l.(string) < r.(string) + }) +} + +// Set is an ordered set data structure. +// +// Its elements must implement the Ordered interface. It uses a +// SkipList for storage, and it gives you similar performance +// guarantees. +// +// To iterate over a set (where s is a *Set): +// +// for i := s.Iterator(); i.Next(); { +// // do something with i.Key(). +// // i.Value() will be nil. +// } +type Set struct { + skiplist SkipList +} + +// NewSet returns a new Set. +func NewSet() *Set { + comparator := func(left, right interface{}) bool { + return left.(Ordered).LessThan(right.(Ordered)) + } + return NewCustomSet(comparator) +} + +// NewCustomSet returns a new Set that will use lessThan as the +// comparison function. lessThan should define a linear order on +// elements you intend to use with the Set. +func NewCustomSet(lessThan func(l, r interface{}) bool) *Set { + return &Set{skiplist: SkipList{ + lessThan: lessThan, + header: &node{ + forward: []*node{nil}, + }, + MaxLevel: DefaultMaxLevel, + }} +} + +// NewIntSet returns a new Set that accepts int elements. +func NewIntSet() *Set { + return NewCustomSet(func(l, r interface{}) bool { + return l.(int) < r.(int) + }) +} + +// NewStringSet returns a new Set that accepts string elements. +func NewStringSet() *Set { + return NewCustomSet(func(l, r interface{}) bool { + return l.(string) < r.(string) + }) +} + +// Add adds key to s. +func (s *Set) Add(key interface{}) { + s.skiplist.Set(key, nil) +} + +// Remove tries to remove key from the set. It returns true if key was +// present. +func (s *Set) Remove(key interface{}) (ok bool) { + _, ok = s.skiplist.Delete(key) + return ok +} + +// Len returns the length of the set. +func (s *Set) Len() int { + return s.skiplist.Len() +} + +// Contains returns true if key is present in s. +func (s *Set) Contains(key interface{}) bool { + _, ok := s.skiplist.Get(key) + return ok +} + +func (s *Set) Iterator() Iterator { + return s.skiplist.Iterator() +} + +// Range returns an iterator that will go through all the elements of +// the set that are greater or equal than from, but less than to. +func (s *Set) Range(from, to interface{}) Iterator { + return s.skiplist.Range(from, to) +} + +// SetMaxLevel sets MaxLevel in the underlying skip list. +func (s *Set) SetMaxLevel(newMaxLevel int) { + s.skiplist.MaxLevel = newMaxLevel +} + +// GetMaxLevel returns MaxLevel fo the underlying skip list. +func (s *Set) GetMaxLevel() int { + return s.skiplist.MaxLevel +} diff --git a/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist_test.go b/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist_test.go new file mode 100644 index 00000000..52ee009d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ryszard/goskiplist/skiplist/skiplist_test.go @@ -0,0 +1,924 @@ +// Copyright 2012 Google Inc. All rights reserved. +// Author: Ric Szopa (Ryszard) + +// Package skiplist implements skip list based maps and sets. +// +// Skip lists are a data structure that can be used in place of +// balanced trees. Skip lists use probabilistic balancing rather than +// strictly enforced balancing and as a result the algorithms for +// insertion and deletion in skip lists are much simpler and +// significantly faster than equivalent algorithms for balanced trees. +// +// Skip lists were first described in Pugh, William (June 1990). "Skip +// lists: a probabilistic alternative to balanced +// trees". Communications of the ACM 33 (6): 668–676 +package skiplist + +import ( + "fmt" + "math/rand" + "sort" + "testing" +) + +func (s *SkipList) printRepr() { + + fmt.Printf("header:\n") + for i, link := range s.header.forward { + if link != nil { + fmt.Printf("\t%d: -> %v\n", i, link.key) + } else { + fmt.Printf("\t%d: -> END\n", i) + } + } + + for node := s.header.next(); node != nil; node = node.next() { + fmt.Printf("%v: %v (level %d)\n", node.key, node.value, len(node.forward)) + for i, link := range node.forward { + if link != nil { + fmt.Printf("\t%d: -> %v\n", i, link.key) + } else { + fmt.Printf("\t%d: -> END\n", i) + } + } + } + fmt.Println() +} + +func TestInitialization(t *testing.T) { + s := NewCustomMap(func(l, r interface{}) bool { + return l.(int) < r.(int) + }) + if !s.lessThan(1, 2) { + t.Errorf("Less than doesn't work correctly.") + } +} + +func TestEmptyNodeNext(t *testing.T) { + n := new(node) + if next := n.next(); next != nil { + t.Errorf("Next() should be nil for an empty node.") + } + + if n.hasNext() { + t.Errorf("hasNext() should be false for an empty node.") + } +} + +func TestEmptyNodePrev(t *testing.T) { + n := new(node) + if previous := n.previous(); previous != nil { + t.Errorf("Previous() should be nil for an empty node.") + } + + if n.hasPrevious() { + t.Errorf("hasPrevious() should be false for an empty node.") + } +} + +func TestNodeHasNext(t *testing.T) { + s := NewIntMap() + s.Set(0, 0) + node := s.header.next() + if node.key != 0 { + t.Fatalf("We got the wrong node: %v.", node) + } + + if node.hasNext() { + t.Errorf("%v should be the last node.", node) + } +} + +func TestNodeHasPrev(t *testing.T) { + s := NewIntMap() + s.Set(0, 0) + node := s.header.previous() + if node != nil { + t.Fatalf("Expected no previous entry, got %v.", node) + } +} + +func (s *SkipList) check(t *testing.T, key, wanted int) { + if got, _ := s.Get(key); got != wanted { + t.Errorf("For key %v wanted value %v, got %v.", key, wanted, got) + } +} + +func TestGet(t *testing.T) { + s := NewIntMap() + s.Set(0, 0) + + if value, present := s.Get(0); !(value == 0 && present) { + t.Errorf("%v, %v instead of %v, %v", value, present, 0, true) + } + + if value, present := s.Get(100); value != nil || present { + t.Errorf("%v, %v instead of %v, %v", value, present, nil, false) + } +} + +func TestGetGreaterOrEqual(t *testing.T) { + s := NewIntMap() + + if _, value, present := s.GetGreaterOrEqual(5); !(value == nil && !present) { + t.Errorf("s.GetGreaterOrEqual(5) should have returned nil and false for an empty map, not %v and %v.", value, present) + } + + s.Set(0, 0) + + if _, value, present := s.GetGreaterOrEqual(5); !(value == nil && !present) { + t.Errorf("s.GetGreaterOrEqual(5) should have returned nil and false for an empty map, not %v and %v.", value, present) + } + + s.Set(10, 10) + + if key, value, present := s.GetGreaterOrEqual(5); !(value == 10 && key == 10 && present) { + t.Errorf("s.GetGreaterOrEqual(5) should have returned 10 and true, not %v and %v.", value, present) + } +} + +func TestSet(t *testing.T) { + s := NewIntMap() + if l := s.Len(); l != 0 { + t.Errorf("Len is not 0, it is %v", l) + } + + s.Set(0, 0) + s.Set(1, 1) + if l := s.Len(); l != 2 { + t.Errorf("Len is not 2, it is %v", l) + } + s.check(t, 0, 0) + if t.Failed() { + t.Errorf("header.Next() after s.Set(0, 0) and s.Set(1, 1): %v.", s.header.next()) + } + s.check(t, 1, 1) + +} + +func TestChange(t *testing.T) { + s := NewIntMap() + s.Set(0, 0) + s.Set(1, 1) + s.Set(2, 2) + + s.Set(0, 7) + if value, _ := s.Get(0); value != 7 { + t.Errorf("Value should be 7, not %d", value) + } + s.Set(1, 8) + if value, _ := s.Get(1); value != 8 { + t.Errorf("Value should be 8, not %d", value) + } + +} + +func TestDelete(t *testing.T) { + s := NewIntMap() + for i := 0; i < 10; i++ { + s.Set(i, i) + } + for i := 0; i < 10; i += 2 { + s.Delete(i) + } + + for i := 0; i < 10; i += 2 { + if _, present := s.Get(i); present { + t.Errorf("%d should not be present in s", i) + } + } + + if v, present := s.Delete(10000); v != nil || present { + t.Errorf("Deleting a non-existent key should return nil, false, and not %v, %v.", v, present) + } + + if t.Failed() { + s.printRepr() + } + +} + +func TestLen(t *testing.T) { + s := NewIntMap() + for i := 0; i < 10; i++ { + s.Set(i, i) + } + if length := s.Len(); length != 10 { + t.Errorf("Length should be equal to 10, not %v.", length) + s.printRepr() + } + for i := 0; i < 5; i++ { + s.Delete(i) + } + if length := s.Len(); length != 5 { + t.Errorf("Length should be equal to 5, not %v.", length) + } + + s.Delete(10000) + + if length := s.Len(); length != 5 { + t.Errorf("Length should be equal to 5, not %v.", length) + } + +} + +func TestIteration(t *testing.T) { + s := NewIntMap() + for i := 0; i < 20; i++ { + s.Set(i, i) + } + + seen := 0 + var lastKey int + + i := s.Iterator() + defer i.Close() + + for i.Next() { + seen++ + lastKey = i.Key().(int) + if i.Key() != i.Value() { + t.Errorf("Wrong value for key %v: %v.", i.Key(), i.Value()) + } + } + + if seen != s.Len() { + t.Errorf("Not all the items in s where iterated through (seen %d, should have seen %d). Last one seen was %d.", seen, s.Len(), lastKey) + } + + for i.Previous() { + if i.Key() != i.Value() { + t.Errorf("Wrong value for key %v: %v.", i.Key(), i.Value()) + } + + if i.Key().(int) >= lastKey { + t.Errorf("Expected key to descend but ascended from %v to %v.", lastKey, i.Key()) + } + + lastKey = i.Key().(int) + } + + if lastKey != 0 { + t.Errorf("Expected to count back to zero, but stopped at key %v.", lastKey) + } +} + +func TestRangeIteration(t *testing.T) { + s := NewIntMap() + for i := 0; i < 20; i++ { + s.Set(i, i) + } + + max, min := 0, 100000 + var lastKey, seen int + + i := s.Range(5, 10) + defer i.Close() + + for i.Next() { + seen++ + lastKey = i.Key().(int) + if lastKey > max { + max = lastKey + } + if lastKey < min { + min = lastKey + } + if i.Key() != i.Value() { + t.Errorf("Wrong value for key %v: %v.", i.Key(), i.Value()) + } + } + + if seen != 5 { + t.Errorf("The number of items yielded is incorrect (should be 5, was %v)", seen) + } + if min != 5 { + t.Errorf("The smallest element should have been 5, not %v", min) + } + + if max != 9 { + t.Errorf("The largest element should have been 9, not %v", max) + } + + if i.Seek(4) { + t.Error("Allowed to seek to invalid range.") + } + + if !i.Seek(5) { + t.Error("Could not seek to an allowed range.") + } + if i.Key().(int) != 5 || i.Value().(int) != 5 { + t.Errorf("Expected 5 for key and 5 for value, got %d and %d", i.Key(), i.Value()) + } + + if !i.Seek(7) { + t.Error("Could not seek to an allowed range.") + } + if i.Key().(int) != 7 || i.Value().(int) != 7 { + t.Errorf("Expected 7 for key and 7 for value, got %d and %d", i.Key(), i.Value()) + } + + if i.Seek(10) { + t.Error("Allowed to seek to invalid range.") + } + + i.Seek(9) + + seen = 0 + min = 100000 + max = -1 + + for i.Previous() { + seen++ + lastKey = i.Key().(int) + if lastKey > max { + max = lastKey + } + if lastKey < min { + min = lastKey + } + if i.Key() != i.Value() { + t.Errorf("Wrong value for key %v: %v.", i.Key(), i.Value()) + } + } + + if seen != 4 { + t.Errorf("The number of items yielded is incorrect (should be 5, was %v)", seen) + } + if min != 5 { + t.Errorf("The smallest element should have been 5, not %v", min) + } + + if max != 8 { + t.Errorf("The largest element should have been 9, not %v", max) + } +} + +func TestSomeMore(t *testing.T) { + s := NewIntMap() + insertions := [...]int{4, 1, 2, 9, 10, 7, 3} + for _, i := range insertions { + s.Set(i, i) + } + for _, i := range insertions { + s.check(t, i, i) + } + +} + +func makeRandomList(n int) *SkipList { + s := NewIntMap() + for i := 0; i < n; i++ { + insert := rand.Int() + s.Set(insert, insert) + } + return s +} + +func LookupBenchmark(b *testing.B, n int) { + b.StopTimer() + s := makeRandomList(n) + b.StartTimer() + for i := 0; i < b.N; i++ { + s.Get(rand.Int()) + } +} + +func SetBenchmark(b *testing.B, n int) { + b.StopTimer() + values := []int{} + for i := 0; i < b.N; i++ { + values = append(values, rand.Int()) + } + s := NewIntMap() + b.StartTimer() + for i := 0; i < b.N; i++ { + s.Set(values[i], values[i]) + } +} + +// Make sure that all the keys are unique and are returned in order. +func TestSanity(t *testing.T) { + s := NewIntMap() + for i := 0; i < 10000; i++ { + insert := rand.Int() + s.Set(insert, insert) + } + var last int = 0 + + i := s.Iterator() + defer i.Close() + + for i.Next() { + if last != 0 && i.Key().(int) <= last { + t.Errorf("Not in order!") + } + last = i.Key().(int) + } + + for i.Previous() { + if last != 0 && i.Key().(int) > last { + t.Errorf("Not in order!") + } + last = i.Key().(int) + } +} + +type MyOrdered struct { + value int +} + +func (me MyOrdered) LessThan(other Ordered) bool { + return me.value < other.(MyOrdered).value +} + +func TestOrdered(t *testing.T) { + s := New() + s.Set(MyOrdered{0}, 0) + s.Set(MyOrdered{1}, 1) + + if val, _ := s.Get(MyOrdered{0}); val != 0 { + t.Errorf("Wrong value for MyOrdered{0}. Should have been %d.", val) + } +} + +func TestNewStringMap(t *testing.T) { + s := NewStringMap() + s.Set("a", 1) + s.Set("b", 2) + if value, _ := s.Get("a"); value != 1 { + t.Errorf("Expected 1, got %v.", value) + } +} + +func TestGetNilKey(t *testing.T) { + s := NewStringMap() + if v, present := s.Get(nil); v != nil || present { + t.Errorf("s.Get(nil) should return nil, false (not %v, %v).", v, present) + } + +} + +func TestSetNilKey(t *testing.T) { + s := NewStringMap() + + defer func() { + if err := recover(); err == nil { + t.Errorf("s.Set(nil, 0) should have panicked.") + } + }() + + s.Set(nil, 0) + +} + +func TestSetMaxLevelInFlight(t *testing.T) { + s := NewIntMap() + s.MaxLevel = 2 + for i := 0; i < 64; i++ { + insert := 2 * rand.Int() + s.Set(insert, insert) + } + + s.MaxLevel = 64 + for i := 0; i < 65536; i++ { + insert := 2*rand.Int() + 1 + s.Set(insert, insert) + } + + i := s.Iterator() + defer i.Close() + + for i.Next() { + if v, _ := s.Get(i.Key()); v != i.Key() { + t.Errorf("Bad values in the skip list (%v). Inserted before the call to s.SetMax(): %t.", v, i.Key().(int)%2 == 0) + } + } +} + +func TestDeletingHighestLevelNodeDoesntBreakSkiplist(t *testing.T) { + s := NewIntMap() + elements := []int{1, 3, 5, 7, 0, 4, 5, 10, 11} + + for _, i := range elements { + s.Set(i, i) + } + + highestLevelNode := s.header.forward[len(s.header.forward)-1] + + s.Delete(highestLevelNode.key) + + seen := 0 + i := s.Iterator() + defer i.Close() + + for i.Next() { + seen++ + } + if seen == 0 { + t.Errorf("Iteration is broken (no elements seen).") + } +} + +func TestNewSet(t *testing.T) { + set := NewIntSet() + elements := []int{1, 3, 5, 7, 0, 4, 5} + + for _, i := range elements { + set.Add(i) + } + + if length := set.Len(); length != 6 { + t.Errorf("set.Len() should be equal to 6, not %v.", length) + } + + if !set.Contains(3) { + t.Errorf("set should contain 3.") + } + + if set.Contains(1000) { + t.Errorf("set should not contain 1000.") + } + + removed := set.Remove(1) + + if !removed { + t.Errorf("Remove returned false for element that was present in set.") + } + + seen := 0 + i := set.Iterator() + defer i.Close() + + for i.Next() { + seen++ + } + + if seen != 5 { + t.Errorf("Iterator() iterated through %v elements. Should have been 5.", seen) + } + + if set.Contains(1) { + t.Errorf("1 was removed, set should not contain 1.") + } + + if length := set.Len(); length != 5 { + t.Errorf("After removing one element, set.Len() should be equal to 5, not %v.", length) + } + + set.SetMaxLevel(10) + if ml := set.GetMaxLevel(); ml != 10 { + t.Errorf("MaxLevel for set should be 10, not %v", ml) + } + +} + +func TestSetRangeIterator(t *testing.T) { + set := NewIntSet() + elements := []int{0, 1, 3, 5} + + for _, i := range elements { + set.Add(i) + } + + seen := 0 + for i := set.Range(2, 1000); i.Next(); { + seen++ + } + if seen != 2 { + t.Errorf("There should have been 2 elements in Range(2, 1000), not %v.", seen) + } + +} + +func TestNewStringSet(t *testing.T) { + set := NewStringSet() + strings := []string{"ala", "ma", "kota"} + for _, v := range strings { + set.Add(v) + } + + if !set.Contains("ala") { + t.Errorf("set should contain \"ala\".") + } +} + +func TestIteratorPrevHoles(t *testing.T) { + m := NewIntMap() + + i := m.Iterator() + defer i.Close() + + m.Set(0, 0) + m.Set(1, 1) + m.Set(2, 2) + + if !i.Next() { + t.Errorf("Expected iterator to move successfully to the next.") + } + + if !i.Next() { + t.Errorf("Expected iterator to move successfully to the next.") + } + + if !i.Next() { + t.Errorf("Expected iterator to move successfully to the next.") + } + + if i.Key().(int) != 2 || i.Value().(int) != 2 { + t.Errorf("Expected iterator to reach key 2 and value 2, got %v and %v.", i.Key(), i.Value()) + } + + if !i.Previous() { + t.Errorf("Expected iterator to move successfully to the previous.") + } + + if i.Key().(int) != 1 || i.Value().(int) != 1 { + t.Errorf("Expected iterator to reach key 1 and value 1, got %v and %v.", i.Key(), i.Value()) + } + + if !i.Next() { + t.Errorf("Expected iterator to move successfully to the next.") + } + + m.Delete(1) + + if !i.Previous() { + t.Errorf("Expected iterator to move successfully to the previous.") + } + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } +} + +func TestIteratorSeek(t *testing.T) { + m := NewIntMap() + + i := m.Seek(0) + + if i != nil { + t.Errorf("Expected nil iterator, but got %v.", i) + } + + i = m.SeekToFirst() + + if i != nil { + t.Errorf("Expected nil iterator, but got %v.", i) + } + + i = m.SeekToLast() + + if i != nil { + t.Errorf("Expected nil iterator, but got %v.", i) + } + + m.Set(0, 0) + + i = m.SeekToFirst() + defer i.Close() + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + i = m.SeekToLast() + defer i.Close() + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + m.Set(1, 1) + + i = m.SeekToFirst() + defer i.Close() + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + i = m.SeekToLast() + defer i.Close() + + if i.Key().(int) != 1 || i.Value().(int) != 1 { + t.Errorf("Expected iterator to reach key 1 and value 1, got %v and %v.", i.Key(), i.Value()) + } + + m.Set(2, 2) + + i = m.SeekToFirst() + defer i.Close() + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + i = m.SeekToLast() + defer i.Close() + + if i.Key().(int) != 2 || i.Value().(int) != 2 { + t.Errorf("Expected iterator to reach key 2 and value 2, got %v and %v.", i.Key(), i.Value()) + } + + i = m.Seek(0) + defer i.Close() + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + i = m.Seek(2) + defer i.Close() + + if i.Key().(int) != 2 || i.Value().(int) != 2 { + t.Errorf("Expected iterator to reach key 2 and value 2, got %v and %v.", i.Key(), i.Value()) + } + + i = m.Seek(1) + defer i.Close() + + if i.Key().(int) != 1 || i.Value().(int) != 1 { + t.Errorf("Expected iterator to reach key 1 and value 1, got %v and %v.", i.Key(), i.Value()) + } + + i = m.Seek(3) + + if i != nil { + t.Errorf("Expected to receive nil iterator, got %v.", i) + } + + m.Set(4, 4) + + i = m.Seek(4) + defer i.Close() + + if i.Key().(int) != 4 || i.Value().(int) != 4 { + t.Errorf("Expected iterator to reach key 4 and value 4, got %v and %v.", i.Key(), i.Value()) + } + + i = m.Seek(3) + defer i.Close() + + if i.Key().(int) != 4 || i.Value().(int) != 4 { + t.Errorf("Expected iterator to reach key 4 and value 4, got %v and %v.", i.Key(), i.Value()) + } + + m.Delete(4) + + i = m.SeekToFirst() + defer i.Close() + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + i = m.SeekToLast() + defer i.Close() + + if i.Key().(int) != 2 || i.Value().(int) != 2 { + t.Errorf("Expected iterator to reach key 2 and value 2, got %v and %v.", i.Key(), i.Value()) + } + + if !i.Seek(2) { + t.Error("Expected iterator to seek to key.") + } + + if i.Key().(int) != 2 || i.Value().(int) != 2 { + t.Errorf("Expected iterator to reach key 2 and value 2, got %v and %v.", i.Key(), i.Value()) + } + + if !i.Seek(1) { + t.Error("Expected iterator to seek to key.") + } + + if i.Key().(int) != 1 || i.Value().(int) != 1 { + t.Errorf("Expected iterator to reach key 1 and value 1, got %v and %v.", i.Key(), i.Value()) + } + + if !i.Seek(0) { + t.Error("Expected iterator to seek to key.") + } + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } + + i = m.SeekToFirst() + defer i.Close() + + if !i.Seek(0) { + t.Error("Expected iterator to seek to key.") + } + + if i.Key().(int) != 0 || i.Value().(int) != 0 { + t.Errorf("Expected iterator to reach key 0 and value 0, got %v and %v.", i.Key(), i.Value()) + } +} + +func BenchmarkLookup16(b *testing.B) { + LookupBenchmark(b, 16) +} + +func BenchmarkLookup256(b *testing.B) { + LookupBenchmark(b, 256) +} + +func BenchmarkLookup65536(b *testing.B) { + LookupBenchmark(b, 65536) +} + +func BenchmarkSet16(b *testing.B) { + SetBenchmark(b, 16) +} + +func BenchmarkSet256(b *testing.B) { + SetBenchmark(b, 256) +} + +func BenchmarkSet65536(b *testing.B) { + SetBenchmark(b, 65536) +} + +func BenchmarkRandomSeek(b *testing.B) { + b.StopTimer() + values := []int{} + s := NewIntMap() + for i := 0; i < b.N; i++ { + r := rand.Int() + values = append(values, r) + s.Set(r, r) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + iterator := s.Seek(values[i]) + if iterator == nil { + b.Errorf("got incorrect value for index %d", i) + } + } +} + +const ( + lookAhead = 10 +) + +// This test is used for the baseline comparison of Iterator.Seek when +// performing forward sequential seek operations. +func BenchmarkForwardSeek(b *testing.B) { + b.StopTimer() + + values := []int{} + s := NewIntMap() + valueCount := b.N + for i := 0; i < valueCount; i++ { + r := rand.Int() + values = append(values, r) + s.Set(r, r) + } + sort.Ints(values) + + b.StartTimer() + for i := 0; i < b.N; i++ { + key := values[i] + iterator := s.Seek(key) + if i < valueCount-lookAhead { + nextKey := values[i+lookAhead] + + iterator = s.Seek(nextKey) + if iterator.Key().(int) != nextKey || iterator.Value().(int) != nextKey { + b.Errorf("%d. expected %d key and %d value, got %d key and %d value", i, nextKey, nextKey, iterator.Key(), iterator.Value()) + } + } + } +} + +// This test demonstrates the amortized cost of a forward sequential seek. +func BenchmarkForwardSeekReusedIterator(b *testing.B) { + b.StopTimer() + + values := []int{} + s := NewIntMap() + valueCount := b.N + for i := 0; i < valueCount; i++ { + r := rand.Int() + values = append(values, r) + s.Set(r, r) + + } + sort.Ints(values) + + b.StartTimer() + for i := 0; i < b.N; i++ { + key := values[i] + iterator := s.Seek(key) + if i < valueCount-lookAhead { + nextKey := values[i+lookAhead] + + if !iterator.Seek(nextKey) { + b.Errorf("%d. expected iterator to seek to %d key; failed.", i, nextKey) + } else if iterator.Key().(int) != nextKey || iterator.Value().(int) != nextKey { + b.Errorf("%d. expected %d key and %d value, got %d key and %d value", i, nextKey, nextKey, iterator.Key(), iterator.Value()) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/steveyen/gtreap/.gitignore b/Godeps/_workspace/src/github.com/steveyen/gtreap/.gitignore new file mode 100644 index 00000000..94b2ac31 --- /dev/null +++ b/Godeps/_workspace/src/github.com/steveyen/gtreap/.gitignore @@ -0,0 +1,5 @@ +#* +*~ +*.test +tmp + diff --git a/Godeps/_workspace/src/github.com/steveyen/gtreap/LICENSE b/Godeps/_workspace/src/github.com/steveyen/gtreap/LICENSE new file mode 100644 index 00000000..26656306 --- /dev/null +++ b/Godeps/_workspace/src/github.com/steveyen/gtreap/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2012 Steve Yen + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/steveyen/gtreap/README.md b/Godeps/_workspace/src/github.com/steveyen/gtreap/README.md new file mode 100644 index 00000000..4cd8de7c --- /dev/null +++ b/Godeps/_workspace/src/github.com/steveyen/gtreap/README.md @@ -0,0 +1,90 @@ +gtreap +------ + +gtreap is an immutable treap implementation in the Go Language + +[![GoDoc](https://godoc.org/github.com/steveyen/gtreap?status.svg)](https://godoc.org/github.com/steveyen/gtreap) [![Build Status](https://drone.io/github.com/steveyen/gtreap/status.png)](https://drone.io/github.com/steveyen/gtreap/latest) [![Coverage Status](https://coveralls.io/repos/steveyen/gtreap/badge.png)](https://coveralls.io/r/steveyen/gtreap) + +Overview +======== + +gtreap implements an immutable treap data structure in golang. + +By treap, this data structure is both a heap and a binary search tree. + +By immutable, any updates/deletes to a treap will return a new treap +which can share internal nodes with the previous treap. All nodes in +this implementation are read-only after their creation. This allows +concurrent readers to operate safely with concurrent writers as +modifications only create new data structures and never modify +existing data structures. This is a simple approach to achieving MVCC +or multi-version concurrency control. + +By heap, items in the treap follow the heap-priority property, where a +parent node will have higher priority than its left and right children +nodes. + +By binary search tree, items are store lexigraphically, ordered by a +user-supplied Compare function. + +To get a probabilistic O(lg N) tree height, you should use a random +priority number during the Upsert() operation. + +LICENSE +======= + +MIT + +Example +======= + + import ( + "math/rand" + "github.com/steveyen/gtreap" + ) + + func stringCompare(a, b interface{}) int { + return bytes.Compare([]byte(a.(string)), []byte(b.(string))) + } + + t := gtreap.NewTreap(stringCompare) + t = t.Upsert("hi", rand.Int()) + t = t.Upsert("hola", rand.Int()) + t = t.Upsert("bye", rand.Int()) + t = t.Upsert("adios", rand.Int()) + + hi = t.Get("hi") + bye = t.Get("bye") + + // Some example Delete()'s... + t = t.Delete("bye") + nilValueHere = t.Get("bye") + t2 = t.Delete("hi") + nilValueHere2 = t2.Get("hi") + + // Since we still hold onto treap t, we can still access "hi". + hiStillExistsInTreapT = t.Get("hi") + + t.VisitAscend("cya", func(i Item) bool { + // This visitor callback will be invoked with every item + // from "cya" onwards. So: "hi", "hola". + // If we want to stop visiting, return false; + // otherwise a true return result means keep visiting items. + return true + }) + +Tips +==== + +The Upsert() method takes both an Item (an interface{}) and a heap +priority. Usually, that priority should be a random int +(math/rand.Int()) or perhaps even a hash of the item. However, if you +want to shuffle more commonly accessed items nearer to the top of the +treap for faster access, at the potential cost of not approaching a +probabilistic O(lg N) tree height, then you might tweak the priority. + +See also +======== + +For a simple, ordered, key-value storage or persistence library built +on immutable treaps, see: https://github.com/steveyen/gkvlite diff --git a/Godeps/_workspace/src/github.com/steveyen/gtreap/treap.go b/Godeps/_workspace/src/github.com/steveyen/gtreap/treap.go new file mode 100644 index 00000000..c1a0a664 --- /dev/null +++ b/Godeps/_workspace/src/github.com/steveyen/gtreap/treap.go @@ -0,0 +1,187 @@ +package gtreap + +type Treap struct { + compare Compare + root *node +} + +// Compare returns an integer comparing the two items +// lexicographically. The result will be 0 if a==b, -1 if a < b, and +// +1 if a > b. +type Compare func(a, b interface{}) int + +// Item can be anything. +type Item interface{} + +type node struct { + item Item + priority int + left *node + right *node +} + +func NewTreap(c Compare) *Treap { + return &Treap{compare: c, root: nil} +} + +func (t *Treap) Min() Item { + n := t.root + if n == nil { + return nil + } + for n.left != nil { + n = n.left + } + return n.item +} + +func (t *Treap) Max() Item { + n := t.root + if n == nil { + return nil + } + for n.right != nil { + n = n.right + } + return n.item +} + +func (t *Treap) Get(target Item) Item { + n := t.root + for { + if n == nil { + break + } + c := t.compare(target, n.item) + if c < 0 { + n = n.left + } else if c > 0 { + n = n.right + } else { + return n.item + } + } + return nil +} + +func (t *Treap) Upsert(item Item, itemPriority int) *Treap { + r := t.union(t.root, &node{item: item, priority: itemPriority}) + return &Treap{compare: t.compare, root: r} +} + +func (t *Treap) union(this *node, that *node) *node { + if this == nil { + return that + } + if that == nil { + return this + } + if this.priority > that.priority { + left, middle, right := t.split(that, this.item) + if middle == nil { + return &node{ + item: this.item, + priority: this.priority, + left: t.union(this.left, left), + right: t.union(this.right, right), + } + } + return &node{ + item: middle.item, + priority: middle.priority, + left: t.union(this.left, left), + right: t.union(this.right, right), + } + } + // We don't use middle because the "that" has precendence. + left, _, right := t.split(this, that.item) + return &node{ + item: that.item, + priority: that.priority, + left: t.union(left, that.left), + right: t.union(right, that.right), + } +} + +// Splits a treap into two treaps based on a split item "s". +// The result tuple-3 means (left, X, right), where X is either... +// nil - meaning the item s was not in the original treap. +// non-null - returning the node that had item s. +// The tuple-3's left result has items < s, +// and the tuple-3's right result has items > s. +func (t *Treap) split(n *node, s Item) (*node, *node, *node) { + if n == nil { + return nil, nil, nil + } + c := t.compare(s, n.item) + if c == 0 { + return n.left, n, n.right + } + if c < 0 { + left, middle, right := t.split(n.left, s) + return left, middle, &node{ + item: n.item, + priority: n.priority, + left: right, + right: n.right, + } + } + left, middle, right := t.split(n.right, s) + return &node{ + item: n.item, + priority: n.priority, + left: n.left, + right: left, + }, middle, right +} + +func (t *Treap) Delete(target Item) *Treap { + left, _, right := t.split(t.root, target) + return &Treap{compare: t.compare, root: t.join(left, right)} +} + +// All the items from this are < items from that. +func (t *Treap) join(this *node, that *node) *node { + if this == nil { + return that + } + if that == nil { + return this + } + if this.priority > that.priority { + return &node{ + item: this.item, + priority: this.priority, + left: this.left, + right: t.join(this.right, that), + } + } + return &node{ + item: that.item, + priority: that.priority, + left: t.join(this, that.left), + right: that.right, + } +} + +type ItemVisitor func(i Item) bool + +// Visit items greater-than-or-equal to the pivot. +func (t *Treap) VisitAscend(pivot Item, visitor ItemVisitor) { + t.visitAscend(t.root, pivot, visitor) +} + +func (t *Treap) visitAscend(n *node, pivot Item, visitor ItemVisitor) bool { + if n == nil { + return true + } + if t.compare(pivot, n.item) <= 0 { + if !t.visitAscend(n.left, pivot, visitor) { + return false + } + if !visitor(n.item) { + return false + } + } + return t.visitAscend(n.right, pivot, visitor) +} diff --git a/Godeps/_workspace/src/github.com/steveyen/gtreap/treap_test.go b/Godeps/_workspace/src/github.com/steveyen/gtreap/treap_test.go new file mode 100644 index 00000000..79216a3d --- /dev/null +++ b/Godeps/_workspace/src/github.com/steveyen/gtreap/treap_test.go @@ -0,0 +1,225 @@ +package gtreap + +import ( + "bytes" + "testing" +) + +func stringCompare(a, b interface{}) int { + return bytes.Compare([]byte(a.(string)), []byte(b.(string))) +} + +func TestTreap(t *testing.T) { + x := NewTreap(stringCompare) + if x == nil { + t.Errorf("expected NewTreap to work") + } + + tests := []struct { + op string + val string + pri int + exp string + }{ + {"get", "not-there", -1, "NIL"}, + {"ups", "a", 100, ""}, + {"get", "a", -1, "a"}, + {"ups", "b", 200, ""}, + {"get", "a", -1, "a"}, + {"get", "b", -1, "b"}, + {"ups", "c", 300, ""}, + {"get", "a", -1, "a"}, + {"get", "b", -1, "b"}, + {"get", "c", -1, "c"}, + {"get", "not-there", -1, "NIL"}, + {"ups", "a", 400, ""}, + {"get", "a", -1, "a"}, + {"get", "b", -1, "b"}, + {"get", "c", -1, "c"}, + {"get", "not-there", -1, "NIL"}, + {"del", "a", -1, ""}, + {"get", "a", -1, "NIL"}, + {"get", "b", -1, "b"}, + {"get", "c", -1, "c"}, + {"get", "not-there", -1, "NIL"}, + {"ups", "a", 10, ""}, + {"get", "a", -1, "a"}, + {"get", "b", -1, "b"}, + {"get", "c", -1, "c"}, + {"get", "not-there", -1, "NIL"}, + {"del", "a", -1, ""}, + {"del", "b", -1, ""}, + {"del", "c", -1, ""}, + {"get", "a", -1, "NIL"}, + {"get", "b", -1, "NIL"}, + {"get", "c", -1, "NIL"}, + {"get", "not-there", -1, "NIL"}, + {"del", "a", -1, ""}, + {"del", "b", -1, ""}, + {"del", "c", -1, ""}, + {"get", "a", -1, "NIL"}, + {"get", "b", -1, "NIL"}, + {"get", "c", -1, "NIL"}, + {"get", "not-there", -1, "NIL"}, + {"ups", "a", 10, ""}, + {"get", "a", -1, "a"}, + {"get", "b", -1, "NIL"}, + {"get", "c", -1, "NIL"}, + {"get", "not-there", -1, "NIL"}, + {"ups", "b", 1000, "b"}, + {"del", "b", -1, ""}, // cover join that is nil + {"ups", "b", 20, "b"}, + {"ups", "c", 12, "c"}, + {"del", "b", -1, ""}, // cover join second return + {"ups", "a", 5, "a"}, // cover upsert existing with lower priority + } + + for testIdx, test := range tests { + switch test.op { + case "get": + i := x.Get(test.val) + if i != test.exp && !(i == nil && test.exp == "NIL") { + t.Errorf("test: %v, on Get, expected: %v, got: %v", testIdx, test.exp, i) + } + case "ups": + x = x.Upsert(test.val, test.pri) + case "del": + x = x.Delete(test.val) + } + } +} + +func load(x *Treap, arr []string) *Treap { + for i, s := range arr { + x = x.Upsert(s, i) + } + return x +} + +func visitExpect(t *testing.T, x *Treap, start string, arr []string) { + n := 0 + x.VisitAscend(start, func(i Item) bool { + if i.(string) != arr[n] { + t.Errorf("expected visit item: %v, saw: %v", arr[n], i) + } + n++ + return true + }) + if n != len(arr) { + t.Errorf("expected # visit callbacks: %v, saw: %v", len(arr), n) + } +} + +func TestVisit(t *testing.T) { + x := NewTreap(stringCompare) + visitExpect(t, x, "a", []string{}) + + x = load(x, []string{"e", "d", "c", "c", "a", "b", "a"}) + + visitX := func() { + visitExpect(t, x, "a", []string{"a", "b", "c", "d", "e"}) + visitExpect(t, x, "a1", []string{"b", "c", "d", "e"}) + visitExpect(t, x, "b", []string{"b", "c", "d", "e"}) + visitExpect(t, x, "b1", []string{"c", "d", "e"}) + visitExpect(t, x, "c", []string{"c", "d", "e"}) + visitExpect(t, x, "c1", []string{"d", "e"}) + visitExpect(t, x, "d", []string{"d", "e"}) + visitExpect(t, x, "d1", []string{"e"}) + visitExpect(t, x, "e", []string{"e"}) + visitExpect(t, x, "f", []string{}) + } + visitX() + + var y *Treap + y = x.Upsert("f", 1) + y = y.Delete("a") + y = y.Upsert("cc", 2) + y = y.Delete("c") + + visitExpect(t, y, "a", []string{"b", "cc", "d", "e", "f"}) + visitExpect(t, y, "a1", []string{"b", "cc", "d", "e", "f"}) + visitExpect(t, y, "b", []string{"b", "cc", "d", "e", "f"}) + visitExpect(t, y, "b1", []string{"cc", "d", "e", "f"}) + visitExpect(t, y, "c", []string{"cc", "d", "e", "f"}) + visitExpect(t, y, "c1", []string{"cc", "d", "e", "f"}) + visitExpect(t, y, "d", []string{"d", "e", "f"}) + visitExpect(t, y, "d1", []string{"e", "f"}) + visitExpect(t, y, "e", []string{"e", "f"}) + visitExpect(t, y, "f", []string{"f"}) + visitExpect(t, y, "z", []string{}) + + // an uninitialized treap + z := NewTreap(stringCompare) + + // a treap to force left traversal of min + lmt := NewTreap(stringCompare) + lmt = lmt.Upsert("b", 2) + lmt = lmt.Upsert("a", 1) + + // The x treap should be unchanged. + visitX() + + if x.Min() != "a" { + t.Errorf("expected min of a") + } + if x.Max() != "e" { + t.Errorf("expected max of d") + } + if y.Min() != "b" { + t.Errorf("expected min of b") + } + if y.Max() != "f" { + t.Errorf("expected max of f") + } + if z.Min() != nil { + t.Errorf("expected min of nil") + } + if z.Max() != nil { + t.Error("expected max of nil") + } + if lmt.Min() != "a" { + t.Errorf("expected min of a") + } + if lmt.Max() != "b" { + t.Errorf("expeced max of b") + } +} + +func visitExpectEndAtC(t *testing.T, x *Treap, start string, arr []string) { + n := 0 + x.VisitAscend(start, func(i Item) bool { + if stringCompare(i, "c") > 0 { + return false + } + if i.(string) != arr[n] { + t.Errorf("expected visit item: %v, saw: %v", arr[n], i) + } + n++ + return true + }) + if n != len(arr) { + t.Errorf("expected # visit callbacks: %v, saw: %v", len(arr), n) + } +} + +func TestVisitEndEarly(t *testing.T) { + x := NewTreap(stringCompare) + visitExpectEndAtC(t, x, "a", []string{}) + + x = load(x, []string{"e", "d", "c", "c", "a", "b", "a", "e"}) + + visitX := func() { + visitExpectEndAtC(t, x, "a", []string{"a", "b", "c"}) + visitExpectEndAtC(t, x, "a1", []string{"b", "c"}) + visitExpectEndAtC(t, x, "b", []string{"b", "c"}) + visitExpectEndAtC(t, x, "b1", []string{"c"}) + visitExpectEndAtC(t, x, "c", []string{"c"}) + visitExpectEndAtC(t, x, "c1", []string{}) + visitExpectEndAtC(t, x, "d", []string{}) + visitExpectEndAtC(t, x, "d1", []string{}) + visitExpectEndAtC(t, x, "e", []string{}) + visitExpectEndAtC(t, x, "f", []string{}) + } + visitX() + +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go new file mode 100644 index 00000000..9f1ec7f2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go @@ -0,0 +1,252 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "encoding/binary" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb" +) + +type ErrBatchCorrupted struct { + Reason string +} + +func (e *ErrBatchCorrupted) Error() string { + return fmt.Sprintf("leveldb: batch corrupted: %s", e.Reason) +} + +func newErrBatchCorrupted(reason string) error { + return errors.NewErrCorrupted(nil, &ErrBatchCorrupted{reason}) +} + +const ( + batchHdrLen = 8 + 4 + batchGrowRec = 3000 +) + +type BatchReplay interface { + Put(key, value []byte) + Delete(key []byte) +} + +// Batch is a write batch. +type Batch struct { + data []byte + rLen, bLen int + seq uint64 + sync bool +} + +func (b *Batch) grow(n int) { + off := len(b.data) + if off == 0 { + off = batchHdrLen + if b.data != nil { + b.data = b.data[:off] + } + } + if cap(b.data)-off < n { + if b.data == nil { + b.data = make([]byte, off, off+n) + } else { + odata := b.data + div := 1 + if b.rLen > batchGrowRec { + div = b.rLen / batchGrowRec + } + b.data = make([]byte, off, off+n+(off-batchHdrLen)/div) + copy(b.data, odata) + } + } +} + +func (b *Batch) appendRec(kt kType, key, value []byte) { + n := 1 + binary.MaxVarintLen32 + len(key) + if kt == ktVal { + n += binary.MaxVarintLen32 + len(value) + } + b.grow(n) + off := len(b.data) + data := b.data[:off+n] + data[off] = byte(kt) + off += 1 + off += binary.PutUvarint(data[off:], uint64(len(key))) + copy(data[off:], key) + off += len(key) + if kt == ktVal { + off += binary.PutUvarint(data[off:], uint64(len(value))) + copy(data[off:], value) + off += len(value) + } + b.data = data[:off] + b.rLen++ + // Include 8-byte ikey header + b.bLen += len(key) + len(value) + 8 +} + +// Put appends 'put operation' of the given key/value pair to the batch. +// It is safe to modify the contents of the argument after Put returns. +func (b *Batch) Put(key, value []byte) { + b.appendRec(ktVal, key, value) +} + +// Delete appends 'delete operation' of the given key to the batch. +// It is safe to modify the contents of the argument after Delete returns. +func (b *Batch) Delete(key []byte) { + b.appendRec(ktDel, key, nil) +} + +// Dump dumps batch contents. The returned slice can be loaded into the +// batch using Load method. +// The returned slice is not its own copy, so the contents should not be +// modified. +func (b *Batch) Dump() []byte { + return b.encode() +} + +// Load loads given slice into the batch. Previous contents of the batch +// will be discarded. +// The given slice will not be copied and will be used as batch buffer, so +// it is not safe to modify the contents of the slice. +func (b *Batch) Load(data []byte) error { + return b.decode(0, data) +} + +// Replay replays batch contents. +func (b *Batch) Replay(r BatchReplay) error { + return b.decodeRec(func(i int, kt kType, key, value []byte) { + switch kt { + case ktVal: + r.Put(key, value) + case ktDel: + r.Delete(key) + } + }) +} + +// Len returns number of records in the batch. +func (b *Batch) Len() int { + return b.rLen +} + +// Reset resets the batch. +func (b *Batch) Reset() { + b.data = b.data[:0] + b.seq = 0 + b.rLen = 0 + b.bLen = 0 + b.sync = false +} + +func (b *Batch) init(sync bool) { + b.sync = sync +} + +func (b *Batch) append(p *Batch) { + if p.rLen > 0 { + b.grow(len(p.data) - batchHdrLen) + b.data = append(b.data, p.data[batchHdrLen:]...) + b.rLen += p.rLen + } + if p.sync { + b.sync = true + } +} + +// size returns sums of key/value pair length plus 8-bytes ikey. +func (b *Batch) size() int { + return b.bLen +} + +func (b *Batch) encode() []byte { + b.grow(0) + binary.LittleEndian.PutUint64(b.data, b.seq) + binary.LittleEndian.PutUint32(b.data[8:], uint32(b.rLen)) + + return b.data +} + +func (b *Batch) decode(prevSeq uint64, data []byte) error { + if len(data) < batchHdrLen { + return newErrBatchCorrupted("too short") + } + + b.seq = binary.LittleEndian.Uint64(data) + if b.seq < prevSeq { + return newErrBatchCorrupted("invalid sequence number") + } + b.rLen = int(binary.LittleEndian.Uint32(data[8:])) + if b.rLen < 0 { + return newErrBatchCorrupted("invalid records length") + } + // No need to be precise at this point, it won't be used anyway + b.bLen = len(data) - batchHdrLen + b.data = data + + return nil +} + +func (b *Batch) decodeRec(f func(i int, kt kType, key, value []byte)) (err error) { + off := batchHdrLen + for i := 0; i < b.rLen; i++ { + if off >= len(b.data) { + return newErrBatchCorrupted("invalid records length") + } + + kt := kType(b.data[off]) + if kt > ktVal { + return newErrBatchCorrupted("bad record: invalid type") + } + off += 1 + + x, n := binary.Uvarint(b.data[off:]) + off += n + if n <= 0 || off+int(x) > len(b.data) { + return newErrBatchCorrupted("bad record: invalid key length") + } + key := b.data[off : off+int(x)] + off += int(x) + var value []byte + if kt == ktVal { + x, n := binary.Uvarint(b.data[off:]) + off += n + if n <= 0 || off+int(x) > len(b.data) { + return newErrBatchCorrupted("bad record: invalid value length") + } + value = b.data[off : off+int(x)] + off += int(x) + } + + f(i, kt, key, value) + } + + return nil +} + +func (b *Batch) memReplay(to *memdb.DB) error { + return b.decodeRec(func(i int, kt kType, key, value []byte) { + ikey := newIkey(key, b.seq+uint64(i), kt) + to.Put(ikey, value) + }) +} + +func (b *Batch) memDecodeAndReplay(prevSeq uint64, data []byte, to *memdb.DB) error { + if err := b.decode(prevSeq, data); err != nil { + return err + } + return b.memReplay(to) +} + +func (b *Batch) revertMemReplay(to *memdb.DB) error { + return b.decodeRec(func(i int, kt kType, key, value []byte) { + ikey := newIkey(key, b.seq+uint64(i), kt) + to.Delete(ikey) + }) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go new file mode 100644 index 00000000..d13d8a58 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go @@ -0,0 +1,120 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bytes" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb" +) + +type tbRec struct { + kt kType + key, value []byte +} + +type testBatch struct { + rec []*tbRec +} + +func (p *testBatch) Put(key, value []byte) { + p.rec = append(p.rec, &tbRec{ktVal, key, value}) +} + +func (p *testBatch) Delete(key []byte) { + p.rec = append(p.rec, &tbRec{ktDel, key, nil}) +} + +func compareBatch(t *testing.T, b1, b2 *Batch) { + if b1.seq != b2.seq { + t.Errorf("invalid seq number want %d, got %d", b1.seq, b2.seq) + } + if b1.Len() != b2.Len() { + t.Fatalf("invalid record length want %d, got %d", b1.Len(), b2.Len()) + } + p1, p2 := new(testBatch), new(testBatch) + err := b1.Replay(p1) + if err != nil { + t.Fatal("error when replaying batch 1: ", err) + } + err = b2.Replay(p2) + if err != nil { + t.Fatal("error when replaying batch 2: ", err) + } + for i := range p1.rec { + r1, r2 := p1.rec[i], p2.rec[i] + if r1.kt != r2.kt { + t.Errorf("invalid type on record '%d' want %d, got %d", i, r1.kt, r2.kt) + } + if !bytes.Equal(r1.key, r2.key) { + t.Errorf("invalid key on record '%d' want %s, got %s", i, string(r1.key), string(r2.key)) + } + if r1.kt == ktVal { + if !bytes.Equal(r1.value, r2.value) { + t.Errorf("invalid value on record '%d' want %s, got %s", i, string(r1.value), string(r2.value)) + } + } + } +} + +func TestBatch_EncodeDecode(t *testing.T) { + b1 := new(Batch) + b1.seq = 10009 + b1.Put([]byte("key1"), []byte("value1")) + b1.Put([]byte("key2"), []byte("value2")) + b1.Delete([]byte("key1")) + b1.Put([]byte("k"), []byte("")) + b1.Put([]byte("zzzzzzzzzzz"), []byte("zzzzzzzzzzzzzzzzzzzzzzzz")) + b1.Delete([]byte("key10000")) + b1.Delete([]byte("k")) + buf := b1.encode() + b2 := new(Batch) + err := b2.decode(0, buf) + if err != nil { + t.Error("error when decoding batch: ", err) + } + compareBatch(t, b1, b2) +} + +func TestBatch_Append(t *testing.T) { + b1 := new(Batch) + b1.seq = 10009 + b1.Put([]byte("key1"), []byte("value1")) + b1.Put([]byte("key2"), []byte("value2")) + b1.Delete([]byte("key1")) + b1.Put([]byte("foo"), []byte("foovalue")) + b1.Put([]byte("bar"), []byte("barvalue")) + b2a := new(Batch) + b2a.seq = 10009 + b2a.Put([]byte("key1"), []byte("value1")) + b2a.Put([]byte("key2"), []byte("value2")) + b2a.Delete([]byte("key1")) + b2b := new(Batch) + b2b.Put([]byte("foo"), []byte("foovalue")) + b2b.Put([]byte("bar"), []byte("barvalue")) + b2a.append(b2b) + compareBatch(t, b1, b2a) +} + +func TestBatch_Size(t *testing.T) { + b := new(Batch) + for i := 0; i < 2; i++ { + b.Put([]byte("key1"), []byte("value1")) + b.Put([]byte("key2"), []byte("value2")) + b.Delete([]byte("key1")) + b.Put([]byte("foo"), []byte("foovalue")) + b.Put([]byte("bar"), []byte("barvalue")) + mem := memdb.New(&iComparer{comparer.DefaultComparer}, 0) + b.memReplay(mem) + if b.size() != mem.Size() { + t.Errorf("invalid batch size calculation, want=%d got=%d", mem.Size(), b.size()) + } + b.Reset() + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go new file mode 100644 index 00000000..0dd60fd8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build !go1.2 + +package leveldb + +import ( + "sync/atomic" + "testing" +) + +func BenchmarkDBReadConcurrent(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.gc() + defer p.close() + + b.ResetTimer() + b.SetBytes(116) + + b.RunParallel(func(pb *testing.PB) { + iter := p.newIter() + defer iter.Release() + for pb.Next() && iter.Next() { + } + }) +} + +func BenchmarkDBReadConcurrent2(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.gc() + defer p.close() + + b.ResetTimer() + b.SetBytes(116) + + var dir uint32 + b.RunParallel(func(pb *testing.PB) { + iter := p.newIter() + defer iter.Release() + if atomic.AddUint32(&dir, 1)%2 == 0 { + for pb.Next() && iter.Next() { + } + } else { + if pb.Next() && iter.Last() { + for pb.Next() && iter.Prev() { + } + } + } + }) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go new file mode 100644 index 00000000..a79655e4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go @@ -0,0 +1,464 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bytes" + "fmt" + "math/rand" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" +) + +func randomString(r *rand.Rand, n int) []byte { + b := new(bytes.Buffer) + for i := 0; i < n; i++ { + b.WriteByte(' ' + byte(r.Intn(95))) + } + return b.Bytes() +} + +func compressibleStr(r *rand.Rand, frac float32, n int) []byte { + nn := int(float32(n) * frac) + rb := randomString(r, nn) + b := make([]byte, 0, n+nn) + for len(b) < n { + b = append(b, rb...) + } + return b[:n] +} + +type valueGen struct { + src []byte + pos int +} + +func newValueGen(frac float32) *valueGen { + v := new(valueGen) + r := rand.New(rand.NewSource(301)) + v.src = make([]byte, 0, 1048576+100) + for len(v.src) < 1048576 { + v.src = append(v.src, compressibleStr(r, frac, 100)...) + } + return v +} + +func (v *valueGen) get(n int) []byte { + if v.pos+n > len(v.src) { + v.pos = 0 + } + v.pos += n + return v.src[v.pos-n : v.pos] +} + +var benchDB = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbbench-%d", os.Getuid())) + +type dbBench struct { + b *testing.B + stor storage.Storage + db *DB + + o *opt.Options + ro *opt.ReadOptions + wo *opt.WriteOptions + + keys, values [][]byte +} + +func openDBBench(b *testing.B, noCompress bool) *dbBench { + _, err := os.Stat(benchDB) + if err == nil { + err = os.RemoveAll(benchDB) + if err != nil { + b.Fatal("cannot remove old db: ", err) + } + } + + p := &dbBench{ + b: b, + o: &opt.Options{}, + ro: &opt.ReadOptions{}, + wo: &opt.WriteOptions{}, + } + p.stor, err = storage.OpenFile(benchDB) + if err != nil { + b.Fatal("cannot open stor: ", err) + } + if noCompress { + p.o.Compression = opt.NoCompression + } + + p.db, err = Open(p.stor, p.o) + if err != nil { + b.Fatal("cannot open db: ", err) + } + + runtime.GOMAXPROCS(runtime.NumCPU()) + return p +} + +func (p *dbBench) reopen() { + p.db.Close() + var err error + p.db, err = Open(p.stor, p.o) + if err != nil { + p.b.Fatal("Reopen: got error: ", err) + } +} + +func (p *dbBench) populate(n int) { + p.keys, p.values = make([][]byte, n), make([][]byte, n) + v := newValueGen(0.5) + for i := range p.keys { + p.keys[i], p.values[i] = []byte(fmt.Sprintf("%016d", i)), v.get(100) + } +} + +func (p *dbBench) randomize() { + m := len(p.keys) + times := m * 2 + r1, r2 := rand.New(rand.NewSource(0xdeadbeef)), rand.New(rand.NewSource(0xbeefface)) + for n := 0; n < times; n++ { + i, j := r1.Int()%m, r2.Int()%m + if i == j { + continue + } + p.keys[i], p.keys[j] = p.keys[j], p.keys[i] + p.values[i], p.values[j] = p.values[j], p.values[i] + } +} + +func (p *dbBench) writes(perBatch int) { + b := p.b + db := p.db + + n := len(p.keys) + m := n / perBatch + if n%perBatch > 0 { + m++ + } + batches := make([]Batch, m) + j := 0 + for i := range batches { + first := true + for ; j < n && ((j+1)%perBatch != 0 || first); j++ { + first = false + batches[i].Put(p.keys[j], p.values[j]) + } + } + runtime.GC() + + b.ResetTimer() + b.StartTimer() + for i := range batches { + err := db.Write(&(batches[i]), p.wo) + if err != nil { + b.Fatal("write failed: ", err) + } + } + b.StopTimer() + b.SetBytes(116) +} + +func (p *dbBench) gc() { + p.keys, p.values = nil, nil + runtime.GC() +} + +func (p *dbBench) puts() { + b := p.b + db := p.db + + b.ResetTimer() + b.StartTimer() + for i := range p.keys { + err := db.Put(p.keys[i], p.values[i], p.wo) + if err != nil { + b.Fatal("put failed: ", err) + } + } + b.StopTimer() + b.SetBytes(116) +} + +func (p *dbBench) fill() { + b := p.b + db := p.db + + perBatch := 10000 + batch := new(Batch) + for i, n := 0, len(p.keys); i < n; { + first := true + for ; i < n && ((i+1)%perBatch != 0 || first); i++ { + first = false + batch.Put(p.keys[i], p.values[i]) + } + err := db.Write(batch, p.wo) + if err != nil { + b.Fatal("write failed: ", err) + } + batch.Reset() + } +} + +func (p *dbBench) gets() { + b := p.b + db := p.db + + b.ResetTimer() + for i := range p.keys { + _, err := db.Get(p.keys[i], p.ro) + if err != nil { + b.Error("got error: ", err) + } + } + b.StopTimer() +} + +func (p *dbBench) seeks() { + b := p.b + + iter := p.newIter() + defer iter.Release() + b.ResetTimer() + for i := range p.keys { + if !iter.Seek(p.keys[i]) { + b.Error("value not found for: ", string(p.keys[i])) + } + } + b.StopTimer() +} + +func (p *dbBench) newIter() iterator.Iterator { + iter := p.db.NewIterator(nil, p.ro) + err := iter.Error() + if err != nil { + p.b.Fatal("cannot create iterator: ", err) + } + return iter +} + +func (p *dbBench) close() { + if bp, err := p.db.GetProperty("leveldb.blockpool"); err == nil { + p.b.Log("Block pool stats: ", bp) + } + p.db.Close() + p.stor.Close() + os.RemoveAll(benchDB) + p.db = nil + p.keys = nil + p.values = nil + runtime.GC() + runtime.GOMAXPROCS(1) +} + +func BenchmarkDBWrite(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.writes(1) + p.close() +} + +func BenchmarkDBWriteBatch(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.writes(1000) + p.close() +} + +func BenchmarkDBWriteUncompressed(b *testing.B) { + p := openDBBench(b, true) + p.populate(b.N) + p.writes(1) + p.close() +} + +func BenchmarkDBWriteBatchUncompressed(b *testing.B) { + p := openDBBench(b, true) + p.populate(b.N) + p.writes(1000) + p.close() +} + +func BenchmarkDBWriteRandom(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.randomize() + p.writes(1) + p.close() +} + +func BenchmarkDBWriteRandomSync(b *testing.B) { + p := openDBBench(b, false) + p.wo.Sync = true + p.populate(b.N) + p.writes(1) + p.close() +} + +func BenchmarkDBOverwrite(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.writes(1) + p.writes(1) + p.close() +} + +func BenchmarkDBOverwriteRandom(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.writes(1) + p.randomize() + p.writes(1) + p.close() +} + +func BenchmarkDBPut(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.puts() + p.close() +} + +func BenchmarkDBRead(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.gc() + + iter := p.newIter() + b.ResetTimer() + for iter.Next() { + } + iter.Release() + b.StopTimer() + b.SetBytes(116) + p.close() +} + +func BenchmarkDBReadGC(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + + iter := p.newIter() + b.ResetTimer() + for iter.Next() { + } + iter.Release() + b.StopTimer() + b.SetBytes(116) + p.close() +} + +func BenchmarkDBReadUncompressed(b *testing.B) { + p := openDBBench(b, true) + p.populate(b.N) + p.fill() + p.gc() + + iter := p.newIter() + b.ResetTimer() + for iter.Next() { + } + iter.Release() + b.StopTimer() + b.SetBytes(116) + p.close() +} + +func BenchmarkDBReadTable(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.reopen() + p.gc() + + iter := p.newIter() + b.ResetTimer() + for iter.Next() { + } + iter.Release() + b.StopTimer() + b.SetBytes(116) + p.close() +} + +func BenchmarkDBReadReverse(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.gc() + + iter := p.newIter() + b.ResetTimer() + iter.Last() + for iter.Prev() { + } + iter.Release() + b.StopTimer() + b.SetBytes(116) + p.close() +} + +func BenchmarkDBReadReverseTable(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.reopen() + p.gc() + + iter := p.newIter() + b.ResetTimer() + iter.Last() + for iter.Prev() { + } + iter.Release() + b.StopTimer() + b.SetBytes(116) + p.close() +} + +func BenchmarkDBSeek(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.seeks() + p.close() +} + +func BenchmarkDBSeekRandom(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.randomize() + p.seeks() + p.close() +} + +func BenchmarkDBGet(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.gets() + p.close() +} + +func BenchmarkDBGetRandom(b *testing.B) { + p := openDBBench(b, false) + p.populate(b.N) + p.fill() + p.randomize() + p.gets() + p.close() +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go new file mode 100644 index 00000000..175e2220 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go @@ -0,0 +1,30 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build !go1.2 + +package cache + +import ( + "math/rand" + "testing" +) + +func BenchmarkLRUCache(b *testing.B) { + c := NewCache(NewLRU(10000)) + + b.SetParallelism(10) + b.RunParallel(func(pb *testing.PB) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for pb.Next() { + key := uint64(r.Intn(1000000)) + c.Get(0, key, func() (int, Value) { + return 1, key + }).Release() + } + }) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go new file mode 100644 index 00000000..abbacf95 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache.go @@ -0,0 +1,676 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package cache provides interface and implementation of a cache algorithms. +package cache + +import ( + "sync" + "sync/atomic" + "unsafe" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +// Cacher provides interface to implements a caching functionality. +// An implementation must be goroutine-safe. +type Cacher interface { + // Capacity returns cache capacity. + Capacity() int + + // SetCapacity sets cache capacity. + SetCapacity(capacity int) + + // Promote promotes the 'cache node'. + Promote(n *Node) + + // Ban evicts the 'cache node' and prevent subsequent 'promote'. + Ban(n *Node) + + // Evict evicts the 'cache node'. + Evict(n *Node) + + // EvictNS evicts 'cache node' with the given namespace. + EvictNS(ns uint64) + + // EvictAll evicts all 'cache node'. + EvictAll() + + // Close closes the 'cache tree' + Close() error +} + +// Value is a 'cacheable object'. It may implements util.Releaser, if +// so the the Release method will be called once object is released. +type Value interface{} + +type CacheGetter struct { + Cache *Cache + NS uint64 +} + +func (g *CacheGetter) Get(key uint64, setFunc func() (size int, value Value)) *Handle { + return g.Cache.Get(g.NS, key, setFunc) +} + +// The hash tables implementation is based on: +// "Dynamic-Sized Nonblocking Hash Tables", by Yujie Liu, Kunlong Zhang, and Michael Spear. ACM Symposium on Principles of Distributed Computing, Jul 2014. + +const ( + mInitialSize = 1 << 4 + mOverflowThreshold = 1 << 5 + mOverflowGrowThreshold = 1 << 7 +) + +type mBucket struct { + mu sync.Mutex + node []*Node + frozen bool +} + +func (b *mBucket) freeze() []*Node { + b.mu.Lock() + defer b.mu.Unlock() + if !b.frozen { + b.frozen = true + } + return b.node +} + +func (b *mBucket) get(r *Cache, h *mNode, hash uint32, ns, key uint64, noset bool) (done, added bool, n *Node) { + b.mu.Lock() + + if b.frozen { + b.mu.Unlock() + return + } + + // Scan the node. + for _, n := range b.node { + if n.hash == hash && n.ns == ns && n.key == key { + atomic.AddInt32(&n.ref, 1) + b.mu.Unlock() + return true, false, n + } + } + + // Get only. + if noset { + b.mu.Unlock() + return true, false, nil + } + + // Create node. + n = &Node{ + r: r, + hash: hash, + ns: ns, + key: key, + ref: 1, + } + // Add node to bucket. + b.node = append(b.node, n) + bLen := len(b.node) + b.mu.Unlock() + + // Update counter. + grow := atomic.AddInt32(&r.nodes, 1) >= h.growThreshold + if bLen > mOverflowThreshold { + grow = grow || atomic.AddInt32(&h.overflow, 1) >= mOverflowGrowThreshold + } + + // Grow. + if grow && atomic.CompareAndSwapInt32(&h.resizeInProgess, 0, 1) { + nhLen := len(h.buckets) << 1 + nh := &mNode{ + buckets: make([]unsafe.Pointer, nhLen), + mask: uint32(nhLen) - 1, + pred: unsafe.Pointer(h), + growThreshold: int32(nhLen * mOverflowThreshold), + shrinkThreshold: int32(nhLen >> 1), + } + ok := atomic.CompareAndSwapPointer(&r.mHead, unsafe.Pointer(h), unsafe.Pointer(nh)) + if !ok { + panic("BUG: failed swapping head") + } + go nh.initBuckets() + } + + return true, true, n +} + +func (b *mBucket) delete(r *Cache, h *mNode, hash uint32, ns, key uint64) (done, deleted bool) { + b.mu.Lock() + + if b.frozen { + b.mu.Unlock() + return + } + + // Scan the node. + var ( + n *Node + bLen int + ) + for i := range b.node { + n = b.node[i] + if n.ns == ns && n.key == key { + if atomic.LoadInt32(&n.ref) == 0 { + deleted = true + + // Call releaser. + if n.value != nil { + if r, ok := n.value.(util.Releaser); ok { + r.Release() + } + n.value = nil + } + + // Remove node from bucket. + b.node = append(b.node[:i], b.node[i+1:]...) + bLen = len(b.node) + } + break + } + } + b.mu.Unlock() + + if deleted { + // Call OnDel. + for _, f := range n.onDel { + f() + } + + // Update counter. + atomic.AddInt32(&r.size, int32(n.size)*-1) + shrink := atomic.AddInt32(&r.nodes, -1) < h.shrinkThreshold + if bLen >= mOverflowThreshold { + atomic.AddInt32(&h.overflow, -1) + } + + // Shrink. + if shrink && len(h.buckets) > mInitialSize && atomic.CompareAndSwapInt32(&h.resizeInProgess, 0, 1) { + nhLen := len(h.buckets) >> 1 + nh := &mNode{ + buckets: make([]unsafe.Pointer, nhLen), + mask: uint32(nhLen) - 1, + pred: unsafe.Pointer(h), + growThreshold: int32(nhLen * mOverflowThreshold), + shrinkThreshold: int32(nhLen >> 1), + } + ok := atomic.CompareAndSwapPointer(&r.mHead, unsafe.Pointer(h), unsafe.Pointer(nh)) + if !ok { + panic("BUG: failed swapping head") + } + go nh.initBuckets() + } + } + + return true, deleted +} + +type mNode struct { + buckets []unsafe.Pointer // []*mBucket + mask uint32 + pred unsafe.Pointer // *mNode + resizeInProgess int32 + + overflow int32 + growThreshold int32 + shrinkThreshold int32 +} + +func (n *mNode) initBucket(i uint32) *mBucket { + if b := (*mBucket)(atomic.LoadPointer(&n.buckets[i])); b != nil { + return b + } + + p := (*mNode)(atomic.LoadPointer(&n.pred)) + if p != nil { + var node []*Node + if n.mask > p.mask { + // Grow. + pb := (*mBucket)(atomic.LoadPointer(&p.buckets[i&p.mask])) + if pb == nil { + pb = p.initBucket(i & p.mask) + } + m := pb.freeze() + // Split nodes. + for _, x := range m { + if x.hash&n.mask == i { + node = append(node, x) + } + } + } else { + // Shrink. + pb0 := (*mBucket)(atomic.LoadPointer(&p.buckets[i])) + if pb0 == nil { + pb0 = p.initBucket(i) + } + pb1 := (*mBucket)(atomic.LoadPointer(&p.buckets[i+uint32(len(n.buckets))])) + if pb1 == nil { + pb1 = p.initBucket(i + uint32(len(n.buckets))) + } + m0 := pb0.freeze() + m1 := pb1.freeze() + // Merge nodes. + node = make([]*Node, 0, len(m0)+len(m1)) + node = append(node, m0...) + node = append(node, m1...) + } + b := &mBucket{node: node} + if atomic.CompareAndSwapPointer(&n.buckets[i], nil, unsafe.Pointer(b)) { + if len(node) > mOverflowThreshold { + atomic.AddInt32(&n.overflow, int32(len(node)-mOverflowThreshold)) + } + return b + } + } + + return (*mBucket)(atomic.LoadPointer(&n.buckets[i])) +} + +func (n *mNode) initBuckets() { + for i := range n.buckets { + n.initBucket(uint32(i)) + } + atomic.StorePointer(&n.pred, nil) +} + +// Cache is a 'cache map'. +type Cache struct { + mu sync.RWMutex + mHead unsafe.Pointer // *mNode + nodes int32 + size int32 + cacher Cacher + closed bool +} + +// NewCache creates a new 'cache map'. The cacher is optional and +// may be nil. +func NewCache(cacher Cacher) *Cache { + h := &mNode{ + buckets: make([]unsafe.Pointer, mInitialSize), + mask: mInitialSize - 1, + growThreshold: int32(mInitialSize * mOverflowThreshold), + shrinkThreshold: 0, + } + for i := range h.buckets { + h.buckets[i] = unsafe.Pointer(&mBucket{}) + } + r := &Cache{ + mHead: unsafe.Pointer(h), + cacher: cacher, + } + return r +} + +func (r *Cache) getBucket(hash uint32) (*mNode, *mBucket) { + h := (*mNode)(atomic.LoadPointer(&r.mHead)) + i := hash & h.mask + b := (*mBucket)(atomic.LoadPointer(&h.buckets[i])) + if b == nil { + b = h.initBucket(i) + } + return h, b +} + +func (r *Cache) delete(n *Node) bool { + for { + h, b := r.getBucket(n.hash) + done, deleted := b.delete(r, h, n.hash, n.ns, n.key) + if done { + return deleted + } + } + return false +} + +// Nodes returns number of 'cache node' in the map. +func (r *Cache) Nodes() int { + return int(atomic.LoadInt32(&r.nodes)) +} + +// Size returns sums of 'cache node' size in the map. +func (r *Cache) Size() int { + return int(atomic.LoadInt32(&r.size)) +} + +// Capacity returns cache capacity. +func (r *Cache) Capacity() int { + if r.cacher == nil { + return 0 + } + return r.cacher.Capacity() +} + +// SetCapacity sets cache capacity. +func (r *Cache) SetCapacity(capacity int) { + if r.cacher != nil { + r.cacher.SetCapacity(capacity) + } +} + +// Get gets 'cache node' with the given namespace and key. +// If cache node is not found and setFunc is not nil, Get will atomically creates +// the 'cache node' by calling setFunc. Otherwise Get will returns nil. +// +// The returned 'cache handle' should be released after use by calling Release +// method. +func (r *Cache) Get(ns, key uint64, setFunc func() (size int, value Value)) *Handle { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return nil + } + + hash := murmur32(ns, key, 0xf00) + for { + h, b := r.getBucket(hash) + done, _, n := b.get(r, h, hash, ns, key, setFunc == nil) + if done { + if n != nil { + n.mu.Lock() + if n.value == nil { + if setFunc == nil { + n.mu.Unlock() + n.unref() + return nil + } + + n.size, n.value = setFunc() + if n.value == nil { + n.size = 0 + n.mu.Unlock() + n.unref() + return nil + } + atomic.AddInt32(&r.size, int32(n.size)) + } + n.mu.Unlock() + if r.cacher != nil { + r.cacher.Promote(n) + } + return &Handle{unsafe.Pointer(n)} + } + + break + } + } + return nil +} + +// Delete removes and ban 'cache node' with the given namespace and key. +// A banned 'cache node' will never inserted into the 'cache tree'. Ban +// only attributed to the particular 'cache node', so when a 'cache node' +// is recreated it will not be banned. +// +// If onDel is not nil, then it will be executed if such 'cache node' +// doesn't exist or once the 'cache node' is released. +// +// Delete return true is such 'cache node' exist. +func (r *Cache) Delete(ns, key uint64, onDel func()) bool { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return false + } + + hash := murmur32(ns, key, 0xf00) + for { + h, b := r.getBucket(hash) + done, _, n := b.get(r, h, hash, ns, key, true) + if done { + if n != nil { + if onDel != nil { + n.mu.Lock() + n.onDel = append(n.onDel, onDel) + n.mu.Unlock() + } + if r.cacher != nil { + r.cacher.Ban(n) + } + n.unref() + return true + } + + break + } + } + + if onDel != nil { + onDel() + } + + return false +} + +// Evict evicts 'cache node' with the given namespace and key. This will +// simply call Cacher.Evict. +// +// Evict return true is such 'cache node' exist. +func (r *Cache) Evict(ns, key uint64) bool { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return false + } + + hash := murmur32(ns, key, 0xf00) + for { + h, b := r.getBucket(hash) + done, _, n := b.get(r, h, hash, ns, key, true) + if done { + if n != nil { + if r.cacher != nil { + r.cacher.Evict(n) + } + n.unref() + return true + } + + break + } + } + + return false +} + +// EvictNS evicts 'cache node' with the given namespace. This will +// simply call Cacher.EvictNS. +func (r *Cache) EvictNS(ns uint64) { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return + } + + if r.cacher != nil { + r.cacher.EvictNS(ns) + } +} + +// EvictAll evicts all 'cache node'. This will simply call Cacher.EvictAll. +func (r *Cache) EvictAll() { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return + } + + if r.cacher != nil { + r.cacher.EvictAll() + } +} + +// Close closes the 'cache map' and releases all 'cache node'. +func (r *Cache) Close() error { + r.mu.Lock() + if !r.closed { + r.closed = true + + if r.cacher != nil { + if err := r.cacher.Close(); err != nil { + return err + } + } + + h := (*mNode)(r.mHead) + h.initBuckets() + + for i := range h.buckets { + b := (*mBucket)(h.buckets[i]) + for _, n := range b.node { + // Call releaser. + if n.value != nil { + if r, ok := n.value.(util.Releaser); ok { + r.Release() + } + n.value = nil + } + + // Call OnDel. + for _, f := range n.onDel { + f() + } + } + } + } + r.mu.Unlock() + return nil +} + +// Node is a 'cache node'. +type Node struct { + r *Cache + + hash uint32 + ns, key uint64 + + mu sync.Mutex + size int + value Value + + ref int32 + onDel []func() + + CacheData unsafe.Pointer +} + +// NS returns this 'cache node' namespace. +func (n *Node) NS() uint64 { + return n.ns +} + +// Key returns this 'cache node' key. +func (n *Node) Key() uint64 { + return n.key +} + +// Size returns this 'cache node' size. +func (n *Node) Size() int { + return n.size +} + +// Value returns this 'cache node' value. +func (n *Node) Value() Value { + return n.value +} + +// Ref returns this 'cache node' ref counter. +func (n *Node) Ref() int32 { + return atomic.LoadInt32(&n.ref) +} + +// GetHandle returns an handle for this 'cache node'. +func (n *Node) GetHandle() *Handle { + if atomic.AddInt32(&n.ref, 1) <= 1 { + panic("BUG: Node.GetHandle on zero ref") + } + return &Handle{unsafe.Pointer(n)} +} + +func (n *Node) unref() { + if atomic.AddInt32(&n.ref, -1) == 0 { + n.r.delete(n) + } +} + +func (n *Node) unrefLocked() { + if atomic.AddInt32(&n.ref, -1) == 0 { + n.r.mu.RLock() + if !n.r.closed { + n.r.delete(n) + } + n.r.mu.RUnlock() + } +} + +type Handle struct { + n unsafe.Pointer // *Node +} + +func (h *Handle) Value() Value { + n := (*Node)(atomic.LoadPointer(&h.n)) + if n != nil { + return n.value + } + return nil +} + +func (h *Handle) Release() { + nPtr := atomic.LoadPointer(&h.n) + if nPtr != nil && atomic.CompareAndSwapPointer(&h.n, nPtr, nil) { + n := (*Node)(nPtr) + n.unrefLocked() + } +} + +func murmur32(ns, key uint64, seed uint32) uint32 { + const ( + m = uint32(0x5bd1e995) + r = 24 + ) + + k1 := uint32(ns >> 32) + k2 := uint32(ns) + k3 := uint32(key >> 32) + k4 := uint32(key) + + k1 *= m + k1 ^= k1 >> r + k1 *= m + + k2 *= m + k2 ^= k2 >> r + k2 *= m + + k3 *= m + k3 ^= k3 >> r + k3 *= m + + k4 *= m + k4 ^= k4 >> r + k4 *= m + + h := seed + + h *= m + h ^= k1 + h *= m + h ^= k2 + h *= m + h ^= k3 + h *= m + h ^= k4 + + h ^= h >> 13 + h *= m + h ^= h >> 15 + + return h +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go new file mode 100644 index 00000000..c2a50156 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go @@ -0,0 +1,554 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package cache + +import ( + "math/rand" + "runtime" + "sync" + "sync/atomic" + "testing" + "time" + "unsafe" +) + +type int32o int32 + +func (o *int32o) acquire() { + if atomic.AddInt32((*int32)(o), 1) != 1 { + panic("BUG: invalid ref") + } +} + +func (o *int32o) Release() { + if atomic.AddInt32((*int32)(o), -1) != 0 { + panic("BUG: invalid ref") + } +} + +type releaserFunc struct { + fn func() + value Value +} + +func (r releaserFunc) Release() { + if r.fn != nil { + r.fn() + } +} + +func set(c *Cache, ns, key uint64, value Value, charge int, relf func()) *Handle { + return c.Get(ns, key, func() (int, Value) { + if relf != nil { + return charge, releaserFunc{relf, value} + } else { + return charge, value + } + }) +} + +func TestCacheMap(t *testing.T) { + runtime.GOMAXPROCS(runtime.NumCPU()) + + nsx := []struct { + nobjects, nhandles, concurrent, repeat int + }{ + {10000, 400, 50, 3}, + {100000, 1000, 100, 10}, + } + + var ( + objects [][]int32o + handles [][]unsafe.Pointer + ) + + for _, x := range nsx { + objects = append(objects, make([]int32o, x.nobjects)) + handles = append(handles, make([]unsafe.Pointer, x.nhandles)) + } + + c := NewCache(nil) + + wg := new(sync.WaitGroup) + var done int32 + + for ns, x := range nsx { + for i := 0; i < x.concurrent; i++ { + wg.Add(1) + go func(ns, i, repeat int, objects []int32o, handles []unsafe.Pointer) { + defer wg.Done() + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for j := len(objects) * repeat; j >= 0; j-- { + key := uint64(r.Intn(len(objects))) + h := c.Get(uint64(ns), key, func() (int, Value) { + o := &objects[key] + o.acquire() + return 1, o + }) + if v := h.Value().(*int32o); v != &objects[key] { + t.Fatalf("#%d invalid value: want=%p got=%p", ns, &objects[key], v) + } + if objects[key] != 1 { + t.Fatalf("#%d invalid object %d: %d", ns, key, objects[key]) + } + if !atomic.CompareAndSwapPointer(&handles[r.Intn(len(handles))], nil, unsafe.Pointer(h)) { + h.Release() + } + } + }(ns, i, x.repeat, objects[ns], handles[ns]) + } + + go func(handles []unsafe.Pointer) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for atomic.LoadInt32(&done) == 0 { + i := r.Intn(len(handles)) + h := (*Handle)(atomic.LoadPointer(&handles[i])) + if h != nil && atomic.CompareAndSwapPointer(&handles[i], unsafe.Pointer(h), nil) { + h.Release() + } + time.Sleep(time.Millisecond) + } + }(handles[ns]) + } + + go func() { + handles := make([]*Handle, 100000) + for atomic.LoadInt32(&done) == 0 { + for i := range handles { + handles[i] = c.Get(999999999, uint64(i), func() (int, Value) { + return 1, 1 + }) + } + for _, h := range handles { + h.Release() + } + } + }() + + wg.Wait() + + atomic.StoreInt32(&done, 1) + + for _, handles0 := range handles { + for i := range handles0 { + h := (*Handle)(atomic.LoadPointer(&handles0[i])) + if h != nil && atomic.CompareAndSwapPointer(&handles0[i], unsafe.Pointer(h), nil) { + h.Release() + } + } + } + + for ns, objects0 := range objects { + for i, o := range objects0 { + if o != 0 { + t.Fatalf("invalid object #%d.%d: ref=%d", ns, i, o) + } + } + } +} + +func TestCacheMap_NodesAndSize(t *testing.T) { + c := NewCache(nil) + if c.Nodes() != 0 { + t.Errorf("invalid nodes counter: want=%d got=%d", 0, c.Nodes()) + } + if c.Size() != 0 { + t.Errorf("invalid size counter: want=%d got=%d", 0, c.Size()) + } + set(c, 0, 1, 1, 1, nil) + set(c, 0, 2, 2, 2, nil) + set(c, 1, 1, 3, 3, nil) + set(c, 2, 1, 4, 1, nil) + if c.Nodes() != 4 { + t.Errorf("invalid nodes counter: want=%d got=%d", 4, c.Nodes()) + } + if c.Size() != 7 { + t.Errorf("invalid size counter: want=%d got=%d", 4, c.Size()) + } +} + +func TestLRUCache_Capacity(t *testing.T) { + c := NewCache(NewLRU(10)) + if c.Capacity() != 10 { + t.Errorf("invalid capacity: want=%d got=%d", 10, c.Capacity()) + } + set(c, 0, 1, 1, 1, nil).Release() + set(c, 0, 2, 2, 2, nil).Release() + set(c, 1, 1, 3, 3, nil).Release() + set(c, 2, 1, 4, 1, nil).Release() + set(c, 2, 2, 5, 1, nil).Release() + set(c, 2, 3, 6, 1, nil).Release() + set(c, 2, 4, 7, 1, nil).Release() + set(c, 2, 5, 8, 1, nil).Release() + if c.Nodes() != 7 { + t.Errorf("invalid nodes counter: want=%d got=%d", 7, c.Nodes()) + } + if c.Size() != 10 { + t.Errorf("invalid size counter: want=%d got=%d", 10, c.Size()) + } + c.SetCapacity(9) + if c.Capacity() != 9 { + t.Errorf("invalid capacity: want=%d got=%d", 9, c.Capacity()) + } + if c.Nodes() != 6 { + t.Errorf("invalid nodes counter: want=%d got=%d", 6, c.Nodes()) + } + if c.Size() != 8 { + t.Errorf("invalid size counter: want=%d got=%d", 8, c.Size()) + } +} + +func TestCacheMap_NilValue(t *testing.T) { + c := NewCache(NewLRU(10)) + h := c.Get(0, 0, func() (size int, value Value) { + return 1, nil + }) + if h != nil { + t.Error("cache handle is non-nil") + } + if c.Nodes() != 0 { + t.Errorf("invalid nodes counter: want=%d got=%d", 0, c.Nodes()) + } + if c.Size() != 0 { + t.Errorf("invalid size counter: want=%d got=%d", 0, c.Size()) + } +} + +func TestLRUCache_GetLatency(t *testing.T) { + runtime.GOMAXPROCS(runtime.NumCPU()) + + const ( + concurrentSet = 30 + concurrentGet = 3 + duration = 3 * time.Second + delay = 3 * time.Millisecond + maxkey = 100000 + ) + + var ( + set, getHit, getAll int32 + getMaxLatency, getDuration int64 + ) + + c := NewCache(NewLRU(5000)) + wg := &sync.WaitGroup{} + until := time.Now().Add(duration) + for i := 0; i < concurrentSet; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for time.Now().Before(until) { + c.Get(0, uint64(r.Intn(maxkey)), func() (int, Value) { + time.Sleep(delay) + atomic.AddInt32(&set, 1) + return 1, 1 + }).Release() + } + }(i) + } + for i := 0; i < concurrentGet; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for { + mark := time.Now() + if mark.Before(until) { + h := c.Get(0, uint64(r.Intn(maxkey)), nil) + latency := int64(time.Now().Sub(mark)) + m := atomic.LoadInt64(&getMaxLatency) + if latency > m { + atomic.CompareAndSwapInt64(&getMaxLatency, m, latency) + } + atomic.AddInt64(&getDuration, latency) + if h != nil { + atomic.AddInt32(&getHit, 1) + h.Release() + } + atomic.AddInt32(&getAll, 1) + } else { + break + } + } + }(i) + } + + wg.Wait() + getAvglatency := time.Duration(getDuration) / time.Duration(getAll) + t.Logf("set=%d getHit=%d getAll=%d getMaxLatency=%v getAvgLatency=%v", + set, getHit, getAll, time.Duration(getMaxLatency), getAvglatency) + + if getAvglatency > delay/3 { + t.Errorf("get avg latency > %v: got=%v", delay/3, getAvglatency) + } +} + +func TestLRUCache_HitMiss(t *testing.T) { + cases := []struct { + key uint64 + value string + }{ + {1, "vvvvvvvvv"}, + {100, "v1"}, + {0, "v2"}, + {12346, "v3"}, + {777, "v4"}, + {999, "v5"}, + {7654, "v6"}, + {2, "v7"}, + {3, "v8"}, + {9, "v9"}, + } + + setfin := 0 + c := NewCache(NewLRU(1000)) + for i, x := range cases { + set(c, 0, x.key, x.value, len(x.value), func() { + setfin++ + }).Release() + for j, y := range cases { + h := c.Get(0, y.key, nil) + if j <= i { + // should hit + if h == nil { + t.Errorf("case '%d' iteration '%d' is miss", i, j) + } else { + if x := h.Value().(releaserFunc).value.(string); x != y.value { + t.Errorf("case '%d' iteration '%d' has invalid value got '%s', want '%s'", i, j, x, y.value) + } + } + } else { + // should miss + if h != nil { + t.Errorf("case '%d' iteration '%d' is hit , value '%s'", i, j, h.Value().(releaserFunc).value.(string)) + } + } + if h != nil { + h.Release() + } + } + } + + for i, x := range cases { + finalizerOk := false + c.Delete(0, x.key, func() { + finalizerOk = true + }) + + if !finalizerOk { + t.Errorf("case %d delete finalizer not executed", i) + } + + for j, y := range cases { + h := c.Get(0, y.key, nil) + if j > i { + // should hit + if h == nil { + t.Errorf("case '%d' iteration '%d' is miss", i, j) + } else { + if x := h.Value().(releaserFunc).value.(string); x != y.value { + t.Errorf("case '%d' iteration '%d' has invalid value got '%s', want '%s'", i, j, x, y.value) + } + } + } else { + // should miss + if h != nil { + t.Errorf("case '%d' iteration '%d' is hit, value '%s'", i, j, h.Value().(releaserFunc).value.(string)) + } + } + if h != nil { + h.Release() + } + } + } + + if setfin != len(cases) { + t.Errorf("some set finalizer may not be executed, want=%d got=%d", len(cases), setfin) + } +} + +func TestLRUCache_Eviction(t *testing.T) { + c := NewCache(NewLRU(12)) + o1 := set(c, 0, 1, 1, 1, nil) + set(c, 0, 2, 2, 1, nil).Release() + set(c, 0, 3, 3, 1, nil).Release() + set(c, 0, 4, 4, 1, nil).Release() + set(c, 0, 5, 5, 1, nil).Release() + if h := c.Get(0, 2, nil); h != nil { // 1,3,4,5,2 + h.Release() + } + set(c, 0, 9, 9, 10, nil).Release() // 5,2,9 + + for _, key := range []uint64{9, 2, 5, 1} { + h := c.Get(0, key, nil) + if h == nil { + t.Errorf("miss for key '%d'", key) + } else { + if x := h.Value().(int); x != int(key) { + t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x) + } + h.Release() + } + } + o1.Release() + for _, key := range []uint64{1, 2, 5} { + h := c.Get(0, key, nil) + if h == nil { + t.Errorf("miss for key '%d'", key) + } else { + if x := h.Value().(int); x != int(key) { + t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x) + } + h.Release() + } + } + for _, key := range []uint64{3, 4, 9} { + h := c.Get(0, key, nil) + if h != nil { + t.Errorf("hit for key '%d'", key) + if x := h.Value().(int); x != int(key) { + t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x) + } + h.Release() + } + } +} + +func TestLRUCache_Evict(t *testing.T) { + c := NewCache(NewLRU(6)) + set(c, 0, 1, 1, 1, nil).Release() + set(c, 0, 2, 2, 1, nil).Release() + set(c, 1, 1, 4, 1, nil).Release() + set(c, 1, 2, 5, 1, nil).Release() + set(c, 2, 1, 6, 1, nil).Release() + set(c, 2, 2, 7, 1, nil).Release() + + for ns := 0; ns < 3; ns++ { + for key := 1; key < 3; key++ { + if h := c.Get(uint64(ns), uint64(key), nil); h != nil { + h.Release() + } else { + t.Errorf("Cache.Get on #%d.%d return nil", ns, key) + } + } + } + + if ok := c.Evict(0, 1); !ok { + t.Error("first Cache.Evict on #0.1 return false") + } + if ok := c.Evict(0, 1); ok { + t.Error("second Cache.Evict on #0.1 return true") + } + if h := c.Get(0, 1, nil); h != nil { + t.Errorf("Cache.Get on #0.1 return non-nil: %v", h.Value()) + } + + c.EvictNS(1) + if h := c.Get(1, 1, nil); h != nil { + t.Errorf("Cache.Get on #1.1 return non-nil: %v", h.Value()) + } + if h := c.Get(1, 2, nil); h != nil { + t.Errorf("Cache.Get on #1.2 return non-nil: %v", h.Value()) + } + + c.EvictAll() + for ns := 0; ns < 3; ns++ { + for key := 1; key < 3; key++ { + if h := c.Get(uint64(ns), uint64(key), nil); h != nil { + t.Errorf("Cache.Get on #%d.%d return non-nil: %v", ns, key, h.Value()) + } + } + } +} + +func TestLRUCache_Delete(t *testing.T) { + delFuncCalled := 0 + delFunc := func() { + delFuncCalled++ + } + + c := NewCache(NewLRU(2)) + set(c, 0, 1, 1, 1, nil).Release() + set(c, 0, 2, 2, 1, nil).Release() + + if ok := c.Delete(0, 1, delFunc); !ok { + t.Error("Cache.Delete on #1 return false") + } + if h := c.Get(0, 1, nil); h != nil { + t.Errorf("Cache.Get on #1 return non-nil: %v", h.Value()) + } + if ok := c.Delete(0, 1, delFunc); ok { + t.Error("Cache.Delete on #1 return true") + } + + h2 := c.Get(0, 2, nil) + if h2 == nil { + t.Error("Cache.Get on #2 return nil") + } + if ok := c.Delete(0, 2, delFunc); !ok { + t.Error("(1) Cache.Delete on #2 return false") + } + if ok := c.Delete(0, 2, delFunc); !ok { + t.Error("(2) Cache.Delete on #2 return false") + } + + set(c, 0, 3, 3, 1, nil).Release() + set(c, 0, 4, 4, 1, nil).Release() + c.Get(0, 2, nil).Release() + + for key := 2; key <= 4; key++ { + if h := c.Get(0, uint64(key), nil); h != nil { + h.Release() + } else { + t.Errorf("Cache.Get on #%d return nil", key) + } + } + + h2.Release() + if h := c.Get(0, 2, nil); h != nil { + t.Errorf("Cache.Get on #2 return non-nil: %v", h.Value()) + } + + if delFuncCalled != 4 { + t.Errorf("delFunc isn't called 4 times: got=%d", delFuncCalled) + } +} + +func TestLRUCache_Close(t *testing.T) { + relFuncCalled := 0 + relFunc := func() { + relFuncCalled++ + } + delFuncCalled := 0 + delFunc := func() { + delFuncCalled++ + } + + c := NewCache(NewLRU(2)) + set(c, 0, 1, 1, 1, relFunc).Release() + set(c, 0, 2, 2, 1, relFunc).Release() + + h3 := set(c, 0, 3, 3, 1, relFunc) + if h3 == nil { + t.Error("Cache.Get on #3 return nil") + } + if ok := c.Delete(0, 3, delFunc); !ok { + t.Error("Cache.Delete on #3 return false") + } + + c.Close() + + if relFuncCalled != 3 { + t.Errorf("relFunc isn't called 3 times: got=%d", relFuncCalled) + } + if delFuncCalled != 1 { + t.Errorf("delFunc isn't called 1 times: got=%d", delFuncCalled) + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru.go new file mode 100644 index 00000000..d9a84cde --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/lru.go @@ -0,0 +1,195 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package cache + +import ( + "sync" + "unsafe" +) + +type lruNode struct { + n *Node + h *Handle + ban bool + + next, prev *lruNode +} + +func (n *lruNode) insert(at *lruNode) { + x := at.next + at.next = n + n.prev = at + n.next = x + x.prev = n +} + +func (n *lruNode) remove() { + if n.prev != nil { + n.prev.next = n.next + n.next.prev = n.prev + n.prev = nil + n.next = nil + } else { + panic("BUG: removing removed node") + } +} + +type lru struct { + mu sync.Mutex + capacity int + used int + recent lruNode +} + +func (r *lru) reset() { + r.recent.next = &r.recent + r.recent.prev = &r.recent + r.used = 0 +} + +func (r *lru) Capacity() int { + r.mu.Lock() + defer r.mu.Unlock() + return r.capacity +} + +func (r *lru) SetCapacity(capacity int) { + var evicted []*lruNode + + r.mu.Lock() + r.capacity = capacity + for r.used > r.capacity { + rn := r.recent.prev + if rn == nil { + panic("BUG: invalid LRU used or capacity counter") + } + rn.remove() + rn.n.CacheData = nil + r.used -= rn.n.Size() + evicted = append(evicted, rn) + } + r.mu.Unlock() + + for _, rn := range evicted { + rn.h.Release() + } +} + +func (r *lru) Promote(n *Node) { + var evicted []*lruNode + + r.mu.Lock() + if n.CacheData == nil { + if n.Size() <= r.capacity { + rn := &lruNode{n: n, h: n.GetHandle()} + rn.insert(&r.recent) + n.CacheData = unsafe.Pointer(rn) + r.used += n.Size() + + for r.used > r.capacity { + rn := r.recent.prev + if rn == nil { + panic("BUG: invalid LRU used or capacity counter") + } + rn.remove() + rn.n.CacheData = nil + r.used -= rn.n.Size() + evicted = append(evicted, rn) + } + } + } else { + rn := (*lruNode)(n.CacheData) + if !rn.ban { + rn.remove() + rn.insert(&r.recent) + } + } + r.mu.Unlock() + + for _, rn := range evicted { + rn.h.Release() + } +} + +func (r *lru) Ban(n *Node) { + r.mu.Lock() + if n.CacheData == nil { + n.CacheData = unsafe.Pointer(&lruNode{n: n, ban: true}) + } else { + rn := (*lruNode)(n.CacheData) + if !rn.ban { + rn.remove() + rn.ban = true + r.used -= rn.n.Size() + r.mu.Unlock() + + rn.h.Release() + rn.h = nil + return + } + } + r.mu.Unlock() +} + +func (r *lru) Evict(n *Node) { + r.mu.Lock() + rn := (*lruNode)(n.CacheData) + if rn == nil || rn.ban { + r.mu.Unlock() + return + } + n.CacheData = nil + r.mu.Unlock() + + rn.h.Release() +} + +func (r *lru) EvictNS(ns uint64) { + var evicted []*lruNode + + r.mu.Lock() + for e := r.recent.prev; e != &r.recent; { + rn := e + e = e.prev + if rn.n.NS() == ns { + rn.remove() + rn.n.CacheData = nil + r.used -= rn.n.Size() + evicted = append(evicted, rn) + } + } + r.mu.Unlock() + + for _, rn := range evicted { + rn.h.Release() + } +} + +func (r *lru) EvictAll() { + r.mu.Lock() + back := r.recent.prev + for rn := back; rn != &r.recent; rn = rn.prev { + rn.n.CacheData = nil + } + r.reset() + r.mu.Unlock() + + for rn := back; rn != &r.recent; rn = rn.prev { + rn.h.Release() + } +} + +func (r *lru) Close() error { + return nil +} + +// NewLRU create a new LRU-cache. +func NewLRU(capacity int) Cacher { + r := &lru{capacity: capacity} + r.reset() + return r +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer.go new file mode 100644 index 00000000..fea0a11e --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer.go @@ -0,0 +1,75 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + +type iComparer struct { + ucmp comparer.Comparer +} + +func (icmp *iComparer) uName() string { + return icmp.ucmp.Name() +} + +func (icmp *iComparer) uCompare(a, b []byte) int { + return icmp.ucmp.Compare(a, b) +} + +func (icmp *iComparer) uSeparator(dst, a, b []byte) []byte { + return icmp.ucmp.Separator(dst, a, b) +} + +func (icmp *iComparer) uSuccessor(dst, b []byte) []byte { + return icmp.ucmp.Successor(dst, b) +} + +func (icmp *iComparer) Name() string { + return icmp.uName() +} + +func (icmp *iComparer) Compare(a, b []byte) int { + x := icmp.ucmp.Compare(iKey(a).ukey(), iKey(b).ukey()) + if x == 0 { + if m, n := iKey(a).num(), iKey(b).num(); m > n { + x = -1 + } else if m < n { + x = 1 + } + } + return x +} + +func (icmp *iComparer) Separator(dst, a, b []byte) []byte { + ua, ub := iKey(a).ukey(), iKey(b).ukey() + dst = icmp.ucmp.Separator(dst, ua, ub) + if dst == nil { + return nil + } + if len(dst) < len(ua) && icmp.uCompare(ua, dst) < 0 { + dst = append(dst, kMaxNumBytes...) + } else { + // Did not close possibilities that n maybe longer than len(ub). + dst = append(dst, a[len(a)-8:]...) + } + return dst +} + +func (icmp *iComparer) Successor(dst, b []byte) []byte { + ub := iKey(b).ukey() + dst = icmp.ucmp.Successor(dst, ub) + if dst == nil { + return nil + } + if len(dst) < len(ub) && icmp.uCompare(ub, dst) < 0 { + dst = append(dst, kMaxNumBytes...) + } else { + // Did not close possibilities that n maybe longer than len(ub). + dst = append(dst, b[len(b)-8:]...) + } + return dst +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go new file mode 100644 index 00000000..14dddf88 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/bytes_comparer.go @@ -0,0 +1,51 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package comparer + +import "bytes" + +type bytesComparer struct{} + +func (bytesComparer) Compare(a, b []byte) int { + return bytes.Compare(a, b) +} + +func (bytesComparer) Name() string { + return "leveldb.BytewiseComparator" +} + +func (bytesComparer) Separator(dst, a, b []byte) []byte { + i, n := 0, len(a) + if n > len(b) { + n = len(b) + } + for ; i < n && a[i] == b[i]; i++ { + } + if i >= n { + // Do not shorten if one string is a prefix of the other + } else if c := a[i]; c < 0xff && c+1 < b[i] { + dst = append(dst, a[:i+1]...) + dst[i]++ + return dst + } + return nil +} + +func (bytesComparer) Successor(dst, b []byte) []byte { + for i, c := range b { + if c != 0xff { + dst = append(dst, b[:i+1]...) + dst[i]++ + return dst + } + } + return nil +} + +// DefaultComparer are default implementation of the Comparer interface. +// It uses the natural ordering, consistent with bytes.Compare. +var DefaultComparer = bytesComparer{} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go new file mode 100644 index 00000000..14a28f16 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer/comparer.go @@ -0,0 +1,57 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package comparer provides interface and implementation for ordering +// sets of data. +package comparer + +// BasicComparer is the interface that wraps the basic Compare method. +type BasicComparer interface { + // Compare returns -1, 0, or +1 depending on whether a is 'less than', + // 'equal to' or 'greater than' b. The two arguments can only be 'equal' + // if their contents are exactly equal. Furthermore, the empty slice + // must be 'less than' any non-empty slice. + Compare(a, b []byte) int +} + +// Comparer defines a total ordering over the space of []byte keys: a 'less +// than' relationship. +type Comparer interface { + BasicComparer + + // Name returns name of the comparer. + // + // The Level-DB on-disk format stores the comparer name, and opening a + // database with a different comparer from the one it was created with + // will result in an error. + // + // An implementation to a new name whenever the comparer implementation + // changes in a way that will cause the relative ordering of any two keys + // to change. + // + // Names starting with "leveldb." are reserved and should not be used + // by any users of this package. + Name() string + + // Bellow are advanced functions used used to reduce the space requirements + // for internal data structures such as index blocks. + + // Separator appends a sequence of bytes x to dst such that a <= x && x < b, + // where 'less than' is consistent with Compare. An implementation should + // return nil if x equal to a. + // + // Either contents of a or b should not by any means modified. Doing so + // may cause corruption on the internal state. + Separator(dst, a, b []byte) []byte + + // Successor appends a sequence of bytes x to dst such that x >= b, where + // 'less than' is consistent with Compare. An implementation should return + // nil if x equal to b. + // + // Contents of b should not by any means modified. Doing so may cause + // corruption on the internal state. + Successor(dst, b []byte) []byte +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go new file mode 100644 index 00000000..3aaf2e1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go @@ -0,0 +1,500 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bytes" + "fmt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "io" + "math/rand" + "testing" +) + +const ctValSize = 1000 + +type dbCorruptHarness struct { + dbHarness +} + +func newDbCorruptHarnessWopt(t *testing.T, o *opt.Options) *dbCorruptHarness { + h := new(dbCorruptHarness) + h.init(t, o) + return h +} + +func newDbCorruptHarness(t *testing.T) *dbCorruptHarness { + return newDbCorruptHarnessWopt(t, &opt.Options{ + BlockCacheCapacity: 100, + Strict: opt.StrictJournalChecksum, + }) +} + +func (h *dbCorruptHarness) recover() { + p := &h.dbHarness + t := p.t + + var err error + p.db, err = Recover(h.stor, h.o) + if err != nil { + t.Fatal("Repair: got error: ", err) + } +} + +func (h *dbCorruptHarness) build(n int) { + p := &h.dbHarness + t := p.t + db := p.db + + batch := new(Batch) + for i := 0; i < n; i++ { + batch.Reset() + batch.Put(tkey(i), tval(i, ctValSize)) + err := db.Write(batch, p.wo) + if err != nil { + t.Fatal("write error: ", err) + } + } +} + +func (h *dbCorruptHarness) buildShuffled(n int, rnd *rand.Rand) { + p := &h.dbHarness + t := p.t + db := p.db + + batch := new(Batch) + for i := range rnd.Perm(n) { + batch.Reset() + batch.Put(tkey(i), tval(i, ctValSize)) + err := db.Write(batch, p.wo) + if err != nil { + t.Fatal("write error: ", err) + } + } +} + +func (h *dbCorruptHarness) deleteRand(n, max int, rnd *rand.Rand) { + p := &h.dbHarness + t := p.t + db := p.db + + batch := new(Batch) + for i := 0; i < n; i++ { + batch.Reset() + batch.Delete(tkey(rnd.Intn(max))) + err := db.Write(batch, p.wo) + if err != nil { + t.Fatal("write error: ", err) + } + } +} + +func (h *dbCorruptHarness) corrupt(ft storage.FileType, fi, offset, n int) { + p := &h.dbHarness + t := p.t + + ff, _ := p.stor.GetFiles(ft) + sff := files(ff) + sff.sort() + if fi < 0 { + fi = len(sff) - 1 + } + if fi >= len(sff) { + t.Fatalf("no such file with type %q with index %d", ft, fi) + } + + file := sff[fi] + + r, err := file.Open() + if err != nil { + t.Fatal("cannot open file: ", err) + } + x, err := r.Seek(0, 2) + if err != nil { + t.Fatal("cannot query file size: ", err) + } + m := int(x) + if _, err := r.Seek(0, 0); err != nil { + t.Fatal(err) + } + + if offset < 0 { + if -offset > m { + offset = 0 + } else { + offset = m + offset + } + } + if offset > m { + offset = m + } + if offset+n > m { + n = m - offset + } + + buf := make([]byte, m) + _, err = io.ReadFull(r, buf) + if err != nil { + t.Fatal("cannot read file: ", err) + } + r.Close() + + for i := 0; i < n; i++ { + buf[offset+i] ^= 0x80 + } + + err = file.Remove() + if err != nil { + t.Fatal("cannot remove old file: ", err) + } + w, err := file.Create() + if err != nil { + t.Fatal("cannot create new file: ", err) + } + _, err = w.Write(buf) + if err != nil { + t.Fatal("cannot write new file: ", err) + } + w.Close() +} + +func (h *dbCorruptHarness) removeAll(ft storage.FileType) { + ff, err := h.stor.GetFiles(ft) + if err != nil { + h.t.Fatal("get files: ", err) + } + for _, f := range ff { + if err := f.Remove(); err != nil { + h.t.Error("remove file: ", err) + } + } +} + +func (h *dbCorruptHarness) removeOne(ft storage.FileType) { + ff, err := h.stor.GetFiles(ft) + if err != nil { + h.t.Fatal("get files: ", err) + } + f := ff[rand.Intn(len(ff))] + h.t.Logf("removing file @%d", f.Num()) + if err := f.Remove(); err != nil { + h.t.Error("remove file: ", err) + } +} + +func (h *dbCorruptHarness) check(min, max int) { + p := &h.dbHarness + t := p.t + db := p.db + + var n, badk, badv, missed, good int + iter := db.NewIterator(nil, p.ro) + for iter.Next() { + k := 0 + fmt.Sscanf(string(iter.Key()), "%d", &k) + if k < n { + badk++ + continue + } + missed += k - n + n = k + 1 + if !bytes.Equal(iter.Value(), tval(k, ctValSize)) { + badv++ + } else { + good++ + } + } + err := iter.Error() + iter.Release() + t.Logf("want=%d..%d got=%d badkeys=%d badvalues=%d missed=%d, err=%v", + min, max, good, badk, badv, missed, err) + if good < min || good > max { + t.Errorf("good entries number not in range") + } +} + +func TestCorruptDB_Journal(t *testing.T) { + h := newDbCorruptHarness(t) + + h.build(100) + h.check(100, 100) + h.closeDB() + h.corrupt(storage.TypeJournal, -1, 19, 1) + h.corrupt(storage.TypeJournal, -1, 32*1024+1000, 1) + + h.openDB() + h.check(36, 36) + + h.close() +} + +func TestCorruptDB_Table(t *testing.T) { + h := newDbCorruptHarness(t) + + h.build(100) + h.compactMem() + h.compactRangeAt(0, "", "") + h.compactRangeAt(1, "", "") + h.closeDB() + h.corrupt(storage.TypeTable, -1, 100, 1) + + h.openDB() + h.check(99, 99) + + h.close() +} + +func TestCorruptDB_TableIndex(t *testing.T) { + h := newDbCorruptHarness(t) + + h.build(10000) + h.compactMem() + h.closeDB() + h.corrupt(storage.TypeTable, -1, -2000, 500) + + h.openDB() + h.check(5000, 9999) + + h.close() +} + +func TestCorruptDB_MissingManifest(t *testing.T) { + rnd := rand.New(rand.NewSource(0x0badda7a)) + h := newDbCorruptHarnessWopt(t, &opt.Options{ + BlockCacheCapacity: 100, + Strict: opt.StrictJournalChecksum, + WriteBuffer: 1000 * 60, + }) + + h.build(1000) + h.compactMem() + h.buildShuffled(1000, rnd) + h.compactMem() + h.deleteRand(500, 1000, rnd) + h.compactMem() + h.buildShuffled(1000, rnd) + h.compactMem() + h.deleteRand(500, 1000, rnd) + h.compactMem() + h.buildShuffled(1000, rnd) + h.compactMem() + h.closeDB() + + h.stor.SetIgnoreOpenErr(storage.TypeManifest) + h.removeAll(storage.TypeManifest) + h.openAssert(false) + h.stor.SetIgnoreOpenErr(0) + + h.recover() + h.check(1000, 1000) + h.build(1000) + h.compactMem() + h.compactRange("", "") + h.closeDB() + + h.recover() + h.check(1000, 1000) + + h.close() +} + +func TestCorruptDB_SequenceNumberRecovery(t *testing.T) { + h := newDbCorruptHarness(t) + + h.put("foo", "v1") + h.put("foo", "v2") + h.put("foo", "v3") + h.put("foo", "v4") + h.put("foo", "v5") + h.closeDB() + + h.recover() + h.getVal("foo", "v5") + h.put("foo", "v6") + h.getVal("foo", "v6") + + h.reopenDB() + h.getVal("foo", "v6") + + h.close() +} + +func TestCorruptDB_SequenceNumberRecoveryTable(t *testing.T) { + h := newDbCorruptHarness(t) + + h.put("foo", "v1") + h.put("foo", "v2") + h.put("foo", "v3") + h.compactMem() + h.put("foo", "v4") + h.put("foo", "v5") + h.compactMem() + h.closeDB() + + h.recover() + h.getVal("foo", "v5") + h.put("foo", "v6") + h.getVal("foo", "v6") + + h.reopenDB() + h.getVal("foo", "v6") + + h.close() +} + +func TestCorruptDB_CorruptedManifest(t *testing.T) { + h := newDbCorruptHarness(t) + + h.put("foo", "hello") + h.compactMem() + h.compactRange("", "") + h.closeDB() + h.corrupt(storage.TypeManifest, -1, 0, 1000) + h.openAssert(false) + + h.recover() + h.getVal("foo", "hello") + + h.close() +} + +func TestCorruptDB_CompactionInputError(t *testing.T) { + h := newDbCorruptHarness(t) + + h.build(10) + h.compactMem() + h.closeDB() + h.corrupt(storage.TypeTable, -1, 100, 1) + + h.openDB() + h.check(9, 9) + + h.build(10000) + h.check(10000, 10000) + + h.close() +} + +func TestCorruptDB_UnrelatedKeys(t *testing.T) { + h := newDbCorruptHarness(t) + + h.build(10) + h.compactMem() + h.closeDB() + h.corrupt(storage.TypeTable, -1, 100, 1) + + h.openDB() + h.put(string(tkey(1000)), string(tval(1000, ctValSize))) + h.getVal(string(tkey(1000)), string(tval(1000, ctValSize))) + h.compactMem() + h.getVal(string(tkey(1000)), string(tval(1000, ctValSize))) + + h.close() +} + +func TestCorruptDB_Level0NewerFileHasOlderSeqnum(t *testing.T) { + h := newDbCorruptHarness(t) + + h.put("a", "v1") + h.put("b", "v1") + h.compactMem() + h.put("a", "v2") + h.put("b", "v2") + h.compactMem() + h.put("a", "v3") + h.put("b", "v3") + h.compactMem() + h.put("c", "v0") + h.put("d", "v0") + h.compactMem() + h.compactRangeAt(1, "", "") + h.closeDB() + + h.recover() + h.getVal("a", "v3") + h.getVal("b", "v3") + h.getVal("c", "v0") + h.getVal("d", "v0") + + h.close() +} + +func TestCorruptDB_RecoverInvalidSeq_Issue53(t *testing.T) { + h := newDbCorruptHarness(t) + + h.put("a", "v1") + h.put("b", "v1") + h.compactMem() + h.put("a", "v2") + h.put("b", "v2") + h.compactMem() + h.put("a", "v3") + h.put("b", "v3") + h.compactMem() + h.put("c", "v0") + h.put("d", "v0") + h.compactMem() + h.compactRangeAt(0, "", "") + h.closeDB() + + h.recover() + h.getVal("a", "v3") + h.getVal("b", "v3") + h.getVal("c", "v0") + h.getVal("d", "v0") + + h.close() +} + +func TestCorruptDB_MissingTableFiles(t *testing.T) { + h := newDbCorruptHarness(t) + + h.put("a", "v1") + h.put("b", "v1") + h.compactMem() + h.put("c", "v2") + h.put("d", "v2") + h.compactMem() + h.put("e", "v3") + h.put("f", "v3") + h.closeDB() + + h.removeOne(storage.TypeTable) + h.openAssert(false) + + h.close() +} + +func TestCorruptDB_RecoverTable(t *testing.T) { + h := newDbCorruptHarnessWopt(t, &opt.Options{ + WriteBuffer: 112 * opt.KiB, + CompactionTableSize: 90 * opt.KiB, + Filter: filter.NewBloomFilter(10), + }) + + h.build(1000) + h.compactMem() + h.compactRangeAt(0, "", "") + h.compactRangeAt(1, "", "") + seq := h.db.seq + h.closeDB() + h.corrupt(storage.TypeTable, 0, 1000, 1) + h.corrupt(storage.TypeTable, 3, 10000, 1) + // Corrupted filter shouldn't affect recovery. + h.corrupt(storage.TypeTable, 3, 113888, 10) + h.corrupt(storage.TypeTable, -1, 20000, 1) + + h.recover() + if h.db.seq != seq { + t.Errorf("invalid seq, want=%d got=%d", seq, h.db.seq) + } + h.check(985, 985) + + h.close() +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go new file mode 100644 index 00000000..4a485b6a --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go @@ -0,0 +1,945 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "container/list" + "fmt" + "io" + "os" + "runtime" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type DB struct { + // DB is a LevelDB database. + // Need 64-bit alignment. + seq uint64 + + // Session. + s *session + + // MemDB. + memMu sync.RWMutex + memPool chan *memdb.DB + mem, frozenMem *memDB + journal *journal.Writer + journalWriter storage.Writer + journalFile storage.File + frozenJournalFile storage.File + frozenSeq uint64 + + // Snapshot. + snapsMu sync.Mutex + snapsList *list.List + + // Stats. + aliveSnaps, aliveIters int32 + + // Write. + writeC chan *Batch + writeMergedC chan bool + writeLockC chan struct{} + writeAckC chan error + writeDelay time.Duration + writeDelayN int + journalC chan *Batch + journalAckC chan error + + // Compaction. + tcompCmdC chan cCmd + tcompPauseC chan chan<- struct{} + mcompCmdC chan cCmd + compErrC chan error + compPerErrC chan error + compErrSetC chan error + compStats []cStats + + // Close. + closeW sync.WaitGroup + closeC chan struct{} + closed uint32 + closer io.Closer +} + +func openDB(s *session) (*DB, error) { + s.log("db@open opening") + start := time.Now() + db := &DB{ + s: s, + // Initial sequence + seq: s.stSeqNum, + // MemDB + memPool: make(chan *memdb.DB, 1), + // Snapshot + snapsList: list.New(), + // Write + writeC: make(chan *Batch), + writeMergedC: make(chan bool), + writeLockC: make(chan struct{}, 1), + writeAckC: make(chan error), + journalC: make(chan *Batch), + journalAckC: make(chan error), + // Compaction + tcompCmdC: make(chan cCmd), + tcompPauseC: make(chan chan<- struct{}), + mcompCmdC: make(chan cCmd), + compErrC: make(chan error), + compPerErrC: make(chan error), + compErrSetC: make(chan error), + compStats: make([]cStats, s.o.GetNumLevel()), + // Close + closeC: make(chan struct{}), + } + + if err := db.recoverJournal(); err != nil { + return nil, err + } + + // Remove any obsolete files. + if err := db.checkAndCleanFiles(); err != nil { + // Close journal. + if db.journal != nil { + db.journal.Close() + db.journalWriter.Close() + } + return nil, err + } + + // Doesn't need to be included in the wait group. + go db.compactionError() + go db.mpoolDrain() + + db.closeW.Add(3) + go db.tCompaction() + go db.mCompaction() + go db.jWriter() + + s.logf("db@open done T·%v", time.Since(start)) + + runtime.SetFinalizer(db, (*DB).Close) + return db, nil +} + +// Open opens or creates a DB for the given storage. +// The DB will be created if not exist, unless ErrorIfMissing is true. +// Also, if ErrorIfExist is true and the DB exist Open will returns +// os.ErrExist error. +// +// Open will return an error with type of ErrCorrupted if corruption +// detected in the DB. Corrupted DB can be recovered with Recover +// function. +// +// The returned DB instance is goroutine-safe. +// The DB must be closed after use, by calling Close method. +func Open(stor storage.Storage, o *opt.Options) (db *DB, err error) { + s, err := newSession(stor, o) + if err != nil { + return + } + defer func() { + if err != nil { + s.close() + s.release() + } + }() + + err = s.recover() + if err != nil { + if !os.IsNotExist(err) || s.o.GetErrorIfMissing() { + return + } + err = s.create() + if err != nil { + return + } + } else if s.o.GetErrorIfExist() { + err = os.ErrExist + return + } + + return openDB(s) +} + +// OpenFile opens or creates a DB for the given path. +// The DB will be created if not exist, unless ErrorIfMissing is true. +// Also, if ErrorIfExist is true and the DB exist OpenFile will returns +// os.ErrExist error. +// +// OpenFile uses standard file-system backed storage implementation as +// desribed in the leveldb/storage package. +// +// OpenFile will return an error with type of ErrCorrupted if corruption +// detected in the DB. Corrupted DB can be recovered with Recover +// function. +// +// The returned DB instance is goroutine-safe. +// The DB must be closed after use, by calling Close method. +func OpenFile(path string, o *opt.Options) (db *DB, err error) { + stor, err := storage.OpenFile(path) + if err != nil { + return + } + db, err = Open(stor, o) + if err != nil { + stor.Close() + } else { + db.closer = stor + } + return +} + +// Recover recovers and opens a DB with missing or corrupted manifest files +// for the given storage. It will ignore any manifest files, valid or not. +// The DB must already exist or it will returns an error. +// Also, Recover will ignore ErrorIfMissing and ErrorIfExist options. +// +// The returned DB instance is goroutine-safe. +// The DB must be closed after use, by calling Close method. +func Recover(stor storage.Storage, o *opt.Options) (db *DB, err error) { + s, err := newSession(stor, o) + if err != nil { + return + } + defer func() { + if err != nil { + s.close() + s.release() + } + }() + + err = recoverTable(s, o) + if err != nil { + return + } + return openDB(s) +} + +// RecoverFile recovers and opens a DB with missing or corrupted manifest files +// for the given path. It will ignore any manifest files, valid or not. +// The DB must already exist or it will returns an error. +// Also, Recover will ignore ErrorIfMissing and ErrorIfExist options. +// +// RecoverFile uses standard file-system backed storage implementation as desribed +// in the leveldb/storage package. +// +// The returned DB instance is goroutine-safe. +// The DB must be closed after use, by calling Close method. +func RecoverFile(path string, o *opt.Options) (db *DB, err error) { + stor, err := storage.OpenFile(path) + if err != nil { + return + } + db, err = Recover(stor, o) + if err != nil { + stor.Close() + } else { + db.closer = stor + } + return +} + +func recoverTable(s *session, o *opt.Options) error { + o = dupOptions(o) + // Mask StrictReader, lets StrictRecovery doing its job. + o.Strict &= ^opt.StrictReader + + // Get all tables and sort it by file number. + tableFiles_, err := s.getFiles(storage.TypeTable) + if err != nil { + return err + } + tableFiles := files(tableFiles_) + tableFiles.sort() + + var ( + maxSeq uint64 + recoveredKey, goodKey, corruptedKey, corruptedBlock, droppedTable int + + // We will drop corrupted table. + strict = o.GetStrict(opt.StrictRecovery) + + rec = &sessionRecord{numLevel: o.GetNumLevel()} + bpool = util.NewBufferPool(o.GetBlockSize() + 5) + ) + buildTable := func(iter iterator.Iterator) (tmp storage.File, size int64, err error) { + tmp = s.newTemp() + writer, err := tmp.Create() + if err != nil { + return + } + defer func() { + writer.Close() + if err != nil { + tmp.Remove() + tmp = nil + } + }() + + // Copy entries. + tw := table.NewWriter(writer, o) + for iter.Next() { + key := iter.Key() + if validIkey(key) { + err = tw.Append(key, iter.Value()) + if err != nil { + return + } + } + } + err = iter.Error() + if err != nil { + return + } + err = tw.Close() + if err != nil { + return + } + err = writer.Sync() + if err != nil { + return + } + size = int64(tw.BytesLen()) + return + } + recoverTable := func(file storage.File) error { + s.logf("table@recovery recovering @%d", file.Num()) + reader, err := file.Open() + if err != nil { + return err + } + var closed bool + defer func() { + if !closed { + reader.Close() + } + }() + + // Get file size. + size, err := reader.Seek(0, 2) + if err != nil { + return err + } + + var ( + tSeq uint64 + tgoodKey, tcorruptedKey, tcorruptedBlock int + imin, imax []byte + ) + tr, err := table.NewReader(reader, size, storage.NewFileInfo(file), nil, bpool, o) + if err != nil { + return err + } + iter := tr.NewIterator(nil, nil) + if itererr, ok := iter.(iterator.ErrorCallbackSetter); ok { + itererr.SetErrorCallback(func(err error) { + if errors.IsCorrupted(err) { + s.logf("table@recovery block corruption @%d %q", file.Num(), err) + tcorruptedBlock++ + } + }) + } + + // Scan the table. + for iter.Next() { + key := iter.Key() + _, seq, _, kerr := parseIkey(key) + if kerr != nil { + tcorruptedKey++ + continue + } + tgoodKey++ + if seq > tSeq { + tSeq = seq + } + if imin == nil { + imin = append([]byte{}, key...) + } + imax = append(imax[:0], key...) + } + if err := iter.Error(); err != nil { + iter.Release() + return err + } + iter.Release() + + goodKey += tgoodKey + corruptedKey += tcorruptedKey + corruptedBlock += tcorruptedBlock + + if strict && (tcorruptedKey > 0 || tcorruptedBlock > 0) { + droppedTable++ + s.logf("table@recovery dropped @%d Gk·%d Ck·%d Cb·%d S·%d Q·%d", file.Num(), tgoodKey, tcorruptedKey, tcorruptedBlock, size, tSeq) + return nil + } + + if tgoodKey > 0 { + if tcorruptedKey > 0 || tcorruptedBlock > 0 { + // Rebuild the table. + s.logf("table@recovery rebuilding @%d", file.Num()) + iter := tr.NewIterator(nil, nil) + tmp, newSize, err := buildTable(iter) + iter.Release() + if err != nil { + return err + } + closed = true + reader.Close() + if err := file.Replace(tmp); err != nil { + return err + } + size = newSize + } + if tSeq > maxSeq { + maxSeq = tSeq + } + recoveredKey += tgoodKey + // Add table to level 0. + rec.addTable(0, file.Num(), uint64(size), imin, imax) + s.logf("table@recovery recovered @%d Gk·%d Ck·%d Cb·%d S·%d Q·%d", file.Num(), tgoodKey, tcorruptedKey, tcorruptedBlock, size, tSeq) + } else { + droppedTable++ + s.logf("table@recovery unrecoverable @%d Ck·%d Cb·%d S·%d", file.Num(), tcorruptedKey, tcorruptedBlock, size) + } + + return nil + } + + // Recover all tables. + if len(tableFiles) > 0 { + s.logf("table@recovery F·%d", len(tableFiles)) + + // Mark file number as used. + s.markFileNum(tableFiles[len(tableFiles)-1].Num()) + + for _, file := range tableFiles { + if err := recoverTable(file); err != nil { + return err + } + } + + s.logf("table@recovery recovered F·%d N·%d Gk·%d Ck·%d Q·%d", len(tableFiles), recoveredKey, goodKey, corruptedKey, maxSeq) + } + + // Set sequence number. + rec.setSeqNum(maxSeq) + + // Create new manifest. + if err := s.create(); err != nil { + return err + } + + // Commit. + return s.commit(rec) +} + +func (db *DB) recoverJournal() error { + // Get all tables and sort it by file number. + journalFiles_, err := db.s.getFiles(storage.TypeJournal) + if err != nil { + return err + } + journalFiles := files(journalFiles_) + journalFiles.sort() + + // Discard older journal. + prev := -1 + for i, file := range journalFiles { + if file.Num() >= db.s.stJournalNum { + if prev >= 0 { + i-- + journalFiles[i] = journalFiles[prev] + } + journalFiles = journalFiles[i:] + break + } else if file.Num() == db.s.stPrevJournalNum { + prev = i + } + } + + var jr *journal.Reader + var of storage.File + var mem *memdb.DB + batch := new(Batch) + cm := newCMem(db.s) + buf := new(util.Buffer) + // Options. + strict := db.s.o.GetStrict(opt.StrictJournal) + checksum := db.s.o.GetStrict(opt.StrictJournalChecksum) + writeBuffer := db.s.o.GetWriteBuffer() + recoverJournal := func(file storage.File) error { + db.logf("journal@recovery recovering @%d", file.Num()) + reader, err := file.Open() + if err != nil { + return err + } + defer reader.Close() + + // Create/reset journal reader instance. + if jr == nil { + jr = journal.NewReader(reader, dropper{db.s, file}, strict, checksum) + } else { + jr.Reset(reader, dropper{db.s, file}, strict, checksum) + } + + // Flush memdb and remove obsolete journal file. + if of != nil { + if mem.Len() > 0 { + if err := cm.flush(mem, 0); err != nil { + return err + } + } + if err := cm.commit(file.Num(), db.seq); err != nil { + return err + } + cm.reset() + of.Remove() + of = nil + } + + // Replay journal to memdb. + mem.Reset() + for { + r, err := jr.Next() + if err != nil { + if err == io.EOF { + break + } + return errors.SetFile(err, file) + } + + buf.Reset() + if _, err := buf.ReadFrom(r); err != nil { + if err == io.ErrUnexpectedEOF { + // This is error returned due to corruption, with strict == false. + continue + } else { + return errors.SetFile(err, file) + } + } + if err := batch.memDecodeAndReplay(db.seq, buf.Bytes(), mem); err != nil { + if strict || !errors.IsCorrupted(err) { + return errors.SetFile(err, file) + } else { + db.s.logf("journal error: %v (skipped)", err) + // We won't apply sequence number as it might be corrupted. + continue + } + } + + // Save sequence number. + db.seq = batch.seq + uint64(batch.Len()) + + // Flush it if large enough. + if mem.Size() >= writeBuffer { + if err := cm.flush(mem, 0); err != nil { + return err + } + mem.Reset() + } + } + + of = file + return nil + } + + // Recover all journals. + if len(journalFiles) > 0 { + db.logf("journal@recovery F·%d", len(journalFiles)) + + // Mark file number as used. + db.s.markFileNum(journalFiles[len(journalFiles)-1].Num()) + + mem = memdb.New(db.s.icmp, writeBuffer) + for _, file := range journalFiles { + if err := recoverJournal(file); err != nil { + return err + } + } + + // Flush the last journal. + if mem.Len() > 0 { + if err := cm.flush(mem, 0); err != nil { + return err + } + } + } + + // Create a new journal. + if _, err := db.newMem(0); err != nil { + return err + } + + // Commit. + if err := cm.commit(db.journalFile.Num(), db.seq); err != nil { + // Close journal. + if db.journal != nil { + db.journal.Close() + db.journalWriter.Close() + } + return err + } + + // Remove the last obsolete journal file. + if of != nil { + of.Remove() + } + + return nil +} + +func (db *DB) get(key []byte, seq uint64, ro *opt.ReadOptions) (value []byte, err error) { + ikey := newIkey(key, seq, ktSeek) + + em, fm := db.getMems() + for _, m := range [...]*memDB{em, fm} { + if m == nil { + continue + } + defer m.decref() + + mk, mv, me := m.mdb.Find(ikey) + if me == nil { + ukey, _, kt, kerr := parseIkey(mk) + if kerr != nil { + // Shouldn't have had happen. + panic(kerr) + } + if db.s.icmp.uCompare(ukey, key) == 0 { + if kt == ktDel { + return nil, ErrNotFound + } + return append([]byte{}, mv...), nil + } + } else if me != ErrNotFound { + return nil, me + } + } + + v := db.s.version() + value, cSched, err := v.get(ikey, ro, false) + v.release() + if cSched { + // Trigger table compaction. + db.compSendTrigger(db.tcompCmdC) + } + return +} + +func (db *DB) has(key []byte, seq uint64, ro *opt.ReadOptions) (ret bool, err error) { + ikey := newIkey(key, seq, ktSeek) + + em, fm := db.getMems() + for _, m := range [...]*memDB{em, fm} { + if m == nil { + continue + } + defer m.decref() + + mk, _, me := m.mdb.Find(ikey) + if me == nil { + ukey, _, kt, kerr := parseIkey(mk) + if kerr != nil { + // Shouldn't have had happen. + panic(kerr) + } + if db.s.icmp.uCompare(ukey, key) == 0 { + if kt == ktDel { + return false, nil + } + return true, nil + } + } else if me != ErrNotFound { + return false, me + } + } + + v := db.s.version() + _, cSched, err := v.get(ikey, ro, true) + v.release() + if cSched { + // Trigger table compaction. + db.compSendTrigger(db.tcompCmdC) + } + if err == nil { + ret = true + } else if err == ErrNotFound { + err = nil + } + return +} + +// Get gets the value for the given key. It returns ErrNotFound if the +// DB does not contains the key. +// +// The returned slice is its own copy, it is safe to modify the contents +// of the returned slice. +// It is safe to modify the contents of the argument after Get returns. +func (db *DB) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) { + err = db.ok() + if err != nil { + return + } + + se := db.acquireSnapshot() + defer db.releaseSnapshot(se) + return db.get(key, se.seq, ro) +} + +// Has returns true if the DB does contains the given key. +// +// It is safe to modify the contents of the argument after Get returns. +func (db *DB) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) { + err = db.ok() + if err != nil { + return + } + + se := db.acquireSnapshot() + defer db.releaseSnapshot(se) + return db.has(key, se.seq, ro) +} + +// NewIterator returns an iterator for the latest snapshot of the +// uderlying DB. +// The returned iterator is not goroutine-safe, but it is safe to use +// multiple iterators concurrently, with each in a dedicated goroutine. +// It is also safe to use an iterator concurrently with modifying its +// underlying DB. The resultant key/value pairs are guaranteed to be +// consistent. +// +// Slice allows slicing the iterator to only contains keys in the given +// range. A nil Range.Start is treated as a key before all keys in the +// DB. And a nil Range.Limit is treated as a key after all keys in +// the DB. +// +// The iterator must be released after use, by calling Release method. +// +// Also read Iterator documentation of the leveldb/iterator package. +func (db *DB) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { + if err := db.ok(); err != nil { + return iterator.NewEmptyIterator(err) + } + + se := db.acquireSnapshot() + defer db.releaseSnapshot(se) + // Iterator holds 'version' lock, 'version' is immutable so snapshot + // can be released after iterator created. + return db.newIterator(se.seq, slice, ro) +} + +// GetSnapshot returns a latest snapshot of the underlying DB. A snapshot +// is a frozen snapshot of a DB state at a particular point in time. The +// content of snapshot are guaranteed to be consistent. +// +// The snapshot must be released after use, by calling Release method. +func (db *DB) GetSnapshot() (*Snapshot, error) { + if err := db.ok(); err != nil { + return nil, err + } + + return db.newSnapshot(), nil +} + +// GetProperty returns value of the given property name. +// +// Property names: +// leveldb.num-files-at-level{n} +// Returns the number of files at level 'n'. +// leveldb.stats +// Returns statistics of the underlying DB. +// leveldb.sstables +// Returns sstables list for each level. +// leveldb.blockpool +// Returns block pool stats. +// leveldb.cachedblock +// Returns size of cached block. +// leveldb.openedtables +// Returns number of opened tables. +// leveldb.alivesnaps +// Returns number of alive snapshots. +// leveldb.aliveiters +// Returns number of alive iterators. +func (db *DB) GetProperty(name string) (value string, err error) { + err = db.ok() + if err != nil { + return + } + + const prefix = "leveldb." + if !strings.HasPrefix(name, prefix) { + return "", errors.New("leveldb: GetProperty: unknown property: " + name) + } + p := name[len(prefix):] + + v := db.s.version() + defer v.release() + + numFilesPrefix := "num-files-at-level" + switch { + case strings.HasPrefix(p, numFilesPrefix): + var level uint + var rest string + n, _ := fmt.Sscanf(p[len(numFilesPrefix):], "%d%s", &level, &rest) + if n != 1 || int(level) >= db.s.o.GetNumLevel() { + err = errors.New("leveldb: GetProperty: invalid property: " + name) + } else { + value = fmt.Sprint(v.tLen(int(level))) + } + case p == "stats": + value = "Compactions\n" + + " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" + + "-------+------------+---------------+---------------+---------------+---------------\n" + for level, tables := range v.tables { + duration, read, write := db.compStats[level].get() + if len(tables) == 0 && duration == 0 { + continue + } + value += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + level, len(tables), float64(tables.size())/1048576.0, duration.Seconds(), + float64(read)/1048576.0, float64(write)/1048576.0) + } + case p == "sstables": + for level, tables := range v.tables { + value += fmt.Sprintf("--- level %d ---\n", level) + for _, t := range tables { + value += fmt.Sprintf("%d:%d[%q .. %q]\n", t.file.Num(), t.size, t.imin, t.imax) + } + } + case p == "blockpool": + value = fmt.Sprintf("%v", db.s.tops.bpool) + case p == "cachedblock": + if db.s.tops.bcache != nil { + value = fmt.Sprintf("%d", db.s.tops.bcache.Size()) + } else { + value = "" + } + case p == "openedtables": + value = fmt.Sprintf("%d", db.s.tops.cache.Size()) + case p == "alivesnaps": + value = fmt.Sprintf("%d", atomic.LoadInt32(&db.aliveSnaps)) + case p == "aliveiters": + value = fmt.Sprintf("%d", atomic.LoadInt32(&db.aliveIters)) + default: + err = errors.New("leveldb: GetProperty: unknown property: " + name) + } + + return +} + +// SizeOf calculates approximate sizes of the given key ranges. +// The length of the returned sizes are equal with the length of the given +// ranges. The returned sizes measure storage space usage, so if the user +// data compresses by a factor of ten, the returned sizes will be one-tenth +// the size of the corresponding user data size. +// The results may not include the sizes of recently written data. +func (db *DB) SizeOf(ranges []util.Range) (Sizes, error) { + if err := db.ok(); err != nil { + return nil, err + } + + v := db.s.version() + defer v.release() + + sizes := make(Sizes, 0, len(ranges)) + for _, r := range ranges { + imin := newIkey(r.Start, kMaxSeq, ktSeek) + imax := newIkey(r.Limit, kMaxSeq, ktSeek) + start, err := v.offsetOf(imin) + if err != nil { + return nil, err + } + limit, err := v.offsetOf(imax) + if err != nil { + return nil, err + } + var size uint64 + if limit >= start { + size = limit - start + } + sizes = append(sizes, size) + } + + return sizes, nil +} + +// Close closes the DB. This will also releases any outstanding snapshot and +// abort any in-flight compaction. +// +// It is not safe to close a DB until all outstanding iterators are released. +// It is valid to call Close multiple times. Other methods should not be +// called after the DB has been closed. +func (db *DB) Close() error { + if !db.setClosed() { + return ErrClosed + } + + start := time.Now() + db.log("db@close closing") + + // Clear the finalizer. + runtime.SetFinalizer(db, nil) + + // Get compaction error. + var err error + select { + case err = <-db.compErrC: + default: + } + + // Signal all goroutines. + close(db.closeC) + + // Wait for all gorotines to exit. + db.closeW.Wait() + + // Lock writer and closes journal. + db.writeLockC <- struct{}{} + if db.journal != nil { + db.journal.Close() + db.journalWriter.Close() + } + + if db.writeDelayN > 0 { + db.logf("db@write was delayed N·%d T·%v", db.writeDelayN, db.writeDelay) + } + + // Close session. + db.s.close() + db.logf("db@close done T·%v", time.Since(start)) + db.s.release() + + if db.closer != nil { + if err1 := db.closer.Close(); err == nil { + err = err1 + } + } + + // NIL'ing pointers. + db.s = nil + db.mem = nil + db.frozenMem = nil + db.journal = nil + db.journalWriter = nil + db.journalFile = nil + db.frozenJournalFile = nil + db.closer = nil + + return err +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go new file mode 100644 index 00000000..5b6fb294 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go @@ -0,0 +1,835 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "sync" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" +) + +var ( + errCompactionTransactExiting = errors.New("leveldb: compaction transact exiting") +) + +type cStats struct { + sync.Mutex + duration time.Duration + read uint64 + write uint64 +} + +func (p *cStats) add(n *cStatsStaging) { + p.Lock() + p.duration += n.duration + p.read += n.read + p.write += n.write + p.Unlock() +} + +func (p *cStats) get() (duration time.Duration, read, write uint64) { + p.Lock() + defer p.Unlock() + return p.duration, p.read, p.write +} + +type cStatsStaging struct { + start time.Time + duration time.Duration + on bool + read uint64 + write uint64 +} + +func (p *cStatsStaging) startTimer() { + if !p.on { + p.start = time.Now() + p.on = true + } +} + +func (p *cStatsStaging) stopTimer() { + if p.on { + p.duration += time.Since(p.start) + p.on = false + } +} + +type cMem struct { + s *session + level int + rec *sessionRecord +} + +func newCMem(s *session) *cMem { + return &cMem{s: s, rec: &sessionRecord{numLevel: s.o.GetNumLevel()}} +} + +func (c *cMem) flush(mem *memdb.DB, level int) error { + s := c.s + + // Write memdb to table. + iter := mem.NewIterator(nil) + defer iter.Release() + t, n, err := s.tops.createFrom(iter) + if err != nil { + return err + } + + // Pick level. + if level < 0 { + v := s.version() + level = v.pickLevel(t.imin.ukey(), t.imax.ukey()) + v.release() + } + c.rec.addTableFile(level, t) + + s.logf("mem@flush created L%d@%d N·%d S·%s %q:%q", level, t.file.Num(), n, shortenb(int(t.size)), t.imin, t.imax) + + c.level = level + return nil +} + +func (c *cMem) reset() { + c.rec = &sessionRecord{numLevel: c.s.o.GetNumLevel()} +} + +func (c *cMem) commit(journal, seq uint64) error { + c.rec.setJournalNum(journal) + c.rec.setSeqNum(seq) + + // Commit changes. + return c.s.commit(c.rec) +} + +func (db *DB) compactionError() { + var ( + err error + wlocked bool + ) +noerr: + // No error. + for { + select { + case err = <-db.compErrSetC: + switch { + case err == nil: + case errors.IsCorrupted(err): + goto hasperr + default: + goto haserr + } + case _, _ = <-db.closeC: + return + } + } +haserr: + // Transient error. + for { + select { + case db.compErrC <- err: + case err = <-db.compErrSetC: + switch { + case err == nil: + goto noerr + case errors.IsCorrupted(err): + goto hasperr + default: + } + case _, _ = <-db.closeC: + return + } + } +hasperr: + // Persistent error. + for { + select { + case db.compErrC <- err: + case db.compPerErrC <- err: + case db.writeLockC <- struct{}{}: + // Hold write lock, so that write won't pass-through. + wlocked = true + case _, _ = <-db.closeC: + if wlocked { + // We should release the lock or Close will hang. + <-db.writeLockC + } + return + } + } +} + +type compactionTransactCounter int + +func (cnt *compactionTransactCounter) incr() { + *cnt++ +} + +type compactionTransactInterface interface { + run(cnt *compactionTransactCounter) error + revert() error +} + +func (db *DB) compactionTransact(name string, t compactionTransactInterface) { + defer func() { + if x := recover(); x != nil { + if x == errCompactionTransactExiting { + if err := t.revert(); err != nil { + db.logf("%s revert error %q", name, err) + } + } + panic(x) + } + }() + + const ( + backoffMin = 1 * time.Second + backoffMax = 8 * time.Second + backoffMul = 2 * time.Second + ) + var ( + backoff = backoffMin + backoffT = time.NewTimer(backoff) + lastCnt = compactionTransactCounter(0) + + disableBackoff = db.s.o.GetDisableCompactionBackoff() + ) + for n := 0; ; n++ { + // Check wether the DB is closed. + if db.isClosed() { + db.logf("%s exiting", name) + db.compactionExitTransact() + } else if n > 0 { + db.logf("%s retrying N·%d", name, n) + } + + // Execute. + cnt := compactionTransactCounter(0) + err := t.run(&cnt) + if err != nil { + db.logf("%s error I·%d %q", name, cnt, err) + } + + // Set compaction error status. + select { + case db.compErrSetC <- err: + case perr := <-db.compPerErrC: + if err != nil { + db.logf("%s exiting (persistent error %q)", name, perr) + db.compactionExitTransact() + } + case _, _ = <-db.closeC: + db.logf("%s exiting", name) + db.compactionExitTransact() + } + if err == nil { + return + } + if errors.IsCorrupted(err) { + db.logf("%s exiting (corruption detected)", name) + db.compactionExitTransact() + } + + if !disableBackoff { + // Reset backoff duration if counter is advancing. + if cnt > lastCnt { + backoff = backoffMin + lastCnt = cnt + } + + // Backoff. + backoffT.Reset(backoff) + if backoff < backoffMax { + backoff *= backoffMul + if backoff > backoffMax { + backoff = backoffMax + } + } + select { + case <-backoffT.C: + case _, _ = <-db.closeC: + db.logf("%s exiting", name) + db.compactionExitTransact() + } + } + } +} + +type compactionTransactFunc struct { + runFunc func(cnt *compactionTransactCounter) error + revertFunc func() error +} + +func (t *compactionTransactFunc) run(cnt *compactionTransactCounter) error { + return t.runFunc(cnt) +} + +func (t *compactionTransactFunc) revert() error { + if t.revertFunc != nil { + return t.revertFunc() + } + return nil +} + +func (db *DB) compactionTransactFunc(name string, run func(cnt *compactionTransactCounter) error, revert func() error) { + db.compactionTransact(name, &compactionTransactFunc{run, revert}) +} + +func (db *DB) compactionExitTransact() { + panic(errCompactionTransactExiting) +} + +func (db *DB) memCompaction() { + mem := db.getFrozenMem() + if mem == nil { + return + } + defer mem.decref() + + c := newCMem(db.s) + stats := new(cStatsStaging) + + db.logf("mem@flush N·%d S·%s", mem.mdb.Len(), shortenb(mem.mdb.Size())) + + // Don't compact empty memdb. + if mem.mdb.Len() == 0 { + db.logf("mem@flush skipping") + // drop frozen mem + db.dropFrozenMem() + return + } + + // Pause table compaction. + resumeC := make(chan struct{}) + select { + case db.tcompPauseC <- (chan<- struct{})(resumeC): + case <-db.compPerErrC: + close(resumeC) + resumeC = nil + case _, _ = <-db.closeC: + return + } + + db.compactionTransactFunc("mem@flush", func(cnt *compactionTransactCounter) (err error) { + stats.startTimer() + defer stats.stopTimer() + return c.flush(mem.mdb, -1) + }, func() error { + for _, r := range c.rec.addedTables { + db.logf("mem@flush revert @%d", r.num) + f := db.s.getTableFile(r.num) + if err := f.Remove(); err != nil { + return err + } + } + return nil + }) + + db.compactionTransactFunc("mem@commit", func(cnt *compactionTransactCounter) (err error) { + stats.startTimer() + defer stats.stopTimer() + return c.commit(db.journalFile.Num(), db.frozenSeq) + }, nil) + + db.logf("mem@flush committed F·%d T·%v", len(c.rec.addedTables), stats.duration) + + for _, r := range c.rec.addedTables { + stats.write += r.size + } + db.compStats[c.level].add(stats) + + // Drop frozen mem. + db.dropFrozenMem() + + // Resume table compaction. + if resumeC != nil { + select { + case <-resumeC: + close(resumeC) + case _, _ = <-db.closeC: + return + } + } + + // Trigger table compaction. + db.compSendTrigger(db.tcompCmdC) +} + +type tableCompactionBuilder struct { + db *DB + s *session + c *compaction + rec *sessionRecord + stat0, stat1 *cStatsStaging + + snapHasLastUkey bool + snapLastUkey []byte + snapLastSeq uint64 + snapIter int + snapKerrCnt int + snapDropCnt int + + kerrCnt int + dropCnt int + + minSeq uint64 + strict bool + tableSize int + + tw *tWriter +} + +func (b *tableCompactionBuilder) appendKV(key, value []byte) error { + // Create new table if not already. + if b.tw == nil { + // Check for pause event. + if b.db != nil { + select { + case ch := <-b.db.tcompPauseC: + b.db.pauseCompaction(ch) + case _, _ = <-b.db.closeC: + b.db.compactionExitTransact() + default: + } + } + + // Create new table. + var err error + b.tw, err = b.s.tops.create() + if err != nil { + return err + } + } + + // Write key/value into table. + return b.tw.append(key, value) +} + +func (b *tableCompactionBuilder) needFlush() bool { + return b.tw.tw.BytesLen() >= b.tableSize +} + +func (b *tableCompactionBuilder) flush() error { + t, err := b.tw.finish() + if err != nil { + return err + } + b.rec.addTableFile(b.c.level+1, t) + b.stat1.write += t.size + b.s.logf("table@build created L%d@%d N·%d S·%s %q:%q", b.c.level+1, t.file.Num(), b.tw.tw.EntriesLen(), shortenb(int(t.size)), t.imin, t.imax) + b.tw = nil + return nil +} + +func (b *tableCompactionBuilder) cleanup() { + if b.tw != nil { + b.tw.drop() + b.tw = nil + } +} + +func (b *tableCompactionBuilder) run(cnt *compactionTransactCounter) error { + snapResumed := b.snapIter > 0 + hasLastUkey := b.snapHasLastUkey // The key might has zero length, so this is necessary. + lastUkey := append([]byte{}, b.snapLastUkey...) + lastSeq := b.snapLastSeq + b.kerrCnt = b.snapKerrCnt + b.dropCnt = b.snapDropCnt + // Restore compaction state. + b.c.restore() + + defer b.cleanup() + + b.stat1.startTimer() + defer b.stat1.stopTimer() + + iter := b.c.newIterator() + defer iter.Release() + for i := 0; iter.Next(); i++ { + // Incr transact counter. + cnt.incr() + + // Skip until last state. + if i < b.snapIter { + continue + } + + resumed := false + if snapResumed { + resumed = true + snapResumed = false + } + + ikey := iter.Key() + ukey, seq, kt, kerr := parseIkey(ikey) + + if kerr == nil { + shouldStop := !resumed && b.c.shouldStopBefore(ikey) + + if !hasLastUkey || b.s.icmp.uCompare(lastUkey, ukey) != 0 { + // First occurrence of this user key. + + // Only rotate tables if ukey doesn't hop across. + if b.tw != nil && (shouldStop || b.needFlush()) { + if err := b.flush(); err != nil { + return err + } + + // Creates snapshot of the state. + b.c.save() + b.snapHasLastUkey = hasLastUkey + b.snapLastUkey = append(b.snapLastUkey[:0], lastUkey...) + b.snapLastSeq = lastSeq + b.snapIter = i + b.snapKerrCnt = b.kerrCnt + b.snapDropCnt = b.dropCnt + } + + hasLastUkey = true + lastUkey = append(lastUkey[:0], ukey...) + lastSeq = kMaxSeq + } + + switch { + case lastSeq <= b.minSeq: + // Dropped because newer entry for same user key exist + fallthrough // (A) + case kt == ktDel && seq <= b.minSeq && b.c.baseLevelForKey(lastUkey): + // For this user key: + // (1) there is no data in higher levels + // (2) data in lower levels will have larger seq numbers + // (3) data in layers that are being compacted here and have + // smaller seq numbers will be dropped in the next + // few iterations of this loop (by rule (A) above). + // Therefore this deletion marker is obsolete and can be dropped. + lastSeq = seq + b.dropCnt++ + continue + default: + lastSeq = seq + } + } else { + if b.strict { + return kerr + } + + // Don't drop corrupted keys. + hasLastUkey = false + lastUkey = lastUkey[:0] + lastSeq = kMaxSeq + b.kerrCnt++ + } + + if err := b.appendKV(ikey, iter.Value()); err != nil { + return err + } + } + + if err := iter.Error(); err != nil { + return err + } + + // Finish last table. + if b.tw != nil && !b.tw.empty() { + return b.flush() + } + return nil +} + +func (b *tableCompactionBuilder) revert() error { + for _, at := range b.rec.addedTables { + b.s.logf("table@build revert @%d", at.num) + f := b.s.getTableFile(at.num) + if err := f.Remove(); err != nil { + return err + } + } + return nil +} + +func (db *DB) tableCompaction(c *compaction, noTrivial bool) { + defer c.release() + + rec := &sessionRecord{numLevel: db.s.o.GetNumLevel()} + rec.addCompPtr(c.level, c.imax) + + if !noTrivial && c.trivial() { + t := c.tables[0][0] + db.logf("table@move L%d@%d -> L%d", c.level, t.file.Num(), c.level+1) + rec.delTable(c.level, t.file.Num()) + rec.addTableFile(c.level+1, t) + db.compactionTransactFunc("table@move", func(cnt *compactionTransactCounter) (err error) { + return db.s.commit(rec) + }, nil) + return + } + + var stats [2]cStatsStaging + for i, tables := range c.tables { + for _, t := range tables { + stats[i].read += t.size + // Insert deleted tables into record + rec.delTable(c.level+i, t.file.Num()) + } + } + sourceSize := int(stats[0].read + stats[1].read) + minSeq := db.minSeq() + db.logf("table@compaction L%d·%d -> L%d·%d S·%s Q·%d", c.level, len(c.tables[0]), c.level+1, len(c.tables[1]), shortenb(sourceSize), minSeq) + + b := &tableCompactionBuilder{ + db: db, + s: db.s, + c: c, + rec: rec, + stat1: &stats[1], + minSeq: minSeq, + strict: db.s.o.GetStrict(opt.StrictCompaction), + tableSize: db.s.o.GetCompactionTableSize(c.level + 1), + } + db.compactionTransact("table@build", b) + + // Commit changes + db.compactionTransactFunc("table@commit", func(cnt *compactionTransactCounter) (err error) { + stats[1].startTimer() + defer stats[1].stopTimer() + return db.s.commit(rec) + }, nil) + + resultSize := int(stats[1].write) + db.logf("table@compaction committed F%s S%s Ke·%d D·%d T·%v", sint(len(rec.addedTables)-len(rec.deletedTables)), sshortenb(resultSize-sourceSize), b.kerrCnt, b.dropCnt, stats[1].duration) + + // Save compaction stats + for i := range stats { + db.compStats[c.level+1].add(&stats[i]) + } +} + +func (db *DB) tableRangeCompaction(level int, umin, umax []byte) { + db.logf("table@compaction range L%d %q:%q", level, umin, umax) + + if level >= 0 { + if c := db.s.getCompactionRange(level, umin, umax); c != nil { + db.tableCompaction(c, true) + } + } else { + v := db.s.version() + m := 1 + for i, t := range v.tables[1:] { + if t.overlaps(db.s.icmp, umin, umax, false) { + m = i + 1 + } + } + v.release() + + for level := 0; level < m; level++ { + if c := db.s.getCompactionRange(level, umin, umax); c != nil { + db.tableCompaction(c, true) + } + } + } +} + +func (db *DB) tableAutoCompaction() { + if c := db.s.pickCompaction(); c != nil { + db.tableCompaction(c, false) + } +} + +func (db *DB) tableNeedCompaction() bool { + v := db.s.version() + defer v.release() + return v.needCompaction() +} + +func (db *DB) pauseCompaction(ch chan<- struct{}) { + select { + case ch <- struct{}{}: + case _, _ = <-db.closeC: + db.compactionExitTransact() + } +} + +type cCmd interface { + ack(err error) +} + +type cIdle struct { + ackC chan<- error +} + +func (r cIdle) ack(err error) { + if r.ackC != nil { + defer func() { + recover() + }() + r.ackC <- err + } +} + +type cRange struct { + level int + min, max []byte + ackC chan<- error +} + +func (r cRange) ack(err error) { + if r.ackC != nil { + defer func() { + recover() + }() + r.ackC <- err + } +} + +// This will trigger auto compation and/or wait for all compaction to be done. +func (db *DB) compSendIdle(compC chan<- cCmd) (err error) { + ch := make(chan error) + defer close(ch) + // Send cmd. + select { + case compC <- cIdle{ch}: + case err = <-db.compErrC: + return + case _, _ = <-db.closeC: + return ErrClosed + } + // Wait cmd. + select { + case err = <-ch: + case err = <-db.compErrC: + case _, _ = <-db.closeC: + return ErrClosed + } + return err +} + +// This will trigger auto compaction but will not wait for it. +func (db *DB) compSendTrigger(compC chan<- cCmd) { + select { + case compC <- cIdle{}: + default: + } +} + +// Send range compaction request. +func (db *DB) compSendRange(compC chan<- cCmd, level int, min, max []byte) (err error) { + ch := make(chan error) + defer close(ch) + // Send cmd. + select { + case compC <- cRange{level, min, max, ch}: + case err := <-db.compErrC: + return err + case _, _ = <-db.closeC: + return ErrClosed + } + // Wait cmd. + select { + case err = <-ch: + case err = <-db.compErrC: + case _, _ = <-db.closeC: + return ErrClosed + } + return err +} + +func (db *DB) mCompaction() { + var x cCmd + + defer func() { + if x := recover(); x != nil { + if x != errCompactionTransactExiting { + panic(x) + } + } + if x != nil { + x.ack(ErrClosed) + } + db.closeW.Done() + }() + + for { + select { + case x = <-db.mcompCmdC: + switch x.(type) { + case cIdle: + db.memCompaction() + x.ack(nil) + x = nil + default: + panic("leveldb: unknown command") + } + case _, _ = <-db.closeC: + return + } + } +} + +func (db *DB) tCompaction() { + var x cCmd + var ackQ []cCmd + + defer func() { + if x := recover(); x != nil { + if x != errCompactionTransactExiting { + panic(x) + } + } + for i := range ackQ { + ackQ[i].ack(ErrClosed) + ackQ[i] = nil + } + if x != nil { + x.ack(ErrClosed) + } + db.closeW.Done() + }() + + for { + if db.tableNeedCompaction() { + select { + case x = <-db.tcompCmdC: + case ch := <-db.tcompPauseC: + db.pauseCompaction(ch) + continue + case _, _ = <-db.closeC: + return + default: + } + } else { + for i := range ackQ { + ackQ[i].ack(nil) + ackQ[i] = nil + } + ackQ = ackQ[:0] + select { + case x = <-db.tcompCmdC: + case ch := <-db.tcompPauseC: + db.pauseCompaction(ch) + continue + case _, _ = <-db.closeC: + return + } + } + if x != nil { + switch cmd := x.(type) { + case cIdle: + ackQ = append(ackQ, x) + case cRange: + db.tableRangeCompaction(cmd.level, cmd.min, cmd.max) + x.ack(nil) + default: + panic("leveldb: unknown command") + } + x = nil + } + db.tableAutoCompaction() + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go new file mode 100644 index 00000000..53b8c8f9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go @@ -0,0 +1,350 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "errors" + "math/rand" + "runtime" + "sync" + "sync/atomic" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +var ( + errInvalidIkey = errors.New("leveldb: Iterator: invalid internal key") +) + +type memdbReleaser struct { + once sync.Once + m *memDB +} + +func (mr *memdbReleaser) Release() { + mr.once.Do(func() { + mr.m.decref() + }) +} + +func (db *DB) newRawIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { + em, fm := db.getMems() + v := db.s.version() + + ti := v.getIterators(slice, ro) + n := len(ti) + 2 + i := make([]iterator.Iterator, 0, n) + emi := em.mdb.NewIterator(slice) + emi.SetReleaser(&memdbReleaser{m: em}) + i = append(i, emi) + if fm != nil { + fmi := fm.mdb.NewIterator(slice) + fmi.SetReleaser(&memdbReleaser{m: fm}) + i = append(i, fmi) + } + i = append(i, ti...) + strict := opt.GetStrict(db.s.o.Options, ro, opt.StrictReader) + mi := iterator.NewMergedIterator(i, db.s.icmp, strict) + mi.SetReleaser(&versionReleaser{v: v}) + return mi +} + +func (db *DB) newIterator(seq uint64, slice *util.Range, ro *opt.ReadOptions) *dbIter { + var islice *util.Range + if slice != nil { + islice = &util.Range{} + if slice.Start != nil { + islice.Start = newIkey(slice.Start, kMaxSeq, ktSeek) + } + if slice.Limit != nil { + islice.Limit = newIkey(slice.Limit, kMaxSeq, ktSeek) + } + } + rawIter := db.newRawIterator(islice, ro) + iter := &dbIter{ + db: db, + icmp: db.s.icmp, + iter: rawIter, + seq: seq, + strict: opt.GetStrict(db.s.o.Options, ro, opt.StrictReader), + key: make([]byte, 0), + value: make([]byte, 0), + } + atomic.AddInt32(&db.aliveIters, 1) + runtime.SetFinalizer(iter, (*dbIter).Release) + return iter +} + +func (db *DB) iterSamplingRate() int { + return rand.Intn(2 * db.s.o.GetIteratorSamplingRate()) +} + +type dir int + +const ( + dirReleased dir = iota - 1 + dirSOI + dirEOI + dirBackward + dirForward +) + +// dbIter represent an interator states over a database session. +type dbIter struct { + db *DB + icmp *iComparer + iter iterator.Iterator + seq uint64 + strict bool + + smaplingGap int + dir dir + key []byte + value []byte + err error + releaser util.Releaser +} + +func (i *dbIter) sampleSeek() { + ikey := i.iter.Key() + i.smaplingGap -= len(ikey) + len(i.iter.Value()) + for i.smaplingGap < 0 { + i.smaplingGap += i.db.iterSamplingRate() + i.db.sampleSeek(ikey) + } +} + +func (i *dbIter) setErr(err error) { + i.err = err + i.key = nil + i.value = nil +} + +func (i *dbIter) iterErr() { + if err := i.iter.Error(); err != nil { + i.setErr(err) + } +} + +func (i *dbIter) Valid() bool { + return i.err == nil && i.dir > dirEOI +} + +func (i *dbIter) First() bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + if i.iter.First() { + i.dir = dirSOI + return i.next() + } + i.dir = dirEOI + i.iterErr() + return false +} + +func (i *dbIter) Last() bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + if i.iter.Last() { + return i.prev() + } + i.dir = dirSOI + i.iterErr() + return false +} + +func (i *dbIter) Seek(key []byte) bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + ikey := newIkey(key, i.seq, ktSeek) + if i.iter.Seek(ikey) { + i.dir = dirSOI + return i.next() + } + i.dir = dirEOI + i.iterErr() + return false +} + +func (i *dbIter) next() bool { + for { + if ukey, seq, kt, kerr := parseIkey(i.iter.Key()); kerr == nil { + i.sampleSeek() + if seq <= i.seq { + switch kt { + case ktDel: + // Skip deleted key. + i.key = append(i.key[:0], ukey...) + i.dir = dirForward + case ktVal: + if i.dir == dirSOI || i.icmp.uCompare(ukey, i.key) > 0 { + i.key = append(i.key[:0], ukey...) + i.value = append(i.value[:0], i.iter.Value()...) + i.dir = dirForward + return true + } + } + } + } else if i.strict { + i.setErr(kerr) + break + } + if !i.iter.Next() { + i.dir = dirEOI + i.iterErr() + break + } + } + return false +} + +func (i *dbIter) Next() bool { + if i.dir == dirEOI || i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + if !i.iter.Next() || (i.dir == dirBackward && !i.iter.Next()) { + i.dir = dirEOI + i.iterErr() + return false + } + return i.next() +} + +func (i *dbIter) prev() bool { + i.dir = dirBackward + del := true + if i.iter.Valid() { + for { + if ukey, seq, kt, kerr := parseIkey(i.iter.Key()); kerr == nil { + i.sampleSeek() + if seq <= i.seq { + if !del && i.icmp.uCompare(ukey, i.key) < 0 { + return true + } + del = (kt == ktDel) + if !del { + i.key = append(i.key[:0], ukey...) + i.value = append(i.value[:0], i.iter.Value()...) + } + } + } else if i.strict { + i.setErr(kerr) + return false + } + if !i.iter.Prev() { + break + } + } + } + if del { + i.dir = dirSOI + i.iterErr() + return false + } + return true +} + +func (i *dbIter) Prev() bool { + if i.dir == dirSOI || i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + switch i.dir { + case dirEOI: + return i.Last() + case dirForward: + for i.iter.Prev() { + if ukey, _, _, kerr := parseIkey(i.iter.Key()); kerr == nil { + i.sampleSeek() + if i.icmp.uCompare(ukey, i.key) < 0 { + goto cont + } + } else if i.strict { + i.setErr(kerr) + return false + } + } + i.dir = dirSOI + i.iterErr() + return false + } + +cont: + return i.prev() +} + +func (i *dbIter) Key() []byte { + if i.err != nil || i.dir <= dirEOI { + return nil + } + return i.key +} + +func (i *dbIter) Value() []byte { + if i.err != nil || i.dir <= dirEOI { + return nil + } + return i.value +} + +func (i *dbIter) Release() { + if i.dir != dirReleased { + // Clear the finalizer. + runtime.SetFinalizer(i, nil) + + if i.releaser != nil { + i.releaser.Release() + i.releaser = nil + } + + i.dir = dirReleased + i.key = nil + i.value = nil + i.iter.Release() + i.iter = nil + atomic.AddInt32(&i.db.aliveIters, -1) + i.db = nil + } +} + +func (i *dbIter) SetReleaser(releaser util.Releaser) { + if i.dir == dirReleased { + panic(util.ErrReleased) + } + if i.releaser != nil && releaser != nil { + panic(util.ErrHasReleaser) + } + i.releaser = releaser +} + +func (i *dbIter) Error() error { + return i.err +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go new file mode 100644 index 00000000..15f6dc3b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go @@ -0,0 +1,183 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "container/list" + "fmt" + "runtime" + "sync" + "sync/atomic" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type snapshotElement struct { + seq uint64 + ref int + e *list.Element +} + +// Acquires a snapshot, based on latest sequence. +func (db *DB) acquireSnapshot() *snapshotElement { + db.snapsMu.Lock() + defer db.snapsMu.Unlock() + + seq := db.getSeq() + + if e := db.snapsList.Back(); e != nil { + se := e.Value.(*snapshotElement) + if se.seq == seq { + se.ref++ + return se + } else if seq < se.seq { + panic("leveldb: sequence number is not increasing") + } + } + se := &snapshotElement{seq: seq, ref: 1} + se.e = db.snapsList.PushBack(se) + return se +} + +// Releases given snapshot element. +func (db *DB) releaseSnapshot(se *snapshotElement) { + db.snapsMu.Lock() + defer db.snapsMu.Unlock() + + se.ref-- + if se.ref == 0 { + db.snapsList.Remove(se.e) + se.e = nil + } else if se.ref < 0 { + panic("leveldb: Snapshot: negative element reference") + } +} + +// Gets minimum sequence that not being snapshoted. +func (db *DB) minSeq() uint64 { + db.snapsMu.Lock() + defer db.snapsMu.Unlock() + + if e := db.snapsList.Front(); e != nil { + return e.Value.(*snapshotElement).seq + } + + return db.getSeq() +} + +// Snapshot is a DB snapshot. +type Snapshot struct { + db *DB + elem *snapshotElement + mu sync.RWMutex + released bool +} + +// Creates new snapshot object. +func (db *DB) newSnapshot() *Snapshot { + snap := &Snapshot{ + db: db, + elem: db.acquireSnapshot(), + } + atomic.AddInt32(&db.aliveSnaps, 1) + runtime.SetFinalizer(snap, (*Snapshot).Release) + return snap +} + +func (snap *Snapshot) String() string { + return fmt.Sprintf("leveldb.Snapshot{%d}", snap.elem.seq) +} + +// Get gets the value for the given key. It returns ErrNotFound if +// the DB does not contains the key. +// +// The caller should not modify the contents of the returned slice, but +// it is safe to modify the contents of the argument after Get returns. +func (snap *Snapshot) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) { + err = snap.db.ok() + if err != nil { + return + } + snap.mu.RLock() + defer snap.mu.RUnlock() + if snap.released { + err = ErrSnapshotReleased + return + } + return snap.db.get(key, snap.elem.seq, ro) +} + +// Has returns true if the DB does contains the given key. +// +// It is safe to modify the contents of the argument after Get returns. +func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) { + err = snap.db.ok() + if err != nil { + return + } + snap.mu.RLock() + defer snap.mu.RUnlock() + if snap.released { + err = ErrSnapshotReleased + return + } + return snap.db.has(key, snap.elem.seq, ro) +} + +// NewIterator returns an iterator for the snapshot of the uderlying DB. +// The returned iterator is not goroutine-safe, but it is safe to use +// multiple iterators concurrently, with each in a dedicated goroutine. +// It is also safe to use an iterator concurrently with modifying its +// underlying DB. The resultant key/value pairs are guaranteed to be +// consistent. +// +// Slice allows slicing the iterator to only contains keys in the given +// range. A nil Range.Start is treated as a key before all keys in the +// DB. And a nil Range.Limit is treated as a key after all keys in +// the DB. +// +// The iterator must be released after use, by calling Release method. +// Releasing the snapshot doesn't mean releasing the iterator too, the +// iterator would be still valid until released. +// +// Also read Iterator documentation of the leveldb/iterator package. +func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { + if err := snap.db.ok(); err != nil { + return iterator.NewEmptyIterator(err) + } + snap.mu.Lock() + defer snap.mu.Unlock() + if snap.released { + return iterator.NewEmptyIterator(ErrSnapshotReleased) + } + // Since iterator already hold version ref, it doesn't need to + // hold snapshot ref. + return snap.db.newIterator(snap.elem.seq, slice, ro) +} + +// Release releases the snapshot. This will not release any returned +// iterators, the iterators would still be valid until released or the +// underlying DB is closed. +// +// Other methods should not be called after the snapshot has been released. +func (snap *Snapshot) Release() { + snap.mu.Lock() + defer snap.mu.Unlock() + + if !snap.released { + // Clear the finalizer. + runtime.SetFinalizer(snap, nil) + + snap.released = true + snap.db.releaseSnapshot(snap.elem) + atomic.AddInt32(&snap.db.aliveSnaps, -1) + snap.db = nil + snap.elem = nil + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go new file mode 100644 index 00000000..d76f34b0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go @@ -0,0 +1,211 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "sync/atomic" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb" +) + +type memDB struct { + db *DB + mdb *memdb.DB + ref int32 +} + +func (m *memDB) incref() { + atomic.AddInt32(&m.ref, 1) +} + +func (m *memDB) decref() { + if ref := atomic.AddInt32(&m.ref, -1); ref == 0 { + // Only put back memdb with std capacity. + if m.mdb.Capacity() == m.db.s.o.GetWriteBuffer() { + m.mdb.Reset() + m.db.mpoolPut(m.mdb) + } + m.db = nil + m.mdb = nil + } else if ref < 0 { + panic("negative memdb ref") + } +} + +// Get latest sequence number. +func (db *DB) getSeq() uint64 { + return atomic.LoadUint64(&db.seq) +} + +// Atomically adds delta to seq. +func (db *DB) addSeq(delta uint64) { + atomic.AddUint64(&db.seq, delta) +} + +func (db *DB) sampleSeek(ikey iKey) { + v := db.s.version() + if v.sampleSeek(ikey) { + // Trigger table compaction. + db.compSendTrigger(db.tcompCmdC) + } + v.release() +} + +func (db *DB) mpoolPut(mem *memdb.DB) { + defer func() { + recover() + }() + select { + case db.memPool <- mem: + default: + } +} + +func (db *DB) mpoolGet() *memdb.DB { + select { + case mem := <-db.memPool: + return mem + default: + return nil + } +} + +func (db *DB) mpoolDrain() { + ticker := time.NewTicker(30 * time.Second) + for { + select { + case <-ticker.C: + select { + case <-db.memPool: + default: + } + case _, _ = <-db.closeC: + close(db.memPool) + return + } + } +} + +// Create new memdb and froze the old one; need external synchronization. +// newMem only called synchronously by the writer. +func (db *DB) newMem(n int) (mem *memDB, err error) { + num := db.s.allocFileNum() + file := db.s.getJournalFile(num) + w, err := file.Create() + if err != nil { + db.s.reuseFileNum(num) + return + } + + db.memMu.Lock() + defer db.memMu.Unlock() + + if db.frozenMem != nil { + panic("still has frozen mem") + } + + if db.journal == nil { + db.journal = journal.NewWriter(w) + } else { + db.journal.Reset(w) + db.journalWriter.Close() + db.frozenJournalFile = db.journalFile + } + db.journalWriter = w + db.journalFile = file + db.frozenMem = db.mem + mdb := db.mpoolGet() + if mdb == nil || mdb.Capacity() < n { + mdb = memdb.New(db.s.icmp, maxInt(db.s.o.GetWriteBuffer(), n)) + } + mem = &memDB{ + db: db, + mdb: mdb, + ref: 2, + } + db.mem = mem + // The seq only incremented by the writer. And whoever called newMem + // should hold write lock, so no need additional synchronization here. + db.frozenSeq = db.seq + return +} + +// Get all memdbs. +func (db *DB) getMems() (e, f *memDB) { + db.memMu.RLock() + defer db.memMu.RUnlock() + if db.mem == nil { + panic("nil effective mem") + } + db.mem.incref() + if db.frozenMem != nil { + db.frozenMem.incref() + } + return db.mem, db.frozenMem +} + +// Get frozen memdb. +func (db *DB) getEffectiveMem() *memDB { + db.memMu.RLock() + defer db.memMu.RUnlock() + if db.mem == nil { + panic("nil effective mem") + } + db.mem.incref() + return db.mem +} + +// Check whether we has frozen memdb. +func (db *DB) hasFrozenMem() bool { + db.memMu.RLock() + defer db.memMu.RUnlock() + return db.frozenMem != nil +} + +// Get frozen memdb. +func (db *DB) getFrozenMem() *memDB { + db.memMu.RLock() + defer db.memMu.RUnlock() + if db.frozenMem != nil { + db.frozenMem.incref() + } + return db.frozenMem +} + +// Drop frozen memdb; assume that frozen memdb isn't nil. +func (db *DB) dropFrozenMem() { + db.memMu.Lock() + if err := db.frozenJournalFile.Remove(); err != nil { + db.logf("journal@remove removing @%d %q", db.frozenJournalFile.Num(), err) + } else { + db.logf("journal@remove removed @%d", db.frozenJournalFile.Num()) + } + db.frozenJournalFile = nil + db.frozenMem.decref() + db.frozenMem = nil + db.memMu.Unlock() +} + +// Set closed flag; return true if not already closed. +func (db *DB) setClosed() bool { + return atomic.CompareAndSwapUint32(&db.closed, 0, 1) +} + +// Check whether DB was closed. +func (db *DB) isClosed() bool { + return atomic.LoadUint32(&db.closed) != 0 +} + +// Check read ok status. +func (db *DB) ok() error { + if db.isClosed() { + return ErrClosed + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go new file mode 100644 index 00000000..966b00aa --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go @@ -0,0 +1,2665 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bytes" + "container/list" + crand "crypto/rand" + "encoding/binary" + "fmt" + "math/rand" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + "unsafe" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +func tkey(i int) []byte { + return []byte(fmt.Sprintf("%016d", i)) +} + +func tval(seed, n int) []byte { + r := rand.New(rand.NewSource(int64(seed))) + return randomString(r, n) +} + +type dbHarness struct { + t *testing.T + + stor *testStorage + db *DB + o *opt.Options + ro *opt.ReadOptions + wo *opt.WriteOptions +} + +func newDbHarnessWopt(t *testing.T, o *opt.Options) *dbHarness { + h := new(dbHarness) + h.init(t, o) + return h +} + +func newDbHarness(t *testing.T) *dbHarness { + return newDbHarnessWopt(t, &opt.Options{}) +} + +func (h *dbHarness) init(t *testing.T, o *opt.Options) { + h.t = t + h.stor = newTestStorage(t) + h.o = o + h.ro = nil + h.wo = nil + + if err := h.openDB0(); err != nil { + // So that it will come after fatal message. + defer h.stor.Close() + h.t.Fatal("Open (init): got error: ", err) + } +} + +func (h *dbHarness) openDB0() (err error) { + h.t.Log("opening DB") + h.db, err = Open(h.stor, h.o) + return +} + +func (h *dbHarness) openDB() { + if err := h.openDB0(); err != nil { + h.t.Fatal("Open: got error: ", err) + } +} + +func (h *dbHarness) closeDB0() error { + h.t.Log("closing DB") + return h.db.Close() +} + +func (h *dbHarness) closeDB() { + if err := h.closeDB0(); err != nil { + h.t.Error("Close: got error: ", err) + } + h.stor.CloseCheck() + runtime.GC() +} + +func (h *dbHarness) reopenDB() { + h.closeDB() + h.openDB() +} + +func (h *dbHarness) close() { + h.closeDB0() + h.db = nil + h.stor.Close() + h.stor = nil + runtime.GC() +} + +func (h *dbHarness) openAssert(want bool) { + db, err := Open(h.stor, h.o) + if err != nil { + if want { + h.t.Error("Open: assert: got error: ", err) + } else { + h.t.Log("Open: assert: got error (expected): ", err) + } + } else { + if !want { + h.t.Error("Open: assert: expect error") + } + db.Close() + } +} + +func (h *dbHarness) write(batch *Batch) { + if err := h.db.Write(batch, h.wo); err != nil { + h.t.Error("Write: got error: ", err) + } +} + +func (h *dbHarness) put(key, value string) { + if err := h.db.Put([]byte(key), []byte(value), h.wo); err != nil { + h.t.Error("Put: got error: ", err) + } +} + +func (h *dbHarness) putMulti(n int, low, hi string) { + for i := 0; i < n; i++ { + h.put(low, "begin") + h.put(hi, "end") + h.compactMem() + } +} + +func (h *dbHarness) maxNextLevelOverlappingBytes(want uint64) { + t := h.t + db := h.db + + var ( + maxOverlaps uint64 + maxLevel int + ) + v := db.s.version() + for i, tt := range v.tables[1 : len(v.tables)-1] { + level := i + 1 + next := v.tables[level+1] + for _, t := range tt { + r := next.getOverlaps(nil, db.s.icmp, t.imin.ukey(), t.imax.ukey(), false) + sum := r.size() + if sum > maxOverlaps { + maxOverlaps = sum + maxLevel = level + } + } + } + v.release() + + if maxOverlaps > want { + t.Errorf("next level most overlapping bytes is more than %d, got=%d level=%d", want, maxOverlaps, maxLevel) + } else { + t.Logf("next level most overlapping bytes is %d, level=%d want=%d", maxOverlaps, maxLevel, want) + } +} + +func (h *dbHarness) delete(key string) { + t := h.t + db := h.db + + err := db.Delete([]byte(key), h.wo) + if err != nil { + t.Error("Delete: got error: ", err) + } +} + +func (h *dbHarness) assertNumKeys(want int) { + iter := h.db.NewIterator(nil, h.ro) + defer iter.Release() + got := 0 + for iter.Next() { + got++ + } + if err := iter.Error(); err != nil { + h.t.Error("assertNumKeys: ", err) + } + if want != got { + h.t.Errorf("assertNumKeys: want=%d got=%d", want, got) + } +} + +func (h *dbHarness) getr(db Reader, key string, expectFound bool) (found bool, v []byte) { + t := h.t + v, err := db.Get([]byte(key), h.ro) + switch err { + case ErrNotFound: + if expectFound { + t.Errorf("Get: key '%s' not found, want found", key) + } + case nil: + found = true + if !expectFound { + t.Errorf("Get: key '%s' found, want not found", key) + } + default: + t.Error("Get: got error: ", err) + } + return +} + +func (h *dbHarness) get(key string, expectFound bool) (found bool, v []byte) { + return h.getr(h.db, key, expectFound) +} + +func (h *dbHarness) getValr(db Reader, key, value string) { + t := h.t + found, r := h.getr(db, key, true) + if !found { + return + } + rval := string(r) + if rval != value { + t.Errorf("Get: invalid value, got '%s', want '%s'", rval, value) + } +} + +func (h *dbHarness) getVal(key, value string) { + h.getValr(h.db, key, value) +} + +func (h *dbHarness) allEntriesFor(key, want string) { + t := h.t + db := h.db + s := db.s + + ikey := newIkey([]byte(key), kMaxSeq, ktVal) + iter := db.newRawIterator(nil, nil) + if !iter.Seek(ikey) && iter.Error() != nil { + t.Error("AllEntries: error during seek, err: ", iter.Error()) + return + } + res := "[ " + first := true + for iter.Valid() { + if ukey, _, kt, kerr := parseIkey(iter.Key()); kerr == nil { + if s.icmp.uCompare(ikey.ukey(), ukey) != 0 { + break + } + if !first { + res += ", " + } + first = false + switch kt { + case ktVal: + res += string(iter.Value()) + case ktDel: + res += "DEL" + } + } else { + if !first { + res += ", " + } + first = false + res += "CORRUPTED" + } + iter.Next() + } + if !first { + res += " " + } + res += "]" + if res != want { + t.Errorf("AllEntries: assert failed for key %q, got=%q want=%q", key, res, want) + } +} + +// Return a string that contains all key,value pairs in order, +// formatted like "(k1->v1)(k2->v2)". +func (h *dbHarness) getKeyVal(want string) { + t := h.t + db := h.db + + s, err := db.GetSnapshot() + if err != nil { + t.Fatal("GetSnapshot: got error: ", err) + } + res := "" + iter := s.NewIterator(nil, nil) + for iter.Next() { + res += fmt.Sprintf("(%s->%s)", string(iter.Key()), string(iter.Value())) + } + iter.Release() + + if res != want { + t.Errorf("GetKeyVal: invalid key/value pair, got=%q want=%q", res, want) + } + s.Release() +} + +func (h *dbHarness) waitCompaction() { + t := h.t + db := h.db + if err := db.compSendIdle(db.tcompCmdC); err != nil { + t.Error("compaction error: ", err) + } +} + +func (h *dbHarness) waitMemCompaction() { + t := h.t + db := h.db + + if err := db.compSendIdle(db.mcompCmdC); err != nil { + t.Error("compaction error: ", err) + } +} + +func (h *dbHarness) compactMem() { + t := h.t + db := h.db + + t.Log("starting memdb compaction") + + db.writeLockC <- struct{}{} + defer func() { + <-db.writeLockC + }() + + if _, err := db.rotateMem(0); err != nil { + t.Error("compaction error: ", err) + } + if err := db.compSendIdle(db.mcompCmdC); err != nil { + t.Error("compaction error: ", err) + } + + if h.totalTables() == 0 { + t.Error("zero tables after mem compaction") + } + + t.Log("memdb compaction done") +} + +func (h *dbHarness) compactRangeAtErr(level int, min, max string, wanterr bool) { + t := h.t + db := h.db + + var _min, _max []byte + if min != "" { + _min = []byte(min) + } + if max != "" { + _max = []byte(max) + } + + t.Logf("starting table range compaction: level=%d, min=%q, max=%q", level, min, max) + + if err := db.compSendRange(db.tcompCmdC, level, _min, _max); err != nil { + if wanterr { + t.Log("CompactRangeAt: got error (expected): ", err) + } else { + t.Error("CompactRangeAt: got error: ", err) + } + } else if wanterr { + t.Error("CompactRangeAt: expect error") + } + + t.Log("table range compaction done") +} + +func (h *dbHarness) compactRangeAt(level int, min, max string) { + h.compactRangeAtErr(level, min, max, false) +} + +func (h *dbHarness) compactRange(min, max string) { + t := h.t + db := h.db + + t.Logf("starting DB range compaction: min=%q, max=%q", min, max) + + var r util.Range + if min != "" { + r.Start = []byte(min) + } + if max != "" { + r.Limit = []byte(max) + } + if err := db.CompactRange(r); err != nil { + t.Error("CompactRange: got error: ", err) + } + + t.Log("DB range compaction done") +} + +func (h *dbHarness) sizeOf(start, limit string) uint64 { + sz, err := h.db.SizeOf([]util.Range{ + {[]byte(start), []byte(limit)}, + }) + if err != nil { + h.t.Error("SizeOf: got error: ", err) + } + return sz.Sum() +} + +func (h *dbHarness) sizeAssert(start, limit string, low, hi uint64) { + sz := h.sizeOf(start, limit) + if sz < low || sz > hi { + h.t.Errorf("sizeOf %q to %q not in range, want %d - %d, got %d", + shorten(start), shorten(limit), low, hi, sz) + } +} + +func (h *dbHarness) getSnapshot() (s *Snapshot) { + s, err := h.db.GetSnapshot() + if err != nil { + h.t.Fatal("GetSnapshot: got error: ", err) + } + return +} +func (h *dbHarness) tablesPerLevel(want string) { + res := "" + nz := 0 + v := h.db.s.version() + for level, tt := range v.tables { + if level > 0 { + res += "," + } + res += fmt.Sprint(len(tt)) + if len(tt) > 0 { + nz = len(res) + } + } + v.release() + res = res[:nz] + if res != want { + h.t.Errorf("invalid tables len, want=%s, got=%s", want, res) + } +} + +func (h *dbHarness) totalTables() (n int) { + v := h.db.s.version() + for _, tt := range v.tables { + n += len(tt) + } + v.release() + return +} + +type keyValue interface { + Key() []byte + Value() []byte +} + +func testKeyVal(t *testing.T, kv keyValue, want string) { + res := string(kv.Key()) + "->" + string(kv.Value()) + if res != want { + t.Errorf("invalid key/value, want=%q, got=%q", want, res) + } +} + +func numKey(num int) string { + return fmt.Sprintf("key%06d", num) +} + +var _bloom_filter = filter.NewBloomFilter(10) + +func truno(t *testing.T, o *opt.Options, f func(h *dbHarness)) { + for i := 0; i < 4; i++ { + func() { + switch i { + case 0: + case 1: + if o == nil { + o = &opt.Options{Filter: _bloom_filter} + } else { + old := o + o = &opt.Options{} + *o = *old + o.Filter = _bloom_filter + } + case 2: + if o == nil { + o = &opt.Options{Compression: opt.NoCompression} + } else { + old := o + o = &opt.Options{} + *o = *old + o.Compression = opt.NoCompression + } + } + h := newDbHarnessWopt(t, o) + defer h.close() + switch i { + case 3: + h.reopenDB() + } + f(h) + }() + } +} + +func trun(t *testing.T, f func(h *dbHarness)) { + truno(t, nil, f) +} + +func testAligned(t *testing.T, name string, offset uintptr) { + if offset%8 != 0 { + t.Errorf("field %s offset is not 64-bit aligned", name) + } +} + +func Test_FieldsAligned(t *testing.T) { + p1 := new(DB) + testAligned(t, "DB.seq", unsafe.Offsetof(p1.seq)) + p2 := new(session) + testAligned(t, "session.stNextFileNum", unsafe.Offsetof(p2.stNextFileNum)) + testAligned(t, "session.stJournalNum", unsafe.Offsetof(p2.stJournalNum)) + testAligned(t, "session.stPrevJournalNum", unsafe.Offsetof(p2.stPrevJournalNum)) + testAligned(t, "session.stSeqNum", unsafe.Offsetof(p2.stSeqNum)) +} + +func TestDB_Locking(t *testing.T) { + h := newDbHarness(t) + defer h.stor.Close() + h.openAssert(false) + h.closeDB() + h.openAssert(true) +} + +func TestDB_Empty(t *testing.T) { + trun(t, func(h *dbHarness) { + h.get("foo", false) + + h.reopenDB() + h.get("foo", false) + }) +} + +func TestDB_ReadWrite(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + h.getVal("foo", "v1") + h.put("bar", "v2") + h.put("foo", "v3") + h.getVal("foo", "v3") + h.getVal("bar", "v2") + + h.reopenDB() + h.getVal("foo", "v3") + h.getVal("bar", "v2") + }) +} + +func TestDB_PutDeleteGet(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + h.getVal("foo", "v1") + h.put("foo", "v2") + h.getVal("foo", "v2") + h.delete("foo") + h.get("foo", false) + + h.reopenDB() + h.get("foo", false) + }) +} + +func TestDB_EmptyBatch(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.get("foo", false) + err := h.db.Write(new(Batch), h.wo) + if err != nil { + t.Error("writing empty batch yield error: ", err) + } + h.get("foo", false) +} + +func TestDB_GetFromFrozen(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 100100}) + defer h.close() + + h.put("foo", "v1") + h.getVal("foo", "v1") + + h.stor.DelaySync(storage.TypeTable) // Block sync calls + h.put("k1", strings.Repeat("x", 100000)) // Fill memtable + h.put("k2", strings.Repeat("y", 100000)) // Trigger compaction + for i := 0; h.db.getFrozenMem() == nil && i < 100; i++ { + time.Sleep(10 * time.Microsecond) + } + if h.db.getFrozenMem() == nil { + h.stor.ReleaseSync(storage.TypeTable) + t.Fatal("No frozen mem") + } + h.getVal("foo", "v1") + h.stor.ReleaseSync(storage.TypeTable) // Release sync calls + + h.reopenDB() + h.getVal("foo", "v1") + h.get("k1", true) + h.get("k2", true) +} + +func TestDB_GetFromTable(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + h.compactMem() + h.getVal("foo", "v1") + }) +} + +func TestDB_GetSnapshot(t *testing.T) { + trun(t, func(h *dbHarness) { + bar := strings.Repeat("b", 200) + h.put("foo", "v1") + h.put(bar, "v1") + + snap, err := h.db.GetSnapshot() + if err != nil { + t.Fatal("GetSnapshot: got error: ", err) + } + + h.put("foo", "v2") + h.put(bar, "v2") + + h.getVal("foo", "v2") + h.getVal(bar, "v2") + h.getValr(snap, "foo", "v1") + h.getValr(snap, bar, "v1") + + h.compactMem() + + h.getVal("foo", "v2") + h.getVal(bar, "v2") + h.getValr(snap, "foo", "v1") + h.getValr(snap, bar, "v1") + + snap.Release() + + h.reopenDB() + h.getVal("foo", "v2") + h.getVal(bar, "v2") + }) +} + +func TestDB_GetLevel0Ordering(t *testing.T) { + trun(t, func(h *dbHarness) { + for i := 0; i < 4; i++ { + h.put("bar", fmt.Sprintf("b%d", i)) + h.put("foo", fmt.Sprintf("v%d", i)) + h.compactMem() + } + h.getVal("foo", "v3") + h.getVal("bar", "b3") + + v := h.db.s.version() + t0len := v.tLen(0) + v.release() + if t0len < 2 { + t.Errorf("level-0 tables is less than 2, got %d", t0len) + } + + h.reopenDB() + h.getVal("foo", "v3") + h.getVal("bar", "b3") + }) +} + +func TestDB_GetOrderedByLevels(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + h.compactMem() + h.compactRange("a", "z") + h.getVal("foo", "v1") + h.put("foo", "v2") + h.compactMem() + h.getVal("foo", "v2") + }) +} + +func TestDB_GetPicksCorrectFile(t *testing.T) { + trun(t, func(h *dbHarness) { + // Arrange to have multiple files in a non-level-0 level. + h.put("a", "va") + h.compactMem() + h.compactRange("a", "b") + h.put("x", "vx") + h.compactMem() + h.compactRange("x", "y") + h.put("f", "vf") + h.compactMem() + h.compactRange("f", "g") + + h.getVal("a", "va") + h.getVal("f", "vf") + h.getVal("x", "vx") + + h.compactRange("", "") + h.getVal("a", "va") + h.getVal("f", "vf") + h.getVal("x", "vx") + }) +} + +func TestDB_GetEncountersEmptyLevel(t *testing.T) { + trun(t, func(h *dbHarness) { + // Arrange for the following to happen: + // * sstable A in level 0 + // * nothing in level 1 + // * sstable B in level 2 + // Then do enough Get() calls to arrange for an automatic compaction + // of sstable A. A bug would cause the compaction to be marked as + // occuring at level 1 (instead of the correct level 0). + + // Step 1: First place sstables in levels 0 and 2 + for i := 0; ; i++ { + if i >= 100 { + t.Fatal("could not fill levels-0 and level-2") + } + v := h.db.s.version() + if v.tLen(0) > 0 && v.tLen(2) > 0 { + v.release() + break + } + v.release() + h.put("a", "begin") + h.put("z", "end") + h.compactMem() + + h.getVal("a", "begin") + h.getVal("z", "end") + } + + // Step 2: clear level 1 if necessary. + h.compactRangeAt(1, "", "") + h.tablesPerLevel("1,0,1") + + h.getVal("a", "begin") + h.getVal("z", "end") + + // Step 3: read a bunch of times + for i := 0; i < 200; i++ { + h.get("missing", false) + } + + // Step 4: Wait for compaction to finish + h.waitCompaction() + + v := h.db.s.version() + if v.tLen(0) > 0 { + t.Errorf("level-0 tables more than 0, got %d", v.tLen(0)) + } + v.release() + + h.getVal("a", "begin") + h.getVal("z", "end") + }) +} + +func TestDB_IterMultiWithDelete(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("a", "va") + h.put("b", "vb") + h.put("c", "vc") + h.delete("b") + h.get("b", false) + + iter := h.db.NewIterator(nil, nil) + iter.Seek([]byte("c")) + testKeyVal(t, iter, "c->vc") + iter.Prev() + testKeyVal(t, iter, "a->va") + iter.Release() + + h.compactMem() + + iter = h.db.NewIterator(nil, nil) + iter.Seek([]byte("c")) + testKeyVal(t, iter, "c->vc") + iter.Prev() + testKeyVal(t, iter, "a->va") + iter.Release() + }) +} + +func TestDB_IteratorPinsRef(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.put("foo", "hello") + + // Get iterator that will yield the current contents of the DB. + iter := h.db.NewIterator(nil, nil) + + // Write to force compactions + h.put("foo", "newvalue1") + for i := 0; i < 100; i++ { + h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10)) + } + h.put("foo", "newvalue2") + + iter.First() + testKeyVal(t, iter, "foo->hello") + if iter.Next() { + t.Errorf("expect eof") + } + iter.Release() +} + +func TestDB_Recover(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + h.put("baz", "v5") + + h.reopenDB() + h.getVal("foo", "v1") + + h.getVal("foo", "v1") + h.getVal("baz", "v5") + h.put("bar", "v2") + h.put("foo", "v3") + + h.reopenDB() + h.getVal("foo", "v3") + h.put("foo", "v4") + h.getVal("foo", "v4") + h.getVal("bar", "v2") + h.getVal("baz", "v5") + }) +} + +func TestDB_RecoverWithEmptyJournal(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + h.put("foo", "v2") + + h.reopenDB() + h.reopenDB() + h.put("foo", "v3") + + h.reopenDB() + h.getVal("foo", "v3") + }) +} + +func TestDB_RecoverDuringMemtableCompaction(t *testing.T) { + truno(t, &opt.Options{WriteBuffer: 1000000}, func(h *dbHarness) { + + h.stor.DelaySync(storage.TypeTable) + h.put("big1", strings.Repeat("x", 10000000)) + h.put("big2", strings.Repeat("y", 1000)) + h.put("bar", "v2") + h.stor.ReleaseSync(storage.TypeTable) + + h.reopenDB() + h.getVal("bar", "v2") + h.getVal("big1", strings.Repeat("x", 10000000)) + h.getVal("big2", strings.Repeat("y", 1000)) + }) +} + +func TestDB_MinorCompactionsHappen(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 10000}) + defer h.close() + + n := 500 + + key := func(i int) string { + return fmt.Sprintf("key%06d", i) + } + + for i := 0; i < n; i++ { + h.put(key(i), key(i)+strings.Repeat("v", 1000)) + } + + for i := 0; i < n; i++ { + h.getVal(key(i), key(i)+strings.Repeat("v", 1000)) + } + + h.reopenDB() + for i := 0; i < n; i++ { + h.getVal(key(i), key(i)+strings.Repeat("v", 1000)) + } +} + +func TestDB_RecoverWithLargeJournal(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.put("big1", strings.Repeat("1", 200000)) + h.put("big2", strings.Repeat("2", 200000)) + h.put("small3", strings.Repeat("3", 10)) + h.put("small4", strings.Repeat("4", 10)) + h.tablesPerLevel("") + + // Make sure that if we re-open with a small write buffer size that + // we flush table files in the middle of a large journal file. + h.o.WriteBuffer = 100000 + h.reopenDB() + h.getVal("big1", strings.Repeat("1", 200000)) + h.getVal("big2", strings.Repeat("2", 200000)) + h.getVal("small3", strings.Repeat("3", 10)) + h.getVal("small4", strings.Repeat("4", 10)) + v := h.db.s.version() + if v.tLen(0) <= 1 { + t.Errorf("tables-0 less than one") + } + v.release() +} + +func TestDB_CompactionsGenerateMultipleFiles(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + WriteBuffer: 10000000, + Compression: opt.NoCompression, + }) + defer h.close() + + v := h.db.s.version() + if v.tLen(0) > 0 { + t.Errorf("level-0 tables more than 0, got %d", v.tLen(0)) + } + v.release() + + n := 80 + + // Write 8MB (80 values, each 100K) + for i := 0; i < n; i++ { + h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10)) + } + + // Reopening moves updates to level-0 + h.reopenDB() + h.compactRangeAt(0, "", "") + + v = h.db.s.version() + if v.tLen(0) > 0 { + t.Errorf("level-0 tables more than 0, got %d", v.tLen(0)) + } + if v.tLen(1) <= 1 { + t.Errorf("level-1 tables less than 1, got %d", v.tLen(1)) + } + v.release() + + for i := 0; i < n; i++ { + h.getVal(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10)) + } +} + +func TestDB_RepeatedWritesToSameKey(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 100000}) + defer h.close() + + maxTables := h.o.GetNumLevel() + h.o.GetWriteL0PauseTrigger() + + value := strings.Repeat("v", 2*h.o.GetWriteBuffer()) + for i := 0; i < 5*maxTables; i++ { + h.put("key", value) + n := h.totalTables() + if n > maxTables { + t.Errorf("total tables exceed %d, got=%d, iter=%d", maxTables, n, i) + } + } +} + +func TestDB_RepeatedWritesToSameKeyAfterReopen(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 100000}) + defer h.close() + + h.reopenDB() + + maxTables := h.o.GetNumLevel() + h.o.GetWriteL0PauseTrigger() + + value := strings.Repeat("v", 2*h.o.GetWriteBuffer()) + for i := 0; i < 5*maxTables; i++ { + h.put("key", value) + n := h.totalTables() + if n > maxTables { + t.Errorf("total tables exceed %d, got=%d, iter=%d", maxTables, n, i) + } + } +} + +func TestDB_SparseMerge(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{Compression: opt.NoCompression}) + defer h.close() + + h.putMulti(h.o.GetNumLevel(), "A", "Z") + + // Suppose there is: + // small amount of data with prefix A + // large amount of data with prefix B + // small amount of data with prefix C + // and that recent updates have made small changes to all three prefixes. + // Check that we do not do a compaction that merges all of B in one shot. + h.put("A", "va") + value := strings.Repeat("x", 1000) + for i := 0; i < 100000; i++ { + h.put(fmt.Sprintf("B%010d", i), value) + } + h.put("C", "vc") + h.compactMem() + h.compactRangeAt(0, "", "") + h.waitCompaction() + + // Make sparse update + h.put("A", "va2") + h.put("B100", "bvalue2") + h.put("C", "vc2") + h.compactMem() + + h.waitCompaction() + h.maxNextLevelOverlappingBytes(20 * 1048576) + h.compactRangeAt(0, "", "") + h.waitCompaction() + h.maxNextLevelOverlappingBytes(20 * 1048576) + h.compactRangeAt(1, "", "") + h.waitCompaction() + h.maxNextLevelOverlappingBytes(20 * 1048576) +} + +func TestDB_SizeOf(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + Compression: opt.NoCompression, + WriteBuffer: 10000000, + }) + defer h.close() + + h.sizeAssert("", "xyz", 0, 0) + h.reopenDB() + h.sizeAssert("", "xyz", 0, 0) + + // Write 8MB (80 values, each 100K) + n := 80 + s1 := 100000 + s2 := 105000 + + for i := 0; i < n; i++ { + h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), s1/10)) + } + + // 0 because SizeOf() does not account for memtable space + h.sizeAssert("", numKey(50), 0, 0) + + for r := 0; r < 3; r++ { + h.reopenDB() + + for cs := 0; cs < n; cs += 10 { + for i := 0; i < n; i += 10 { + h.sizeAssert("", numKey(i), uint64(s1*i), uint64(s2*i)) + h.sizeAssert("", numKey(i)+".suffix", uint64(s1*(i+1)), uint64(s2*(i+1))) + h.sizeAssert(numKey(i), numKey(i+10), uint64(s1*10), uint64(s2*10)) + } + + h.sizeAssert("", numKey(50), uint64(s1*50), uint64(s2*50)) + h.sizeAssert("", numKey(50)+".suffix", uint64(s1*50), uint64(s2*50)) + + h.compactRangeAt(0, numKey(cs), numKey(cs+9)) + } + + v := h.db.s.version() + if v.tLen(0) != 0 { + t.Errorf("level-0 tables was not zero, got %d", v.tLen(0)) + } + if v.tLen(1) == 0 { + t.Error("level-1 tables was zero") + } + v.release() + } +} + +func TestDB_SizeOf_MixOfSmallAndLarge(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{Compression: opt.NoCompression}) + defer h.close() + + sizes := []uint64{ + 10000, + 10000, + 100000, + 10000, + 100000, + 10000, + 300000, + 10000, + } + + for i, n := range sizes { + h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), int(n)/10)) + } + + for r := 0; r < 3; r++ { + h.reopenDB() + + var x uint64 + for i, n := range sizes { + y := x + if i > 0 { + y += 1000 + } + h.sizeAssert("", numKey(i), x, y) + x += n + } + + h.sizeAssert(numKey(3), numKey(5), 110000, 111000) + + h.compactRangeAt(0, "", "") + } +} + +func TestDB_Snapshot(t *testing.T) { + trun(t, func(h *dbHarness) { + h.put("foo", "v1") + s1 := h.getSnapshot() + h.put("foo", "v2") + s2 := h.getSnapshot() + h.put("foo", "v3") + s3 := h.getSnapshot() + h.put("foo", "v4") + + h.getValr(s1, "foo", "v1") + h.getValr(s2, "foo", "v2") + h.getValr(s3, "foo", "v3") + h.getVal("foo", "v4") + + s3.Release() + h.getValr(s1, "foo", "v1") + h.getValr(s2, "foo", "v2") + h.getVal("foo", "v4") + + s1.Release() + h.getValr(s2, "foo", "v2") + h.getVal("foo", "v4") + + s2.Release() + h.getVal("foo", "v4") + }) +} + +func TestDB_SnapshotList(t *testing.T) { + db := &DB{snapsList: list.New()} + e0a := db.acquireSnapshot() + e0b := db.acquireSnapshot() + db.seq = 1 + e1 := db.acquireSnapshot() + db.seq = 2 + e2 := db.acquireSnapshot() + + if db.minSeq() != 0 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } + db.releaseSnapshot(e0a) + if db.minSeq() != 0 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } + db.releaseSnapshot(e2) + if db.minSeq() != 0 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } + db.releaseSnapshot(e0b) + if db.minSeq() != 1 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } + e2 = db.acquireSnapshot() + if db.minSeq() != 1 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } + db.releaseSnapshot(e1) + if db.minSeq() != 2 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } + db.releaseSnapshot(e2) + if db.minSeq() != 2 { + t.Fatalf("invalid sequence number, got=%d", db.minSeq()) + } +} + +func TestDB_HiddenValuesAreRemoved(t *testing.T) { + trun(t, func(h *dbHarness) { + s := h.db.s + + h.put("foo", "v1") + h.compactMem() + m := h.o.GetMaxMemCompationLevel() + v := s.version() + num := v.tLen(m) + v.release() + if num != 1 { + t.Errorf("invalid level-%d len, want=1 got=%d", m, num) + } + + // Place a table at level last-1 to prevent merging with preceding mutation + h.put("a", "begin") + h.put("z", "end") + h.compactMem() + v = s.version() + if v.tLen(m) != 1 { + t.Errorf("invalid level-%d len, want=1 got=%d", m, v.tLen(m)) + } + if v.tLen(m-1) != 1 { + t.Errorf("invalid level-%d len, want=1 got=%d", m-1, v.tLen(m-1)) + } + v.release() + + h.delete("foo") + h.put("foo", "v2") + h.allEntriesFor("foo", "[ v2, DEL, v1 ]") + h.compactMem() + h.allEntriesFor("foo", "[ v2, DEL, v1 ]") + h.compactRangeAt(m-2, "", "z") + // DEL eliminated, but v1 remains because we aren't compacting that level + // (DEL can be eliminated because v2 hides v1). + h.allEntriesFor("foo", "[ v2, v1 ]") + h.compactRangeAt(m-1, "", "") + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + h.allEntriesFor("foo", "[ v2 ]") + }) +} + +func TestDB_DeletionMarkers2(t *testing.T) { + h := newDbHarness(t) + defer h.close() + s := h.db.s + + h.put("foo", "v1") + h.compactMem() + m := h.o.GetMaxMemCompationLevel() + v := s.version() + num := v.tLen(m) + v.release() + if num != 1 { + t.Errorf("invalid level-%d len, want=1 got=%d", m, num) + } + + // Place a table at level last-1 to prevent merging with preceding mutation + h.put("a", "begin") + h.put("z", "end") + h.compactMem() + v = s.version() + if v.tLen(m) != 1 { + t.Errorf("invalid level-%d len, want=1 got=%d", m, v.tLen(m)) + } + if v.tLen(m-1) != 1 { + t.Errorf("invalid level-%d len, want=1 got=%d", m-1, v.tLen(m-1)) + } + v.release() + + h.delete("foo") + h.allEntriesFor("foo", "[ DEL, v1 ]") + h.compactMem() // Moves to level last-2 + h.allEntriesFor("foo", "[ DEL, v1 ]") + h.compactRangeAt(m-2, "", "") + // DEL kept: "last" file overlaps + h.allEntriesFor("foo", "[ DEL, v1 ]") + h.compactRangeAt(m-1, "", "") + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + h.allEntriesFor("foo", "[ ]") +} + +func TestDB_CompactionTableOpenError(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{OpenFilesCacheCapacity: -1}) + defer h.close() + + im := 10 + jm := 10 + for r := 0; r < 2; r++ { + for i := 0; i < im; i++ { + for j := 0; j < jm; j++ { + h.put(fmt.Sprintf("k%d,%d", i, j), fmt.Sprintf("v%d,%d", i, j)) + } + h.compactMem() + } + } + + if n := h.totalTables(); n != im*2 { + t.Errorf("total tables is %d, want %d", n, im) + } + + h.stor.SetEmuErr(storage.TypeTable, tsOpOpen) + go h.db.CompactRange(util.Range{}) + if err := h.db.compSendIdle(h.db.tcompCmdC); err != nil { + t.Log("compaction error: ", err) + } + h.closeDB0() + h.openDB() + h.stor.SetEmuErr(0, tsOpOpen) + + for i := 0; i < im; i++ { + for j := 0; j < jm; j++ { + h.getVal(fmt.Sprintf("k%d,%d", i, j), fmt.Sprintf("v%d,%d", i, j)) + } + } +} + +func TestDB_OverlapInLevel0(t *testing.T) { + trun(t, func(h *dbHarness) { + if h.o.GetMaxMemCompationLevel() != 2 { + t.Fatal("fix test to reflect the config") + } + + // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. + h.put("100", "v100") + h.put("999", "v999") + h.compactMem() + h.delete("100") + h.delete("999") + h.compactMem() + h.tablesPerLevel("0,1,1") + + // Make files spanning the following ranges in level-0: + // files[0] 200 .. 900 + // files[1] 300 .. 500 + // Note that files are sorted by min key. + h.put("300", "v300") + h.put("500", "v500") + h.compactMem() + h.put("200", "v200") + h.put("600", "v600") + h.put("900", "v900") + h.compactMem() + h.tablesPerLevel("2,1,1") + + // Compact away the placeholder files we created initially + h.compactRangeAt(1, "", "") + h.compactRangeAt(2, "", "") + h.tablesPerLevel("2") + + // Do a memtable compaction. Before bug-fix, the compaction would + // not detect the overlap with level-0 files and would incorrectly place + // the deletion in a deeper level. + h.delete("600") + h.compactMem() + h.tablesPerLevel("3") + h.get("600", false) + }) +} + +func TestDB_L0_CompactionBug_Issue44_a(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.reopenDB() + h.put("b", "v") + h.reopenDB() + h.delete("b") + h.delete("a") + h.reopenDB() + h.delete("a") + h.reopenDB() + h.put("a", "v") + h.reopenDB() + h.reopenDB() + h.getKeyVal("(a->v)") + h.waitCompaction() + h.getKeyVal("(a->v)") +} + +func TestDB_L0_CompactionBug_Issue44_b(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.reopenDB() + h.put("", "") + h.reopenDB() + h.delete("e") + h.put("", "") + h.reopenDB() + h.put("c", "cv") + h.reopenDB() + h.put("", "") + h.reopenDB() + h.put("", "") + h.waitCompaction() + h.reopenDB() + h.put("d", "dv") + h.reopenDB() + h.put("", "") + h.reopenDB() + h.delete("d") + h.delete("b") + h.reopenDB() + h.getKeyVal("(->)(c->cv)") + h.waitCompaction() + h.getKeyVal("(->)(c->cv)") +} + +func TestDB_SingleEntryMemCompaction(t *testing.T) { + trun(t, func(h *dbHarness) { + for i := 0; i < 10; i++ { + h.put("big", strings.Repeat("v", opt.DefaultWriteBuffer)) + h.compactMem() + h.put("key", strings.Repeat("v", opt.DefaultBlockSize)) + h.compactMem() + h.put("k", "v") + h.compactMem() + h.put("", "") + h.compactMem() + h.put("verybig", strings.Repeat("v", opt.DefaultWriteBuffer*2)) + h.compactMem() + } + }) +} + +func TestDB_ManifestWriteError(t *testing.T) { + for i := 0; i < 2; i++ { + func() { + h := newDbHarness(t) + defer h.close() + + h.put("foo", "bar") + h.getVal("foo", "bar") + + // Mem compaction (will succeed) + h.compactMem() + h.getVal("foo", "bar") + v := h.db.s.version() + if n := v.tLen(h.o.GetMaxMemCompationLevel()); n != 1 { + t.Errorf("invalid total tables, want=1 got=%d", n) + } + v.release() + + if i == 0 { + h.stor.SetEmuErr(storage.TypeManifest, tsOpWrite) + } else { + h.stor.SetEmuErr(storage.TypeManifest, tsOpSync) + } + + // Merging compaction (will fail) + h.compactRangeAtErr(h.o.GetMaxMemCompationLevel(), "", "", true) + + h.db.Close() + h.stor.SetEmuErr(0, tsOpWrite) + h.stor.SetEmuErr(0, tsOpSync) + + // Should not lose data + h.openDB() + h.getVal("foo", "bar") + }() + } +} + +func assertErr(t *testing.T, err error, wanterr bool) { + if err != nil { + if wanterr { + t.Log("AssertErr: got error (expected): ", err) + } else { + t.Error("AssertErr: got error: ", err) + } + } else if wanterr { + t.Error("AssertErr: expect error") + } +} + +func TestDB_ClosedIsClosed(t *testing.T) { + h := newDbHarness(t) + db := h.db + + var iter, iter2 iterator.Iterator + var snap *Snapshot + func() { + defer h.close() + + h.put("k", "v") + h.getVal("k", "v") + + iter = db.NewIterator(nil, h.ro) + iter.Seek([]byte("k")) + testKeyVal(t, iter, "k->v") + + var err error + snap, err = db.GetSnapshot() + if err != nil { + t.Fatal("GetSnapshot: got error: ", err) + } + + h.getValr(snap, "k", "v") + + iter2 = snap.NewIterator(nil, h.ro) + iter2.Seek([]byte("k")) + testKeyVal(t, iter2, "k->v") + + h.put("foo", "v2") + h.delete("foo") + + // closing DB + iter.Release() + iter2.Release() + }() + + assertErr(t, db.Put([]byte("x"), []byte("y"), h.wo), true) + _, err := db.Get([]byte("k"), h.ro) + assertErr(t, err, true) + + if iter.Valid() { + t.Errorf("iter.Valid should false") + } + assertErr(t, iter.Error(), false) + testKeyVal(t, iter, "->") + if iter.Seek([]byte("k")) { + t.Errorf("iter.Seek should false") + } + assertErr(t, iter.Error(), true) + + assertErr(t, iter2.Error(), false) + + _, err = snap.Get([]byte("k"), h.ro) + assertErr(t, err, true) + + _, err = db.GetSnapshot() + assertErr(t, err, true) + + iter3 := db.NewIterator(nil, h.ro) + assertErr(t, iter3.Error(), true) + + iter3 = snap.NewIterator(nil, h.ro) + assertErr(t, iter3.Error(), true) + + assertErr(t, db.Delete([]byte("k"), h.wo), true) + + _, err = db.GetProperty("leveldb.stats") + assertErr(t, err, true) + + _, err = db.SizeOf([]util.Range{{[]byte("a"), []byte("z")}}) + assertErr(t, err, true) + + assertErr(t, db.CompactRange(util.Range{}), true) + + assertErr(t, db.Close(), true) +} + +type numberComparer struct{} + +func (numberComparer) num(x []byte) (n int) { + fmt.Sscan(string(x[1:len(x)-1]), &n) + return +} + +func (numberComparer) Name() string { + return "test.NumberComparer" +} + +func (p numberComparer) Compare(a, b []byte) int { + return p.num(a) - p.num(b) +} + +func (numberComparer) Separator(dst, a, b []byte) []byte { return nil } +func (numberComparer) Successor(dst, b []byte) []byte { return nil } + +func TestDB_CustomComparer(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + Comparer: numberComparer{}, + WriteBuffer: 1000, + }) + defer h.close() + + h.put("[10]", "ten") + h.put("[0x14]", "twenty") + for i := 0; i < 2; i++ { + h.getVal("[10]", "ten") + h.getVal("[0xa]", "ten") + h.getVal("[20]", "twenty") + h.getVal("[0x14]", "twenty") + h.get("[15]", false) + h.get("[0xf]", false) + h.compactMem() + h.compactRange("[0]", "[9999]") + } + + for n := 0; n < 2; n++ { + for i := 0; i < 100; i++ { + v := fmt.Sprintf("[%d]", i*10) + h.put(v, v) + } + h.compactMem() + h.compactRange("[0]", "[1000000]") + } +} + +func TestDB_ManualCompaction(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + if h.o.GetMaxMemCompationLevel() != 2 { + t.Fatal("fix test to reflect the config") + } + + h.putMulti(3, "p", "q") + h.tablesPerLevel("1,1,1") + + // Compaction range falls before files + h.compactRange("", "c") + h.tablesPerLevel("1,1,1") + + // Compaction range falls after files + h.compactRange("r", "z") + h.tablesPerLevel("1,1,1") + + // Compaction range overlaps files + h.compactRange("p1", "p9") + h.tablesPerLevel("0,0,1") + + // Populate a different range + h.putMulti(3, "c", "e") + h.tablesPerLevel("1,1,2") + + // Compact just the new range + h.compactRange("b", "f") + h.tablesPerLevel("0,0,2") + + // Compact all + h.putMulti(1, "a", "z") + h.tablesPerLevel("0,1,2") + h.compactRange("", "") + h.tablesPerLevel("0,0,1") +} + +func TestDB_BloomFilter(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + DisableBlockCache: true, + Filter: filter.NewBloomFilter(10), + }) + defer h.close() + + key := func(i int) string { + return fmt.Sprintf("key%06d", i) + } + + const n = 10000 + + // Populate multiple layers + for i := 0; i < n; i++ { + h.put(key(i), key(i)) + } + h.compactMem() + h.compactRange("a", "z") + for i := 0; i < n; i += 100 { + h.put(key(i), key(i)) + } + h.compactMem() + + // Prevent auto compactions triggered by seeks + h.stor.DelaySync(storage.TypeTable) + + // Lookup present keys. Should rarely read from small sstable. + h.stor.SetReadCounter(storage.TypeTable) + for i := 0; i < n; i++ { + h.getVal(key(i), key(i)) + } + cnt := int(h.stor.ReadCounter()) + t.Logf("lookup of %d present keys yield %d sstable I/O reads", n, cnt) + + if min, max := n, n+2*n/100; cnt < min || cnt > max { + t.Errorf("num of sstable I/O reads of present keys not in range of %d - %d, got %d", min, max, cnt) + } + + // Lookup missing keys. Should rarely read from either sstable. + h.stor.ResetReadCounter() + for i := 0; i < n; i++ { + h.get(key(i)+".missing", false) + } + cnt = int(h.stor.ReadCounter()) + t.Logf("lookup of %d missing keys yield %d sstable I/O reads", n, cnt) + if max := 3 * n / 100; cnt > max { + t.Errorf("num of sstable I/O reads of missing keys was more than %d, got %d", max, cnt) + } + + h.stor.ReleaseSync(storage.TypeTable) +} + +func TestDB_Concurrent(t *testing.T) { + const n, secs, maxkey = 4, 2, 1000 + + runtime.GOMAXPROCS(n) + trun(t, func(h *dbHarness) { + var closeWg sync.WaitGroup + var stop uint32 + var cnt [n]uint32 + + for i := 0; i < n; i++ { + closeWg.Add(1) + go func(i int) { + var put, get, found uint + defer func() { + t.Logf("goroutine %d stopped after %d ops, put=%d get=%d found=%d missing=%d", + i, cnt[i], put, get, found, get-found) + closeWg.Done() + }() + + rnd := rand.New(rand.NewSource(int64(1000 + i))) + for atomic.LoadUint32(&stop) == 0 { + x := cnt[i] + + k := rnd.Intn(maxkey) + kstr := fmt.Sprintf("%016d", k) + + if (rnd.Int() % 2) > 0 { + put++ + h.put(kstr, fmt.Sprintf("%d.%d.%-1000d", k, i, x)) + } else { + get++ + v, err := h.db.Get([]byte(kstr), h.ro) + if err == nil { + found++ + rk, ri, rx := 0, -1, uint32(0) + fmt.Sscanf(string(v), "%d.%d.%d", &rk, &ri, &rx) + if rk != k { + t.Errorf("invalid key want=%d got=%d", k, rk) + } + if ri < 0 || ri >= n { + t.Error("invalid goroutine number: ", ri) + } else { + tx := atomic.LoadUint32(&(cnt[ri])) + if rx > tx { + t.Errorf("invalid seq number, %d > %d ", rx, tx) + } + } + } else if err != ErrNotFound { + t.Error("Get: got error: ", err) + return + } + } + atomic.AddUint32(&cnt[i], 1) + } + }(i) + } + + time.Sleep(secs * time.Second) + atomic.StoreUint32(&stop, 1) + closeWg.Wait() + }) + + runtime.GOMAXPROCS(1) +} + +func TestDB_Concurrent2(t *testing.T) { + const n, n2 = 4, 4000 + + runtime.GOMAXPROCS(n*2 + 2) + truno(t, &opt.Options{WriteBuffer: 30}, func(h *dbHarness) { + var closeWg sync.WaitGroup + var stop uint32 + + for i := 0; i < n; i++ { + closeWg.Add(1) + go func(i int) { + for k := 0; atomic.LoadUint32(&stop) == 0; k++ { + h.put(fmt.Sprintf("k%d", k), fmt.Sprintf("%d.%d.", k, i)+strings.Repeat("x", 10)) + } + closeWg.Done() + }(i) + } + + for i := 0; i < n; i++ { + closeWg.Add(1) + go func(i int) { + for k := 1000000; k < 0 || atomic.LoadUint32(&stop) == 0; k-- { + h.put(fmt.Sprintf("k%d", k), fmt.Sprintf("%d.%d.", k, i)+strings.Repeat("x", 10)) + } + closeWg.Done() + }(i) + } + + cmp := comparer.DefaultComparer + for i := 0; i < n2; i++ { + closeWg.Add(1) + go func(i int) { + it := h.db.NewIterator(nil, nil) + var pk []byte + for it.Next() { + kk := it.Key() + if cmp.Compare(kk, pk) <= 0 { + t.Errorf("iter %d: %q is successor of %q", i, pk, kk) + } + pk = append(pk[:0], kk...) + var k, vk, vi int + if n, err := fmt.Sscanf(string(it.Key()), "k%d", &k); err != nil { + t.Errorf("iter %d: Scanf error on key %q: %v", i, it.Key(), err) + } else if n < 1 { + t.Errorf("iter %d: Cannot parse key %q", i, it.Key()) + } + if n, err := fmt.Sscanf(string(it.Value()), "%d.%d", &vk, &vi); err != nil { + t.Errorf("iter %d: Scanf error on value %q: %v", i, it.Value(), err) + } else if n < 2 { + t.Errorf("iter %d: Cannot parse value %q", i, it.Value()) + } + + if vk != k { + t.Errorf("iter %d: invalid value i=%d, want=%d got=%d", i, vi, k, vk) + } + } + if err := it.Error(); err != nil { + t.Errorf("iter %d: Got error: %v", i, err) + } + it.Release() + closeWg.Done() + }(i) + } + + atomic.StoreUint32(&stop, 1) + closeWg.Wait() + }) + + runtime.GOMAXPROCS(1) +} + +func TestDB_CreateReopenDbOnFile(t *testing.T) { + dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestCreateReopenDbOnFile-%d", os.Getuid())) + if err := os.RemoveAll(dbpath); err != nil { + t.Fatal("cannot remove old db: ", err) + } + defer os.RemoveAll(dbpath) + + for i := 0; i < 3; i++ { + stor, err := storage.OpenFile(dbpath) + if err != nil { + t.Fatalf("(%d) cannot open storage: %s", i, err) + } + db, err := Open(stor, nil) + if err != nil { + t.Fatalf("(%d) cannot open db: %s", i, err) + } + if err := db.Put([]byte("foo"), []byte("bar"), nil); err != nil { + t.Fatalf("(%d) cannot write to db: %s", i, err) + } + if err := db.Close(); err != nil { + t.Fatalf("(%d) cannot close db: %s", i, err) + } + if err := stor.Close(); err != nil { + t.Fatalf("(%d) cannot close storage: %s", i, err) + } + } +} + +func TestDB_CreateReopenDbOnFile2(t *testing.T) { + dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestCreateReopenDbOnFile2-%d", os.Getuid())) + if err := os.RemoveAll(dbpath); err != nil { + t.Fatal("cannot remove old db: ", err) + } + defer os.RemoveAll(dbpath) + + for i := 0; i < 3; i++ { + db, err := OpenFile(dbpath, nil) + if err != nil { + t.Fatalf("(%d) cannot open db: %s", i, err) + } + if err := db.Put([]byte("foo"), []byte("bar"), nil); err != nil { + t.Fatalf("(%d) cannot write to db: %s", i, err) + } + if err := db.Close(); err != nil { + t.Fatalf("(%d) cannot close db: %s", i, err) + } + } +} + +func TestDB_DeletionMarkersOnMemdb(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.put("foo", "v1") + h.compactMem() + h.delete("foo") + h.get("foo", false) + h.getKeyVal("") +} + +func TestDB_LeveldbIssue178(t *testing.T) { + nKeys := (opt.DefaultCompactionTableSize / 30) * 5 + key1 := func(i int) string { + return fmt.Sprintf("my_key_%d", i) + } + key2 := func(i int) string { + return fmt.Sprintf("my_key_%d_xxx", i) + } + + // Disable compression since it affects the creation of layers and the + // code below is trying to test against a very specific scenario. + h := newDbHarnessWopt(t, &opt.Options{Compression: opt.NoCompression}) + defer h.close() + + // Create first key range. + batch := new(Batch) + for i := 0; i < nKeys; i++ { + batch.Put([]byte(key1(i)), []byte("value for range 1 key")) + } + h.write(batch) + + // Create second key range. + batch.Reset() + for i := 0; i < nKeys; i++ { + batch.Put([]byte(key2(i)), []byte("value for range 2 key")) + } + h.write(batch) + + // Delete second key range. + batch.Reset() + for i := 0; i < nKeys; i++ { + batch.Delete([]byte(key2(i))) + } + h.write(batch) + h.waitMemCompaction() + + // Run manual compaction. + h.compactRange(key1(0), key1(nKeys-1)) + + // Checking the keys. + h.assertNumKeys(nKeys) +} + +func TestDB_LeveldbIssue200(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + h.put("1", "b") + h.put("2", "c") + h.put("3", "d") + h.put("4", "e") + h.put("5", "f") + + iter := h.db.NewIterator(nil, h.ro) + + // Add an element that should not be reflected in the iterator. + h.put("25", "cd") + + iter.Seek([]byte("5")) + assertBytes(t, []byte("5"), iter.Key()) + iter.Prev() + assertBytes(t, []byte("4"), iter.Key()) + iter.Prev() + assertBytes(t, []byte("3"), iter.Key()) + iter.Next() + assertBytes(t, []byte("4"), iter.Key()) + iter.Next() + assertBytes(t, []byte("5"), iter.Key()) +} + +func TestDB_GoleveldbIssue74(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + WriteBuffer: 1 * opt.MiB, + }) + defer h.close() + + const n, dur = 10000, 5 * time.Second + + runtime.GOMAXPROCS(runtime.NumCPU()) + + until := time.Now().Add(dur) + wg := new(sync.WaitGroup) + wg.Add(2) + var done uint32 + go func() { + var i int + defer func() { + t.Logf("WRITER DONE #%d", i) + atomic.StoreUint32(&done, 1) + wg.Done() + }() + + b := new(Batch) + for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { + iv := fmt.Sprintf("VAL%010d", i) + for k := 0; k < n; k++ { + key := fmt.Sprintf("KEY%06d", k) + b.Put([]byte(key), []byte(key+iv)) + b.Put([]byte(fmt.Sprintf("PTR%06d", k)), []byte(key)) + } + h.write(b) + + b.Reset() + snap := h.getSnapshot() + iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil) + var k int + for ; iter.Next(); k++ { + ptrKey := iter.Key() + key := iter.Value() + + if _, err := snap.Get(ptrKey, nil); err != nil { + t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, ptrKey, err) + } + if value, err := snap.Get(key, nil); err != nil { + t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, key, err) + } else if string(value) != string(key)+iv { + t.Fatalf("WRITER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+iv, value) + } + + b.Delete(key) + b.Delete(ptrKey) + } + h.write(b) + iter.Release() + snap.Release() + if k != n { + t.Fatalf("#%d %d != %d", i, k, n) + } + } + }() + go func() { + var i int + defer func() { + t.Logf("READER DONE #%d", i) + atomic.StoreUint32(&done, 1) + wg.Done() + }() + for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { + snap := h.getSnapshot() + iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil) + var prevValue string + var k int + for ; iter.Next(); k++ { + ptrKey := iter.Key() + key := iter.Value() + + if _, err := snap.Get(ptrKey, nil); err != nil { + t.Fatalf("READER #%d snapshot.Get %q: %v", i, ptrKey, err) + } + + if value, err := snap.Get(key, nil); err != nil { + t.Fatalf("READER #%d snapshot.Get %q: %v", i, key, err) + } else if prevValue != "" && string(value) != string(key)+prevValue { + t.Fatalf("READER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+prevValue, value) + } else { + prevValue = string(value[len(key):]) + } + } + iter.Release() + snap.Release() + if k > 0 && k != n { + t.Fatalf("#%d %d != %d", i, k, n) + } + } + }() + wg.Wait() +} + +func TestDB_GetProperties(t *testing.T) { + h := newDbHarness(t) + defer h.close() + + _, err := h.db.GetProperty("leveldb.num-files-at-level") + if err == nil { + t.Error("GetProperty() failed to detect missing level") + } + + _, err = h.db.GetProperty("leveldb.num-files-at-level0") + if err != nil { + t.Error("got unexpected error", err) + } + + _, err = h.db.GetProperty("leveldb.num-files-at-level0x") + if err == nil { + t.Error("GetProperty() failed to detect invalid level") + } +} + +func TestDB_GoleveldbIssue72and83(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + WriteBuffer: 1 * opt.MiB, + OpenFilesCacheCapacity: 3, + }) + defer h.close() + + const n, wn, dur = 10000, 100, 30 * time.Second + + runtime.GOMAXPROCS(runtime.NumCPU()) + + randomData := func(prefix byte, i int) []byte { + data := make([]byte, 1+4+32+64+32) + _, err := crand.Reader.Read(data[1 : len(data)-8]) + if err != nil { + panic(err) + } + data[0] = prefix + binary.LittleEndian.PutUint32(data[len(data)-8:], uint32(i)) + binary.LittleEndian.PutUint32(data[len(data)-4:], util.NewCRC(data[:len(data)-4]).Value()) + return data + } + + keys := make([][]byte, n) + for i := range keys { + keys[i] = randomData(1, 0) + } + + until := time.Now().Add(dur) + wg := new(sync.WaitGroup) + wg.Add(3) + var done uint32 + go func() { + i := 0 + defer func() { + t.Logf("WRITER DONE #%d", i) + wg.Done() + }() + + b := new(Batch) + for ; i < wn && atomic.LoadUint32(&done) == 0; i++ { + b.Reset() + for _, k1 := range keys { + k2 := randomData(2, i) + b.Put(k2, randomData(42, i)) + b.Put(k1, k2) + } + if err := h.db.Write(b, h.wo); err != nil { + atomic.StoreUint32(&done, 1) + t.Fatalf("WRITER #%d db.Write: %v", i, err) + } + } + }() + go func() { + var i int + defer func() { + t.Logf("READER0 DONE #%d", i) + atomic.StoreUint32(&done, 1) + wg.Done() + }() + for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { + snap := h.getSnapshot() + seq := snap.elem.seq + if seq == 0 { + snap.Release() + continue + } + iter := snap.NewIterator(util.BytesPrefix([]byte{1}), nil) + writei := int(seq/(n*2) - 1) + var k int + for ; iter.Next(); k++ { + k1 := iter.Key() + k2 := iter.Value() + k1checksum0 := binary.LittleEndian.Uint32(k1[len(k1)-4:]) + k1checksum1 := util.NewCRC(k1[:len(k1)-4]).Value() + if k1checksum0 != k1checksum1 { + t.Fatalf("READER0 #%d.%d W#%d invalid K1 checksum: %#x != %#x", i, k, k1checksum0, k1checksum0) + } + k2checksum0 := binary.LittleEndian.Uint32(k2[len(k2)-4:]) + k2checksum1 := util.NewCRC(k2[:len(k2)-4]).Value() + if k2checksum0 != k2checksum1 { + t.Fatalf("READER0 #%d.%d W#%d invalid K2 checksum: %#x != %#x", i, k, k2checksum0, k2checksum1) + } + kwritei := int(binary.LittleEndian.Uint32(k2[len(k2)-8:])) + if writei != kwritei { + t.Fatalf("READER0 #%d.%d W#%d invalid write iteration num: %d", i, k, writei, kwritei) + } + if _, err := snap.Get(k2, nil); err != nil { + t.Fatalf("READER0 #%d.%d W#%d snap.Get: %v\nk1: %x\n -> k2: %x", i, k, writei, err, k1, k2) + } + } + if err := iter.Error(); err != nil { + t.Fatalf("READER0 #%d.%d W#%d snap.Iterator: %v", i, k, writei, err) + } + iter.Release() + snap.Release() + if k > 0 && k != n { + t.Fatalf("READER0 #%d W#%d short read, got=%d want=%d", i, writei, k, n) + } + } + }() + go func() { + var i int + defer func() { + t.Logf("READER1 DONE #%d", i) + atomic.StoreUint32(&done, 1) + wg.Done() + }() + for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { + iter := h.db.NewIterator(nil, nil) + seq := iter.(*dbIter).seq + if seq == 0 { + iter.Release() + continue + } + writei := int(seq/(n*2) - 1) + var k int + for ok := iter.Last(); ok; ok = iter.Prev() { + k++ + } + if err := iter.Error(); err != nil { + t.Fatalf("READER1 #%d.%d W#%d db.Iterator: %v", i, k, writei, err) + } + iter.Release() + if m := (writei+1)*n + n; k != m { + t.Fatalf("READER1 #%d W#%d short read, got=%d want=%d", i, writei, k, m) + } + } + }() + + wg.Wait() +} + +func TestDB_TransientError(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + WriteBuffer: 128 * opt.KiB, + OpenFilesCacheCapacity: 3, + DisableCompactionBackoff: true, + }) + defer h.close() + + const ( + nSnap = 20 + nKey = 10000 + ) + + var ( + snaps [nSnap]*Snapshot + b = &Batch{} + ) + for i := range snaps { + vtail := fmt.Sprintf("VAL%030d", i) + b.Reset() + for k := 0; k < nKey; k++ { + key := fmt.Sprintf("KEY%8d", k) + b.Put([]byte(key), []byte(key+vtail)) + } + h.stor.SetEmuRandErr(storage.TypeTable, tsOpOpen, tsOpRead, tsOpReadAt) + if err := h.db.Write(b, nil); err != nil { + t.Logf("WRITE #%d error: %v", i, err) + h.stor.SetEmuRandErr(0, tsOpOpen, tsOpRead, tsOpReadAt, tsOpWrite) + for { + if err := h.db.Write(b, nil); err == nil { + break + } else if errors.IsCorrupted(err) { + t.Fatalf("WRITE #%d corrupted: %v", i, err) + } + } + } + + snaps[i] = h.db.newSnapshot() + b.Reset() + for k := 0; k < nKey; k++ { + key := fmt.Sprintf("KEY%8d", k) + b.Delete([]byte(key)) + } + h.stor.SetEmuRandErr(storage.TypeTable, tsOpOpen, tsOpRead, tsOpReadAt) + if err := h.db.Write(b, nil); err != nil { + t.Logf("WRITE #%d error: %v", i, err) + h.stor.SetEmuRandErr(0, tsOpOpen, tsOpRead, tsOpReadAt) + for { + if err := h.db.Write(b, nil); err == nil { + break + } else if errors.IsCorrupted(err) { + t.Fatalf("WRITE #%d corrupted: %v", i, err) + } + } + } + } + h.stor.SetEmuRandErr(0, tsOpOpen, tsOpRead, tsOpReadAt) + + runtime.GOMAXPROCS(runtime.NumCPU()) + + rnd := rand.New(rand.NewSource(0xecafdaed)) + wg := &sync.WaitGroup{} + for i, snap := range snaps { + wg.Add(2) + + go func(i int, snap *Snapshot, sk []int) { + defer wg.Done() + + vtail := fmt.Sprintf("VAL%030d", i) + for _, k := range sk { + key := fmt.Sprintf("KEY%8d", k) + xvalue, err := snap.Get([]byte(key), nil) + if err != nil { + t.Fatalf("READER_GET #%d SEQ=%d K%d error: %v", i, snap.elem.seq, k, err) + } + value := key + vtail + if !bytes.Equal([]byte(value), xvalue) { + t.Fatalf("READER_GET #%d SEQ=%d K%d invalid value: want %q, got %q", i, snap.elem.seq, k, value, xvalue) + } + } + }(i, snap, rnd.Perm(nKey)) + + go func(i int, snap *Snapshot) { + defer wg.Done() + + vtail := fmt.Sprintf("VAL%030d", i) + iter := snap.NewIterator(nil, nil) + defer iter.Release() + for k := 0; k < nKey; k++ { + if !iter.Next() { + if err := iter.Error(); err != nil { + t.Fatalf("READER_ITER #%d K%d error: %v", i, k, err) + } else { + t.Fatalf("READER_ITER #%d K%d eoi", i, k) + } + } + key := fmt.Sprintf("KEY%8d", k) + xkey := iter.Key() + if !bytes.Equal([]byte(key), xkey) { + t.Fatalf("READER_ITER #%d K%d invalid key: want %q, got %q", i, k, key, xkey) + } + value := key + vtail + xvalue := iter.Value() + if !bytes.Equal([]byte(value), xvalue) { + t.Fatalf("READER_ITER #%d K%d invalid value: want %q, got %q", i, k, value, xvalue) + } + } + }(i, snap) + } + + wg.Wait() +} + +func TestDB_UkeyShouldntHopAcrossTable(t *testing.T) { + h := newDbHarnessWopt(t, &opt.Options{ + WriteBuffer: 112 * opt.KiB, + CompactionTableSize: 90 * opt.KiB, + CompactionExpandLimitFactor: 1, + }) + defer h.close() + + const ( + nSnap = 190 + nKey = 140 + ) + + var ( + snaps [nSnap]*Snapshot + b = &Batch{} + ) + for i := range snaps { + vtail := fmt.Sprintf("VAL%030d", i) + b.Reset() + for k := 0; k < nKey; k++ { + key := fmt.Sprintf("KEY%08d", k) + b.Put([]byte(key), []byte(key+vtail)) + } + if err := h.db.Write(b, nil); err != nil { + t.Fatalf("WRITE #%d error: %v", i, err) + } + + snaps[i] = h.db.newSnapshot() + b.Reset() + for k := 0; k < nKey; k++ { + key := fmt.Sprintf("KEY%08d", k) + b.Delete([]byte(key)) + } + if err := h.db.Write(b, nil); err != nil { + t.Fatalf("WRITE #%d error: %v", i, err) + } + } + + h.compactMem() + + h.waitCompaction() + for level, tables := range h.db.s.stVersion.tables { + for _, table := range tables { + t.Logf("L%d@%d %q:%q", level, table.file.Num(), table.imin, table.imax) + } + } + + h.compactRangeAt(0, "", "") + h.waitCompaction() + for level, tables := range h.db.s.stVersion.tables { + for _, table := range tables { + t.Logf("L%d@%d %q:%q", level, table.file.Num(), table.imin, table.imax) + } + } + h.compactRangeAt(1, "", "") + h.waitCompaction() + for level, tables := range h.db.s.stVersion.tables { + for _, table := range tables { + t.Logf("L%d@%d %q:%q", level, table.file.Num(), table.imin, table.imax) + } + } + runtime.GOMAXPROCS(runtime.NumCPU()) + + wg := &sync.WaitGroup{} + for i, snap := range snaps { + wg.Add(1) + + go func(i int, snap *Snapshot) { + defer wg.Done() + + vtail := fmt.Sprintf("VAL%030d", i) + for k := 0; k < nKey; k++ { + key := fmt.Sprintf("KEY%08d", k) + xvalue, err := snap.Get([]byte(key), nil) + if err != nil { + t.Fatalf("READER_GET #%d SEQ=%d K%d error: %v", i, snap.elem.seq, k, err) + } + value := key + vtail + if !bytes.Equal([]byte(value), xvalue) { + t.Fatalf("READER_GET #%d SEQ=%d K%d invalid value: want %q, got %q", i, snap.elem.seq, k, value, xvalue) + } + } + }(i, snap) + } + + wg.Wait() +} + +func TestDB_TableCompactionBuilder(t *testing.T) { + stor := newTestStorage(t) + defer stor.Close() + + const nSeq = 99 + + o := &opt.Options{ + WriteBuffer: 112 * opt.KiB, + CompactionTableSize: 43 * opt.KiB, + CompactionExpandLimitFactor: 1, + CompactionGPOverlapsFactor: 1, + DisableBlockCache: true, + } + s, err := newSession(stor, o) + if err != nil { + t.Fatal(err) + } + if err := s.create(); err != nil { + t.Fatal(err) + } + defer s.close() + var ( + seq uint64 + targetSize = 5 * o.CompactionTableSize + value = bytes.Repeat([]byte{'0'}, 100) + ) + for i := 0; i < 2; i++ { + tw, err := s.tops.create() + if err != nil { + t.Fatal(err) + } + for k := 0; tw.tw.BytesLen() < targetSize; k++ { + key := []byte(fmt.Sprintf("%09d", k)) + seq += nSeq - 1 + for x := uint64(0); x < nSeq; x++ { + if err := tw.append(newIkey(key, seq-x, ktVal), value); err != nil { + t.Fatal(err) + } + } + } + tf, err := tw.finish() + if err != nil { + t.Fatal(err) + } + rec := &sessionRecord{numLevel: s.o.GetNumLevel()} + rec.addTableFile(i, tf) + if err := s.commit(rec); err != nil { + t.Fatal(err) + } + } + + // Build grandparent. + v := s.version() + c := newCompaction(s, v, 1, append(tFiles{}, v.tables[1]...)) + rec := &sessionRecord{numLevel: s.o.GetNumLevel()} + b := &tableCompactionBuilder{ + s: s, + c: c, + rec: rec, + stat1: new(cStatsStaging), + minSeq: 0, + strict: true, + tableSize: o.CompactionTableSize/3 + 961, + } + if err := b.run(new(compactionTransactCounter)); err != nil { + t.Fatal(err) + } + for _, t := range c.tables[0] { + rec.delTable(c.level, t.file.Num()) + } + if err := s.commit(rec); err != nil { + t.Fatal(err) + } + c.release() + + // Build level-1. + v = s.version() + c = newCompaction(s, v, 0, append(tFiles{}, v.tables[0]...)) + rec = &sessionRecord{numLevel: s.o.GetNumLevel()} + b = &tableCompactionBuilder{ + s: s, + c: c, + rec: rec, + stat1: new(cStatsStaging), + minSeq: 0, + strict: true, + tableSize: o.CompactionTableSize, + } + if err := b.run(new(compactionTransactCounter)); err != nil { + t.Fatal(err) + } + for _, t := range c.tables[0] { + rec.delTable(c.level, t.file.Num()) + } + // Move grandparent to level-3 + for _, t := range v.tables[2] { + rec.delTable(2, t.file.Num()) + rec.addTableFile(3, t) + } + if err := s.commit(rec); err != nil { + t.Fatal(err) + } + c.release() + + v = s.version() + for level, want := range []bool{false, true, false, true, false} { + got := len(v.tables[level]) > 0 + if want != got { + t.Fatalf("invalid level-%d tables len: want %v, got %v", level, want, got) + } + } + for i, f := range v.tables[1][:len(v.tables[1])-1] { + nf := v.tables[1][i+1] + if bytes.Equal(f.imax.ukey(), nf.imin.ukey()) { + t.Fatalf("KEY %q hop across table %d .. %d", f.imax.ukey(), f.file.Num(), nf.file.Num()) + } + } + v.release() + + // Compaction with transient error. + v = s.version() + c = newCompaction(s, v, 1, append(tFiles{}, v.tables[1]...)) + rec = &sessionRecord{numLevel: s.o.GetNumLevel()} + b = &tableCompactionBuilder{ + s: s, + c: c, + rec: rec, + stat1: new(cStatsStaging), + minSeq: 0, + strict: true, + tableSize: o.CompactionTableSize, + } + stor.SetEmuErrOnce(storage.TypeTable, tsOpSync) + stor.SetEmuRandErr(storage.TypeTable, tsOpRead, tsOpReadAt, tsOpWrite) + stor.SetEmuRandErrProb(0xf0) + for { + if err := b.run(new(compactionTransactCounter)); err != nil { + t.Logf("(expected) b.run: %v", err) + } else { + break + } + } + if err := s.commit(rec); err != nil { + t.Fatal(err) + } + c.release() + + stor.SetEmuErrOnce(0, tsOpSync) + stor.SetEmuRandErr(0, tsOpRead, tsOpReadAt, tsOpWrite) + + v = s.version() + if len(v.tables[1]) != len(v.tables[2]) { + t.Fatalf("invalid tables length, want %d, got %d", len(v.tables[1]), len(v.tables[2])) + } + for i, f0 := range v.tables[1] { + f1 := v.tables[2][i] + iter0 := s.tops.newIterator(f0, nil, nil) + iter1 := s.tops.newIterator(f1, nil, nil) + for j := 0; true; j++ { + next0 := iter0.Next() + next1 := iter1.Next() + if next0 != next1 { + t.Fatalf("#%d.%d invalid eoi: want %v, got %v", i, j, next0, next1) + } + key0 := iter0.Key() + key1 := iter1.Key() + if !bytes.Equal(key0, key1) { + t.Fatalf("#%d.%d invalid key: want %q, got %q", i, j, key0, key1) + } + if next0 == false { + break + } + } + iter0.Release() + iter1.Release() + } + v.release() +} + +func testDB_IterTriggeredCompaction(t *testing.T, limitDiv int) { + const ( + vSize = 200 * opt.KiB + tSize = 100 * opt.MiB + mIter = 100 + n = tSize / vSize + ) + + h := newDbHarnessWopt(t, &opt.Options{ + Compression: opt.NoCompression, + DisableBlockCache: true, + }) + defer h.close() + + key := func(x int) string { + return fmt.Sprintf("v%06d", x) + } + + // Fill. + value := strings.Repeat("x", vSize) + for i := 0; i < n; i++ { + h.put(key(i), value) + } + h.compactMem() + + // Delete all. + for i := 0; i < n; i++ { + h.delete(key(i)) + } + h.compactMem() + + var ( + limit = n / limitDiv + + startKey = key(0) + limitKey = key(limit) + maxKey = key(n) + slice = &util.Range{Limit: []byte(limitKey)} + + initialSize0 = h.sizeOf(startKey, limitKey) + initialSize1 = h.sizeOf(limitKey, maxKey) + ) + + t.Logf("inital size %s [rest %s]", shortenb(int(initialSize0)), shortenb(int(initialSize1))) + + for r := 0; true; r++ { + if r >= mIter { + t.Fatal("taking too long to compact") + } + + // Iterates. + iter := h.db.NewIterator(slice, h.ro) + for iter.Next() { + } + if err := iter.Error(); err != nil { + t.Fatalf("Iter err: %v", err) + } + iter.Release() + + // Wait compaction. + h.waitCompaction() + + // Check size. + size0 := h.sizeOf(startKey, limitKey) + size1 := h.sizeOf(limitKey, maxKey) + t.Logf("#%03d size %s [rest %s]", r, shortenb(int(size0)), shortenb(int(size1))) + if size0 < initialSize0/10 { + break + } + } + + if initialSize1 > 0 { + h.sizeAssert(limitKey, maxKey, initialSize1/4-opt.MiB, initialSize1+opt.MiB) + } +} + +func TestDB_IterTriggeredCompaction(t *testing.T) { + testDB_IterTriggeredCompaction(t, 1) +} + +func TestDB_IterTriggeredCompactionHalf(t *testing.T) { + testDB_IterTriggeredCompaction(t, 2) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go new file mode 100644 index 00000000..dd092a45 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go @@ -0,0 +1,100 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +// Reader is the interface that wraps basic Get and NewIterator methods. +// This interface implemented by both DB and Snapshot. +type Reader interface { + Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) + NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator +} + +type Sizes []uint64 + +// Sum returns sum of the sizes. +func (p Sizes) Sum() (n uint64) { + for _, s := range p { + n += s + } + return n +} + +// Logging. +func (db *DB) log(v ...interface{}) { db.s.log(v...) } +func (db *DB) logf(format string, v ...interface{}) { db.s.logf(format, v...) } + +// Check and clean files. +func (db *DB) checkAndCleanFiles() error { + v := db.s.version() + defer v.release() + + tablesMap := make(map[uint64]bool) + for _, tables := range v.tables { + for _, t := range tables { + tablesMap[t.file.Num()] = false + } + } + + files, err := db.s.getFiles(storage.TypeAll) + if err != nil { + return err + } + + var nTables int + var rem []storage.File + for _, f := range files { + keep := true + switch f.Type() { + case storage.TypeManifest: + keep = f.Num() >= db.s.manifestFile.Num() + case storage.TypeJournal: + if db.frozenJournalFile != nil { + keep = f.Num() >= db.frozenJournalFile.Num() + } else { + keep = f.Num() >= db.journalFile.Num() + } + case storage.TypeTable: + _, keep = tablesMap[f.Num()] + if keep { + tablesMap[f.Num()] = true + nTables++ + } + } + + if !keep { + rem = append(rem, f) + } + } + + if nTables != len(tablesMap) { + var missing []*storage.FileInfo + for num, present := range tablesMap { + if !present { + missing = append(missing, &storage.FileInfo{Type: storage.TypeTable, Num: num}) + db.logf("db@janitor table missing @%d", num) + } + } + return errors.NewErrCorrupted(nil, &errors.ErrMissingFiles{Files: missing}) + } + + db.logf("db@janitor F·%d G·%d", len(files), len(rem)) + for _, f := range rem { + db.logf("db@janitor removing %s-%d", f.Type(), f.Num()) + if err := f.Remove(); err != nil { + return err + } + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go new file mode 100644 index 00000000..966b2e6a --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go @@ -0,0 +1,311 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +func (db *DB) writeJournal(b *Batch) error { + w, err := db.journal.Next() + if err != nil { + return err + } + if _, err := w.Write(b.encode()); err != nil { + return err + } + if err := db.journal.Flush(); err != nil { + return err + } + if b.sync { + return db.journalWriter.Sync() + } + return nil +} + +func (db *DB) jWriter() { + defer db.closeW.Done() + for { + select { + case b := <-db.journalC: + if b != nil { + db.journalAckC <- db.writeJournal(b) + } + case _, _ = <-db.closeC: + return + } + } +} + +func (db *DB) rotateMem(n int) (mem *memDB, err error) { + // Wait for pending memdb compaction. + err = db.compSendIdle(db.mcompCmdC) + if err != nil { + return + } + + // Create new memdb and journal. + mem, err = db.newMem(n) + if err != nil { + return + } + + // Schedule memdb compaction. + db.compSendTrigger(db.mcompCmdC) + return +} + +func (db *DB) flush(n int) (mem *memDB, nn int, err error) { + delayed := false + flush := func() (retry bool) { + v := db.s.version() + defer v.release() + mem = db.getEffectiveMem() + defer func() { + if retry { + mem.decref() + mem = nil + } + }() + nn = mem.mdb.Free() + switch { + case v.tLen(0) >= db.s.o.GetWriteL0SlowdownTrigger() && !delayed: + delayed = true + time.Sleep(time.Millisecond) + case nn >= n: + return false + case v.tLen(0) >= db.s.o.GetWriteL0PauseTrigger(): + delayed = true + err = db.compSendIdle(db.tcompCmdC) + if err != nil { + return false + } + default: + // Allow memdb to grow if it has no entry. + if mem.mdb.Len() == 0 { + nn = n + } else { + mem.decref() + mem, err = db.rotateMem(n) + if err == nil { + nn = mem.mdb.Free() + } else { + nn = 0 + } + } + return false + } + return true + } + start := time.Now() + for flush() { + } + if delayed { + db.writeDelay += time.Since(start) + db.writeDelayN++ + } else if db.writeDelayN > 0 { + db.logf("db@write was delayed N·%d T·%v", db.writeDelayN, db.writeDelay) + db.writeDelay = 0 + db.writeDelayN = 0 + } + return +} + +// Write apply the given batch to the DB. The batch will be applied +// sequentially. +// +// It is safe to modify the contents of the arguments after Write returns. +func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) { + err = db.ok() + if err != nil || b == nil || b.Len() == 0 { + return + } + + b.init(wo.GetSync()) + + // The write happen synchronously. + select { + case db.writeC <- b: + if <-db.writeMergedC { + return <-db.writeAckC + } + case db.writeLockC <- struct{}{}: + case err = <-db.compPerErrC: + return + case _, _ = <-db.closeC: + return ErrClosed + } + + merged := 0 + danglingMerge := false + defer func() { + if danglingMerge { + db.writeMergedC <- false + } else { + <-db.writeLockC + } + for i := 0; i < merged; i++ { + db.writeAckC <- err + } + }() + + mem, memFree, err := db.flush(b.size()) + if err != nil { + return + } + defer mem.decref() + + // Calculate maximum size of the batch. + m := 1 << 20 + if x := b.size(); x <= 128<<10 { + m = x + (128 << 10) + } + m = minInt(m, memFree) + + // Merge with other batch. +drain: + for b.size() < m && !b.sync { + select { + case nb := <-db.writeC: + if b.size()+nb.size() <= m { + b.append(nb) + db.writeMergedC <- true + merged++ + } else { + danglingMerge = true + break drain + } + default: + break drain + } + } + + // Set batch first seq number relative from last seq. + b.seq = db.seq + 1 + + // Write journal concurrently if it is large enough. + if b.size() >= (128 << 10) { + // Push the write batch to the journal writer + select { + case db.journalC <- b: + // Write into memdb + if berr := b.memReplay(mem.mdb); berr != nil { + panic(berr) + } + case err = <-db.compPerErrC: + return + case _, _ = <-db.closeC: + err = ErrClosed + return + } + // Wait for journal writer + select { + case err = <-db.journalAckC: + if err != nil { + // Revert memdb if error detected + if berr := b.revertMemReplay(mem.mdb); berr != nil { + panic(berr) + } + return + } + case _, _ = <-db.closeC: + err = ErrClosed + return + } + } else { + err = db.writeJournal(b) + if err != nil { + return + } + if berr := b.memReplay(mem.mdb); berr != nil { + panic(berr) + } + } + + // Set last seq number. + db.addSeq(uint64(b.Len())) + + if b.size() >= memFree { + db.rotateMem(0) + } + return +} + +// Put sets the value for the given key. It overwrites any previous value +// for that key; a DB is not a multi-map. +// +// It is safe to modify the contents of the arguments after Put returns. +func (db *DB) Put(key, value []byte, wo *opt.WriteOptions) error { + b := new(Batch) + b.Put(key, value) + return db.Write(b, wo) +} + +// Delete deletes the value for the given key. It returns ErrNotFound if +// the DB does not contain the key. +// +// It is safe to modify the contents of the arguments after Delete returns. +func (db *DB) Delete(key []byte, wo *opt.WriteOptions) error { + b := new(Batch) + b.Delete(key) + return db.Write(b, wo) +} + +func isMemOverlaps(icmp *iComparer, mem *memdb.DB, min, max []byte) bool { + iter := mem.NewIterator(nil) + defer iter.Release() + return (max == nil || (iter.First() && icmp.uCompare(max, iKey(iter.Key()).ukey()) >= 0)) && + (min == nil || (iter.Last() && icmp.uCompare(min, iKey(iter.Key()).ukey()) <= 0)) +} + +// CompactRange compacts the underlying DB for the given key range. +// In particular, deleted and overwritten versions are discarded, +// and the data is rearranged to reduce the cost of operations +// needed to access the data. This operation should typically only +// be invoked by users who understand the underlying implementation. +// +// A nil Range.Start is treated as a key before all keys in the DB. +// And a nil Range.Limit is treated as a key after all keys in the DB. +// Therefore if both is nil then it will compact entire DB. +func (db *DB) CompactRange(r util.Range) error { + if err := db.ok(); err != nil { + return err + } + + // Lock writer. + select { + case db.writeLockC <- struct{}{}: + case err := <-db.compPerErrC: + return err + case _, _ = <-db.closeC: + return ErrClosed + } + + // Check for overlaps in memdb. + mem := db.getEffectiveMem() + defer mem.decref() + if isMemOverlaps(db.s.icmp, mem.mdb, r.Start, r.Limit) { + // Memdb compaction. + if _, err := db.rotateMem(0); err != nil { + <-db.writeLockC + return err + } + <-db.writeLockC + if err := db.compSendIdle(db.mcompCmdC); err != nil { + return err + } + } else { + <-db.writeLockC + } + + // Table compaction. + return db.compSendRange(db.tcompCmdC, -1, r.Start, r.Limit) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/doc.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/doc.go new file mode 100644 index 00000000..53f13bb2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/doc.go @@ -0,0 +1,90 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package leveldb provides implementation of LevelDB key/value database. +// +// Create or open a database: +// +// db, err := leveldb.OpenFile("path/to/db", nil) +// ... +// defer db.Close() +// ... +// +// Read or modify the database content: +// +// // Remember that the contents of the returned slice should not be modified. +// data, err := db.Get([]byte("key"), nil) +// ... +// err = db.Put([]byte("key"), []byte("value"), nil) +// ... +// err = db.Delete([]byte("key"), nil) +// ... +// +// Iterate over database content: +// +// iter := db.NewIterator(nil, nil) +// for iter.Next() { +// // Remember that the contents of the returned slice should not be modified, and +// // only valid until the next call to Next. +// key := iter.Key() +// value := iter.Value() +// ... +// } +// iter.Release() +// err = iter.Error() +// ... +// +// Iterate over subset of database content with a particular prefix: +// iter := db.NewIterator(util.BytesPrefix([]byte("foo-")), nil) +// for iter.Next() { +// // Use key/value. +// ... +// } +// iter.Release() +// err = iter.Error() +// ... +// +// Seek-then-Iterate: +// +// iter := db.NewIterator(nil, nil) +// for ok := iter.Seek(key); ok; ok = iter.Next() { +// // Use key/value. +// ... +// } +// iter.Release() +// err = iter.Error() +// ... +// +// Iterate over subset of database content: +// +// iter := db.NewIterator(&util.Range{Start: []byte("foo"), Limit: []byte("xoo")}, nil) +// for iter.Next() { +// // Use key/value. +// ... +// } +// iter.Release() +// err = iter.Error() +// ... +// +// Batch writes: +// +// batch := new(leveldb.Batch) +// batch.Put([]byte("foo"), []byte("value")) +// batch.Put([]byte("bar"), []byte("another value")) +// batch.Delete([]byte("baz")) +// err = db.Write(batch, nil) +// ... +// +// Use bloom filter: +// +// o := &opt.Options{ +// Filter: filter.NewBloomFilter(10), +// } +// db, err := leveldb.OpenFile("path/to/db", o) +// ... +// defer db.Close() +// ... +package leveldb diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go new file mode 100644 index 00000000..d55e9f5b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go @@ -0,0 +1,18 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" +) + +var ( + ErrNotFound = errors.ErrNotFound + ErrSnapshotReleased = errors.New("leveldb: snapshot released") + ErrIterReleased = errors.New("leveldb: iterator released") + ErrClosed = errors.New("leveldb: closed") +) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go new file mode 100644 index 00000000..ede9e1a8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go @@ -0,0 +1,76 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package errors provides common error types used throughout leveldb. +package errors + +import ( + "errors" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +var ( + ErrNotFound = New("leveldb: not found") + ErrReleased = util.ErrReleased + ErrHasReleaser = util.ErrHasReleaser +) + +// New returns an error that formats as the given text. +func New(text string) error { + return errors.New(text) +} + +// ErrCorrupted is the type that wraps errors that indicate corruption in +// the database. +type ErrCorrupted struct { + File *storage.FileInfo + Err error +} + +func (e *ErrCorrupted) Error() string { + if e.File != nil { + return fmt.Sprintf("%v [file=%v]", e.Err, e.File) + } else { + return e.Err.Error() + } +} + +// NewErrCorrupted creates new ErrCorrupted error. +func NewErrCorrupted(f storage.File, err error) error { + return &ErrCorrupted{storage.NewFileInfo(f), err} +} + +// IsCorrupted returns a boolean indicating whether the error is indicating +// a corruption. +func IsCorrupted(err error) bool { + switch err.(type) { + case *ErrCorrupted: + return true + } + return false +} + +// ErrMissingFiles is the type that indicating a corruption due to missing +// files. +type ErrMissingFiles struct { + Files []*storage.FileInfo +} + +func (e *ErrMissingFiles) Error() string { return "file missing" } + +// SetFile sets 'file info' of the given error with the given file. +// Currently only ErrCorrupted is supported, otherwise will do nothing. +func SetFile(err error, f storage.File) error { + switch x := err.(type) { + case *ErrCorrupted: + x.File = storage.NewFileInfo(f) + return x + } + return err +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go new file mode 100644 index 00000000..ac29384d --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +var _ = testutil.Defer(func() { + Describe("Leveldb external", func() { + o := &opt.Options{ + DisableBlockCache: true, + BlockRestartInterval: 5, + BlockSize: 80, + Compression: opt.NoCompression, + OpenFilesCacheCapacity: -1, + Strict: opt.StrictAll, + WriteBuffer: 1000, + CompactionTableSize: 2000, + } + + Describe("write test", func() { + It("should do write correctly", func(done Done) { + db := newTestingDB(o, nil, nil) + t := testutil.DBTesting{ + DB: db, + Deleted: testutil.KeyValue_Generate(nil, 500, 1, 50, 5, 5).Clone(), + } + testutil.DoDBTesting(&t) + db.TestClose() + done <- true + }, 20.0) + }) + + Describe("read test", func() { + testutil.AllKeyValueTesting(nil, nil, func(kv testutil.KeyValue) testutil.DB { + // Building the DB. + db := newTestingDB(o, nil, nil) + kv.IterateShuffled(nil, func(i int, key, value []byte) { + err := db.TestPut(key, value) + Expect(err).NotTo(HaveOccurred()) + }) + + return db + }, func(db testutil.DB) { + db.(*testingDB).TestClose() + }) + }) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter.go new file mode 100644 index 00000000..974e2af3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter.go @@ -0,0 +1,31 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" +) + +type iFilter struct { + filter.Filter +} + +func (f iFilter) Contains(filter, key []byte) bool { + return f.Filter.Contains(filter, iKey(key).ukey()) +} + +func (f iFilter) NewGenerator() filter.FilterGenerator { + return iFilterGenerator{f.Filter.NewGenerator()} +} + +type iFilterGenerator struct { + filter.FilterGenerator +} + +func (g iFilterGenerator) Add(key []byte) { + g.FilterGenerator.Add(iKey(key).ukey()) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom.go new file mode 100644 index 00000000..7ac0fa12 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom.go @@ -0,0 +1,116 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package filter + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +func bloomHash(key []byte) uint32 { + return util.Hash(key, 0xbc9f1d34) +} + +type bloomFilter int + +// The bloom filter serializes its parameters and is backward compatible +// with respect to them. Therefor, its parameters are not added to its +// name. +func (bloomFilter) Name() string { + return "leveldb.BuiltinBloomFilter" +} + +func (f bloomFilter) Contains(filter, key []byte) bool { + nBytes := len(filter) - 1 + if nBytes < 1 { + return false + } + nBits := uint32(nBytes * 8) + + // Use the encoded k so that we can read filters generated by + // bloom filters created using different parameters. + k := filter[nBytes] + if k > 30 { + // Reserved for potentially new encodings for short bloom filters. + // Consider it a match. + return true + } + + kh := bloomHash(key) + delta := (kh >> 17) | (kh << 15) // Rotate right 17 bits + for j := uint8(0); j < k; j++ { + bitpos := kh % nBits + if (uint32(filter[bitpos/8]) & (1 << (bitpos % 8))) == 0 { + return false + } + kh += delta + } + return true +} + +func (f bloomFilter) NewGenerator() FilterGenerator { + // Round down to reduce probing cost a little bit. + k := uint8(f * 69 / 100) // 0.69 =~ ln(2) + if k < 1 { + k = 1 + } else if k > 30 { + k = 30 + } + return &bloomFilterGenerator{ + n: int(f), + k: k, + } +} + +type bloomFilterGenerator struct { + n int + k uint8 + + keyHashes []uint32 +} + +func (g *bloomFilterGenerator) Add(key []byte) { + // Use double-hashing to generate a sequence of hash values. + // See analysis in [Kirsch,Mitzenmacher 2006]. + g.keyHashes = append(g.keyHashes, bloomHash(key)) +} + +func (g *bloomFilterGenerator) Generate(b Buffer) { + // Compute bloom filter size (in both bits and bytes) + nBits := uint32(len(g.keyHashes) * g.n) + // For small n, we can see a very high false positive rate. Fix it + // by enforcing a minimum bloom filter length. + if nBits < 64 { + nBits = 64 + } + nBytes := (nBits + 7) / 8 + nBits = nBytes * 8 + + dest := b.Alloc(int(nBytes) + 1) + dest[nBytes] = g.k + for _, kh := range g.keyHashes { + delta := (kh >> 17) | (kh << 15) // Rotate right 17 bits + for j := uint8(0); j < g.k; j++ { + bitpos := kh % nBits + dest[bitpos/8] |= (1 << (bitpos % 8)) + kh += delta + } + } + + g.keyHashes = g.keyHashes[:0] +} + +// NewBloomFilter creates a new initialized bloom filter for given +// bitsPerKey. +// +// Since bitsPerKey is persisted individually for each bloom filter +// serialization, bloom filters are backwards compatible with respect to +// changing bitsPerKey. This means that no big performance penalty will +// be experienced when changing the parameter. See documentation for +// opt.Options.Filter for more information. +func NewBloomFilter(bitsPerKey int) Filter { + return bloomFilter(bitsPerKey) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go new file mode 100644 index 00000000..0117e184 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go @@ -0,0 +1,142 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package filter + +import ( + "encoding/binary" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" + "testing" +) + +type harness struct { + t *testing.T + + bloom Filter + generator FilterGenerator + filter []byte +} + +func newHarness(t *testing.T) *harness { + bloom := NewBloomFilter(10) + return &harness{ + t: t, + bloom: bloom, + generator: bloom.NewGenerator(), + } +} + +func (h *harness) add(key []byte) { + h.generator.Add(key) +} + +func (h *harness) addNum(key uint32) { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], key) + h.add(b[:]) +} + +func (h *harness) build() { + b := &util.Buffer{} + h.generator.Generate(b) + h.filter = b.Bytes() +} + +func (h *harness) reset() { + h.filter = nil +} + +func (h *harness) filterLen() int { + return len(h.filter) +} + +func (h *harness) assert(key []byte, want, silent bool) bool { + got := h.bloom.Contains(h.filter, key) + if !silent && got != want { + h.t.Errorf("assert on '%v' failed got '%v', want '%v'", key, got, want) + } + return got +} + +func (h *harness) assertNum(key uint32, want, silent bool) bool { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], key) + return h.assert(b[:], want, silent) +} + +func TestBloomFilter_Empty(t *testing.T) { + h := newHarness(t) + h.build() + h.assert([]byte("hello"), false, false) + h.assert([]byte("world"), false, false) +} + +func TestBloomFilter_Small(t *testing.T) { + h := newHarness(t) + h.add([]byte("hello")) + h.add([]byte("world")) + h.build() + h.assert([]byte("hello"), true, false) + h.assert([]byte("world"), true, false) + h.assert([]byte("x"), false, false) + h.assert([]byte("foo"), false, false) +} + +func nextN(n int) int { + switch { + case n < 10: + n += 1 + case n < 100: + n += 10 + case n < 1000: + n += 100 + default: + n += 1000 + } + return n +} + +func TestBloomFilter_VaryingLengths(t *testing.T) { + h := newHarness(t) + var mediocre, good int + for n := 1; n < 10000; n = nextN(n) { + h.reset() + for i := 0; i < n; i++ { + h.addNum(uint32(i)) + } + h.build() + + got := h.filterLen() + want := (n * 10 / 8) + 40 + if got > want { + t.Errorf("filter len test failed, '%d' > '%d'", got, want) + } + + for i := 0; i < n; i++ { + h.assertNum(uint32(i), true, false) + } + + var rate float32 + for i := 0; i < 10000; i++ { + if h.assertNum(uint32(i+1000000000), true, true) { + rate++ + } + } + rate /= 10000 + if rate > 0.02 { + t.Errorf("false positive rate is more than 2%%, got %v, at len %d", rate, n) + } + if rate > 0.0125 { + mediocre++ + } else { + good++ + } + } + t.Logf("false positive rate: %d good, %d mediocre", good, mediocre) + if mediocre > good/5 { + t.Error("mediocre false positive rate is more than expected") + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/filter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/filter.go new file mode 100644 index 00000000..7a925c5a --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/filter.go @@ -0,0 +1,60 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package filter provides interface and implementation of probabilistic +// data structure. +// +// The filter is resposible for creating small filter from a set of keys. +// These filter will then used to test whether a key is a member of the set. +// In many cases, a filter can cut down the number of disk seeks from a +// handful to a single disk seek per DB.Get call. +package filter + +// Buffer is the interface that wraps basic Alloc, Write and WriteByte methods. +type Buffer interface { + // Alloc allocs n bytes of slice from the buffer. This also advancing + // write offset. + Alloc(n int) []byte + + // Write appends the contents of p to the buffer. + Write(p []byte) (n int, err error) + + // WriteByte appends the byte c to the buffer. + WriteByte(c byte) error +} + +// Filter is the filter. +type Filter interface { + // Name returns the name of this policy. + // + // Note that if the filter encoding changes in an incompatible way, + // the name returned by this method must be changed. Otherwise, old + // incompatible filters may be passed to methods of this type. + Name() string + + // NewGenerator creates a new filter generator. + NewGenerator() FilterGenerator + + // Contains returns true if the filter contains the given key. + // + // The filter are filters generated by the filter generator. + Contains(filter, key []byte) bool +} + +// FilterGenerator is the filter generator. +type FilterGenerator interface { + // Add adds a key to the filter generator. + // + // The key may become invalid after call to this method end, therefor + // key must be copied if implementation require keeping key for later + // use. The key should not modified directly, doing so may cause + // undefined results. + Add(key []byte) + + // Generate generates filters based on keys passed so far. After call + // to Generate the filter generator maybe resetted, depends on implementation. + Generate(b Buffer) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter.go new file mode 100644 index 00000000..6f95a019 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter.go @@ -0,0 +1,184 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package iterator + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +// BasicArray is the interface that wraps basic Len and Search method. +type BasicArray interface { + // Len returns length of the array. + Len() int + + // Search finds smallest index that point to a key that is greater + // than or equal to the given key. + Search(key []byte) int +} + +// Array is the interface that wraps BasicArray and basic Index method. +type Array interface { + BasicArray + + // Index returns key/value pair with index of i. + Index(i int) (key, value []byte) +} + +// Array is the interface that wraps BasicArray and basic Get method. +type ArrayIndexer interface { + BasicArray + + // Get returns a new data iterator with index of i. + Get(i int) Iterator +} + +type basicArrayIterator struct { + util.BasicReleaser + array BasicArray + pos int + err error +} + +func (i *basicArrayIterator) Valid() bool { + return i.pos >= 0 && i.pos < i.array.Len() && !i.Released() +} + +func (i *basicArrayIterator) First() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + if i.array.Len() == 0 { + i.pos = -1 + return false + } + i.pos = 0 + return true +} + +func (i *basicArrayIterator) Last() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + n := i.array.Len() + if n == 0 { + i.pos = 0 + return false + } + i.pos = n - 1 + return true +} + +func (i *basicArrayIterator) Seek(key []byte) bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + n := i.array.Len() + if n == 0 { + i.pos = 0 + return false + } + i.pos = i.array.Search(key) + if i.pos >= n { + return false + } + return true +} + +func (i *basicArrayIterator) Next() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + i.pos++ + if n := i.array.Len(); i.pos >= n { + i.pos = n + return false + } + return true +} + +func (i *basicArrayIterator) Prev() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + i.pos-- + if i.pos < 0 { + i.pos = -1 + return false + } + return true +} + +func (i *basicArrayIterator) Error() error { return i.err } + +type arrayIterator struct { + basicArrayIterator + array Array + pos int + key, value []byte +} + +func (i *arrayIterator) updateKV() { + if i.pos == i.basicArrayIterator.pos { + return + } + i.pos = i.basicArrayIterator.pos + if i.Valid() { + i.key, i.value = i.array.Index(i.pos) + } else { + i.key = nil + i.value = nil + } +} + +func (i *arrayIterator) Key() []byte { + i.updateKV() + return i.key +} + +func (i *arrayIterator) Value() []byte { + i.updateKV() + return i.value +} + +type arrayIteratorIndexer struct { + basicArrayIterator + array ArrayIndexer +} + +func (i *arrayIteratorIndexer) Get() Iterator { + if i.Valid() { + return i.array.Get(i.basicArrayIterator.pos) + } + return nil +} + +// NewArrayIterator returns an iterator from the given array. +func NewArrayIterator(array Array) Iterator { + return &arrayIterator{ + basicArrayIterator: basicArrayIterator{array: array, pos: -1}, + array: array, + pos: -1, + } +} + +// NewArrayIndexer returns an index iterator from the given array. +func NewArrayIndexer(array ArrayIndexer) IteratorIndexer { + return &arrayIteratorIndexer{ + basicArrayIterator: basicArrayIterator{array: array, pos: -1}, + array: array, + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go new file mode 100644 index 00000000..1dfd280c --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go @@ -0,0 +1,30 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package iterator_test + +import ( + . "github.com/onsi/ginkgo" + + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +var _ = testutil.Defer(func() { + Describe("Array iterator", func() { + It("Should iterates and seeks correctly", func() { + // Build key/value. + kv := testutil.KeyValue_Generate(nil, 70, 1, 5, 3, 3) + + // Test the iterator. + t := testutil.IteratorTesting{ + KeyValue: kv.Clone(), + Iter: NewArrayIterator(kv), + } + testutil.DoIteratorTesting(&t) + }) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter.go new file mode 100644 index 00000000..f255b0aa --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter.go @@ -0,0 +1,242 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package iterator + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +// IteratorIndexer is the interface that wraps CommonIterator and basic Get +// method. IteratorIndexer provides index for indexed iterator. +type IteratorIndexer interface { + CommonIterator + + // Get returns a new data iterator for the current position, or nil if + // done. + Get() Iterator +} + +type indexedIterator struct { + util.BasicReleaser + index IteratorIndexer + strict bool + + data Iterator + err error + errf func(err error) + closed bool +} + +func (i *indexedIterator) setData() { + if i.data != nil { + i.data.Release() + } + i.data = i.index.Get() +} + +func (i *indexedIterator) clearData() { + if i.data != nil { + i.data.Release() + } + i.data = nil +} + +func (i *indexedIterator) indexErr() { + if err := i.index.Error(); err != nil { + if i.errf != nil { + i.errf(err) + } + i.err = err + } +} + +func (i *indexedIterator) dataErr() bool { + if err := i.data.Error(); err != nil { + if i.errf != nil { + i.errf(err) + } + if i.strict || !errors.IsCorrupted(err) { + i.err = err + return true + } + } + return false +} + +func (i *indexedIterator) Valid() bool { + return i.data != nil && i.data.Valid() +} + +func (i *indexedIterator) First() bool { + if i.err != nil { + return false + } else if i.Released() { + i.err = ErrIterReleased + return false + } + + if !i.index.First() { + i.indexErr() + i.clearData() + return false + } + i.setData() + return i.Next() +} + +func (i *indexedIterator) Last() bool { + if i.err != nil { + return false + } else if i.Released() { + i.err = ErrIterReleased + return false + } + + if !i.index.Last() { + i.indexErr() + i.clearData() + return false + } + i.setData() + if !i.data.Last() { + if i.dataErr() { + return false + } + i.clearData() + return i.Prev() + } + return true +} + +func (i *indexedIterator) Seek(key []byte) bool { + if i.err != nil { + return false + } else if i.Released() { + i.err = ErrIterReleased + return false + } + + if !i.index.Seek(key) { + i.indexErr() + i.clearData() + return false + } + i.setData() + if !i.data.Seek(key) { + if i.dataErr() { + return false + } + i.clearData() + return i.Next() + } + return true +} + +func (i *indexedIterator) Next() bool { + if i.err != nil { + return false + } else if i.Released() { + i.err = ErrIterReleased + return false + } + + switch { + case i.data != nil && !i.data.Next(): + if i.dataErr() { + return false + } + i.clearData() + fallthrough + case i.data == nil: + if !i.index.Next() { + i.indexErr() + return false + } + i.setData() + return i.Next() + } + return true +} + +func (i *indexedIterator) Prev() bool { + if i.err != nil { + return false + } else if i.Released() { + i.err = ErrIterReleased + return false + } + + switch { + case i.data != nil && !i.data.Prev(): + if i.dataErr() { + return false + } + i.clearData() + fallthrough + case i.data == nil: + if !i.index.Prev() { + i.indexErr() + return false + } + i.setData() + if !i.data.Last() { + if i.dataErr() { + return false + } + i.clearData() + return i.Prev() + } + } + return true +} + +func (i *indexedIterator) Key() []byte { + if i.data == nil { + return nil + } + return i.data.Key() +} + +func (i *indexedIterator) Value() []byte { + if i.data == nil { + return nil + } + return i.data.Value() +} + +func (i *indexedIterator) Release() { + i.clearData() + i.index.Release() + i.BasicReleaser.Release() +} + +func (i *indexedIterator) Error() error { + if i.err != nil { + return i.err + } + if err := i.index.Error(); err != nil { + return err + } + return nil +} + +func (i *indexedIterator) SetErrorCallback(f func(err error)) { + i.errf = f +} + +// NewIndexedIterator returns an 'indexed iterator'. An index is iterator +// that returns another iterator, a 'data iterator'. A 'data iterator' is the +// iterator that contains actual key/value pairs. +// +// If strict is true the any 'corruption errors' (i.e errors.IsCorrupted(err) == true) +// won't be ignored and will halt 'indexed iterator', otherwise the iterator will +// continue to the next 'data iterator'. Corruption on 'index iterator' will not be +// ignored and will halt the iterator. +func NewIndexedIterator(index IteratorIndexer, strict bool) Iterator { + return &indexedIterator{index: index, strict: strict} +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go new file mode 100644 index 00000000..1827fe72 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go @@ -0,0 +1,83 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package iterator_test + +import ( + "sort" + + . "github.com/onsi/ginkgo" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +type keyValue struct { + key []byte + testutil.KeyValue +} + +type keyValueIndex []keyValue + +func (x keyValueIndex) Search(key []byte) int { + return sort.Search(x.Len(), func(i int) bool { + return comparer.DefaultComparer.Compare(x[i].key, key) >= 0 + }) +} + +func (x keyValueIndex) Len() int { return len(x) } +func (x keyValueIndex) Index(i int) (key, value []byte) { return x[i].key, nil } +func (x keyValueIndex) Get(i int) Iterator { return NewArrayIterator(x[i]) } + +var _ = testutil.Defer(func() { + Describe("Indexed iterator", func() { + Test := func(n ...int) func() { + if len(n) == 0 { + rnd := testutil.NewRand() + n = make([]int, rnd.Intn(17)+3) + for i := range n { + n[i] = rnd.Intn(19) + 1 + } + } + + return func() { + It("Should iterates and seeks correctly", func(done Done) { + // Build key/value. + index := make(keyValueIndex, len(n)) + sum := 0 + for _, x := range n { + sum += x + } + kv := testutil.KeyValue_Generate(nil, sum, 1, 10, 4, 4) + for i, j := 0, 0; i < len(n); i++ { + for x := n[i]; x > 0; x-- { + key, value := kv.Index(j) + index[i].key = key + index[i].Put(key, value) + j++ + } + } + + // Test the iterator. + t := testutil.IteratorTesting{ + KeyValue: kv.Clone(), + Iter: NewIndexedIterator(NewArrayIndexer(index), true), + } + testutil.DoIteratorTesting(&t) + done <- true + }, 1.5) + } + } + + Describe("with 100 keys", Test(100)) + Describe("with 50-50 keys", Test(50, 50)) + Describe("with 50-1 keys", Test(50, 1)) + Describe("with 50-1-50 keys", Test(50, 1, 50)) + Describe("with 1-50 keys", Test(1, 50)) + Describe("with random N-keys", Test()) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter.go new file mode 100644 index 00000000..64502252 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter.go @@ -0,0 +1,131 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package iterator provides interface and implementation to traverse over +// contents of a database. +package iterator + +import ( + "errors" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +var ( + ErrIterReleased = errors.New("leveldb/iterator: iterator released") +) + +// IteratorSeeker is the interface that wraps the 'seeks method'. +type IteratorSeeker interface { + // First moves the iterator to the first key/value pair. If the iterator + // only contains one key/value pair then First and Last whould moves + // to the same key/value pair. + // It returns whether such pair exist. + First() bool + + // Last moves the iterator to the last key/value pair. If the iterator + // only contains one key/value pair then First and Last whould moves + // to the same key/value pair. + // It returns whether such pair exist. + Last() bool + + // Seek moves the iterator to the first key/value pair whose key is greater + // than or equal to the given key. + // It returns whether such pair exist. + // + // It is safe to modify the contents of the argument after Seek returns. + Seek(key []byte) bool + + // Next moves the iterator to the next key/value pair. + // It returns whether the iterator is exhausted. + Next() bool + + // Prev moves the iterator to the previous key/value pair. + // It returns whether the iterator is exhausted. + Prev() bool +} + +// CommonIterator is the interface that wraps common interator methods. +type CommonIterator interface { + IteratorSeeker + + // util.Releaser is the interface that wraps basic Release method. + // When called Release will releases any resources associated with the + // iterator. + util.Releaser + + // util.ReleaseSetter is the interface that wraps the basic SetReleaser + // method. + util.ReleaseSetter + + // TODO: Remove this when ready. + Valid() bool + + // Error returns any accumulated error. Exhausting all the key/value pairs + // is not considered to be an error. + Error() error +} + +// Iterator iterates over a DB's key/value pairs in key order. +// +// When encouter an error any 'seeks method' will return false and will +// yield no key/value pairs. The error can be queried by calling the Error +// method. Calling Release is still necessary. +// +// An iterator must be released after use, but it is not necessary to read +// an iterator until exhaustion. +// Also, an iterator is not necessarily goroutine-safe, but it is safe to use +// multiple iterators concurrently, with each in a dedicated goroutine. +type Iterator interface { + CommonIterator + + // Key returns the key of the current key/value pair, or nil if done. + // The caller should not modify the contents of the returned slice, and + // its contents may change on the next call to any 'seeks method'. + Key() []byte + + // Value returns the key of the current key/value pair, or nil if done. + // The caller should not modify the contents of the returned slice, and + // its contents may change on the next call to any 'seeks method'. + Value() []byte +} + +// ErrorCallbackSetter is the interface that wraps basic SetErrorCallback +// method. +// +// ErrorCallbackSetter implemented by indexed and merged iterator. +type ErrorCallbackSetter interface { + // SetErrorCallback allows set an error callback of the coresponding + // iterator. Use nil to clear the callback. + SetErrorCallback(f func(err error)) +} + +type emptyIterator struct { + util.BasicReleaser + err error +} + +func (i *emptyIterator) rErr() { + if i.err == nil && i.Released() { + i.err = ErrIterReleased + } +} + +func (*emptyIterator) Valid() bool { return false } +func (i *emptyIterator) First() bool { i.rErr(); return false } +func (i *emptyIterator) Last() bool { i.rErr(); return false } +func (i *emptyIterator) Seek(key []byte) bool { i.rErr(); return false } +func (i *emptyIterator) Next() bool { i.rErr(); return false } +func (i *emptyIterator) Prev() bool { i.rErr(); return false } +func (*emptyIterator) Key() []byte { return nil } +func (*emptyIterator) Value() []byte { return nil } +func (i *emptyIterator) Error() error { return i.err } + +// NewEmptyIterator creates an empty iterator. The err parameter can be +// nil, but if not nil the given err will be returned by Error method. +func NewEmptyIterator(err error) Iterator { + return &emptyIterator{err: err} +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go new file mode 100644 index 00000000..13feccb5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go @@ -0,0 +1,11 @@ +package iterator_test + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +func TestIterator(t *testing.T) { + testutil.RunSuite(t, "Iterator Suite") +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter.go new file mode 100644 index 00000000..4115f5ef --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter.go @@ -0,0 +1,304 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package iterator + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type dir int + +const ( + dirReleased dir = iota - 1 + dirSOI + dirEOI + dirBackward + dirForward +) + +type mergedIterator struct { + cmp comparer.Comparer + iters []Iterator + strict bool + + keys [][]byte + index int + dir dir + err error + errf func(err error) + releaser util.Releaser +} + +func assertKey(key []byte) []byte { + if key == nil { + panic("leveldb/iterator: nil key") + } + return key +} + +func (i *mergedIterator) iterErr(iter Iterator) bool { + if err := iter.Error(); err != nil { + if i.errf != nil { + i.errf(err) + } + if i.strict || !errors.IsCorrupted(err) { + i.err = err + return true + } + } + return false +} + +func (i *mergedIterator) Valid() bool { + return i.err == nil && i.dir > dirEOI +} + +func (i *mergedIterator) First() bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + for x, iter := range i.iters { + switch { + case iter.First(): + i.keys[x] = assertKey(iter.Key()) + case i.iterErr(iter): + return false + default: + i.keys[x] = nil + } + } + i.dir = dirSOI + return i.next() +} + +func (i *mergedIterator) Last() bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + for x, iter := range i.iters { + switch { + case iter.Last(): + i.keys[x] = assertKey(iter.Key()) + case i.iterErr(iter): + return false + default: + i.keys[x] = nil + } + } + i.dir = dirEOI + return i.prev() +} + +func (i *mergedIterator) Seek(key []byte) bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + for x, iter := range i.iters { + switch { + case iter.Seek(key): + i.keys[x] = assertKey(iter.Key()) + case i.iterErr(iter): + return false + default: + i.keys[x] = nil + } + } + i.dir = dirSOI + return i.next() +} + +func (i *mergedIterator) next() bool { + var key []byte + if i.dir == dirForward { + key = i.keys[i.index] + } + for x, tkey := range i.keys { + if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) < 0) { + key = tkey + i.index = x + } + } + if key == nil { + i.dir = dirEOI + return false + } + i.dir = dirForward + return true +} + +func (i *mergedIterator) Next() bool { + if i.dir == dirEOI || i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + switch i.dir { + case dirSOI: + return i.First() + case dirBackward: + key := append([]byte{}, i.keys[i.index]...) + if !i.Seek(key) { + return false + } + return i.Next() + } + + x := i.index + iter := i.iters[x] + switch { + case iter.Next(): + i.keys[x] = assertKey(iter.Key()) + case i.iterErr(iter): + return false + default: + i.keys[x] = nil + } + return i.next() +} + +func (i *mergedIterator) prev() bool { + var key []byte + if i.dir == dirBackward { + key = i.keys[i.index] + } + for x, tkey := range i.keys { + if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) > 0) { + key = tkey + i.index = x + } + } + if key == nil { + i.dir = dirSOI + return false + } + i.dir = dirBackward + return true +} + +func (i *mergedIterator) Prev() bool { + if i.dir == dirSOI || i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + switch i.dir { + case dirEOI: + return i.Last() + case dirForward: + key := append([]byte{}, i.keys[i.index]...) + for x, iter := range i.iters { + if x == i.index { + continue + } + seek := iter.Seek(key) + switch { + case seek && iter.Prev(), !seek && iter.Last(): + i.keys[x] = assertKey(iter.Key()) + case i.iterErr(iter): + return false + default: + i.keys[x] = nil + } + } + } + + x := i.index + iter := i.iters[x] + switch { + case iter.Prev(): + i.keys[x] = assertKey(iter.Key()) + case i.iterErr(iter): + return false + default: + i.keys[x] = nil + } + return i.prev() +} + +func (i *mergedIterator) Key() []byte { + if i.err != nil || i.dir <= dirEOI { + return nil + } + return i.keys[i.index] +} + +func (i *mergedIterator) Value() []byte { + if i.err != nil || i.dir <= dirEOI { + return nil + } + return i.iters[i.index].Value() +} + +func (i *mergedIterator) Release() { + if i.dir != dirReleased { + i.dir = dirReleased + for _, iter := range i.iters { + iter.Release() + } + i.iters = nil + i.keys = nil + if i.releaser != nil { + i.releaser.Release() + i.releaser = nil + } + } +} + +func (i *mergedIterator) SetReleaser(releaser util.Releaser) { + if i.dir == dirReleased { + panic(util.ErrReleased) + } + if i.releaser != nil && releaser != nil { + panic(util.ErrHasReleaser) + } + i.releaser = releaser +} + +func (i *mergedIterator) Error() error { + return i.err +} + +func (i *mergedIterator) SetErrorCallback(f func(err error)) { + i.errf = f +} + +// NewMergedIterator returns an iterator that merges its input. Walking the +// resultant iterator will return all key/value pairs of all input iterators +// in strictly increasing key order, as defined by cmp. +// The input's key ranges may overlap, but there are assumed to be no duplicate +// keys: if iters[i] contains a key k then iters[j] will not contain that key k. +// None of the iters may be nil. +// +// If strict is true the any 'corruption errors' (i.e errors.IsCorrupted(err) == true) +// won't be ignored and will halt 'merged iterator', otherwise the iterator will +// continue to the next 'input iterator'. +func NewMergedIterator(iters []Iterator, cmp comparer.Comparer, strict bool) Iterator { + return &mergedIterator{ + iters: iters, + cmp: cmp, + strict: strict, + keys: make([][]byte, len(iters)), + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go new file mode 100644 index 00000000..66fa37b7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go @@ -0,0 +1,60 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package iterator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + . "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +var _ = testutil.Defer(func() { + Describe("Merged iterator", func() { + Test := func(filled int, empty int) func() { + return func() { + It("Should iterates and seeks correctly", func(done Done) { + rnd := testutil.NewRand() + + // Build key/value. + filledKV := make([]testutil.KeyValue, filled) + kv := testutil.KeyValue_Generate(nil, 100, 1, 10, 4, 4) + kv.Iterate(func(i int, key, value []byte) { + filledKV[rnd.Intn(filled)].Put(key, value) + }) + + // Create itearators. + iters := make([]Iterator, filled+empty) + for i := range iters { + if empty == 0 || (rnd.Int()%2 == 0 && filled > 0) { + filled-- + Expect(filledKV[filled].Len()).ShouldNot(BeZero()) + iters[i] = NewArrayIterator(filledKV[filled]) + } else { + empty-- + iters[i] = NewEmptyIterator(nil) + } + } + + // Test the iterator. + t := testutil.IteratorTesting{ + KeyValue: kv.Clone(), + Iter: NewMergedIterator(iters, comparer.DefaultComparer, true), + } + testutil.DoIteratorTesting(&t) + done <- true + }, 1.5) + } + } + + Describe("with three, all filled iterators", Test(3, 0)) + Describe("with one filled, one empty iterators", Test(1, 1)) + Describe("with one filled, two empty iterators", Test(1, 2)) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go new file mode 100644 index 00000000..cfbc774c --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go @@ -0,0 +1,520 @@ +// Copyright 2011 The LevelDB-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Taken from: https://code.google.com/p/leveldb-go/source/browse/leveldb/record/record.go?r=1d5ccbe03246da926391ee12d1c6caae054ff4b0 +// License, authors and contributors informations can be found at bellow URLs respectively: +// https://code.google.com/p/leveldb-go/source/browse/LICENSE +// https://code.google.com/p/leveldb-go/source/browse/AUTHORS +// https://code.google.com/p/leveldb-go/source/browse/CONTRIBUTORS + +// Package journal reads and writes sequences of journals. Each journal is a stream +// of bytes that completes before the next journal starts. +// +// When reading, call Next to obtain an io.Reader for the next journal. Next will +// return io.EOF when there are no more journals. It is valid to call Next +// without reading the current journal to exhaustion. +// +// When writing, call Next to obtain an io.Writer for the next journal. Calling +// Next finishes the current journal. Call Close to finish the final journal. +// +// Optionally, call Flush to finish the current journal and flush the underlying +// writer without starting a new journal. To start a new journal after flushing, +// call Next. +// +// Neither Readers or Writers are safe to use concurrently. +// +// Example code: +// func read(r io.Reader) ([]string, error) { +// var ss []string +// journals := journal.NewReader(r, nil, true, true) +// for { +// j, err := journals.Next() +// if err == io.EOF { +// break +// } +// if err != nil { +// return nil, err +// } +// s, err := ioutil.ReadAll(j) +// if err != nil { +// return nil, err +// } +// ss = append(ss, string(s)) +// } +// return ss, nil +// } +// +// func write(w io.Writer, ss []string) error { +// journals := journal.NewWriter(w) +// for _, s := range ss { +// j, err := journals.Next() +// if err != nil { +// return err +// } +// if _, err := j.Write([]byte(s)), err != nil { +// return err +// } +// } +// return journals.Close() +// } +// +// The wire format is that the stream is divided into 32KiB blocks, and each +// block contains a number of tightly packed chunks. Chunks cannot cross block +// boundaries. The last block may be shorter than 32 KiB. Any unused bytes in a +// block must be zero. +// +// A journal maps to one or more chunks. Each chunk has a 7 byte header (a 4 +// byte checksum, a 2 byte little-endian uint16 length, and a 1 byte chunk type) +// followed by a payload. The checksum is over the chunk type and the payload. +// +// There are four chunk types: whether the chunk is the full journal, or the +// first, middle or last chunk of a multi-chunk journal. A multi-chunk journal +// has one first chunk, zero or more middle chunks, and one last chunk. +// +// The wire format allows for limited recovery in the face of data corruption: +// on a format error (such as a checksum mismatch), the reader moves to the +// next block and looks for the next full or first chunk. +package journal + +import ( + "encoding/binary" + "fmt" + "io" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +// These constants are part of the wire format and should not be changed. +const ( + fullChunkType = 1 + firstChunkType = 2 + middleChunkType = 3 + lastChunkType = 4 +) + +const ( + blockSize = 32 * 1024 + headerSize = 7 +) + +type flusher interface { + Flush() error +} + +// ErrCorrupted is the error type that generated by corrupted block or chunk. +type ErrCorrupted struct { + Size int + Reason string +} + +func (e *ErrCorrupted) Error() string { + return fmt.Sprintf("leveldb/journal: block/chunk corrupted: %s (%d bytes)", e.Reason, e.Size) +} + +// Dropper is the interface that wrap simple Drop method. The Drop +// method will be called when the journal reader dropping a block or chunk. +type Dropper interface { + Drop(err error) +} + +// Reader reads journals from an underlying io.Reader. +type Reader struct { + // r is the underlying reader. + r io.Reader + // the dropper. + dropper Dropper + // strict flag. + strict bool + // checksum flag. + checksum bool + // seq is the sequence number of the current journal. + seq int + // buf[i:j] is the unread portion of the current chunk's payload. + // The low bound, i, excludes the chunk header. + i, j int + // n is the number of bytes of buf that are valid. Once reading has started, + // only the final block can have n < blockSize. + n int + // last is whether the current chunk is the last chunk of the journal. + last bool + // err is any accumulated error. + err error + // buf is the buffer. + buf [blockSize]byte +} + +// NewReader returns a new reader. The dropper may be nil, and if +// strict is true then corrupted or invalid chunk will halt the journal +// reader entirely. +func NewReader(r io.Reader, dropper Dropper, strict, checksum bool) *Reader { + return &Reader{ + r: r, + dropper: dropper, + strict: strict, + checksum: checksum, + last: true, + } +} + +var errSkip = errors.New("leveldb/journal: skipped") + +func (r *Reader) corrupt(n int, reason string, skip bool) error { + if r.dropper != nil { + r.dropper.Drop(&ErrCorrupted{n, reason}) + } + if r.strict && !skip { + r.err = errors.NewErrCorrupted(nil, &ErrCorrupted{n, reason}) + return r.err + } + return errSkip +} + +// nextChunk sets r.buf[r.i:r.j] to hold the next chunk's payload, reading the +// next block into the buffer if necessary. +func (r *Reader) nextChunk(first bool) error { + for { + if r.j+headerSize <= r.n { + checksum := binary.LittleEndian.Uint32(r.buf[r.j+0 : r.j+4]) + length := binary.LittleEndian.Uint16(r.buf[r.j+4 : r.j+6]) + chunkType := r.buf[r.j+6] + + if checksum == 0 && length == 0 && chunkType == 0 { + // Drop entire block. + m := r.n - r.j + r.i = r.n + r.j = r.n + return r.corrupt(m, "zero header", false) + } else { + m := r.n - r.j + r.i = r.j + headerSize + r.j = r.j + headerSize + int(length) + if r.j > r.n { + // Drop entire block. + r.i = r.n + r.j = r.n + return r.corrupt(m, "chunk length overflows block", false) + } else if r.checksum && checksum != util.NewCRC(r.buf[r.i-1:r.j]).Value() { + // Drop entire block. + r.i = r.n + r.j = r.n + return r.corrupt(m, "checksum mismatch", false) + } + } + if first && chunkType != fullChunkType && chunkType != firstChunkType { + m := r.j - r.i + r.i = r.j + // Report the error, but skip it. + return r.corrupt(m+headerSize, "orphan chunk", true) + } + r.last = chunkType == fullChunkType || chunkType == lastChunkType + return nil + } + + // The last block. + if r.n < blockSize && r.n > 0 { + if !first { + return r.corrupt(0, "missing chunk part", false) + } + r.err = io.EOF + return r.err + } + + // Read block. + n, err := io.ReadFull(r.r, r.buf[:]) + if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { + return err + } + if n == 0 { + if !first { + return r.corrupt(0, "missing chunk part", false) + } + r.err = io.EOF + return r.err + } + r.i, r.j, r.n = 0, 0, n + } +} + +// Next returns a reader for the next journal. It returns io.EOF if there are no +// more journals. The reader returned becomes stale after the next Next call, +// and should no longer be used. If strict is false, the reader will returns +// io.ErrUnexpectedEOF error when found corrupted journal. +func (r *Reader) Next() (io.Reader, error) { + r.seq++ + if r.err != nil { + return nil, r.err + } + r.i = r.j + for { + if err := r.nextChunk(true); err == nil { + break + } else if err != errSkip { + return nil, err + } + } + return &singleReader{r, r.seq, nil}, nil +} + +// Reset resets the journal reader, allows reuse of the journal reader. Reset returns +// last accumulated error. +func (r *Reader) Reset(reader io.Reader, dropper Dropper, strict, checksum bool) error { + r.seq++ + err := r.err + r.r = reader + r.dropper = dropper + r.strict = strict + r.checksum = checksum + r.i = 0 + r.j = 0 + r.n = 0 + r.last = true + r.err = nil + return err +} + +type singleReader struct { + r *Reader + seq int + err error +} + +func (x *singleReader) Read(p []byte) (int, error) { + r := x.r + if r.seq != x.seq { + return 0, errors.New("leveldb/journal: stale reader") + } + if x.err != nil { + return 0, x.err + } + if r.err != nil { + return 0, r.err + } + for r.i == r.j { + if r.last { + return 0, io.EOF + } + x.err = r.nextChunk(false) + if x.err != nil { + if x.err == errSkip { + x.err = io.ErrUnexpectedEOF + } + return 0, x.err + } + } + n := copy(p, r.buf[r.i:r.j]) + r.i += n + return n, nil +} + +func (x *singleReader) ReadByte() (byte, error) { + r := x.r + if r.seq != x.seq { + return 0, errors.New("leveldb/journal: stale reader") + } + if x.err != nil { + return 0, x.err + } + if r.err != nil { + return 0, r.err + } + for r.i == r.j { + if r.last { + return 0, io.EOF + } + x.err = r.nextChunk(false) + if x.err != nil { + if x.err == errSkip { + x.err = io.ErrUnexpectedEOF + } + return 0, x.err + } + } + c := r.buf[r.i] + r.i++ + return c, nil +} + +// Writer writes journals to an underlying io.Writer. +type Writer struct { + // w is the underlying writer. + w io.Writer + // seq is the sequence number of the current journal. + seq int + // f is w as a flusher. + f flusher + // buf[i:j] is the bytes that will become the current chunk. + // The low bound, i, includes the chunk header. + i, j int + // buf[:written] has already been written to w. + // written is zero unless Flush has been called. + written int + // first is whether the current chunk is the first chunk of the journal. + first bool + // pending is whether a chunk is buffered but not yet written. + pending bool + // err is any accumulated error. + err error + // buf is the buffer. + buf [blockSize]byte +} + +// NewWriter returns a new Writer. +func NewWriter(w io.Writer) *Writer { + f, _ := w.(flusher) + return &Writer{ + w: w, + f: f, + } +} + +// fillHeader fills in the header for the pending chunk. +func (w *Writer) fillHeader(last bool) { + if w.i+headerSize > w.j || w.j > blockSize { + panic("leveldb/journal: bad writer state") + } + if last { + if w.first { + w.buf[w.i+6] = fullChunkType + } else { + w.buf[w.i+6] = lastChunkType + } + } else { + if w.first { + w.buf[w.i+6] = firstChunkType + } else { + w.buf[w.i+6] = middleChunkType + } + } + binary.LittleEndian.PutUint32(w.buf[w.i+0:w.i+4], util.NewCRC(w.buf[w.i+6:w.j]).Value()) + binary.LittleEndian.PutUint16(w.buf[w.i+4:w.i+6], uint16(w.j-w.i-headerSize)) +} + +// writeBlock writes the buffered block to the underlying writer, and reserves +// space for the next chunk's header. +func (w *Writer) writeBlock() { + _, w.err = w.w.Write(w.buf[w.written:]) + w.i = 0 + w.j = headerSize + w.written = 0 +} + +// writePending finishes the current journal and writes the buffer to the +// underlying writer. +func (w *Writer) writePending() { + if w.err != nil { + return + } + if w.pending { + w.fillHeader(true) + w.pending = false + } + _, w.err = w.w.Write(w.buf[w.written:w.j]) + w.written = w.j +} + +// Close finishes the current journal and closes the writer. +func (w *Writer) Close() error { + w.seq++ + w.writePending() + if w.err != nil { + return w.err + } + w.err = errors.New("leveldb/journal: closed Writer") + return nil +} + +// Flush finishes the current journal, writes to the underlying writer, and +// flushes it if that writer implements interface{ Flush() error }. +func (w *Writer) Flush() error { + w.seq++ + w.writePending() + if w.err != nil { + return w.err + } + if w.f != nil { + w.err = w.f.Flush() + return w.err + } + return nil +} + +// Reset resets the journal writer, allows reuse of the journal writer. Reset +// will also closes the journal writer if not already. +func (w *Writer) Reset(writer io.Writer) (err error) { + w.seq++ + if w.err == nil { + w.writePending() + err = w.err + } + w.w = writer + w.f, _ = writer.(flusher) + w.i = 0 + w.j = 0 + w.written = 0 + w.first = false + w.pending = false + w.err = nil + return +} + +// Next returns a writer for the next journal. The writer returned becomes stale +// after the next Close, Flush or Next call, and should no longer be used. +func (w *Writer) Next() (io.Writer, error) { + w.seq++ + if w.err != nil { + return nil, w.err + } + if w.pending { + w.fillHeader(true) + } + w.i = w.j + w.j = w.j + headerSize + // Check if there is room in the block for the header. + if w.j > blockSize { + // Fill in the rest of the block with zeroes. + for k := w.i; k < blockSize; k++ { + w.buf[k] = 0 + } + w.writeBlock() + if w.err != nil { + return nil, w.err + } + } + w.first = true + w.pending = true + return singleWriter{w, w.seq}, nil +} + +type singleWriter struct { + w *Writer + seq int +} + +func (x singleWriter) Write(p []byte) (int, error) { + w := x.w + if w.seq != x.seq { + return 0, errors.New("leveldb/journal: stale writer") + } + if w.err != nil { + return 0, w.err + } + n0 := len(p) + for len(p) > 0 { + // Write a block, if it is full. + if w.j == blockSize { + w.fillHeader(false) + w.writeBlock() + if w.err != nil { + return 0, w.err + } + w.first = false + } + // Copy bytes into the buffer. + n := copy(w.buf[w.j:], p) + w.j += n + p = p[n:] + } + return n0, nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go new file mode 100644 index 00000000..0fcf2259 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go @@ -0,0 +1,818 @@ +// Copyright 2011 The LevelDB-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Taken from: https://code.google.com/p/leveldb-go/source/browse/leveldb/record/record_test.go?r=df1fa28f7f3be6c3935548169002309c12967135 +// License, authors and contributors informations can be found at bellow URLs respectively: +// https://code.google.com/p/leveldb-go/source/browse/LICENSE +// https://code.google.com/p/leveldb-go/source/browse/AUTHORS +// https://code.google.com/p/leveldb-go/source/browse/CONTRIBUTORS + +package journal + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "math/rand" + "strings" + "testing" +) + +type dropper struct { + t *testing.T +} + +func (d dropper) Drop(err error) { + d.t.Log(err) +} + +func short(s string) string { + if len(s) < 64 { + return s + } + return fmt.Sprintf("%s...(skipping %d bytes)...%s", s[:20], len(s)-40, s[len(s)-20:]) +} + +// big returns a string of length n, composed of repetitions of partial. +func big(partial string, n int) string { + return strings.Repeat(partial, n/len(partial)+1)[:n] +} + +func TestEmpty(t *testing.T) { + buf := new(bytes.Buffer) + r := NewReader(buf, dropper{t}, true, true) + if _, err := r.Next(); err != io.EOF { + t.Fatalf("got %v, want %v", err, io.EOF) + } +} + +func testGenerator(t *testing.T, reset func(), gen func() (string, bool)) { + buf := new(bytes.Buffer) + + reset() + w := NewWriter(buf) + for { + s, ok := gen() + if !ok { + break + } + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write([]byte(s)); err != nil { + t.Fatal(err) + } + } + if err := w.Close(); err != nil { + t.Fatal(err) + } + + reset() + r := NewReader(buf, dropper{t}, true, true) + for { + s, ok := gen() + if !ok { + break + } + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + x, err := ioutil.ReadAll(rr) + if err != nil { + t.Fatal(err) + } + if string(x) != s { + t.Fatalf("got %q, want %q", short(string(x)), short(s)) + } + } + if _, err := r.Next(); err != io.EOF { + t.Fatalf("got %v, want %v", err, io.EOF) + } +} + +func testLiterals(t *testing.T, s []string) { + var i int + reset := func() { + i = 0 + } + gen := func() (string, bool) { + if i == len(s) { + return "", false + } + i++ + return s[i-1], true + } + testGenerator(t, reset, gen) +} + +func TestMany(t *testing.T) { + const n = 1e5 + var i int + reset := func() { + i = 0 + } + gen := func() (string, bool) { + if i == n { + return "", false + } + i++ + return fmt.Sprintf("%d.", i-1), true + } + testGenerator(t, reset, gen) +} + +func TestRandom(t *testing.T) { + const n = 1e2 + var ( + i int + r *rand.Rand + ) + reset := func() { + i, r = 0, rand.New(rand.NewSource(0)) + } + gen := func() (string, bool) { + if i == n { + return "", false + } + i++ + return strings.Repeat(string(uint8(i)), r.Intn(2*blockSize+16)), true + } + testGenerator(t, reset, gen) +} + +func TestBasic(t *testing.T) { + testLiterals(t, []string{ + strings.Repeat("a", 1000), + strings.Repeat("b", 97270), + strings.Repeat("c", 8000), + }) +} + +func TestBoundary(t *testing.T) { + for i := blockSize - 16; i < blockSize+16; i++ { + s0 := big("abcd", i) + for j := blockSize - 16; j < blockSize+16; j++ { + s1 := big("ABCDE", j) + testLiterals(t, []string{s0, s1}) + testLiterals(t, []string{s0, "", s1}) + testLiterals(t, []string{s0, "x", s1}) + } + } +} + +func TestFlush(t *testing.T) { + buf := new(bytes.Buffer) + w := NewWriter(buf) + // Write a couple of records. Everything should still be held + // in the record.Writer buffer, so that buf.Len should be 0. + w0, _ := w.Next() + w0.Write([]byte("0")) + w1, _ := w.Next() + w1.Write([]byte("11")) + if got, want := buf.Len(), 0; got != want { + t.Fatalf("buffer length #0: got %d want %d", got, want) + } + // Flush the record.Writer buffer, which should yield 17 bytes. + // 17 = 2*7 + 1 + 2, which is two headers and 1 + 2 payload bytes. + if err := w.Flush(); err != nil { + t.Fatal(err) + } + if got, want := buf.Len(), 17; got != want { + t.Fatalf("buffer length #1: got %d want %d", got, want) + } + // Do another write, one that isn't large enough to complete the block. + // The write should not have flowed through to buf. + w2, _ := w.Next() + w2.Write(bytes.Repeat([]byte("2"), 10000)) + if got, want := buf.Len(), 17; got != want { + t.Fatalf("buffer length #2: got %d want %d", got, want) + } + // Flushing should get us up to 10024 bytes written. + // 10024 = 17 + 7 + 10000. + if err := w.Flush(); err != nil { + t.Fatal(err) + } + if got, want := buf.Len(), 10024; got != want { + t.Fatalf("buffer length #3: got %d want %d", got, want) + } + // Do a bigger write, one that completes the current block. + // We should now have 32768 bytes (a complete block), without + // an explicit flush. + w3, _ := w.Next() + w3.Write(bytes.Repeat([]byte("3"), 40000)) + if got, want := buf.Len(), 32768; got != want { + t.Fatalf("buffer length #4: got %d want %d", got, want) + } + // Flushing should get us up to 50038 bytes written. + // 50038 = 10024 + 2*7 + 40000. There are two headers because + // the one record was split into two chunks. + if err := w.Flush(); err != nil { + t.Fatal(err) + } + if got, want := buf.Len(), 50038; got != want { + t.Fatalf("buffer length #5: got %d want %d", got, want) + } + // Check that reading those records give the right lengths. + r := NewReader(buf, dropper{t}, true, true) + wants := []int64{1, 2, 10000, 40000} + for i, want := range wants { + rr, _ := r.Next() + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #%d: %v", i, err) + } + if n != want { + t.Fatalf("read #%d: got %d bytes want %d", i, n, want) + } + } +} + +func TestNonExhaustiveRead(t *testing.T) { + const n = 100 + buf := new(bytes.Buffer) + p := make([]byte, 10) + rnd := rand.New(rand.NewSource(1)) + + w := NewWriter(buf) + for i := 0; i < n; i++ { + length := len(p) + rnd.Intn(3*blockSize) + s := string(uint8(i)) + "123456789abcdefgh" + ww, _ := w.Next() + ww.Write([]byte(big(s, length))) + } + if err := w.Close(); err != nil { + t.Fatal(err) + } + + r := NewReader(buf, dropper{t}, true, true) + for i := 0; i < n; i++ { + rr, _ := r.Next() + _, err := io.ReadFull(rr, p) + if err != nil { + t.Fatal(err) + } + want := string(uint8(i)) + "123456789" + if got := string(p); got != want { + t.Fatalf("read #%d: got %q want %q", i, got, want) + } + } +} + +func TestStaleReader(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + w0, err := w.Next() + if err != nil { + t.Fatal(err) + } + w0.Write([]byte("0")) + w1, err := w.Next() + if err != nil { + t.Fatal(err) + } + w1.Write([]byte("11")) + if err := w.Close(); err != nil { + t.Fatal(err) + } + + r := NewReader(buf, dropper{t}, true, true) + r0, err := r.Next() + if err != nil { + t.Fatal(err) + } + r1, err := r.Next() + if err != nil { + t.Fatal(err) + } + p := make([]byte, 1) + if _, err := r0.Read(p); err == nil || !strings.Contains(err.Error(), "stale") { + t.Fatalf("stale read #0: unexpected error: %v", err) + } + if _, err := r1.Read(p); err != nil { + t.Fatalf("fresh read #1: got %v want nil error", err) + } + if p[0] != '1' { + t.Fatalf("fresh read #1: byte contents: got '%c' want '1'", p[0]) + } +} + +func TestStaleWriter(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + w0, err := w.Next() + if err != nil { + t.Fatal(err) + } + w1, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := w0.Write([]byte("0")); err == nil || !strings.Contains(err.Error(), "stale") { + t.Fatalf("stale write #0: unexpected error: %v", err) + } + if _, err := w1.Write([]byte("11")); err != nil { + t.Fatalf("fresh write #1: got %v want nil error", err) + } + if err := w.Flush(); err != nil { + t.Fatalf("flush: %v", err) + } + if _, err := w1.Write([]byte("0")); err == nil || !strings.Contains(err.Error(), "stale") { + t.Fatalf("stale write #1: unexpected error: %v", err) + } +} + +func TestCorrupt_MissingLastBlock(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + + // First record. + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-1024)); err != nil { + t.Fatalf("write #0: unexpected error: %v", err) + } + + // Second record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil { + t.Fatalf("write #1: unexpected error: %v", err) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + // Cut the last block. + b := buf.Bytes()[:blockSize] + r := NewReader(bytes.NewReader(b), dropper{t}, false, true) + + // First read. + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #0: %v", err) + } + if n != blockSize-1024 { + t.Fatalf("read #0: got %d bytes want %d", n, blockSize-1024) + } + + // Second read. + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != io.ErrUnexpectedEOF { + t.Fatalf("read #1: unexpected error: %v", err) + } + + if _, err := r.Next(); err != io.EOF { + t.Fatalf("last next: unexpected error: %v", err) + } +} + +func TestCorrupt_CorruptedFirstBlock(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + + // First record. + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil { + t.Fatalf("write #0: unexpected error: %v", err) + } + + // Second record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil { + t.Fatalf("write #1: unexpected error: %v", err) + } + + // Third record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil { + t.Fatalf("write #2: unexpected error: %v", err) + } + + // Fourth record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+2)); err != nil { + t.Fatalf("write #3: unexpected error: %v", err) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + b := buf.Bytes() + // Corrupting block #0. + for i := 0; i < 1024; i++ { + b[i] = '1' + } + + r := NewReader(bytes.NewReader(b), dropper{t}, false, true) + + // First read (third record). + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #0: %v", err) + } + if want := int64(blockSize-headerSize) + 1; n != want { + t.Fatalf("read #0: got %d bytes want %d", n, want) + } + + // Second read (fourth record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #1: %v", err) + } + if want := int64(blockSize-headerSize) + 2; n != want { + t.Fatalf("read #1: got %d bytes want %d", n, want) + } + + if _, err := r.Next(); err != io.EOF { + t.Fatalf("last next: unexpected error: %v", err) + } +} + +func TestCorrupt_CorruptedMiddleBlock(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + + // First record. + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil { + t.Fatalf("write #0: unexpected error: %v", err) + } + + // Second record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil { + t.Fatalf("write #1: unexpected error: %v", err) + } + + // Third record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil { + t.Fatalf("write #2: unexpected error: %v", err) + } + + // Fourth record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+2)); err != nil { + t.Fatalf("write #3: unexpected error: %v", err) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + b := buf.Bytes() + // Corrupting block #1. + for i := 0; i < 1024; i++ { + b[blockSize+i] = '1' + } + + r := NewReader(bytes.NewReader(b), dropper{t}, false, true) + + // First read (first record). + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #0: %v", err) + } + if want := int64(blockSize / 2); n != want { + t.Fatalf("read #0: got %d bytes want %d", n, want) + } + + // Second read (second record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != io.ErrUnexpectedEOF { + t.Fatalf("read #1: unexpected error: %v", err) + } + + // Third read (fourth record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #2: %v", err) + } + if want := int64(blockSize-headerSize) + 2; n != want { + t.Fatalf("read #2: got %d bytes want %d", n, want) + } + + if _, err := r.Next(); err != io.EOF { + t.Fatalf("last next: unexpected error: %v", err) + } +} + +func TestCorrupt_CorruptedLastBlock(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + + // First record. + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil { + t.Fatalf("write #0: unexpected error: %v", err) + } + + // Second record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil { + t.Fatalf("write #1: unexpected error: %v", err) + } + + // Third record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil { + t.Fatalf("write #2: unexpected error: %v", err) + } + + // Fourth record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+2)); err != nil { + t.Fatalf("write #3: unexpected error: %v", err) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + b := buf.Bytes() + // Corrupting block #3. + for i := len(b) - 1; i > len(b)-1024; i-- { + b[i] = '1' + } + + r := NewReader(bytes.NewReader(b), dropper{t}, false, true) + + // First read (first record). + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #0: %v", err) + } + if want := int64(blockSize / 2); n != want { + t.Fatalf("read #0: got %d bytes want %d", n, want) + } + + // Second read (second record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #1: %v", err) + } + if want := int64(blockSize - headerSize); n != want { + t.Fatalf("read #1: got %d bytes want %d", n, want) + } + + // Third read (third record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #2: %v", err) + } + if want := int64(blockSize-headerSize) + 1; n != want { + t.Fatalf("read #2: got %d bytes want %d", n, want) + } + + // Fourth read (fourth record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != io.ErrUnexpectedEOF { + t.Fatalf("read #3: unexpected error: %v", err) + } + + if _, err := r.Next(); err != io.EOF { + t.Fatalf("last next: unexpected error: %v", err) + } +} + +func TestCorrupt_FirstChuckLengthOverflow(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + + // First record. + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil { + t.Fatalf("write #0: unexpected error: %v", err) + } + + // Second record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil { + t.Fatalf("write #1: unexpected error: %v", err) + } + + // Third record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil { + t.Fatalf("write #2: unexpected error: %v", err) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + b := buf.Bytes() + // Corrupting record #1. + x := blockSize + binary.LittleEndian.PutUint16(b[x+4:], 0xffff) + + r := NewReader(bytes.NewReader(b), dropper{t}, false, true) + + // First read (first record). + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #0: %v", err) + } + if want := int64(blockSize / 2); n != want { + t.Fatalf("read #0: got %d bytes want %d", n, want) + } + + // Second read (second record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != io.ErrUnexpectedEOF { + t.Fatalf("read #1: unexpected error: %v", err) + } + + if _, err := r.Next(); err != io.EOF { + t.Fatalf("last next: unexpected error: %v", err) + } +} + +func TestCorrupt_MiddleChuckLengthOverflow(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + + // First record. + ww, err := w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil { + t.Fatalf("write #0: unexpected error: %v", err) + } + + // Second record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil { + t.Fatalf("write #1: unexpected error: %v", err) + } + + // Third record. + ww, err = w.Next() + if err != nil { + t.Fatal(err) + } + if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil { + t.Fatalf("write #2: unexpected error: %v", err) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + b := buf.Bytes() + // Corrupting record #1. + x := blockSize/2 + headerSize + binary.LittleEndian.PutUint16(b[x+4:], 0xffff) + + r := NewReader(bytes.NewReader(b), dropper{t}, false, true) + + // First read (first record). + rr, err := r.Next() + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #0: %v", err) + } + if want := int64(blockSize / 2); n != want { + t.Fatalf("read #0: got %d bytes want %d", n, want) + } + + // Second read (third record). + rr, err = r.Next() + if err != nil { + t.Fatal(err) + } + n, err = io.Copy(ioutil.Discard, rr) + if err != nil { + t.Fatalf("read #1: %v", err) + } + if want := int64(blockSize-headerSize) + 1; n != want { + t.Fatalf("read #1: got %d bytes want %d", n, want) + } + + if _, err := r.Next(); err != io.EOF { + t.Fatalf("last next: unexpected error: %v", err) + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go new file mode 100644 index 00000000..0ae8088d --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go @@ -0,0 +1,142 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "encoding/binary" + "fmt" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" +) + +type ErrIkeyCorrupted struct { + Ikey []byte + Reason string +} + +func (e *ErrIkeyCorrupted) Error() string { + return fmt.Sprintf("leveldb: iKey %q corrupted: %s", e.Ikey, e.Reason) +} + +func newErrIkeyCorrupted(ikey []byte, reason string) error { + return errors.NewErrCorrupted(nil, &ErrIkeyCorrupted{append([]byte{}, ikey...), reason}) +} + +type kType int + +func (kt kType) String() string { + switch kt { + case ktDel: + return "d" + case ktVal: + return "v" + } + return "x" +} + +// Value types encoded as the last component of internal keys. +// Don't modify; this value are saved to disk. +const ( + ktDel kType = iota + ktVal +) + +// ktSeek defines the kType that should be passed when constructing an +// internal key for seeking to a particular sequence number (since we +// sort sequence numbers in decreasing order and the value type is +// embedded as the low 8 bits in the sequence number in internal keys, +// we need to use the highest-numbered ValueType, not the lowest). +const ktSeek = ktVal + +const ( + // Maximum value possible for sequence number; the 8-bits are + // used by value type, so its can packed together in single + // 64-bit integer. + kMaxSeq uint64 = (uint64(1) << 56) - 1 + // Maximum value possible for packed sequence number and type. + kMaxNum uint64 = (kMaxSeq << 8) | uint64(ktSeek) +) + +// Maximum number encoded in bytes. +var kMaxNumBytes = make([]byte, 8) + +func init() { + binary.LittleEndian.PutUint64(kMaxNumBytes, kMaxNum) +} + +type iKey []byte + +func newIkey(ukey []byte, seq uint64, kt kType) iKey { + if seq > kMaxSeq { + panic("leveldb: invalid sequence number") + } else if kt > ktVal { + panic("leveldb: invalid type") + } + + ik := make(iKey, len(ukey)+8) + copy(ik, ukey) + binary.LittleEndian.PutUint64(ik[len(ukey):], (seq<<8)|uint64(kt)) + return ik +} + +func parseIkey(ik []byte) (ukey []byte, seq uint64, kt kType, err error) { + if len(ik) < 8 { + return nil, 0, 0, newErrIkeyCorrupted(ik, "invalid length") + } + num := binary.LittleEndian.Uint64(ik[len(ik)-8:]) + seq, kt = uint64(num>>8), kType(num&0xff) + if kt > ktVal { + return nil, 0, 0, newErrIkeyCorrupted(ik, "invalid type") + } + ukey = ik[:len(ik)-8] + return +} + +func validIkey(ik []byte) bool { + _, _, _, err := parseIkey(ik) + return err == nil +} + +func (ik iKey) assert() { + if ik == nil { + panic("leveldb: nil iKey") + } + if len(ik) < 8 { + panic(fmt.Sprintf("leveldb: iKey %q, len=%d: invalid length", []byte(ik), len(ik))) + } +} + +func (ik iKey) ukey() []byte { + ik.assert() + return ik[:len(ik)-8] +} + +func (ik iKey) num() uint64 { + ik.assert() + return binary.LittleEndian.Uint64(ik[len(ik)-8:]) +} + +func (ik iKey) parseNum() (seq uint64, kt kType) { + num := ik.num() + seq, kt = uint64(num>>8), kType(num&0xff) + if kt > ktVal { + panic(fmt.Sprintf("leveldb: iKey %q, len=%d: invalid type %#x", []byte(ik), len(ik), kt)) + } + return +} + +func (ik iKey) String() string { + if ik == nil { + return "" + } + + if ukey, seq, kt, err := parseIkey(ik); err == nil { + return fmt.Sprintf("%s,%s%d", shorten(string(ukey)), kt, seq) + } else { + return "" + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go new file mode 100644 index 00000000..044a1770 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go @@ -0,0 +1,133 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bytes" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" +) + +var defaultIComparer = &iComparer{comparer.DefaultComparer} + +func ikey(key string, seq uint64, kt kType) iKey { + return newIkey([]byte(key), uint64(seq), kt) +} + +func shortSep(a, b []byte) []byte { + dst := make([]byte, len(a)) + dst = defaultIComparer.Separator(dst[:0], a, b) + if dst == nil { + return a + } + return dst +} + +func shortSuccessor(b []byte) []byte { + dst := make([]byte, len(b)) + dst = defaultIComparer.Successor(dst[:0], b) + if dst == nil { + return b + } + return dst +} + +func testSingleKey(t *testing.T, key string, seq uint64, kt kType) { + ik := ikey(key, seq, kt) + + if !bytes.Equal(ik.ukey(), []byte(key)) { + t.Errorf("user key does not equal, got %v, want %v", string(ik.ukey()), key) + } + + rseq, rt := ik.parseNum() + if rseq != seq { + t.Errorf("seq number does not equal, got %v, want %v", rseq, seq) + } + if rt != kt { + t.Errorf("type does not equal, got %v, want %v", rt, kt) + } + + if rukey, rseq, rt, kerr := parseIkey(ik); kerr == nil { + if !bytes.Equal(rukey, []byte(key)) { + t.Errorf("user key does not equal, got %v, want %v", string(ik.ukey()), key) + } + if rseq != seq { + t.Errorf("seq number does not equal, got %v, want %v", rseq, seq) + } + if rt != kt { + t.Errorf("type does not equal, got %v, want %v", rt, kt) + } + } else { + t.Errorf("key error: %v", kerr) + } +} + +func TestIkey_EncodeDecode(t *testing.T) { + keys := []string{"", "k", "hello", "longggggggggggggggggggggg"} + seqs := []uint64{ + 1, 2, 3, + (1 << 8) - 1, 1 << 8, (1 << 8) + 1, + (1 << 16) - 1, 1 << 16, (1 << 16) + 1, + (1 << 32) - 1, 1 << 32, (1 << 32) + 1, + } + for _, key := range keys { + for _, seq := range seqs { + testSingleKey(t, key, seq, ktVal) + testSingleKey(t, "hello", 1, ktDel) + } + } +} + +func assertBytes(t *testing.T, want, got []byte) { + if !bytes.Equal(got, want) { + t.Errorf("assert failed, got %v, want %v", got, want) + } +} + +func TestIkeyShortSeparator(t *testing.T) { + // When user keys are same + assertBytes(t, ikey("foo", 100, ktVal), + shortSep(ikey("foo", 100, ktVal), + ikey("foo", 99, ktVal))) + assertBytes(t, ikey("foo", 100, ktVal), + shortSep(ikey("foo", 100, ktVal), + ikey("foo", 101, ktVal))) + assertBytes(t, ikey("foo", 100, ktVal), + shortSep(ikey("foo", 100, ktVal), + ikey("foo", 100, ktVal))) + assertBytes(t, ikey("foo", 100, ktVal), + shortSep(ikey("foo", 100, ktVal), + ikey("foo", 100, ktDel))) + + // When user keys are misordered + assertBytes(t, ikey("foo", 100, ktVal), + shortSep(ikey("foo", 100, ktVal), + ikey("bar", 99, ktVal))) + + // When user keys are different, but correctly ordered + assertBytes(t, ikey("g", uint64(kMaxSeq), ktSeek), + shortSep(ikey("foo", 100, ktVal), + ikey("hello", 200, ktVal))) + + // When start user key is prefix of limit user key + assertBytes(t, ikey("foo", 100, ktVal), + shortSep(ikey("foo", 100, ktVal), + ikey("foobar", 200, ktVal))) + + // When limit user key is prefix of start user key + assertBytes(t, ikey("foobar", 100, ktVal), + shortSep(ikey("foobar", 100, ktVal), + ikey("foo", 200, ktVal))) +} + +func TestIkeyShortestSuccessor(t *testing.T) { + assertBytes(t, ikey("g", uint64(kMaxSeq), ktSeek), + shortSuccessor(ikey("foo", 100, ktVal))) + assertBytes(t, ikey("\xff\xff", 100, ktVal), + shortSuccessor(ikey("\xff\xff", 100, ktVal))) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go new file mode 100644 index 00000000..c935a9cf --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go @@ -0,0 +1,11 @@ +package leveldb + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +func TestLevelDB(t *testing.T) { + testutil.RunSuite(t, "LevelDB Suite") +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go new file mode 100644 index 00000000..2478b1ef --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package memdb + +import ( + "encoding/binary" + "math/rand" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" +) + +func BenchmarkPut(b *testing.B) { + buf := make([][4]byte, b.N) + for i := range buf { + binary.LittleEndian.PutUint32(buf[i][:], uint32(i)) + } + + b.ResetTimer() + p := New(comparer.DefaultComparer, 0) + for i := range buf { + p.Put(buf[i][:], nil) + } +} + +func BenchmarkPutRandom(b *testing.B) { + buf := make([][4]byte, b.N) + for i := range buf { + binary.LittleEndian.PutUint32(buf[i][:], uint32(rand.Int())) + } + + b.ResetTimer() + p := New(comparer.DefaultComparer, 0) + for i := range buf { + p.Put(buf[i][:], nil) + } +} + +func BenchmarkGet(b *testing.B) { + buf := make([][4]byte, b.N) + for i := range buf { + binary.LittleEndian.PutUint32(buf[i][:], uint32(i)) + } + + p := New(comparer.DefaultComparer, 0) + for i := range buf { + p.Put(buf[i][:], nil) + } + + b.ResetTimer() + for i := range buf { + p.Get(buf[i][:]) + } +} + +func BenchmarkGetRandom(b *testing.B) { + buf := make([][4]byte, b.N) + for i := range buf { + binary.LittleEndian.PutUint32(buf[i][:], uint32(i)) + } + + p := New(comparer.DefaultComparer, 0) + for i := range buf { + p.Put(buf[i][:], nil) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + p.Get(buf[rand.Int()%b.N][:]) + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go new file mode 100644 index 00000000..9b109e1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go @@ -0,0 +1,468 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package memdb provides in-memory key/value database implementation. +package memdb + +import ( + "math/rand" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +var ( + ErrNotFound = errors.ErrNotFound + ErrIterReleased = errors.New("leveldb/memdb: iterator released") +) + +const tMaxHeight = 12 + +type dbIter struct { + util.BasicReleaser + p *DB + slice *util.Range + node int + forward bool + key, value []byte + err error +} + +func (i *dbIter) fill(checkStart, checkLimit bool) bool { + if i.node != 0 { + n := i.p.nodeData[i.node] + m := n + i.p.nodeData[i.node+nKey] + i.key = i.p.kvData[n:m] + if i.slice != nil { + switch { + case checkLimit && i.slice.Limit != nil && i.p.cmp.Compare(i.key, i.slice.Limit) >= 0: + fallthrough + case checkStart && i.slice.Start != nil && i.p.cmp.Compare(i.key, i.slice.Start) < 0: + i.node = 0 + goto bail + } + } + i.value = i.p.kvData[m : m+i.p.nodeData[i.node+nVal]] + return true + } +bail: + i.key = nil + i.value = nil + return false +} + +func (i *dbIter) Valid() bool { + return i.node != 0 +} + +func (i *dbIter) First() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + i.forward = true + i.p.mu.RLock() + defer i.p.mu.RUnlock() + if i.slice != nil && i.slice.Start != nil { + i.node, _ = i.p.findGE(i.slice.Start, false) + } else { + i.node = i.p.nodeData[nNext] + } + return i.fill(false, true) +} + +func (i *dbIter) Last() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + i.forward = false + i.p.mu.RLock() + defer i.p.mu.RUnlock() + if i.slice != nil && i.slice.Limit != nil { + i.node = i.p.findLT(i.slice.Limit) + } else { + i.node = i.p.findLast() + } + return i.fill(true, false) +} + +func (i *dbIter) Seek(key []byte) bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + i.forward = true + i.p.mu.RLock() + defer i.p.mu.RUnlock() + if i.slice != nil && i.slice.Start != nil && i.p.cmp.Compare(key, i.slice.Start) < 0 { + key = i.slice.Start + } + i.node, _ = i.p.findGE(key, false) + return i.fill(false, true) +} + +func (i *dbIter) Next() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + if i.node == 0 { + if !i.forward { + return i.First() + } + return false + } + i.forward = true + i.p.mu.RLock() + defer i.p.mu.RUnlock() + i.node = i.p.nodeData[i.node+nNext] + return i.fill(false, true) +} + +func (i *dbIter) Prev() bool { + if i.Released() { + i.err = ErrIterReleased + return false + } + + if i.node == 0 { + if i.forward { + return i.Last() + } + return false + } + i.forward = false + i.p.mu.RLock() + defer i.p.mu.RUnlock() + i.node = i.p.findLT(i.key) + return i.fill(true, false) +} + +func (i *dbIter) Key() []byte { + return i.key +} + +func (i *dbIter) Value() []byte { + return i.value +} + +func (i *dbIter) Error() error { return i.err } + +func (i *dbIter) Release() { + if !i.Released() { + i.p = nil + i.node = 0 + i.key = nil + i.value = nil + i.BasicReleaser.Release() + } +} + +const ( + nKV = iota + nKey + nVal + nHeight + nNext +) + +// DB is an in-memory key/value database. +type DB struct { + cmp comparer.BasicComparer + rnd *rand.Rand + + mu sync.RWMutex + kvData []byte + // Node data: + // [0] : KV offset + // [1] : Key length + // [2] : Value length + // [3] : Height + // [3..height] : Next nodes + nodeData []int + prevNode [tMaxHeight]int + maxHeight int + n int + kvSize int +} + +func (p *DB) randHeight() (h int) { + const branching = 4 + h = 1 + for h < tMaxHeight && p.rnd.Int()%branching == 0 { + h++ + } + return +} + +func (p *DB) findGE(key []byte, prev bool) (int, bool) { + node := 0 + h := p.maxHeight - 1 + for { + next := p.nodeData[node+nNext+h] + cmp := 1 + if next != 0 { + o := p.nodeData[next] + cmp = p.cmp.Compare(p.kvData[o:o+p.nodeData[next+nKey]], key) + } + if cmp < 0 { + // Keep searching in this list + node = next + } else { + if prev { + p.prevNode[h] = node + } else if cmp == 0 { + return next, true + } + if h == 0 { + return next, cmp == 0 + } + h-- + } + } +} + +func (p *DB) findLT(key []byte) int { + node := 0 + h := p.maxHeight - 1 + for { + next := p.nodeData[node+nNext+h] + o := p.nodeData[next] + if next == 0 || p.cmp.Compare(p.kvData[o:o+p.nodeData[next+nKey]], key) >= 0 { + if h == 0 { + break + } + h-- + } else { + node = next + } + } + return node +} + +func (p *DB) findLast() int { + node := 0 + h := p.maxHeight - 1 + for { + next := p.nodeData[node+nNext+h] + if next == 0 { + if h == 0 { + break + } + h-- + } else { + node = next + } + } + return node +} + +// Put sets the value for the given key. It overwrites any previous value +// for that key; a DB is not a multi-map. +// +// It is safe to modify the contents of the arguments after Put returns. +func (p *DB) Put(key []byte, value []byte) error { + p.mu.Lock() + defer p.mu.Unlock() + + if node, exact := p.findGE(key, true); exact { + kvOffset := len(p.kvData) + p.kvData = append(p.kvData, key...) + p.kvData = append(p.kvData, value...) + p.nodeData[node] = kvOffset + m := p.nodeData[node+nVal] + p.nodeData[node+nVal] = len(value) + p.kvSize += len(value) - m + return nil + } + + h := p.randHeight() + if h > p.maxHeight { + for i := p.maxHeight; i < h; i++ { + p.prevNode[i] = 0 + } + p.maxHeight = h + } + + kvOffset := len(p.kvData) + p.kvData = append(p.kvData, key...) + p.kvData = append(p.kvData, value...) + // Node + node := len(p.nodeData) + p.nodeData = append(p.nodeData, kvOffset, len(key), len(value), h) + for i, n := range p.prevNode[:h] { + m := n + 4 + i + p.nodeData = append(p.nodeData, p.nodeData[m]) + p.nodeData[m] = node + } + + p.kvSize += len(key) + len(value) + p.n++ + return nil +} + +// Delete deletes the value for the given key. It returns ErrNotFound if +// the DB does not contain the key. +// +// It is safe to modify the contents of the arguments after Delete returns. +func (p *DB) Delete(key []byte) error { + p.mu.Lock() + defer p.mu.Unlock() + + node, exact := p.findGE(key, true) + if !exact { + return ErrNotFound + } + + h := p.nodeData[node+nHeight] + for i, n := range p.prevNode[:h] { + m := n + 4 + i + p.nodeData[m] = p.nodeData[p.nodeData[m]+nNext+i] + } + + p.kvSize -= p.nodeData[node+nKey] + p.nodeData[node+nVal] + p.n-- + return nil +} + +// Contains returns true if the given key are in the DB. +// +// It is safe to modify the contents of the arguments after Contains returns. +func (p *DB) Contains(key []byte) bool { + p.mu.RLock() + _, exact := p.findGE(key, false) + p.mu.RUnlock() + return exact +} + +// Get gets the value for the given key. It returns error.ErrNotFound if the +// DB does not contain the key. +// +// The caller should not modify the contents of the returned slice, but +// it is safe to modify the contents of the argument after Get returns. +func (p *DB) Get(key []byte) (value []byte, err error) { + p.mu.RLock() + if node, exact := p.findGE(key, false); exact { + o := p.nodeData[node] + p.nodeData[node+nKey] + value = p.kvData[o : o+p.nodeData[node+nVal]] + } else { + err = ErrNotFound + } + p.mu.RUnlock() + return +} + +// Find finds key/value pair whose key is greater than or equal to the +// given key. It returns ErrNotFound if the table doesn't contain +// such pair. +// +// The caller should not modify the contents of the returned slice, but +// it is safe to modify the contents of the argument after Find returns. +func (p *DB) Find(key []byte) (rkey, value []byte, err error) { + p.mu.RLock() + if node, _ := p.findGE(key, false); node != 0 { + n := p.nodeData[node] + m := n + p.nodeData[node+nKey] + rkey = p.kvData[n:m] + value = p.kvData[m : m+p.nodeData[node+nVal]] + } else { + err = ErrNotFound + } + p.mu.RUnlock() + return +} + +// NewIterator returns an iterator of the DB. +// The returned iterator is not goroutine-safe, but it is safe to use +// multiple iterators concurrently, with each in a dedicated goroutine. +// It is also safe to use an iterator concurrently with modifying its +// underlying DB. However, the resultant key/value pairs are not guaranteed +// to be a consistent snapshot of the DB at a particular point in time. +// +// Slice allows slicing the iterator to only contains keys in the given +// range. A nil Range.Start is treated as a key before all keys in the +// DB. And a nil Range.Limit is treated as a key after all keys in +// the DB. +// +// The iterator must be released after use, by calling Release method. +// +// Also read Iterator documentation of the leveldb/iterator package. +func (p *DB) NewIterator(slice *util.Range) iterator.Iterator { + return &dbIter{p: p, slice: slice} +} + +// Capacity returns keys/values buffer capacity. +func (p *DB) Capacity() int { + p.mu.RLock() + defer p.mu.RUnlock() + return cap(p.kvData) +} + +// Size returns sum of keys and values length. Note that deleted +// key/value will not be accouted for, but it will still consume +// the buffer, since the buffer is append only. +func (p *DB) Size() int { + p.mu.RLock() + defer p.mu.RUnlock() + return p.kvSize +} + +// Free returns keys/values free buffer before need to grow. +func (p *DB) Free() int { + p.mu.RLock() + defer p.mu.RUnlock() + return cap(p.kvData) - len(p.kvData) +} + +// Len returns the number of entries in the DB. +func (p *DB) Len() int { + p.mu.RLock() + defer p.mu.RUnlock() + return p.n +} + +// Reset resets the DB to initial empty state. Allows reuse the buffer. +func (p *DB) Reset() { + p.rnd = rand.New(rand.NewSource(0xdeadbeef)) + p.maxHeight = 1 + p.n = 0 + p.kvSize = 0 + p.kvData = p.kvData[:0] + p.nodeData = p.nodeData[:4+tMaxHeight] + p.nodeData[nKV] = 0 + p.nodeData[nKey] = 0 + p.nodeData[nVal] = 0 + p.nodeData[nHeight] = tMaxHeight + for n := 0; n < tMaxHeight; n++ { + p.nodeData[4+n] = 0 + p.prevNode[n] = 0 + } +} + +// New creates a new initalized in-memory key/value DB. The capacity +// is the initial key/value buffer capacity. The capacity is advisory, +// not enforced. +// +// The returned DB instance is goroutine-safe. +func New(cmp comparer.BasicComparer, capacity int) *DB { + p := &DB{ + cmp: cmp, + rnd: rand.New(rand.NewSource(0xdeadbeef)), + maxHeight: 1, + kvData: make([]byte, 0, capacity), + nodeData: make([]int, 4+tMaxHeight), + } + p.nodeData[nHeight] = tMaxHeight + return p +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go new file mode 100644 index 00000000..a490636b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go @@ -0,0 +1,11 @@ +package memdb + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +func TestMemDB(t *testing.T) { + testutil.RunSuite(t, "MemDB Suite") +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go new file mode 100644 index 00000000..8a73e5d3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go @@ -0,0 +1,135 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package memdb + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +func (p *DB) TestFindLT(key []byte) (rkey, value []byte, err error) { + p.mu.RLock() + if node := p.findLT(key); node != 0 { + n := p.nodeData[node] + m := n + p.nodeData[node+nKey] + rkey = p.kvData[n:m] + value = p.kvData[m : m+p.nodeData[node+nVal]] + } else { + err = ErrNotFound + } + p.mu.RUnlock() + return +} + +func (p *DB) TestFindLast() (rkey, value []byte, err error) { + p.mu.RLock() + if node := p.findLast(); node != 0 { + n := p.nodeData[node] + m := n + p.nodeData[node+nKey] + rkey = p.kvData[n:m] + value = p.kvData[m : m+p.nodeData[node+nVal]] + } else { + err = ErrNotFound + } + p.mu.RUnlock() + return +} + +func (p *DB) TestPut(key []byte, value []byte) error { + p.Put(key, value) + return nil +} + +func (p *DB) TestDelete(key []byte) error { + p.Delete(key) + return nil +} + +func (p *DB) TestFind(key []byte) (rkey, rvalue []byte, err error) { + return p.Find(key) +} + +func (p *DB) TestGet(key []byte) (value []byte, err error) { + return p.Get(key) +} + +func (p *DB) TestNewIterator(slice *util.Range) iterator.Iterator { + return p.NewIterator(slice) +} + +var _ = testutil.Defer(func() { + Describe("Memdb", func() { + Describe("write test", func() { + It("should do write correctly", func() { + db := New(comparer.DefaultComparer, 0) + t := testutil.DBTesting{ + DB: db, + Deleted: testutil.KeyValue_Generate(nil, 1000, 1, 30, 5, 5).Clone(), + PostFn: func(t *testutil.DBTesting) { + Expect(db.Len()).Should(Equal(t.Present.Len())) + Expect(db.Size()).Should(Equal(t.Present.Size())) + switch t.Act { + case testutil.DBPut, testutil.DBOverwrite: + Expect(db.Contains(t.ActKey)).Should(BeTrue()) + default: + Expect(db.Contains(t.ActKey)).Should(BeFalse()) + } + }, + } + testutil.DoDBTesting(&t) + }) + }) + + Describe("read test", func() { + testutil.AllKeyValueTesting(nil, func(kv testutil.KeyValue) testutil.DB { + // Building the DB. + db := New(comparer.DefaultComparer, 0) + kv.IterateShuffled(nil, func(i int, key, value []byte) { + db.Put(key, value) + }) + + if kv.Len() > 1 { + It("Should find correct keys with findLT", func() { + testutil.ShuffledIndex(nil, kv.Len()-1, 1, func(i int) { + key_, key, _ := kv.IndexInexact(i + 1) + expectedKey, expectedValue := kv.Index(i) + + // Using key that exist. + rkey, rvalue, err := db.TestFindLT(key) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q -> %q", key, expectedKey) + Expect(rkey).Should(Equal(expectedKey), "Key") + Expect(rvalue).Should(Equal(expectedValue), "Value for key %q -> %q", key, expectedKey) + + // Using key that doesn't exist. + rkey, rvalue, err = db.TestFindLT(key_) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q) -> %q", key_, key, expectedKey) + Expect(rkey).Should(Equal(expectedKey)) + Expect(rvalue).Should(Equal(expectedValue), "Value for key %q (%q) -> %q", key_, key, expectedKey) + }) + }) + } + + if kv.Len() > 0 { + It("Should find last key with findLast", func() { + key, value := kv.Index(kv.Len() - 1) + rkey, rvalue, err := db.TestFindLast() + Expect(err).ShouldNot(HaveOccurred()) + Expect(rkey).Should(Equal(key)) + Expect(rvalue).Should(Equal(value)) + }) + } + + return db + }, nil, nil) + }) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go new file mode 100644 index 00000000..79051dfb --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go @@ -0,0 +1,639 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package opt provides sets of options used by LevelDB. +package opt + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "math" +) + +const ( + KiB = 1024 + MiB = KiB * 1024 + GiB = MiB * 1024 +) + +var ( + DefaultBlockCacher = LRUCacher + DefaultBlockCacheCapacity = 8 * MiB + DefaultBlockRestartInterval = 16 + DefaultBlockSize = 4 * KiB + DefaultCompactionExpandLimitFactor = 25 + DefaultCompactionGPOverlapsFactor = 10 + DefaultCompactionL0Trigger = 4 + DefaultCompactionSourceLimitFactor = 1 + DefaultCompactionTableSize = 2 * MiB + DefaultCompactionTableSizeMultiplier = 1.0 + DefaultCompactionTotalSize = 10 * MiB + DefaultCompactionTotalSizeMultiplier = 10.0 + DefaultCompressionType = SnappyCompression + DefaultIteratorSamplingRate = 1 * MiB + DefaultMaxMemCompationLevel = 2 + DefaultNumLevel = 7 + DefaultOpenFilesCacher = LRUCacher + DefaultOpenFilesCacheCapacity = 500 + DefaultWriteBuffer = 4 * MiB + DefaultWriteL0PauseTrigger = 12 + DefaultWriteL0SlowdownTrigger = 8 +) + +// Cacher is a caching algorithm. +type Cacher interface { + New(capacity int) cache.Cacher +} + +type CacherFunc struct { + NewFunc func(capacity int) cache.Cacher +} + +func (f *CacherFunc) New(capacity int) cache.Cacher { + if f.NewFunc != nil { + return f.NewFunc(capacity) + } + return nil +} + +func noCacher(int) cache.Cacher { return nil } + +var ( + // LRUCacher is the LRU-cache algorithm. + LRUCacher = &CacherFunc{cache.NewLRU} + + // NoCacher is the value to disable caching algorithm. + NoCacher = &CacherFunc{} +) + +// Compression is the 'sorted table' block compression algorithm to use. +type Compression uint + +func (c Compression) String() string { + switch c { + case DefaultCompression: + return "default" + case NoCompression: + return "none" + case SnappyCompression: + return "snappy" + } + return "invalid" +} + +const ( + DefaultCompression Compression = iota + NoCompression + SnappyCompression + nCompression +) + +// Strict is the DB 'strict level'. +type Strict uint + +const ( + // If present then a corrupted or invalid chunk or block in manifest + // journal will cause an error instead of being dropped. + // This will prevent database with corrupted manifest to be opened. + StrictManifest Strict = 1 << iota + + // If present then journal chunk checksum will be verified. + StrictJournalChecksum + + // If present then a corrupted or invalid chunk or block in journal + // will cause an error instead of being dropped. + // This will prevent database with corrupted journal to be opened. + StrictJournal + + // If present then 'sorted table' block checksum will be verified. + // This has effect on both 'read operation' and compaction. + StrictBlockChecksum + + // If present then a corrupted 'sorted table' will fails compaction. + // The database will enter read-only mode. + StrictCompaction + + // If present then a corrupted 'sorted table' will halts 'read operation'. + StrictReader + + // If present then leveldb.Recover will drop corrupted 'sorted table'. + StrictRecovery + + // This only applicable for ReadOptions, if present then this ReadOptions + // 'strict level' will override global ones. + StrictOverride + + // StrictAll enables all strict flags. + StrictAll = StrictManifest | StrictJournalChecksum | StrictJournal | StrictBlockChecksum | StrictCompaction | StrictReader | StrictRecovery + + // DefaultStrict is the default strict flags. Specify any strict flags + // will override default strict flags as whole (i.e. not OR'ed). + DefaultStrict = StrictJournalChecksum | StrictBlockChecksum | StrictCompaction | StrictReader + + // NoStrict disables all strict flags. Override default strict flags. + NoStrict = ^StrictAll +) + +// Options holds the optional parameters for the DB at large. +type Options struct { + // AltFilters defines one or more 'alternative filters'. + // 'alternative filters' will be used during reads if a filter block + // does not match with the 'effective filter'. + // + // The default value is nil + AltFilters []filter.Filter + + // BlockCacher provides cache algorithm for LevelDB 'sorted table' block caching. + // Specify NoCacher to disable caching algorithm. + // + // The default value is LRUCacher. + BlockCacher Cacher + + // BlockCacheCapacity defines the capacity of the 'sorted table' block caching. + // Use -1 for zero, this has same effect as specifying NoCacher to BlockCacher. + // + // The default value is 8MiB. + BlockCacheCapacity int + + // BlockRestartInterval is the number of keys between restart points for + // delta encoding of keys. + // + // The default value is 16. + BlockRestartInterval int + + // BlockSize is the minimum uncompressed size in bytes of each 'sorted table' + // block. + // + // The default value is 4KiB. + BlockSize int + + // CompactionExpandLimitFactor limits compaction size after expanded. + // This will be multiplied by table size limit at compaction target level. + // + // The default value is 25. + CompactionExpandLimitFactor int + + // CompactionGPOverlapsFactor limits overlaps in grandparent (Level + 2) that a + // single 'sorted table' generates. + // This will be multiplied by table size limit at grandparent level. + // + // The default value is 10. + CompactionGPOverlapsFactor int + + // CompactionL0Trigger defines number of 'sorted table' at level-0 that will + // trigger compaction. + // + // The default value is 4. + CompactionL0Trigger int + + // CompactionSourceLimitFactor limits compaction source size. This doesn't apply to + // level-0. + // This will be multiplied by table size limit at compaction target level. + // + // The default value is 1. + CompactionSourceLimitFactor int + + // CompactionTableSize limits size of 'sorted table' that compaction generates. + // The limits for each level will be calculated as: + // CompactionTableSize * (CompactionTableSizeMultiplier ^ Level) + // The multiplier for each level can also fine-tuned using CompactionTableSizeMultiplierPerLevel. + // + // The default value is 2MiB. + CompactionTableSize int + + // CompactionTableSizeMultiplier defines multiplier for CompactionTableSize. + // + // The default value is 1. + CompactionTableSizeMultiplier float64 + + // CompactionTableSizeMultiplierPerLevel defines per-level multiplier for + // CompactionTableSize. + // Use zero to skip a level. + // + // The default value is nil. + CompactionTableSizeMultiplierPerLevel []float64 + + // CompactionTotalSize limits total size of 'sorted table' for each level. + // The limits for each level will be calculated as: + // CompactionTotalSize * (CompactionTotalSizeMultiplier ^ Level) + // The multiplier for each level can also fine-tuned using + // CompactionTotalSizeMultiplierPerLevel. + // + // The default value is 10MiB. + CompactionTotalSize int + + // CompactionTotalSizeMultiplier defines multiplier for CompactionTotalSize. + // + // The default value is 10. + CompactionTotalSizeMultiplier float64 + + // CompactionTotalSizeMultiplierPerLevel defines per-level multiplier for + // CompactionTotalSize. + // Use zero to skip a level. + // + // The default value is nil. + CompactionTotalSizeMultiplierPerLevel []float64 + + // Comparer defines a total ordering over the space of []byte keys: a 'less + // than' relationship. The same comparison algorithm must be used for reads + // and writes over the lifetime of the DB. + // + // The default value uses the same ordering as bytes.Compare. + Comparer comparer.Comparer + + // Compression defines the 'sorted table' block compression to use. + // + // The default value (DefaultCompression) uses snappy compression. + Compression Compression + + // DisableBlockCache allows disable use of cache.Cache functionality on + // 'sorted table' block. + // + // The default value is false. + DisableBlockCache bool + + // DisableCompactionBackoff allows disable compaction retry backoff. + // + // The default value is false. + DisableCompactionBackoff bool + + // ErrorIfExist defines whether an error should returned if the DB already + // exist. + // + // The default value is false. + ErrorIfExist bool + + // ErrorIfMissing defines whether an error should returned if the DB is + // missing. If false then the database will be created if missing, otherwise + // an error will be returned. + // + // The default value is false. + ErrorIfMissing bool + + // Filter defines an 'effective filter' to use. An 'effective filter' + // if defined will be used to generate per-table filter block. + // The filter name will be stored on disk. + // During reads LevelDB will try to find matching filter from + // 'effective filter' and 'alternative filters'. + // + // Filter can be changed after a DB has been created. It is recommended + // to put old filter to the 'alternative filters' to mitigate lack of + // filter during transition period. + // + // A filter is used to reduce disk reads when looking for a specific key. + // + // The default value is nil. + Filter filter.Filter + + // IteratorSamplingRate defines approximate gap (in bytes) between read + // sampling of an iterator. The samples will be used to determine when + // compaction should be triggered. + // + // The default is 1MiB. + IteratorSamplingRate int + + // MaxMemCompationLevel defines maximum level a newly compacted 'memdb' + // will be pushed into if doesn't creates overlap. This should less than + // NumLevel. Use -1 for level-0. + // + // The default is 2. + MaxMemCompationLevel int + + // NumLevel defines number of database level. The level shouldn't changed + // between opens, or the database will panic. + // + // The default is 7. + NumLevel int + + // OpenFilesCacher provides cache algorithm for open files caching. + // Specify NoCacher to disable caching algorithm. + // + // The default value is LRUCacher. + OpenFilesCacher Cacher + + // OpenFilesCacheCapacity defines the capacity of the open files caching. + // Use -1 for zero, this has same effect as specifying NoCacher to OpenFilesCacher. + // + // The default value is 500. + OpenFilesCacheCapacity int + + // Strict defines the DB strict level. + Strict Strict + + // WriteBuffer defines maximum size of a 'memdb' before flushed to + // 'sorted table'. 'memdb' is an in-memory DB backed by an on-disk + // unsorted journal. + // + // LevelDB may held up to two 'memdb' at the same time. + // + // The default value is 4MiB. + WriteBuffer int + + // WriteL0StopTrigger defines number of 'sorted table' at level-0 that will + // pause write. + // + // The default value is 12. + WriteL0PauseTrigger int + + // WriteL0SlowdownTrigger defines number of 'sorted table' at level-0 that + // will trigger write slowdown. + // + // The default value is 8. + WriteL0SlowdownTrigger int +} + +func (o *Options) GetAltFilters() []filter.Filter { + if o == nil { + return nil + } + return o.AltFilters +} + +func (o *Options) GetBlockCacher() Cacher { + if o == nil || o.BlockCacher == nil { + return DefaultBlockCacher + } else if o.BlockCacher == NoCacher { + return nil + } + return o.BlockCacher +} + +func (o *Options) GetBlockCacheCapacity() int { + if o == nil || o.BlockCacheCapacity == 0 { + return DefaultBlockCacheCapacity + } else if o.BlockCacheCapacity < 0 { + return 0 + } + return o.BlockCacheCapacity +} + +func (o *Options) GetBlockRestartInterval() int { + if o == nil || o.BlockRestartInterval <= 0 { + return DefaultBlockRestartInterval + } + return o.BlockRestartInterval +} + +func (o *Options) GetBlockSize() int { + if o == nil || o.BlockSize <= 0 { + return DefaultBlockSize + } + return o.BlockSize +} + +func (o *Options) GetCompactionExpandLimit(level int) int { + factor := DefaultCompactionExpandLimitFactor + if o != nil && o.CompactionExpandLimitFactor > 0 { + factor = o.CompactionExpandLimitFactor + } + return o.GetCompactionTableSize(level+1) * factor +} + +func (o *Options) GetCompactionGPOverlaps(level int) int { + factor := DefaultCompactionGPOverlapsFactor + if o != nil && o.CompactionGPOverlapsFactor > 0 { + factor = o.CompactionGPOverlapsFactor + } + return o.GetCompactionTableSize(level+2) * factor +} + +func (o *Options) GetCompactionL0Trigger() int { + if o == nil || o.CompactionL0Trigger == 0 { + return DefaultCompactionL0Trigger + } + return o.CompactionL0Trigger +} + +func (o *Options) GetCompactionSourceLimit(level int) int { + factor := DefaultCompactionSourceLimitFactor + if o != nil && o.CompactionSourceLimitFactor > 0 { + factor = o.CompactionSourceLimitFactor + } + return o.GetCompactionTableSize(level+1) * factor +} + +func (o *Options) GetCompactionTableSize(level int) int { + var ( + base = DefaultCompactionTableSize + mult float64 + ) + if o != nil { + if o.CompactionTableSize > 0 { + base = o.CompactionTableSize + } + if len(o.CompactionTableSizeMultiplierPerLevel) > level && o.CompactionTableSizeMultiplierPerLevel[level] > 0 { + mult = o.CompactionTableSizeMultiplierPerLevel[level] + } else if o.CompactionTableSizeMultiplier > 0 { + mult = math.Pow(o.CompactionTableSizeMultiplier, float64(level)) + } + } + if mult == 0 { + mult = math.Pow(DefaultCompactionTableSizeMultiplier, float64(level)) + } + return int(float64(base) * mult) +} + +func (o *Options) GetCompactionTotalSize(level int) int64 { + var ( + base = DefaultCompactionTotalSize + mult float64 + ) + if o != nil { + if o.CompactionTotalSize > 0 { + base = o.CompactionTotalSize + } + if len(o.CompactionTotalSizeMultiplierPerLevel) > level && o.CompactionTotalSizeMultiplierPerLevel[level] > 0 { + mult = o.CompactionTotalSizeMultiplierPerLevel[level] + } else if o.CompactionTotalSizeMultiplier > 0 { + mult = math.Pow(o.CompactionTotalSizeMultiplier, float64(level)) + } + } + if mult == 0 { + mult = math.Pow(DefaultCompactionTotalSizeMultiplier, float64(level)) + } + return int64(float64(base) * mult) +} + +func (o *Options) GetComparer() comparer.Comparer { + if o == nil || o.Comparer == nil { + return comparer.DefaultComparer + } + return o.Comparer +} + +func (o *Options) GetCompression() Compression { + if o == nil || o.Compression <= DefaultCompression || o.Compression >= nCompression { + return DefaultCompressionType + } + return o.Compression +} + +func (o *Options) GetDisableCompactionBackoff() bool { + if o == nil { + return false + } + return o.DisableCompactionBackoff +} + +func (o *Options) GetErrorIfExist() bool { + if o == nil { + return false + } + return o.ErrorIfExist +} + +func (o *Options) GetErrorIfMissing() bool { + if o == nil { + return false + } + return o.ErrorIfMissing +} + +func (o *Options) GetFilter() filter.Filter { + if o == nil { + return nil + } + return o.Filter +} + +func (o *Options) GetIteratorSamplingRate() int { + if o == nil || o.IteratorSamplingRate <= 0 { + return DefaultIteratorSamplingRate + } + return o.IteratorSamplingRate +} + +func (o *Options) GetMaxMemCompationLevel() int { + level := DefaultMaxMemCompationLevel + if o != nil { + if o.MaxMemCompationLevel > 0 { + level = o.MaxMemCompationLevel + } else if o.MaxMemCompationLevel < 0 { + level = 0 + } + } + if level >= o.GetNumLevel() { + return o.GetNumLevel() - 1 + } + return level +} + +func (o *Options) GetNumLevel() int { + if o == nil || o.NumLevel <= 0 { + return DefaultNumLevel + } + return o.NumLevel +} + +func (o *Options) GetOpenFilesCacher() Cacher { + if o == nil || o.OpenFilesCacher == nil { + return DefaultOpenFilesCacher + } + if o.OpenFilesCacher == NoCacher { + return nil + } + return o.OpenFilesCacher +} + +func (o *Options) GetOpenFilesCacheCapacity() int { + if o == nil || o.OpenFilesCacheCapacity == 0 { + return DefaultOpenFilesCacheCapacity + } else if o.OpenFilesCacheCapacity < 0 { + return 0 + } + return o.OpenFilesCacheCapacity +} + +func (o *Options) GetStrict(strict Strict) bool { + if o == nil || o.Strict == 0 { + return DefaultStrict&strict != 0 + } + return o.Strict&strict != 0 +} + +func (o *Options) GetWriteBuffer() int { + if o == nil || o.WriteBuffer <= 0 { + return DefaultWriteBuffer + } + return o.WriteBuffer +} + +func (o *Options) GetWriteL0PauseTrigger() int { + if o == nil || o.WriteL0PauseTrigger == 0 { + return DefaultWriteL0PauseTrigger + } + return o.WriteL0PauseTrigger +} + +func (o *Options) GetWriteL0SlowdownTrigger() int { + if o == nil || o.WriteL0SlowdownTrigger == 0 { + return DefaultWriteL0SlowdownTrigger + } + return o.WriteL0SlowdownTrigger +} + +// ReadOptions holds the optional parameters for 'read operation'. The +// 'read operation' includes Get, Find and NewIterator. +type ReadOptions struct { + // DontFillCache defines whether block reads for this 'read operation' + // should be cached. If false then the block will be cached. This does + // not affects already cached block. + // + // The default value is false. + DontFillCache bool + + // Strict will be OR'ed with global DB 'strict level' unless StrictOverride + // is present. Currently only StrictReader that has effect here. + Strict Strict +} + +func (ro *ReadOptions) GetDontFillCache() bool { + if ro == nil { + return false + } + return ro.DontFillCache +} + +func (ro *ReadOptions) GetStrict(strict Strict) bool { + if ro == nil { + return false + } + return ro.Strict&strict != 0 +} + +// WriteOptions holds the optional parameters for 'write operation'. The +// 'write operation' includes Write, Put and Delete. +type WriteOptions struct { + // Sync is whether to sync underlying writes from the OS buffer cache + // through to actual disk, if applicable. Setting Sync can result in + // slower writes. + // + // If false, and the machine crashes, then some recent writes may be lost. + // Note that if it is just the process that crashes (and the machine does + // not) then no writes will be lost. + // + // In other words, Sync being false has the same semantics as a write + // system call. Sync being true means write followed by fsync. + // + // The default value is false. + Sync bool +} + +func (wo *WriteOptions) GetSync() bool { + if wo == nil { + return false + } + return wo.Sync +} + +func GetStrict(o *Options, ro *ReadOptions, strict Strict) bool { + if ro.GetStrict(StrictOverride) { + return ro.GetStrict(strict) + } else { + return o.GetStrict(strict) || ro.GetStrict(strict) + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go new file mode 100644 index 00000000..6b9b20a9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go @@ -0,0 +1,92 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" +) + +func dupOptions(o *opt.Options) *opt.Options { + newo := &opt.Options{} + if o != nil { + *newo = *o + } + if newo.Strict == 0 { + newo.Strict = opt.DefaultStrict + } + return newo +} + +func (s *session) setOptions(o *opt.Options) { + no := dupOptions(o) + // Alternative filters. + if filters := o.GetAltFilters(); len(filters) > 0 { + no.AltFilters = make([]filter.Filter, len(filters)) + for i, filter := range filters { + no.AltFilters[i] = &iFilter{filter} + } + } + // Comparer. + s.icmp = &iComparer{o.GetComparer()} + no.Comparer = s.icmp + // Filter. + if filter := o.GetFilter(); filter != nil { + no.Filter = &iFilter{filter} + } + + s.o = &cachedOptions{Options: no} + s.o.cache() +} + +type cachedOptions struct { + *opt.Options + + compactionExpandLimit []int + compactionGPOverlaps []int + compactionSourceLimit []int + compactionTableSize []int + compactionTotalSize []int64 +} + +func (co *cachedOptions) cache() { + numLevel := co.Options.GetNumLevel() + + co.compactionExpandLimit = make([]int, numLevel) + co.compactionGPOverlaps = make([]int, numLevel) + co.compactionSourceLimit = make([]int, numLevel) + co.compactionTableSize = make([]int, numLevel) + co.compactionTotalSize = make([]int64, numLevel) + + for level := 0; level < numLevel; level++ { + co.compactionExpandLimit[level] = co.Options.GetCompactionExpandLimit(level) + co.compactionGPOverlaps[level] = co.Options.GetCompactionGPOverlaps(level) + co.compactionSourceLimit[level] = co.Options.GetCompactionSourceLimit(level) + co.compactionTableSize[level] = co.Options.GetCompactionTableSize(level) + co.compactionTotalSize[level] = co.Options.GetCompactionTotalSize(level) + } +} + +func (co *cachedOptions) GetCompactionExpandLimit(level int) int { + return co.compactionExpandLimit[level] +} + +func (co *cachedOptions) GetCompactionGPOverlaps(level int) int { + return co.compactionGPOverlaps[level] +} + +func (co *cachedOptions) GetCompactionSourceLimit(level int) int { + return co.compactionSourceLimit[level] +} + +func (co *cachedOptions) GetCompactionTableSize(level int) int { + return co.compactionTableSize[level] +} + +func (co *cachedOptions) GetCompactionTotalSize(level int) int64 { + return co.compactionTotalSize[level] +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go new file mode 100644 index 00000000..814737dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go @@ -0,0 +1,455 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "fmt" + "io" + "os" + "sync" + "sync/atomic" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type ErrManifestCorrupted struct { + Field string + Reason string +} + +func (e *ErrManifestCorrupted) Error() string { + return fmt.Sprintf("leveldb: manifest corrupted (field '%s'): %s", e.Field, e.Reason) +} + +func newErrManifestCorrupted(f storage.File, field, reason string) error { + return errors.NewErrCorrupted(f, &ErrManifestCorrupted{field, reason}) +} + +// session represent a persistent database session. +type session struct { + // Need 64-bit alignment. + stNextFileNum uint64 // current unused file number + stJournalNum uint64 // current journal file number; need external synchronization + stPrevJournalNum uint64 // prev journal file number; no longer used; for compatibility with older version of leveldb + stSeqNum uint64 // last mem compacted seq; need external synchronization + stTempFileNum uint64 + + stor storage.Storage + storLock util.Releaser + o *cachedOptions + icmp *iComparer + tops *tOps + + manifest *journal.Writer + manifestWriter storage.Writer + manifestFile storage.File + + stCompPtrs []iKey // compaction pointers; need external synchronization + stVersion *version // current version + vmu sync.Mutex +} + +// Creates new initialized session instance. +func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) { + if stor == nil { + return nil, os.ErrInvalid + } + storLock, err := stor.Lock() + if err != nil { + return + } + s = &session{ + stor: stor, + storLock: storLock, + stCompPtrs: make([]iKey, o.GetNumLevel()), + } + s.setOptions(o) + s.tops = newTableOps(s) + s.setVersion(newVersion(s)) + s.log("log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed") + return +} + +// Close session. +func (s *session) close() { + s.tops.close() + if s.manifest != nil { + s.manifest.Close() + } + if s.manifestWriter != nil { + s.manifestWriter.Close() + } + s.manifest = nil + s.manifestWriter = nil + s.manifestFile = nil + s.stVersion = nil +} + +// Release session lock. +func (s *session) release() { + s.storLock.Release() +} + +// Create a new database session; need external synchronization. +func (s *session) create() error { + // create manifest + return s.newManifest(nil, nil) +} + +// Recover a database session; need external synchronization. +func (s *session) recover() (err error) { + defer func() { + if os.IsNotExist(err) { + // Don't return os.ErrNotExist if the underlying storage contains + // other files that belong to LevelDB. So the DB won't get trashed. + if files, _ := s.stor.GetFiles(storage.TypeAll); len(files) > 0 { + err = &errors.ErrCorrupted{File: &storage.FileInfo{Type: storage.TypeManifest}, Err: &errors.ErrMissingFiles{}} + } + } + }() + + m, err := s.stor.GetManifest() + if err != nil { + return + } + + reader, err := m.Open() + if err != nil { + return + } + defer reader.Close() + strict := s.o.GetStrict(opt.StrictManifest) + jr := journal.NewReader(reader, dropper{s, m}, strict, true) + + staging := s.stVersion.newStaging() + rec := &sessionRecord{numLevel: s.o.GetNumLevel()} + for { + var r io.Reader + r, err = jr.Next() + if err != nil { + if err == io.EOF { + err = nil + break + } + return errors.SetFile(err, m) + } + + err = rec.decode(r) + if err == nil { + // save compact pointers + for _, r := range rec.compPtrs { + s.stCompPtrs[r.level] = iKey(r.ikey) + } + // commit record to version staging + staging.commit(rec) + } else { + err = errors.SetFile(err, m) + if strict || !errors.IsCorrupted(err) { + return + } else { + s.logf("manifest error: %v (skipped)", errors.SetFile(err, m)) + } + } + rec.resetCompPtrs() + rec.resetAddedTables() + rec.resetDeletedTables() + } + + switch { + case !rec.has(recComparer): + return newErrManifestCorrupted(m, "comparer", "missing") + case rec.comparer != s.icmp.uName(): + return newErrManifestCorrupted(m, "comparer", fmt.Sprintf("mismatch: want '%s', got '%s'", s.icmp.uName(), rec.comparer)) + case !rec.has(recNextFileNum): + return newErrManifestCorrupted(m, "next-file-num", "missing") + case !rec.has(recJournalNum): + return newErrManifestCorrupted(m, "journal-file-num", "missing") + case !rec.has(recSeqNum): + return newErrManifestCorrupted(m, "seq-num", "missing") + } + + s.manifestFile = m + s.setVersion(staging.finish()) + s.setNextFileNum(rec.nextFileNum) + s.recordCommited(rec) + return nil +} + +// Commit session; need external synchronization. +func (s *session) commit(r *sessionRecord) (err error) { + v := s.version() + defer v.release() + + // spawn new version based on current version + nv := v.spawn(r) + + if s.manifest == nil { + // manifest journal writer not yet created, create one + err = s.newManifest(r, nv) + } else { + err = s.flushManifest(r) + } + + // finally, apply new version if no error rise + if err == nil { + s.setVersion(nv) + } + + return +} + +// Pick a compaction based on current state; need external synchronization. +func (s *session) pickCompaction() *compaction { + v := s.version() + + var level int + var t0 tFiles + if v.cScore >= 1 { + level = v.cLevel + cptr := s.stCompPtrs[level] + tables := v.tables[level] + for _, t := range tables { + if cptr == nil || s.icmp.Compare(t.imax, cptr) > 0 { + t0 = append(t0, t) + break + } + } + if len(t0) == 0 { + t0 = append(t0, tables[0]) + } + } else { + if p := atomic.LoadPointer(&v.cSeek); p != nil { + ts := (*tSet)(p) + level = ts.level + t0 = append(t0, ts.table) + } else { + v.release() + return nil + } + } + + return newCompaction(s, v, level, t0) +} + +// Create compaction from given level and range; need external synchronization. +func (s *session) getCompactionRange(level int, umin, umax []byte) *compaction { + v := s.version() + + t0 := v.tables[level].getOverlaps(nil, s.icmp, umin, umax, level == 0) + if len(t0) == 0 { + v.release() + return nil + } + + // Avoid compacting too much in one shot in case the range is large. + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if level > 0 { + limit := uint64(v.s.o.GetCompactionSourceLimit(level)) + total := uint64(0) + for i, t := range t0 { + total += t.size + if total >= limit { + s.logf("table@compaction limiting F·%d -> F·%d", len(t0), i+1) + t0 = t0[:i+1] + break + } + } + } + + return newCompaction(s, v, level, t0) +} + +func newCompaction(s *session, v *version, level int, t0 tFiles) *compaction { + c := &compaction{ + s: s, + v: v, + level: level, + tables: [2]tFiles{t0, nil}, + maxGPOverlaps: uint64(s.o.GetCompactionGPOverlaps(level)), + tPtrs: make([]int, s.o.GetNumLevel()), + } + c.expand() + c.save() + return c +} + +// compaction represent a compaction state. +type compaction struct { + s *session + v *version + + level int + tables [2]tFiles + maxGPOverlaps uint64 + + gp tFiles + gpi int + seenKey bool + gpOverlappedBytes uint64 + imin, imax iKey + tPtrs []int + released bool + + snapGPI int + snapSeenKey bool + snapGPOverlappedBytes uint64 + snapTPtrs []int +} + +func (c *compaction) save() { + c.snapGPI = c.gpi + c.snapSeenKey = c.seenKey + c.snapGPOverlappedBytes = c.gpOverlappedBytes + c.snapTPtrs = append(c.snapTPtrs[:0], c.tPtrs...) +} + +func (c *compaction) restore() { + c.gpi = c.snapGPI + c.seenKey = c.snapSeenKey + c.gpOverlappedBytes = c.snapGPOverlappedBytes + c.tPtrs = append(c.tPtrs[:0], c.snapTPtrs...) +} + +func (c *compaction) release() { + if !c.released { + c.released = true + c.v.release() + } +} + +// Expand compacted tables; need external synchronization. +func (c *compaction) expand() { + limit := uint64(c.s.o.GetCompactionExpandLimit(c.level)) + vt0, vt1 := c.v.tables[c.level], c.v.tables[c.level+1] + + t0, t1 := c.tables[0], c.tables[1] + imin, imax := t0.getRange(c.s.icmp) + // We expand t0 here just incase ukey hop across tables. + t0 = vt0.getOverlaps(t0, c.s.icmp, imin.ukey(), imax.ukey(), c.level == 0) + if len(t0) != len(c.tables[0]) { + imin, imax = t0.getRange(c.s.icmp) + } + t1 = vt1.getOverlaps(t1, c.s.icmp, imin.ukey(), imax.ukey(), false) + // Get entire range covered by compaction. + amin, amax := append(t0, t1...).getRange(c.s.icmp) + + // See if we can grow the number of inputs in "level" without + // changing the number of "level+1" files we pick up. + if len(t1) > 0 { + exp0 := vt0.getOverlaps(nil, c.s.icmp, amin.ukey(), amax.ukey(), c.level == 0) + if len(exp0) > len(t0) && t1.size()+exp0.size() < limit { + xmin, xmax := exp0.getRange(c.s.icmp) + exp1 := vt1.getOverlaps(nil, c.s.icmp, xmin.ukey(), xmax.ukey(), false) + if len(exp1) == len(t1) { + c.s.logf("table@compaction expanding L%d+L%d (F·%d S·%s)+(F·%d S·%s) -> (F·%d S·%s)+(F·%d S·%s)", + c.level, c.level+1, len(t0), shortenb(int(t0.size())), len(t1), shortenb(int(t1.size())), + len(exp0), shortenb(int(exp0.size())), len(exp1), shortenb(int(exp1.size()))) + imin, imax = xmin, xmax + t0, t1 = exp0, exp1 + amin, amax = append(t0, t1...).getRange(c.s.icmp) + } + } + } + + // Compute the set of grandparent files that overlap this compaction + // (parent == level+1; grandparent == level+2) + if c.level+2 < c.s.o.GetNumLevel() { + c.gp = c.v.tables[c.level+2].getOverlaps(c.gp, c.s.icmp, amin.ukey(), amax.ukey(), false) + } + + c.tables[0], c.tables[1] = t0, t1 + c.imin, c.imax = imin, imax +} + +// Check whether compaction is trivial. +func (c *compaction) trivial() bool { + return len(c.tables[0]) == 1 && len(c.tables[1]) == 0 && c.gp.size() <= c.maxGPOverlaps +} + +func (c *compaction) baseLevelForKey(ukey []byte) bool { + for level, tables := range c.v.tables[c.level+2:] { + for c.tPtrs[level] < len(tables) { + t := tables[c.tPtrs[level]] + if c.s.icmp.uCompare(ukey, t.imax.ukey()) <= 0 { + // We've advanced far enough. + if c.s.icmp.uCompare(ukey, t.imin.ukey()) >= 0 { + // Key falls in this file's range, so definitely not base level. + return false + } + break + } + c.tPtrs[level]++ + } + } + return true +} + +func (c *compaction) shouldStopBefore(ikey iKey) bool { + for ; c.gpi < len(c.gp); c.gpi++ { + gp := c.gp[c.gpi] + if c.s.icmp.Compare(ikey, gp.imax) <= 0 { + break + } + if c.seenKey { + c.gpOverlappedBytes += gp.size + } + } + c.seenKey = true + + if c.gpOverlappedBytes > c.maxGPOverlaps { + // Too much overlap for current output; start new output. + c.gpOverlappedBytes = 0 + return true + } + return false +} + +// Creates an iterator. +func (c *compaction) newIterator() iterator.Iterator { + // Creates iterator slice. + icap := len(c.tables) + if c.level == 0 { + // Special case for level-0 + icap = len(c.tables[0]) + 1 + } + its := make([]iterator.Iterator, 0, icap) + + // Options. + ro := &opt.ReadOptions{ + DontFillCache: true, + Strict: opt.StrictOverride, + } + strict := c.s.o.GetStrict(opt.StrictCompaction) + if strict { + ro.Strict |= opt.StrictReader + } + + for i, tables := range c.tables { + if len(tables) == 0 { + continue + } + + // Level-0 is not sorted and may overlaps each other. + if c.level+i == 0 { + for _, t := range tables { + its = append(its, c.s.tops.newIterator(t, nil, ro)) + } + } else { + it := iterator.NewIndexedIterator(tables.newIndexIterator(c.s.tops, c.s.icmp, nil, ro), strict) + its = append(its, it) + } + } + + return iterator.NewMergedIterator(its, c.s.icmp, strict) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go new file mode 100644 index 00000000..0fc9457c --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go @@ -0,0 +1,313 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bufio" + "encoding/binary" + "io" + "strings" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" +) + +type byteReader interface { + io.Reader + io.ByteReader +} + +// These numbers are written to disk and should not be changed. +const ( + recComparer = 1 + recJournalNum = 2 + recNextFileNum = 3 + recSeqNum = 4 + recCompPtr = 5 + recDelTable = 6 + recAddTable = 7 + // 8 was used for large value refs + recPrevJournalNum = 9 +) + +type cpRecord struct { + level int + ikey iKey +} + +type atRecord struct { + level int + num uint64 + size uint64 + imin iKey + imax iKey +} + +type dtRecord struct { + level int + num uint64 +} + +type sessionRecord struct { + numLevel int + + hasRec int + comparer string + journalNum uint64 + prevJournalNum uint64 + nextFileNum uint64 + seqNum uint64 + compPtrs []cpRecord + addedTables []atRecord + deletedTables []dtRecord + + scratch [binary.MaxVarintLen64]byte + err error +} + +func (p *sessionRecord) has(rec int) bool { + return p.hasRec&(1<= uint64(p.numLevel) { + p.err = errors.NewErrCorrupted(nil, &ErrManifestCorrupted{field, "invalid level number"}) + return 0 + } + return int(x) +} + +func (p *sessionRecord) decode(r io.Reader) error { + br, ok := r.(byteReader) + if !ok { + br = bufio.NewReader(r) + } + p.err = nil + for p.err == nil { + rec := p.readUvarintMayEOF("field-header", br, true) + if p.err != nil { + if p.err == io.EOF { + return nil + } + return p.err + } + switch rec { + case recComparer: + x := p.readBytes("comparer", br) + if p.err == nil { + p.setComparer(string(x)) + } + case recJournalNum: + x := p.readUvarint("journal-num", br) + if p.err == nil { + p.setJournalNum(x) + } + case recPrevJournalNum: + x := p.readUvarint("prev-journal-num", br) + if p.err == nil { + p.setPrevJournalNum(x) + } + case recNextFileNum: + x := p.readUvarint("next-file-num", br) + if p.err == nil { + p.setNextFileNum(x) + } + case recSeqNum: + x := p.readUvarint("seq-num", br) + if p.err == nil { + p.setSeqNum(x) + } + case recCompPtr: + level := p.readLevel("comp-ptr.level", br) + ikey := p.readBytes("comp-ptr.ikey", br) + if p.err == nil { + p.addCompPtr(level, iKey(ikey)) + } + case recAddTable: + level := p.readLevel("add-table.level", br) + num := p.readUvarint("add-table.num", br) + size := p.readUvarint("add-table.size", br) + imin := p.readBytes("add-table.imin", br) + imax := p.readBytes("add-table.imax", br) + if p.err == nil { + p.addTable(level, num, size, imin, imax) + } + case recDelTable: + level := p.readLevel("del-table.level", br) + num := p.readUvarint("del-table.num", br) + if p.err == nil { + p.delTable(level, num) + } + } + } + + return p.err +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go new file mode 100644 index 00000000..3bcd984c --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go @@ -0,0 +1,64 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "bytes" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" +) + +func decodeEncode(v *sessionRecord) (res bool, err error) { + b := new(bytes.Buffer) + err = v.encode(b) + if err != nil { + return + } + v2 := &sessionRecord{numLevel: opt.DefaultNumLevel} + err = v.decode(b) + if err != nil { + return + } + b2 := new(bytes.Buffer) + err = v2.encode(b2) + if err != nil { + return + } + return bytes.Equal(b.Bytes(), b2.Bytes()), nil +} + +func TestSessionRecord_EncodeDecode(t *testing.T) { + big := uint64(1) << 50 + v := &sessionRecord{numLevel: opt.DefaultNumLevel} + i := uint64(0) + test := func() { + res, err := decodeEncode(v) + if err != nil { + t.Fatalf("error when testing encode/decode sessionRecord: %v", err) + } + if !res { + t.Error("encode/decode test failed at iteration:", i) + } + } + + for ; i < 4; i++ { + test() + v.addTable(3, big+300+i, big+400+i, + newIkey([]byte("foo"), big+500+1, ktVal), + newIkey([]byte("zoo"), big+600+1, ktDel)) + v.delTable(4, big+700+i) + v.addCompPtr(int(i), newIkey([]byte("x"), big+900+1, ktVal)) + } + + v.setComparer("foo") + v.setJournalNum(big + 100) + v.setPrevJournalNum(big + 99) + v.setNextFileNum(big + 200) + v.setSeqNum(big + 1000) + test() +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go new file mode 100644 index 00000000..cd2aa50e --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go @@ -0,0 +1,248 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "fmt" + "sync/atomic" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" +) + +type dropper struct { + s *session + // Logging. + file storage.File +} + +func (d dropper) Drop(err error) { + if e, ok := err.(*journal.ErrCorrupted); ok { + d.s.logf("journal@drop %s-%d S·%s %q", d.file.Type(), d.file.Num(), shortenb(e.Size), e.Reason) + } else { + d.s.logf("journal@drop %s-%d %q", d.file.Type(), d.file.Num(), err) + } +} + +func (s *session) log(v ...interface{}) { s.stor.Log(fmt.Sprint(v...)) } +func (s *session) logf(format string, v ...interface{}) { s.stor.Log(fmt.Sprintf(format, v...)) } + +// File utils. + +func (s *session) getJournalFile(num uint64) storage.File { + return s.stor.GetFile(num, storage.TypeJournal) +} + +func (s *session) getTableFile(num uint64) storage.File { + return s.stor.GetFile(num, storage.TypeTable) +} + +func (s *session) getFiles(t storage.FileType) ([]storage.File, error) { + return s.stor.GetFiles(t) +} + +func (s *session) newTemp() storage.File { + num := atomic.AddUint64(&s.stTempFileNum, 1) - 1 + return s.stor.GetFile(num, storage.TypeTemp) +} + +func (s *session) tableFileFromRecord(r atRecord) *tFile { + return newTableFile(s.getTableFile(r.num), r.size, r.imin, r.imax) +} + +// Session state. + +// Get current version. This will incr version ref, must call +// version.release (exactly once) after use. +func (s *session) version() *version { + s.vmu.Lock() + defer s.vmu.Unlock() + s.stVersion.ref++ + return s.stVersion +} + +// Set current version to v. +func (s *session) setVersion(v *version) { + s.vmu.Lock() + v.ref = 1 // Holds by session. + if old := s.stVersion; old != nil { + v.ref++ // Holds by old version. + old.next = v + old.releaseNB() + } + s.stVersion = v + s.vmu.Unlock() +} + +// Get current unused file number. +func (s *session) nextFileNum() uint64 { + return atomic.LoadUint64(&s.stNextFileNum) +} + +// Set current unused file number to num. +func (s *session) setNextFileNum(num uint64) { + atomic.StoreUint64(&s.stNextFileNum, num) +} + +// Mark file number as used. +func (s *session) markFileNum(num uint64) { + nextFileNum := num + 1 + for { + old, x := s.stNextFileNum, nextFileNum + if old > x { + x = old + } + if atomic.CompareAndSwapUint64(&s.stNextFileNum, old, x) { + break + } + } +} + +// Allocate a file number. +func (s *session) allocFileNum() uint64 { + return atomic.AddUint64(&s.stNextFileNum, 1) - 1 +} + +// Reuse given file number. +func (s *session) reuseFileNum(num uint64) { + for { + old, x := s.stNextFileNum, num + if old != x+1 { + x = old + } + if atomic.CompareAndSwapUint64(&s.stNextFileNum, old, x) { + break + } + } +} + +// Manifest related utils. + +// Fill given session record obj with current states; need external +// synchronization. +func (s *session) fillRecord(r *sessionRecord, snapshot bool) { + r.setNextFileNum(s.nextFileNum()) + + if snapshot { + if !r.has(recJournalNum) { + r.setJournalNum(s.stJournalNum) + } + + if !r.has(recSeqNum) { + r.setSeqNum(s.stSeqNum) + } + + for level, ik := range s.stCompPtrs { + if ik != nil { + r.addCompPtr(level, ik) + } + } + + r.setComparer(s.icmp.uName()) + } +} + +// Mark if record has been committed, this will update session state; +// need external synchronization. +func (s *session) recordCommited(r *sessionRecord) { + if r.has(recJournalNum) { + s.stJournalNum = r.journalNum + } + + if r.has(recPrevJournalNum) { + s.stPrevJournalNum = r.prevJournalNum + } + + if r.has(recSeqNum) { + s.stSeqNum = r.seqNum + } + + for _, p := range r.compPtrs { + s.stCompPtrs[p.level] = iKey(p.ikey) + } +} + +// Create a new manifest file; need external synchronization. +func (s *session) newManifest(rec *sessionRecord, v *version) (err error) { + num := s.allocFileNum() + file := s.stor.GetFile(num, storage.TypeManifest) + writer, err := file.Create() + if err != nil { + return + } + jw := journal.NewWriter(writer) + + if v == nil { + v = s.version() + defer v.release() + } + if rec == nil { + rec = &sessionRecord{numLevel: s.o.GetNumLevel()} + } + s.fillRecord(rec, true) + v.fillRecord(rec) + + defer func() { + if err == nil { + s.recordCommited(rec) + if s.manifest != nil { + s.manifest.Close() + } + if s.manifestWriter != nil { + s.manifestWriter.Close() + } + if s.manifestFile != nil { + s.manifestFile.Remove() + } + s.manifestFile = file + s.manifestWriter = writer + s.manifest = jw + } else { + writer.Close() + file.Remove() + s.reuseFileNum(num) + } + }() + + w, err := jw.Next() + if err != nil { + return + } + err = rec.encode(w) + if err != nil { + return + } + err = jw.Flush() + if err != nil { + return + } + err = s.stor.SetManifest(file) + return +} + +// Flush record to disk. +func (s *session) flushManifest(rec *sessionRecord) (err error) { + s.fillRecord(rec, false) + w, err := s.manifest.Next() + if err != nil { + return + } + err = rec.encode(w) + if err != nil { + return + } + err = s.manifest.Flush() + if err != nil { + return + } + err = s.manifestWriter.Sync() + if err != nil { + return + } + s.recordCommited(rec) + return +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go new file mode 100644 index 00000000..229bee71 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go @@ -0,0 +1,534 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reservefs. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package storage + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "time" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +var errFileOpen = errors.New("leveldb/storage: file still open") + +type fileLock interface { + release() error +} + +type fileStorageLock struct { + fs *fileStorage +} + +func (lock *fileStorageLock) Release() { + fs := lock.fs + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.slock == lock { + fs.slock = nil + } + return +} + +// fileStorage is a file-system backed storage. +type fileStorage struct { + path string + + mu sync.Mutex + flock fileLock + slock *fileStorageLock + logw *os.File + buf []byte + // Opened file counter; if open < 0 means closed. + open int + day int +} + +// OpenFile returns a new filesytem-backed storage implementation with the given +// path. This also hold a file lock, so any subsequent attempt to open the same +// path will fail. +// +// The storage must be closed after use, by calling Close method. +func OpenFile(path string) (Storage, error) { + if err := os.MkdirAll(path, 0755); err != nil { + return nil, err + } + + flock, err := newFileLock(filepath.Join(path, "LOCK")) + if err != nil { + return nil, err + } + + defer func() { + if err != nil { + flock.release() + } + }() + + rename(filepath.Join(path, "LOG"), filepath.Join(path, "LOG.old")) + logw, err := os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return nil, err + } + + fs := &fileStorage{path: path, flock: flock, logw: logw} + runtime.SetFinalizer(fs, (*fileStorage).Close) + return fs, nil +} + +func (fs *fileStorage) Lock() (util.Releaser, error) { + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.open < 0 { + return nil, ErrClosed + } + if fs.slock != nil { + return nil, ErrLocked + } + fs.slock = &fileStorageLock{fs: fs} + return fs.slock, nil +} + +func itoa(buf []byte, i int, wid int) []byte { + var u uint = uint(i) + if u == 0 && wid <= 1 { + return append(buf, '0') + } + + // Assemble decimal in reverse order. + var b [32]byte + bp := len(b) + for ; u > 0 || wid > 0; u /= 10 { + bp-- + wid-- + b[bp] = byte(u%10) + '0' + } + return append(buf, b[bp:]...) +} + +func (fs *fileStorage) printDay(t time.Time) { + if fs.day == t.Day() { + return + } + fs.day = t.Day() + fs.logw.Write([]byte("=============== " + t.Format("Jan 2, 2006 (MST)") + " ===============\n")) +} + +func (fs *fileStorage) doLog(t time.Time, str string) { + fs.printDay(t) + hour, min, sec := t.Clock() + msec := t.Nanosecond() / 1e3 + // time + fs.buf = itoa(fs.buf[:0], hour, 2) + fs.buf = append(fs.buf, ':') + fs.buf = itoa(fs.buf, min, 2) + fs.buf = append(fs.buf, ':') + fs.buf = itoa(fs.buf, sec, 2) + fs.buf = append(fs.buf, '.') + fs.buf = itoa(fs.buf, msec, 6) + fs.buf = append(fs.buf, ' ') + // write + fs.buf = append(fs.buf, []byte(str)...) + fs.buf = append(fs.buf, '\n') + fs.logw.Write(fs.buf) +} + +func (fs *fileStorage) Log(str string) { + t := time.Now() + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.open < 0 { + return + } + fs.doLog(t, str) +} + +func (fs *fileStorage) log(str string) { + fs.doLog(time.Now(), str) +} + +func (fs *fileStorage) GetFile(num uint64, t FileType) File { + return &file{fs: fs, num: num, t: t} +} + +func (fs *fileStorage) GetFiles(t FileType) (ff []File, err error) { + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.open < 0 { + return nil, ErrClosed + } + dir, err := os.Open(fs.path) + if err != nil { + return + } + fnn, err := dir.Readdirnames(0) + // Close the dir first before checking for Readdirnames error. + if err := dir.Close(); err != nil { + fs.log(fmt.Sprintf("close dir: %v", err)) + } + if err != nil { + return + } + f := &file{fs: fs} + for _, fn := range fnn { + if f.parse(fn) && (f.t&t) != 0 { + ff = append(ff, f) + f = &file{fs: fs} + } + } + return +} + +func (fs *fileStorage) GetManifest() (f File, err error) { + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.open < 0 { + return nil, ErrClosed + } + dir, err := os.Open(fs.path) + if err != nil { + return + } + fnn, err := dir.Readdirnames(0) + // Close the dir first before checking for Readdirnames error. + if err := dir.Close(); err != nil { + fs.log(fmt.Sprintf("close dir: %v", err)) + } + if err != nil { + return + } + // Find latest CURRENT file. + var rem []string + var pend bool + var cerr error + for _, fn := range fnn { + if strings.HasPrefix(fn, "CURRENT") { + pend1 := len(fn) > 7 + // Make sure it is valid name for a CURRENT file, otherwise skip it. + if pend1 { + if fn[7] != '.' || len(fn) < 9 { + fs.log(fmt.Sprintf("skipping %s: invalid file name", fn)) + continue + } + if _, e1 := strconv.ParseUint(fn[8:], 10, 0); e1 != nil { + fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", fn, e1)) + continue + } + } + path := filepath.Join(fs.path, fn) + r, e1 := os.OpenFile(path, os.O_RDONLY, 0) + if e1 != nil { + return nil, e1 + } + b, e1 := ioutil.ReadAll(r) + if e1 != nil { + r.Close() + return nil, e1 + } + f1 := &file{fs: fs} + if len(b) < 1 || b[len(b)-1] != '\n' || !f1.parse(string(b[:len(b)-1])) { + fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", fn)) + if pend1 { + rem = append(rem, fn) + } + if !pend1 || cerr == nil { + cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn) + } + } else if f != nil && f1.Num() < f.Num() { + fs.log(fmt.Sprintf("skipping %s: obsolete", fn)) + if pend1 { + rem = append(rem, fn) + } + } else { + f = f1 + pend = pend1 + } + if err := r.Close(); err != nil { + fs.log(fmt.Sprintf("close %s: %v", fn, err)) + } + } + } + // Don't remove any files if there is no valid CURRENT file. + if f == nil { + if cerr != nil { + err = cerr + } else { + err = os.ErrNotExist + } + return + } + // Rename pending CURRENT file to an effective CURRENT. + if pend { + path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f.Num()) + if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil { + fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %v", f.Num(), err)) + } + } + // Remove obsolete or incomplete pending CURRENT files. + for _, fn := range rem { + path := filepath.Join(fs.path, fn) + if err := os.Remove(path); err != nil { + fs.log(fmt.Sprintf("remove %s: %v", fn, err)) + } + } + return +} + +func (fs *fileStorage) SetManifest(f File) (err error) { + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.open < 0 { + return ErrClosed + } + f2, ok := f.(*file) + if !ok || f2.t != TypeManifest { + return ErrInvalidFile + } + defer func() { + if err != nil { + fs.log(fmt.Sprintf("CURRENT: %v", err)) + } + }() + path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f2.Num()) + w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return err + } + _, err = fmt.Fprintln(w, f2.name()) + // Close the file first. + if err := w.Close(); err != nil { + fs.log(fmt.Sprintf("close CURRENT.%d: %v", f2.num, err)) + } + if err != nil { + return err + } + return rename(path, filepath.Join(fs.path, "CURRENT")) +} + +func (fs *fileStorage) Close() error { + fs.mu.Lock() + defer fs.mu.Unlock() + if fs.open < 0 { + return ErrClosed + } + // Clear the finalizer. + runtime.SetFinalizer(fs, nil) + + if fs.open > 0 { + fs.log(fmt.Sprintf("refuse to close, %d files still open", fs.open)) + return fmt.Errorf("leveldb/storage: cannot close, %d files still open", fs.open) + } + fs.open = -1 + e1 := fs.logw.Close() + err := fs.flock.release() + if err == nil { + err = e1 + } + return err +} + +type fileWrap struct { + *os.File + f *file +} + +func (fw fileWrap) Sync() error { + if err := fw.File.Sync(); err != nil { + return err + } + if fw.f.Type() == TypeManifest { + // Also sync parent directory if file type is manifest. + // See: https://code.google.com/p/leveldb/issues/detail?id=190. + if err := syncDir(fw.f.fs.path); err != nil { + return err + } + } + return nil +} + +func (fw fileWrap) Close() error { + f := fw.f + f.fs.mu.Lock() + defer f.fs.mu.Unlock() + if !f.open { + return ErrClosed + } + f.open = false + f.fs.open-- + err := fw.File.Close() + if err != nil { + f.fs.log(fmt.Sprintf("close %s.%d: %v", f.Type(), f.Num(), err)) + } + return err +} + +type file struct { + fs *fileStorage + num uint64 + t FileType + open bool +} + +func (f *file) Open() (Reader, error) { + f.fs.mu.Lock() + defer f.fs.mu.Unlock() + if f.fs.open < 0 { + return nil, ErrClosed + } + if f.open { + return nil, errFileOpen + } + of, err := os.OpenFile(f.path(), os.O_RDONLY, 0) + if err != nil { + if f.hasOldName() && os.IsNotExist(err) { + of, err = os.OpenFile(f.oldPath(), os.O_RDONLY, 0) + if err == nil { + goto ok + } + } + return nil, err + } +ok: + f.open = true + f.fs.open++ + return fileWrap{of, f}, nil +} + +func (f *file) Create() (Writer, error) { + f.fs.mu.Lock() + defer f.fs.mu.Unlock() + if f.fs.open < 0 { + return nil, ErrClosed + } + if f.open { + return nil, errFileOpen + } + of, err := os.OpenFile(f.path(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return nil, err + } + f.open = true + f.fs.open++ + return fileWrap{of, f}, nil +} + +func (f *file) Replace(newfile File) error { + f.fs.mu.Lock() + defer f.fs.mu.Unlock() + if f.fs.open < 0 { + return ErrClosed + } + newfile2, ok := newfile.(*file) + if !ok { + return ErrInvalidFile + } + if f.open || newfile2.open { + return errFileOpen + } + return rename(newfile2.path(), f.path()) +} + +func (f *file) Type() FileType { + return f.t +} + +func (f *file) Num() uint64 { + return f.num +} + +func (f *file) Remove() error { + f.fs.mu.Lock() + defer f.fs.mu.Unlock() + if f.fs.open < 0 { + return ErrClosed + } + if f.open { + return errFileOpen + } + err := os.Remove(f.path()) + if err != nil { + f.fs.log(fmt.Sprintf("remove %s.%d: %v", f.Type(), f.Num(), err)) + } + // Also try remove file with old name, just in case. + if f.hasOldName() { + if e1 := os.Remove(f.oldPath()); !os.IsNotExist(e1) { + f.fs.log(fmt.Sprintf("remove %s.%d: %v (old name)", f.Type(), f.Num(), err)) + err = e1 + } + } + return err +} + +func (f *file) hasOldName() bool { + return f.t == TypeTable +} + +func (f *file) oldName() string { + switch f.t { + case TypeTable: + return fmt.Sprintf("%06d.sst", f.num) + } + return f.name() +} + +func (f *file) oldPath() string { + return filepath.Join(f.fs.path, f.oldName()) +} + +func (f *file) name() string { + switch f.t { + case TypeManifest: + return fmt.Sprintf("MANIFEST-%06d", f.num) + case TypeJournal: + return fmt.Sprintf("%06d.log", f.num) + case TypeTable: + return fmt.Sprintf("%06d.ldb", f.num) + case TypeTemp: + return fmt.Sprintf("%06d.tmp", f.num) + default: + panic("invalid file type") + } +} + +func (f *file) path() string { + return filepath.Join(f.fs.path, f.name()) +} + +func (f *file) parse(name string) bool { + var num uint64 + var tail string + _, err := fmt.Sscanf(name, "%d.%s", &num, &tail) + if err == nil { + switch tail { + case "log": + f.t = TypeJournal + case "ldb", "sst": + f.t = TypeTable + case "tmp": + f.t = TypeTemp + default: + return false + } + f.num = num + return true + } + n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail) + if n == 1 { + f.t = TypeManifest + f.num = num + return true + } + + return false +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go new file mode 100644 index 00000000..42940d76 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go @@ -0,0 +1,52 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package storage + +import ( + "os" + "path/filepath" +) + +type plan9FileLock struct { + f *os.File +} + +func (fl *plan9FileLock) release() error { + return fl.f.Close() +} + +func newFileLock(path string) (fl fileLock, err error) { + f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644) + if err != nil { + return + } + fl = &plan9FileLock{f: f} + return +} + +func rename(oldpath, newpath string) error { + if _, err := os.Stat(newpath); err == nil { + if err := os.Remove(newpath); err != nil { + return err + } + } + + _, fname := filepath.Split(newpath) + return os.Rename(oldpath, fname) +} + +func syncDir(name string) error { + f, err := os.Open(name) + if err != nil { + return err + } + defer f.Close() + if err := f.Sync(); err != nil { + return err + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go new file mode 100644 index 00000000..102031bf --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go @@ -0,0 +1,68 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build solaris + +package storage + +import ( + "os" + "syscall" +) + +type unixFileLock struct { + f *os.File +} + +func (fl *unixFileLock) release() error { + if err := setFileLock(fl.f, false); err != nil { + return err + } + return fl.f.Close() +} + +func newFileLock(path string) (fl fileLock, err error) { + f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return + } + err = setFileLock(f, true) + if err != nil { + f.Close() + return + } + fl = &unixFileLock{f: f} + return +} + +func setFileLock(f *os.File, lock bool) error { + flock := syscall.Flock_t{ + Type: syscall.F_UNLCK, + Start: 0, + Len: 0, + Whence: 1, + } + if lock { + flock.Type = syscall.F_WRLCK + } + return syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &flock) +} + +func rename(oldpath, newpath string) error { + return os.Rename(oldpath, newpath) +} + +func syncDir(name string) error { + f, err := os.Open(name) + if err != nil { + return err + } + defer f.Close() + if err := f.Sync(); err != nil { + return err + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go new file mode 100644 index 00000000..92abcbb7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go @@ -0,0 +1,142 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package storage + +import ( + "fmt" + "os" + "path/filepath" + "testing" +) + +var cases = []struct { + oldName []string + name string + ftype FileType + num uint64 +}{ + {nil, "000100.log", TypeJournal, 100}, + {nil, "000000.log", TypeJournal, 0}, + {[]string{"000000.sst"}, "000000.ldb", TypeTable, 0}, + {nil, "MANIFEST-000002", TypeManifest, 2}, + {nil, "MANIFEST-000007", TypeManifest, 7}, + {nil, "18446744073709551615.log", TypeJournal, 18446744073709551615}, + {nil, "000100.tmp", TypeTemp, 100}, +} + +var invalidCases = []string{ + "", + "foo", + "foo-dx-100.log", + ".log", + "", + "manifest", + "CURREN", + "CURRENTX", + "MANIFES", + "MANIFEST", + "MANIFEST-", + "XMANIFEST-3", + "MANIFEST-3x", + "LOC", + "LOCKx", + "LO", + "LOGx", + "18446744073709551616.log", + "184467440737095516150.log", + "100", + "100.", + "100.lop", +} + +func TestFileStorage_CreateFileName(t *testing.T) { + for _, c := range cases { + f := &file{num: c.num, t: c.ftype} + if f.name() != c.name { + t.Errorf("invalid filename got '%s', want '%s'", f.name(), c.name) + } + } +} + +func TestFileStorage_ParseFileName(t *testing.T) { + for _, c := range cases { + for _, name := range append([]string{c.name}, c.oldName...) { + f := new(file) + if !f.parse(name) { + t.Errorf("cannot parse filename '%s'", name) + continue + } + if f.Type() != c.ftype { + t.Errorf("filename '%s' invalid type got '%d', want '%d'", name, f.Type(), c.ftype) + } + if f.Num() != c.num { + t.Errorf("filename '%s' invalid number got '%d', want '%d'", name, f.Num(), c.num) + } + } + } +} + +func TestFileStorage_InvalidFileName(t *testing.T) { + for _, name := range invalidCases { + f := new(file) + if f.parse(name) { + t.Errorf("filename '%s' should be invalid", name) + } + } +} + +func TestFileStorage_Locking(t *testing.T) { + path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestfd-%d", os.Getuid())) + + _, err := os.Stat(path) + if err == nil { + err = os.RemoveAll(path) + if err != nil { + t.Fatal("RemoveAll: got error: ", err) + } + } + + p1, err := OpenFile(path) + if err != nil { + t.Fatal("OpenFile(1): got error: ", err) + } + + defer os.RemoveAll(path) + + p2, err := OpenFile(path) + if err != nil { + t.Logf("OpenFile(2): got error: %s (expected)", err) + } else { + p2.Close() + p1.Close() + t.Fatal("OpenFile(2): expect error") + } + + p1.Close() + + p3, err := OpenFile(path) + if err != nil { + t.Fatal("OpenFile(3): got error: ", err) + } + defer p3.Close() + + l, err := p3.Lock() + if err != nil { + t.Fatal("storage lock failed(1): ", err) + } + _, err = p3.Lock() + if err == nil { + t.Fatal("expect error for second storage lock attempt") + } else { + t.Logf("storage lock got error: %s (expected)", err) + } + l.Release() + _, err = p3.Lock() + if err != nil { + t.Fatal("storage lock failed(2): ", err) + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go new file mode 100644 index 00000000..d0a604b7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go @@ -0,0 +1,63 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package storage + +import ( + "os" + "syscall" +) + +type unixFileLock struct { + f *os.File +} + +func (fl *unixFileLock) release() error { + if err := setFileLock(fl.f, false); err != nil { + return err + } + return fl.f.Close() +} + +func newFileLock(path string) (fl fileLock, err error) { + f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return + } + err = setFileLock(f, true) + if err != nil { + f.Close() + return + } + fl = &unixFileLock{f: f} + return +} + +func setFileLock(f *os.File, lock bool) error { + how := syscall.LOCK_UN + if lock { + how = syscall.LOCK_EX + } + return syscall.Flock(int(f.Fd()), how|syscall.LOCK_NB) +} + +func rename(oldpath, newpath string) error { + return os.Rename(oldpath, newpath) +} + +func syncDir(name string) error { + f, err := os.Open(name) + if err != nil { + return err + } + defer f.Close() + if err := f.Sync(); err != nil { + return err + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go new file mode 100644 index 00000000..50c3c454 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go @@ -0,0 +1,69 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package storage + +import ( + "syscall" + "unsafe" +) + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procMoveFileExW = modkernel32.NewProc("MoveFileExW") +) + +const ( + _MOVEFILE_REPLACE_EXISTING = 1 +) + +type windowsFileLock struct { + fd syscall.Handle +} + +func (fl *windowsFileLock) release() error { + return syscall.Close(fl.fd) +} + +func newFileLock(path string) (fl fileLock, err error) { + pathp, err := syscall.UTF16PtrFromString(path) + if err != nil { + return + } + fd, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.CREATE_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0) + if err != nil { + return + } + fl = &windowsFileLock{fd: fd} + return +} + +func moveFileEx(from *uint16, to *uint16, flags uint32) error { + r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) + if r1 == 0 { + if e1 != 0 { + return error(e1) + } else { + return syscall.EINVAL + } + } + return nil +} + +func rename(oldpath, newpath string) error { + from, err := syscall.UTF16PtrFromString(oldpath) + if err != nil { + return err + } + to, err := syscall.UTF16PtrFromString(newpath) + if err != nil { + return err + } + return moveFileEx(from, to, _MOVEFILE_REPLACE_EXISTING) +} + +func syncDir(name string) error { return nil } diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go new file mode 100644 index 00000000..241fca6a --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go @@ -0,0 +1,203 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package storage + +import ( + "bytes" + "os" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +const typeShift = 3 + +type memStorageLock struct { + ms *memStorage +} + +func (lock *memStorageLock) Release() { + ms := lock.ms + ms.mu.Lock() + defer ms.mu.Unlock() + if ms.slock == lock { + ms.slock = nil + } + return +} + +// memStorage is a memory-backed storage. +type memStorage struct { + mu sync.Mutex + slock *memStorageLock + files map[uint64]*memFile + manifest *memFilePtr +} + +// NewMemStorage returns a new memory-backed storage implementation. +func NewMemStorage() Storage { + return &memStorage{ + files: make(map[uint64]*memFile), + } +} + +func (ms *memStorage) Lock() (util.Releaser, error) { + ms.mu.Lock() + defer ms.mu.Unlock() + if ms.slock != nil { + return nil, ErrLocked + } + ms.slock = &memStorageLock{ms: ms} + return ms.slock, nil +} + +func (*memStorage) Log(str string) {} + +func (ms *memStorage) GetFile(num uint64, t FileType) File { + return &memFilePtr{ms: ms, num: num, t: t} +} + +func (ms *memStorage) GetFiles(t FileType) ([]File, error) { + ms.mu.Lock() + var ff []File + for x, _ := range ms.files { + num, mt := x>>typeShift, FileType(x)&TypeAll + if mt&t == 0 { + continue + } + ff = append(ff, &memFilePtr{ms: ms, num: num, t: mt}) + } + ms.mu.Unlock() + return ff, nil +} + +func (ms *memStorage) GetManifest() (File, error) { + ms.mu.Lock() + defer ms.mu.Unlock() + if ms.manifest == nil { + return nil, os.ErrNotExist + } + return ms.manifest, nil +} + +func (ms *memStorage) SetManifest(f File) error { + fm, ok := f.(*memFilePtr) + if !ok || fm.t != TypeManifest { + return ErrInvalidFile + } + ms.mu.Lock() + ms.manifest = fm + ms.mu.Unlock() + return nil +} + +func (*memStorage) Close() error { return nil } + +type memReader struct { + *bytes.Reader + m *memFile +} + +func (mr *memReader) Close() error { + return mr.m.Close() +} + +type memFile struct { + bytes.Buffer + ms *memStorage + open bool +} + +func (*memFile) Sync() error { return nil } +func (m *memFile) Close() error { + m.ms.mu.Lock() + m.open = false + m.ms.mu.Unlock() + return nil +} + +type memFilePtr struct { + ms *memStorage + num uint64 + t FileType +} + +func (p *memFilePtr) x() uint64 { + return p.Num()< +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package storage + +import ( + "bytes" + "testing" +) + +func TestMemStorage(t *testing.T) { + m := NewMemStorage() + + l, err := m.Lock() + if err != nil { + t.Fatal("storage lock failed(1): ", err) + } + _, err = m.Lock() + if err == nil { + t.Fatal("expect error for second storage lock attempt") + } else { + t.Logf("storage lock got error: %s (expected)", err) + } + l.Release() + _, err = m.Lock() + if err != nil { + t.Fatal("storage lock failed(2): ", err) + } + + f := m.GetFile(1, TypeTable) + if f.Num() != 1 && f.Type() != TypeTable { + t.Fatal("invalid file number and type") + } + w, _ := f.Create() + w.Write([]byte("abc")) + w.Close() + if ff, _ := m.GetFiles(TypeAll); len(ff) != 1 { + t.Fatal("invalid GetFiles len") + } + buf := new(bytes.Buffer) + r, err := f.Open() + if err != nil { + t.Fatal("Open: got error: ", err) + } + buf.ReadFrom(r) + r.Close() + if got := buf.String(); got != "abc" { + t.Fatalf("Read: invalid value, want=abc got=%s", got) + } + if _, err := f.Open(); err != nil { + t.Fatal("Open: got error: ", err) + } + if _, err := m.GetFile(1, TypeTable).Open(); err == nil { + t.Fatal("expecting error") + } + f.Remove() + if ff, _ := m.GetFiles(TypeAll); len(ff) != 0 { + t.Fatal("invalid GetFiles len", len(ff)) + } + if _, err := f.Open(); err == nil { + t.Fatal("expecting error") + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go new file mode 100644 index 00000000..8117af3b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go @@ -0,0 +1,157 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package storage provides storage abstraction for LevelDB. +package storage + +import ( + "errors" + "fmt" + "io" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type FileType uint32 + +const ( + TypeManifest FileType = 1 << iota + TypeJournal + TypeTable + TypeTemp + + TypeAll = TypeManifest | TypeJournal | TypeTable | TypeTemp +) + +func (t FileType) String() string { + switch t { + case TypeManifest: + return "manifest" + case TypeJournal: + return "journal" + case TypeTable: + return "table" + case TypeTemp: + return "temp" + } + return fmt.Sprintf("", t) +} + +var ( + ErrInvalidFile = errors.New("leveldb/storage: invalid file for argument") + ErrLocked = errors.New("leveldb/storage: already locked") + ErrClosed = errors.New("leveldb/storage: closed") +) + +// Syncer is the interface that wraps basic Sync method. +type Syncer interface { + // Sync commits the current contents of the file to stable storage. + Sync() error +} + +// Reader is the interface that groups the basic Read, Seek, ReadAt and Close +// methods. +type Reader interface { + io.ReadSeeker + io.ReaderAt + io.Closer +} + +// Writer is the interface that groups the basic Write, Sync and Close +// methods. +type Writer interface { + io.WriteCloser + Syncer +} + +// File is the file. A file instance must be goroutine-safe. +type File interface { + // Open opens the file for read. Returns os.ErrNotExist error + // if the file does not exist. + // Returns ErrClosed if the underlying storage is closed. + Open() (r Reader, err error) + + // Create creates the file for writting. Truncate the file if + // already exist. + // Returns ErrClosed if the underlying storage is closed. + Create() (w Writer, err error) + + // Replace replaces file with newfile. + // Returns ErrClosed if the underlying storage is closed. + Replace(newfile File) error + + // Type returns the file type + Type() FileType + + // Num returns the file number. + Num() uint64 + + // Remove removes the file. + // Returns ErrClosed if the underlying storage is closed. + Remove() error +} + +// Storage is the storage. A storage instance must be goroutine-safe. +type Storage interface { + // Lock locks the storage. Any subsequent attempt to call Lock will fail + // until the last lock released. + // After use the caller should call the Release method. + Lock() (l util.Releaser, err error) + + // Log logs a string. This is used for logging. An implementation + // may write to a file, stdout or simply do nothing. + Log(str string) + + // GetFile returns a file for the given number and type. GetFile will never + // returns nil, even if the underlying storage is closed. + GetFile(num uint64, t FileType) File + + // GetFiles returns a slice of files that match the given file types. + // The file types may be OR'ed together. + GetFiles(t FileType) ([]File, error) + + // GetManifest returns a manifest file. Returns os.ErrNotExist if manifest + // file does not exist. + GetManifest() (File, error) + + // SetManifest sets the given file as manifest file. The given file should + // be a manifest file type or error will be returned. + SetManifest(f File) error + + // Close closes the storage. It is valid to call Close multiple times. + // Other methods should not be called after the storage has been closed. + Close() error +} + +// FileInfo wraps basic file info. +type FileInfo struct { + Type FileType + Num uint64 +} + +func (fi FileInfo) String() string { + switch fi.Type { + case TypeManifest: + return fmt.Sprintf("MANIFEST-%06d", fi.Num) + case TypeJournal: + return fmt.Sprintf("%06d.log", fi.Num) + case TypeTable: + return fmt.Sprintf("%06d.ldb", fi.Num) + case TypeTemp: + return fmt.Sprintf("%06d.tmp", fi.Num) + default: + return fmt.Sprintf("%#x-%d", fi.Type, fi.Num) + } +} + +// NewFileInfo creates new FileInfo from the given File. It will returns nil +// if File is nil. +func NewFileInfo(f File) *FileInfo { + if f == nil { + return nil + } + return &FileInfo{f.Type(), f.Num()} +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go new file mode 100644 index 00000000..ec5159ad --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go @@ -0,0 +1,539 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENE file. + +package leveldb + +import ( + "errors" + "fmt" + "io" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +const typeShift = 4 + +var ( + tsErrInvalidFile = errors.New("leveldb.testStorage: invalid file for argument") + tsErrFileOpen = errors.New("leveldb.testStorage: file still open") +) + +var ( + tsFSEnv = os.Getenv("GOLEVELDB_USEFS") + tsTempdir = os.Getenv("GOLEVELDB_TEMPDIR") + tsKeepFS = tsFSEnv == "2" + tsFS = tsKeepFS || tsFSEnv == "" || tsFSEnv == "1" + tsMU = &sync.Mutex{} + tsNum = 0 +) + +type tsOp uint + +const ( + tsOpOpen tsOp = iota + tsOpCreate + tsOpRead + tsOpReadAt + tsOpWrite + tsOpSync + + tsOpNum +) + +type tsLock struct { + ts *testStorage + r util.Releaser +} + +func (l tsLock) Release() { + l.r.Release() + l.ts.t.Log("I: storage lock released") +} + +type tsReader struct { + tf tsFile + storage.Reader +} + +func (tr tsReader) Read(b []byte) (n int, err error) { + ts := tr.tf.ts + ts.countRead(tr.tf.Type()) + if tr.tf.shouldErrLocked(tsOpRead) { + return 0, errors.New("leveldb.testStorage: emulated read error") + } + n, err = tr.Reader.Read(b) + if err != nil && err != io.EOF { + ts.t.Errorf("E: read error, num=%d type=%v n=%d: %v", tr.tf.Num(), tr.tf.Type(), n, err) + } + return +} + +func (tr tsReader) ReadAt(b []byte, off int64) (n int, err error) { + ts := tr.tf.ts + ts.countRead(tr.tf.Type()) + if tr.tf.shouldErrLocked(tsOpReadAt) { + return 0, errors.New("leveldb.testStorage: emulated readAt error") + } + n, err = tr.Reader.ReadAt(b, off) + if err != nil && err != io.EOF { + ts.t.Errorf("E: readAt error, num=%d type=%v off=%d n=%d: %v", tr.tf.Num(), tr.tf.Type(), off, n, err) + } + return +} + +func (tr tsReader) Close() (err error) { + err = tr.Reader.Close() + tr.tf.close("reader", err) + return +} + +type tsWriter struct { + tf tsFile + storage.Writer +} + +func (tw tsWriter) Write(b []byte) (n int, err error) { + if tw.tf.shouldErrLocked(tsOpWrite) { + return 0, errors.New("leveldb.testStorage: emulated write error") + } + n, err = tw.Writer.Write(b) + if err != nil { + tw.tf.ts.t.Errorf("E: write error, num=%d type=%v n=%d: %v", tw.tf.Num(), tw.tf.Type(), n, err) + } + return +} + +func (tw tsWriter) Sync() (err error) { + ts := tw.tf.ts + ts.mu.Lock() + for ts.emuDelaySync&tw.tf.Type() != 0 { + ts.cond.Wait() + } + ts.mu.Unlock() + if tw.tf.shouldErrLocked(tsOpSync) { + return errors.New("leveldb.testStorage: emulated sync error") + } + err = tw.Writer.Sync() + if err != nil { + tw.tf.ts.t.Errorf("E: sync error, num=%d type=%v: %v", tw.tf.Num(), tw.tf.Type(), err) + } + return +} + +func (tw tsWriter) Close() (err error) { + err = tw.Writer.Close() + tw.tf.close("writer", err) + return +} + +type tsFile struct { + ts *testStorage + storage.File +} + +func (tf tsFile) x() uint64 { + return tf.Num()<>typeShift, storage.FileType(x)&storage.TypeAll + ts.t.Errorf("E: * num=%d type=%v writer=%v", num, tt, writer) + } + } + ts.mu.Unlock() +} + +func newTestStorage(t *testing.T) *testStorage { + var stor storage.Storage + var closeFn func() error + if tsFS { + for { + tsMU.Lock() + num := tsNum + tsNum++ + tsMU.Unlock() + tempdir := tsTempdir + if tempdir == "" { + tempdir = os.TempDir() + } + path := filepath.Join(tempdir, fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num)) + if _, err := os.Stat(path); err != nil { + stor, err = storage.OpenFile(path) + if err != nil { + t.Fatalf("F: cannot create storage: %v", err) + } + t.Logf("I: storage created: %s", path) + closeFn = func() error { + for _, name := range []string{"LOG.old", "LOG"} { + f, err := os.Open(filepath.Join(path, name)) + if err != nil { + continue + } + if log, err := ioutil.ReadAll(f); err != nil { + t.Logf("---------------------- %s ----------------------", name) + t.Logf("cannot read log: %v", err) + t.Logf("---------------------- %s ----------------------", name) + } else if len(log) > 0 { + t.Logf("---------------------- %s ----------------------\n%s", name, string(log)) + t.Logf("---------------------- %s ----------------------", name) + } + f.Close() + } + if t.Failed() { + t.Logf("testing failed, test DB preserved at %s", path) + return nil + } + if tsKeepFS { + return nil + } + return os.RemoveAll(path) + } + + break + } + } + } else { + stor = storage.NewMemStorage() + } + ts := &testStorage{ + t: t, + Storage: stor, + closeFn: closeFn, + opens: make(map[uint64]bool), + emuErrOnceMap: make(map[uint64]uint), + emuRandErrProb: 0x999, + emuRandRand: rand.New(rand.NewSource(0xfacedead)), + } + ts.cond.L = &ts.mu + return ts +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go new file mode 100644 index 00000000..8de50b06 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go @@ -0,0 +1,521 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "fmt" + "sort" + "sync/atomic" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type // tFile holds basic information about a table. +tFile struct { + file storage.File + seekLeft int32 + size uint64 + imin, imax iKey +} + +// Returns true if given key is after largest key of this table. +func (t *tFile) after(icmp *iComparer, ukey []byte) bool { + return ukey != nil && icmp.uCompare(ukey, t.imax.ukey()) > 0 +} + +// Returns true if given key is before smallest key of this table. +func (t *tFile) before(icmp *iComparer, ukey []byte) bool { + return ukey != nil && icmp.uCompare(ukey, t.imin.ukey()) < 0 +} + +// Returns true if given key range overlaps with this table key range. +func (t *tFile) overlaps(icmp *iComparer, umin, umax []byte) bool { + return !t.after(icmp, umin) && !t.before(icmp, umax) +} + +// Cosumes one seek and return current seeks left. +func (t *tFile) consumeSeek() int32 { + return atomic.AddInt32(&t.seekLeft, -1) +} + +// Creates new tFile. +func newTableFile(file storage.File, size uint64, imin, imax iKey) *tFile { + f := &tFile{ + file: file, + size: size, + imin: imin, + imax: imax, + } + + // We arrange to automatically compact this file after + // a certain number of seeks. Let's assume: + // (1) One seek costs 10ms + // (2) Writing or reading 1MB costs 10ms (100MB/s) + // (3) A compaction of 1MB does 25MB of IO: + // 1MB read from this level + // 10-12MB read from next level (boundaries may be misaligned) + // 10-12MB written to next level + // This implies that 25 seeks cost the same as the compaction + // of 1MB of data. I.e., one seek costs approximately the + // same as the compaction of 40KB of data. We are a little + // conservative and allow approximately one seek for every 16KB + // of data before triggering a compaction. + f.seekLeft = int32(size / 16384) + if f.seekLeft < 100 { + f.seekLeft = 100 + } + + return f +} + +// tFiles hold multiple tFile. +type tFiles []*tFile + +func (tf tFiles) Len() int { return len(tf) } +func (tf tFiles) Swap(i, j int) { tf[i], tf[j] = tf[j], tf[i] } + +func (tf tFiles) nums() string { + x := "[ " + for i, f := range tf { + if i != 0 { + x += ", " + } + x += fmt.Sprint(f.file.Num()) + } + x += " ]" + return x +} + +// Returns true if i smallest key is less than j. +// This used for sort by key in ascending order. +func (tf tFiles) lessByKey(icmp *iComparer, i, j int) bool { + a, b := tf[i], tf[j] + n := icmp.Compare(a.imin, b.imin) + if n == 0 { + return a.file.Num() < b.file.Num() + } + return n < 0 +} + +// Returns true if i file number is greater than j. +// This used for sort by file number in descending order. +func (tf tFiles) lessByNum(i, j int) bool { + return tf[i].file.Num() > tf[j].file.Num() +} + +// Sorts tables by key in ascending order. +func (tf tFiles) sortByKey(icmp *iComparer) { + sort.Sort(&tFilesSortByKey{tFiles: tf, icmp: icmp}) +} + +// Sorts tables by file number in descending order. +func (tf tFiles) sortByNum() { + sort.Sort(&tFilesSortByNum{tFiles: tf}) +} + +// Returns sum of all tables size. +func (tf tFiles) size() (sum uint64) { + for _, t := range tf { + sum += t.size + } + return sum +} + +// Searches smallest index of tables whose its smallest +// key is after or equal with given key. +func (tf tFiles) searchMin(icmp *iComparer, ikey iKey) int { + return sort.Search(len(tf), func(i int) bool { + return icmp.Compare(tf[i].imin, ikey) >= 0 + }) +} + +// Searches smallest index of tables whose its largest +// key is after or equal with given key. +func (tf tFiles) searchMax(icmp *iComparer, ikey iKey) int { + return sort.Search(len(tf), func(i int) bool { + return icmp.Compare(tf[i].imax, ikey) >= 0 + }) +} + +// Returns true if given key range overlaps with one or more +// tables key range. If unsorted is true then binary search will not be used. +func (tf tFiles) overlaps(icmp *iComparer, umin, umax []byte, unsorted bool) bool { + if unsorted { + // Check against all files. + for _, t := range tf { + if t.overlaps(icmp, umin, umax) { + return true + } + } + return false + } + + i := 0 + if len(umin) > 0 { + // Find the earliest possible internal key for min. + i = tf.searchMax(icmp, newIkey(umin, kMaxSeq, ktSeek)) + } + if i >= len(tf) { + // Beginning of range is after all files, so no overlap. + return false + } + return !tf[i].before(icmp, umax) +} + +// Returns tables whose its key range overlaps with given key range. +// Range will be expanded if ukey found hop across tables. +// If overlapped is true then the search will be restarted if umax +// expanded. +// The dst content will be overwritten. +func (tf tFiles) getOverlaps(dst tFiles, icmp *iComparer, umin, umax []byte, overlapped bool) tFiles { + dst = dst[:0] + for i := 0; i < len(tf); { + t := tf[i] + if t.overlaps(icmp, umin, umax) { + if umin != nil && icmp.uCompare(t.imin.ukey(), umin) < 0 { + umin = t.imin.ukey() + dst = dst[:0] + i = 0 + continue + } else if umax != nil && icmp.uCompare(t.imax.ukey(), umax) > 0 { + umax = t.imax.ukey() + // Restart search if it is overlapped. + if overlapped { + dst = dst[:0] + i = 0 + continue + } + } + + dst = append(dst, t) + } + i++ + } + + return dst +} + +// Returns tables key range. +func (tf tFiles) getRange(icmp *iComparer) (imin, imax iKey) { + for i, t := range tf { + if i == 0 { + imin, imax = t.imin, t.imax + continue + } + if icmp.Compare(t.imin, imin) < 0 { + imin = t.imin + } + if icmp.Compare(t.imax, imax) > 0 { + imax = t.imax + } + } + + return +} + +// Creates iterator index from tables. +func (tf tFiles) newIndexIterator(tops *tOps, icmp *iComparer, slice *util.Range, ro *opt.ReadOptions) iterator.IteratorIndexer { + if slice != nil { + var start, limit int + if slice.Start != nil { + start = tf.searchMax(icmp, iKey(slice.Start)) + } + if slice.Limit != nil { + limit = tf.searchMin(icmp, iKey(slice.Limit)) + } else { + limit = tf.Len() + } + tf = tf[start:limit] + } + return iterator.NewArrayIndexer(&tFilesArrayIndexer{ + tFiles: tf, + tops: tops, + icmp: icmp, + slice: slice, + ro: ro, + }) +} + +// Tables iterator index. +type tFilesArrayIndexer struct { + tFiles + tops *tOps + icmp *iComparer + slice *util.Range + ro *opt.ReadOptions +} + +func (a *tFilesArrayIndexer) Search(key []byte) int { + return a.searchMax(a.icmp, iKey(key)) +} + +func (a *tFilesArrayIndexer) Get(i int) iterator.Iterator { + if i == 0 || i == a.Len()-1 { + return a.tops.newIterator(a.tFiles[i], a.slice, a.ro) + } + return a.tops.newIterator(a.tFiles[i], nil, a.ro) +} + +// Helper type for sortByKey. +type tFilesSortByKey struct { + tFiles + icmp *iComparer +} + +func (x *tFilesSortByKey) Less(i, j int) bool { + return x.lessByKey(x.icmp, i, j) +} + +// Helper type for sortByNum. +type tFilesSortByNum struct { + tFiles +} + +func (x *tFilesSortByNum) Less(i, j int) bool { + return x.lessByNum(i, j) +} + +// Table operations. +type tOps struct { + s *session + cache *cache.Cache + bcache *cache.Cache + bpool *util.BufferPool +} + +// Creates an empty table and returns table writer. +func (t *tOps) create() (*tWriter, error) { + file := t.s.getTableFile(t.s.allocFileNum()) + fw, err := file.Create() + if err != nil { + return nil, err + } + return &tWriter{ + t: t, + file: file, + w: fw, + tw: table.NewWriter(fw, t.s.o.Options), + }, nil +} + +// Builds table from src iterator. +func (t *tOps) createFrom(src iterator.Iterator) (f *tFile, n int, err error) { + w, err := t.create() + if err != nil { + return + } + + defer func() { + if err != nil { + w.drop() + } + }() + + for src.Next() { + err = w.append(src.Key(), src.Value()) + if err != nil { + return + } + } + err = src.Error() + if err != nil { + return + } + + n = w.tw.EntriesLen() + f, err = w.finish() + return +} + +// Opens table. It returns a cache handle, which should +// be released after use. +func (t *tOps) open(f *tFile) (ch *cache.Handle, err error) { + num := f.file.Num() + ch = t.cache.Get(0, num, func() (size int, value cache.Value) { + var r storage.Reader + r, err = f.file.Open() + if err != nil { + return 0, nil + } + + var bcache *cache.CacheGetter + if t.bcache != nil { + bcache = &cache.CacheGetter{Cache: t.bcache, NS: num} + } + + var tr *table.Reader + tr, err = table.NewReader(r, int64(f.size), storage.NewFileInfo(f.file), bcache, t.bpool, t.s.o.Options) + if err != nil { + r.Close() + return 0, nil + } + return 1, tr + + }) + if ch == nil && err == nil { + err = ErrClosed + } + return +} + +// Finds key/value pair whose key is greater than or equal to the +// given key. +func (t *tOps) find(f *tFile, key []byte, ro *opt.ReadOptions) (rkey, rvalue []byte, err error) { + ch, err := t.open(f) + if err != nil { + return nil, nil, err + } + defer ch.Release() + return ch.Value().(*table.Reader).Find(key, true, ro) +} + +// Finds key that is greater than or equal to the given key. +func (t *tOps) findKey(f *tFile, key []byte, ro *opt.ReadOptions) (rkey []byte, err error) { + ch, err := t.open(f) + if err != nil { + return nil, err + } + defer ch.Release() + return ch.Value().(*table.Reader).FindKey(key, true, ro) +} + +// Returns approximate offset of the given key. +func (t *tOps) offsetOf(f *tFile, key []byte) (offset uint64, err error) { + ch, err := t.open(f) + if err != nil { + return + } + defer ch.Release() + offset_, err := ch.Value().(*table.Reader).OffsetOf(key) + return uint64(offset_), err +} + +// Creates an iterator from the given table. +func (t *tOps) newIterator(f *tFile, slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { + ch, err := t.open(f) + if err != nil { + return iterator.NewEmptyIterator(err) + } + iter := ch.Value().(*table.Reader).NewIterator(slice, ro) + iter.SetReleaser(ch) + return iter +} + +// Removes table from persistent storage. It waits until +// no one use the the table. +func (t *tOps) remove(f *tFile) { + num := f.file.Num() + t.cache.Delete(0, num, func() { + if err := f.file.Remove(); err != nil { + t.s.logf("table@remove removing @%d %q", num, err) + } else { + t.s.logf("table@remove removed @%d", num) + } + if t.bcache != nil { + t.bcache.EvictNS(num) + } + }) +} + +// Closes the table ops instance. It will close all tables, +// regadless still used or not. +func (t *tOps) close() { + t.bpool.Close() + t.cache.Close() + if t.bcache != nil { + t.bcache.Close() + } +} + +// Creates new initialized table ops instance. +func newTableOps(s *session) *tOps { + var ( + cacher cache.Cacher + bcache *cache.Cache + ) + if s.o.GetOpenFilesCacheCapacity() > 0 { + cacher = cache.NewLRU(s.o.GetOpenFilesCacheCapacity()) + } + if !s.o.DisableBlockCache { + var bcacher cache.Cacher + if s.o.GetBlockCacheCapacity() > 0 { + bcacher = cache.NewLRU(s.o.GetBlockCacheCapacity()) + } + bcache = cache.NewCache(bcacher) + } + return &tOps{ + s: s, + cache: cache.NewCache(cacher), + bcache: bcache, + bpool: util.NewBufferPool(s.o.GetBlockSize() + 5), + } +} + +// tWriter wraps the table writer. It keep track of file descriptor +// and added key range. +type tWriter struct { + t *tOps + + file storage.File + w storage.Writer + tw *table.Writer + + first, last []byte +} + +// Append key/value pair to the table. +func (w *tWriter) append(key, value []byte) error { + if w.first == nil { + w.first = append([]byte{}, key...) + } + w.last = append(w.last[:0], key...) + return w.tw.Append(key, value) +} + +// Returns true if the table is empty. +func (w *tWriter) empty() bool { + return w.first == nil +} + +// Closes the storage.Writer. +func (w *tWriter) close() { + if w.w != nil { + w.w.Close() + w.w = nil + } +} + +// Finalizes the table and returns table file. +func (w *tWriter) finish() (f *tFile, err error) { + defer w.close() + err = w.tw.Close() + if err != nil { + return + } + err = w.w.Sync() + if err != nil { + return + } + f = newTableFile(w.file, uint64(w.tw.BytesLen()), iKey(w.first), iKey(w.last)) + return +} + +// Drops the table. +func (w *tWriter) drop() { + w.close() + w.file.Remove() + w.t.s.reuseFileNum(w.file.Num()) + w.file = nil + w.tw = nil + w.first = nil + w.last = nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go new file mode 100644 index 00000000..7cc07ec8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go @@ -0,0 +1,139 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package table + +import ( + "encoding/binary" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type blockTesting struct { + tr *Reader + b *block +} + +func (t *blockTesting) TestNewIterator(slice *util.Range) iterator.Iterator { + return t.tr.newBlockIter(t.b, nil, slice, false) +} + +var _ = testutil.Defer(func() { + Describe("Block", func() { + Build := func(kv *testutil.KeyValue, restartInterval int) *blockTesting { + // Building the block. + bw := &blockWriter{ + restartInterval: restartInterval, + scratch: make([]byte, 30), + } + kv.Iterate(func(i int, key, value []byte) { + bw.append(key, value) + }) + bw.finish() + + // Opening the block. + data := bw.buf.Bytes() + restartsLen := int(binary.LittleEndian.Uint32(data[len(data)-4:])) + return &blockTesting{ + tr: &Reader{cmp: comparer.DefaultComparer}, + b: &block{ + data: data, + restartsLen: restartsLen, + restartsOffset: len(data) - (restartsLen+1)*4, + }, + } + } + + Describe("read test", func() { + for restartInterval := 1; restartInterval <= 5; restartInterval++ { + Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() { + kv := &testutil.KeyValue{} + Text := func() string { + return fmt.Sprintf("and %d keys", kv.Len()) + } + + Test := func() { + // Make block. + br := Build(kv, restartInterval) + // Do testing. + testutil.KeyValueTesting(nil, kv.Clone(), br, nil, nil) + } + + Describe(Text(), Test) + + kv.PutString("", "empty") + Describe(Text(), Test) + + kv.PutString("a1", "foo") + Describe(Text(), Test) + + kv.PutString("a2", "v") + Describe(Text(), Test) + + kv.PutString("a3qqwrkks", "hello") + Describe(Text(), Test) + + kv.PutString("a4", "bar") + Describe(Text(), Test) + + kv.PutString("a5111111", "v5") + kv.PutString("a6", "") + kv.PutString("a7", "v7") + kv.PutString("a8", "vvvvvvvvvvvvvvvvvvvvvv8") + kv.PutString("b", "v9") + kv.PutString("c9", "v9") + kv.PutString("c91", "v9") + kv.PutString("d0", "v9") + Describe(Text(), Test) + }) + } + }) + + Describe("out-of-bound slice test", func() { + kv := &testutil.KeyValue{} + kv.PutString("k1", "v1") + kv.PutString("k2", "v2") + kv.PutString("k3abcdefgg", "v3") + kv.PutString("k4", "v4") + kv.PutString("k5", "v5") + for restartInterval := 1; restartInterval <= 5; restartInterval++ { + Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() { + // Make block. + bt := Build(kv, restartInterval) + + Test := func(r *util.Range) func(done Done) { + return func(done Done) { + iter := bt.TestNewIterator(r) + Expect(iter.Error()).ShouldNot(HaveOccurred()) + + t := testutil.IteratorTesting{ + KeyValue: kv.Clone(), + Iter: iter, + } + + testutil.DoIteratorTesting(&t) + iter.Release() + done <- true + } + } + + It("Should do iterations and seeks correctly #0", + Test(&util.Range{Start: []byte("k0"), Limit: []byte("k6")}), 2.0) + + It("Should do iterations and seeks correctly #1", + Test(&util.Range{Start: []byte(""), Limit: []byte("zzzzzzz")}), 2.0) + }) + } + }) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go new file mode 100644 index 00000000..7a0a557d --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go @@ -0,0 +1,1106 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package table + +import ( + "encoding/binary" + "fmt" + "io" + "sort" + "strings" + "sync" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy" +) + +var ( + ErrNotFound = errors.ErrNotFound + ErrReaderReleased = errors.New("leveldb/table: reader released") + ErrIterReleased = errors.New("leveldb/table: iterator released") +) + +type ErrCorrupted struct { + Pos int64 + Size int64 + Kind string + Reason string +} + +func (e *ErrCorrupted) Error() string { + return fmt.Sprintf("leveldb/table: corruption on %s (pos=%d): %s", e.Kind, e.Pos, e.Reason) +} + +func max(x, y int) int { + if x > y { + return x + } + return y +} + +type block struct { + bpool *util.BufferPool + bh blockHandle + data []byte + restartsLen int + restartsOffset int +} + +func (b *block) seek(cmp comparer.Comparer, rstart, rlimit int, key []byte) (index, offset int, err error) { + index = sort.Search(b.restartsLen-rstart-(b.restartsLen-rlimit), func(i int) bool { + offset := int(binary.LittleEndian.Uint32(b.data[b.restartsOffset+4*(rstart+i):])) + offset += 1 // shared always zero, since this is a restart point + v1, n1 := binary.Uvarint(b.data[offset:]) // key length + _, n2 := binary.Uvarint(b.data[offset+n1:]) // value length + m := offset + n1 + n2 + return cmp.Compare(b.data[m:m+int(v1)], key) > 0 + }) + rstart - 1 + if index < rstart { + // The smallest key is greater-than key sought. + index = rstart + } + offset = int(binary.LittleEndian.Uint32(b.data[b.restartsOffset+4*index:])) + return +} + +func (b *block) restartIndex(rstart, rlimit, offset int) int { + return sort.Search(b.restartsLen-rstart-(b.restartsLen-rlimit), func(i int) bool { + return int(binary.LittleEndian.Uint32(b.data[b.restartsOffset+4*(rstart+i):])) > offset + }) + rstart - 1 +} + +func (b *block) restartOffset(index int) int { + return int(binary.LittleEndian.Uint32(b.data[b.restartsOffset+4*index:])) +} + +func (b *block) entry(offset int) (key, value []byte, nShared, n int, err error) { + if offset >= b.restartsOffset { + if offset != b.restartsOffset { + err = &ErrCorrupted{Reason: "entries offset not aligned"} + } + return + } + v0, n0 := binary.Uvarint(b.data[offset:]) // Shared prefix length + v1, n1 := binary.Uvarint(b.data[offset+n0:]) // Key length + v2, n2 := binary.Uvarint(b.data[offset+n0+n1:]) // Value length + m := n0 + n1 + n2 + n = m + int(v1) + int(v2) + if n0 <= 0 || n1 <= 0 || n2 <= 0 || offset+n > b.restartsOffset { + err = &ErrCorrupted{Reason: "entries corrupted"} + return + } + key = b.data[offset+m : offset+m+int(v1)] + value = b.data[offset+m+int(v1) : offset+n] + nShared = int(v0) + return +} + +func (b *block) Release() { + b.bpool.Put(b.data) + b.bpool = nil + b.data = nil +} + +type dir int + +const ( + dirReleased dir = iota - 1 + dirSOI + dirEOI + dirBackward + dirForward +) + +type blockIter struct { + tr *Reader + block *block + blockReleaser util.Releaser + releaser util.Releaser + key, value []byte + offset int + // Previous offset, only filled by Next. + prevOffset int + prevNode []int + prevKeys []byte + restartIndex int + // Iterator direction. + dir dir + // Restart index slice range. + riStart int + riLimit int + // Offset slice range. + offsetStart int + offsetRealStart int + offsetLimit int + // Error. + err error +} + +func (i *blockIter) sErr(err error) { + i.err = err + i.key = nil + i.value = nil + i.prevNode = nil + i.prevKeys = nil +} + +func (i *blockIter) reset() { + if i.dir == dirBackward { + i.prevNode = i.prevNode[:0] + i.prevKeys = i.prevKeys[:0] + } + i.restartIndex = i.riStart + i.offset = i.offsetStart + i.dir = dirSOI + i.key = i.key[:0] + i.value = nil +} + +func (i *blockIter) isFirst() bool { + switch i.dir { + case dirForward: + return i.prevOffset == i.offsetRealStart + case dirBackward: + return len(i.prevNode) == 1 && i.restartIndex == i.riStart + } + return false +} + +func (i *blockIter) isLast() bool { + switch i.dir { + case dirForward, dirBackward: + return i.offset == i.offsetLimit + } + return false +} + +func (i *blockIter) First() bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + if i.dir == dirBackward { + i.prevNode = i.prevNode[:0] + i.prevKeys = i.prevKeys[:0] + } + i.dir = dirSOI + return i.Next() +} + +func (i *blockIter) Last() bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + if i.dir == dirBackward { + i.prevNode = i.prevNode[:0] + i.prevKeys = i.prevKeys[:0] + } + i.dir = dirEOI + return i.Prev() +} + +func (i *blockIter) Seek(key []byte) bool { + if i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + ri, offset, err := i.block.seek(i.tr.cmp, i.riStart, i.riLimit, key) + if err != nil { + i.sErr(err) + return false + } + i.restartIndex = ri + i.offset = max(i.offsetStart, offset) + if i.dir == dirSOI || i.dir == dirEOI { + i.dir = dirForward + } + for i.Next() { + if i.tr.cmp.Compare(i.key, key) >= 0 { + return true + } + } + return false +} + +func (i *blockIter) Next() bool { + if i.dir == dirEOI || i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + if i.dir == dirSOI { + i.restartIndex = i.riStart + i.offset = i.offsetStart + } else if i.dir == dirBackward { + i.prevNode = i.prevNode[:0] + i.prevKeys = i.prevKeys[:0] + } + for i.offset < i.offsetRealStart { + key, value, nShared, n, err := i.block.entry(i.offset) + if err != nil { + i.sErr(i.tr.fixErrCorruptedBH(i.block.bh, err)) + return false + } + if n == 0 { + i.dir = dirEOI + return false + } + i.key = append(i.key[:nShared], key...) + i.value = value + i.offset += n + } + if i.offset >= i.offsetLimit { + i.dir = dirEOI + if i.offset != i.offsetLimit { + i.sErr(i.tr.newErrCorruptedBH(i.block.bh, "entries offset not aligned")) + } + return false + } + key, value, nShared, n, err := i.block.entry(i.offset) + if err != nil { + i.sErr(i.tr.fixErrCorruptedBH(i.block.bh, err)) + return false + } + if n == 0 { + i.dir = dirEOI + return false + } + i.key = append(i.key[:nShared], key...) + i.value = value + i.prevOffset = i.offset + i.offset += n + i.dir = dirForward + return true +} + +func (i *blockIter) Prev() bool { + if i.dir == dirSOI || i.err != nil { + return false + } else if i.dir == dirReleased { + i.err = ErrIterReleased + return false + } + + var ri int + if i.dir == dirForward { + // Change direction. + i.offset = i.prevOffset + if i.offset == i.offsetRealStart { + i.dir = dirSOI + return false + } + ri = i.block.restartIndex(i.restartIndex, i.riLimit, i.offset) + i.dir = dirBackward + } else if i.dir == dirEOI { + // At the end of iterator. + i.restartIndex = i.riLimit + i.offset = i.offsetLimit + if i.offset == i.offsetRealStart { + i.dir = dirSOI + return false + } + ri = i.riLimit - 1 + i.dir = dirBackward + } else if len(i.prevNode) == 1 { + // This is the end of a restart range. + i.offset = i.prevNode[0] + i.prevNode = i.prevNode[:0] + if i.restartIndex == i.riStart { + i.dir = dirSOI + return false + } + i.restartIndex-- + ri = i.restartIndex + } else { + // In the middle of restart range, get from cache. + n := len(i.prevNode) - 3 + node := i.prevNode[n:] + i.prevNode = i.prevNode[:n] + // Get the key. + ko := node[0] + i.key = append(i.key[:0], i.prevKeys[ko:]...) + i.prevKeys = i.prevKeys[:ko] + // Get the value. + vo := node[1] + vl := vo + node[2] + i.value = i.block.data[vo:vl] + i.offset = vl + return true + } + // Build entries cache. + i.key = i.key[:0] + i.value = nil + offset := i.block.restartOffset(ri) + if offset == i.offset { + ri -= 1 + if ri < 0 { + i.dir = dirSOI + return false + } + offset = i.block.restartOffset(ri) + } + i.prevNode = append(i.prevNode, offset) + for { + key, value, nShared, n, err := i.block.entry(offset) + if err != nil { + i.sErr(i.tr.fixErrCorruptedBH(i.block.bh, err)) + return false + } + if offset >= i.offsetRealStart { + if i.value != nil { + // Appends 3 variables: + // 1. Previous keys offset + // 2. Value offset in the data block + // 3. Value length + i.prevNode = append(i.prevNode, len(i.prevKeys), offset-len(i.value), len(i.value)) + i.prevKeys = append(i.prevKeys, i.key...) + } + i.value = value + } + i.key = append(i.key[:nShared], key...) + offset += n + // Stop if target offset reached. + if offset >= i.offset { + if offset != i.offset { + i.sErr(i.tr.newErrCorruptedBH(i.block.bh, "entries offset not aligned")) + return false + } + + break + } + } + i.restartIndex = ri + i.offset = offset + return true +} + +func (i *blockIter) Key() []byte { + if i.err != nil || i.dir <= dirEOI { + return nil + } + return i.key +} + +func (i *blockIter) Value() []byte { + if i.err != nil || i.dir <= dirEOI { + return nil + } + return i.value +} + +func (i *blockIter) Release() { + if i.dir != dirReleased { + i.tr = nil + i.block = nil + i.prevNode = nil + i.prevKeys = nil + i.key = nil + i.value = nil + i.dir = dirReleased + if i.blockReleaser != nil { + i.blockReleaser.Release() + i.blockReleaser = nil + } + if i.releaser != nil { + i.releaser.Release() + i.releaser = nil + } + } +} + +func (i *blockIter) SetReleaser(releaser util.Releaser) { + if i.dir == dirReleased { + panic(util.ErrReleased) + } + if i.releaser != nil && releaser != nil { + panic(util.ErrHasReleaser) + } + i.releaser = releaser +} + +func (i *blockIter) Valid() bool { + return i.err == nil && (i.dir == dirBackward || i.dir == dirForward) +} + +func (i *blockIter) Error() error { + return i.err +} + +type filterBlock struct { + bpool *util.BufferPool + data []byte + oOffset int + baseLg uint + filtersNum int +} + +func (b *filterBlock) contains(filter filter.Filter, offset uint64, key []byte) bool { + i := int(offset >> b.baseLg) + if i < b.filtersNum { + o := b.data[b.oOffset+i*4:] + n := int(binary.LittleEndian.Uint32(o)) + m := int(binary.LittleEndian.Uint32(o[4:])) + if n < m && m <= b.oOffset { + return filter.Contains(b.data[n:m], key) + } else if n == m { + return false + } + } + return true +} + +func (b *filterBlock) Release() { + b.bpool.Put(b.data) + b.bpool = nil + b.data = nil +} + +type indexIter struct { + *blockIter + tr *Reader + slice *util.Range + // Options + fillCache bool +} + +func (i *indexIter) Get() iterator.Iterator { + value := i.Value() + if value == nil { + return nil + } + dataBH, n := decodeBlockHandle(value) + if n == 0 { + return iterator.NewEmptyIterator(i.tr.newErrCorruptedBH(i.tr.indexBH, "bad data block handle")) + } + + var slice *util.Range + if i.slice != nil && (i.blockIter.isFirst() || i.blockIter.isLast()) { + slice = i.slice + } + return i.tr.getDataIterErr(dataBH, slice, i.tr.verifyChecksum, i.fillCache) +} + +// Reader is a table reader. +type Reader struct { + mu sync.RWMutex + fi *storage.FileInfo + reader io.ReaderAt + cache *cache.CacheGetter + err error + bpool *util.BufferPool + // Options + o *opt.Options + cmp comparer.Comparer + filter filter.Filter + verifyChecksum bool + + dataEnd int64 + metaBH, indexBH, filterBH blockHandle + indexBlock *block + filterBlock *filterBlock +} + +func (r *Reader) blockKind(bh blockHandle) string { + switch bh.offset { + case r.metaBH.offset: + return "meta-block" + case r.indexBH.offset: + return "index-block" + case r.filterBH.offset: + if r.filterBH.length > 0 { + return "filter-block" + } + } + return "data-block" +} + +func (r *Reader) newErrCorrupted(pos, size int64, kind, reason string) error { + return &errors.ErrCorrupted{File: r.fi, Err: &ErrCorrupted{Pos: pos, Size: size, Kind: kind, Reason: reason}} +} + +func (r *Reader) newErrCorruptedBH(bh blockHandle, reason string) error { + return r.newErrCorrupted(int64(bh.offset), int64(bh.length), r.blockKind(bh), reason) +} + +func (r *Reader) fixErrCorruptedBH(bh blockHandle, err error) error { + if cerr, ok := err.(*ErrCorrupted); ok { + cerr.Pos = int64(bh.offset) + cerr.Size = int64(bh.length) + cerr.Kind = r.blockKind(bh) + return &errors.ErrCorrupted{File: r.fi, Err: cerr} + } + return err +} + +func (r *Reader) readRawBlock(bh blockHandle, verifyChecksum bool) ([]byte, error) { + data := r.bpool.Get(int(bh.length + blockTrailerLen)) + if _, err := r.reader.ReadAt(data, int64(bh.offset)); err != nil && err != io.EOF { + return nil, err + } + + if verifyChecksum { + n := bh.length + 1 + checksum0 := binary.LittleEndian.Uint32(data[n:]) + checksum1 := util.NewCRC(data[:n]).Value() + if checksum0 != checksum1 { + r.bpool.Put(data) + return nil, r.newErrCorruptedBH(bh, fmt.Sprintf("checksum mismatch, want=%#x got=%#x", checksum0, checksum1)) + } + } + + switch data[bh.length] { + case blockTypeNoCompression: + data = data[:bh.length] + case blockTypeSnappyCompression: + decLen, err := snappy.DecodedLen(data[:bh.length]) + if err != nil { + return nil, r.newErrCorruptedBH(bh, err.Error()) + } + decData := r.bpool.Get(decLen) + decData, err = snappy.Decode(decData, data[:bh.length]) + r.bpool.Put(data) + if err != nil { + r.bpool.Put(decData) + return nil, r.newErrCorruptedBH(bh, err.Error()) + } + data = decData + default: + r.bpool.Put(data) + return nil, r.newErrCorruptedBH(bh, fmt.Sprintf("unknown compression type %#x", data[bh.length])) + } + return data, nil +} + +func (r *Reader) readBlock(bh blockHandle, verifyChecksum bool) (*block, error) { + data, err := r.readRawBlock(bh, verifyChecksum) + if err != nil { + return nil, err + } + restartsLen := int(binary.LittleEndian.Uint32(data[len(data)-4:])) + b := &block{ + bpool: r.bpool, + bh: bh, + data: data, + restartsLen: restartsLen, + restartsOffset: len(data) - (restartsLen+1)*4, + } + return b, nil +} + +func (r *Reader) readBlockCached(bh blockHandle, verifyChecksum, fillCache bool) (*block, util.Releaser, error) { + if r.cache != nil { + var ( + err error + ch *cache.Handle + ) + if fillCache { + ch = r.cache.Get(bh.offset, func() (size int, value cache.Value) { + var b *block + b, err = r.readBlock(bh, verifyChecksum) + if err != nil { + return 0, nil + } + return cap(b.data), b + }) + } else { + ch = r.cache.Get(bh.offset, nil) + } + if ch != nil { + b, ok := ch.Value().(*block) + if !ok { + ch.Release() + return nil, nil, errors.New("leveldb/table: inconsistent block type") + } + return b, ch, err + } else if err != nil { + return nil, nil, err + } + } + + b, err := r.readBlock(bh, verifyChecksum) + return b, b, err +} + +func (r *Reader) readFilterBlock(bh blockHandle) (*filterBlock, error) { + data, err := r.readRawBlock(bh, true) + if err != nil { + return nil, err + } + n := len(data) + if n < 5 { + return nil, r.newErrCorruptedBH(bh, "too short") + } + m := n - 5 + oOffset := int(binary.LittleEndian.Uint32(data[m:])) + if oOffset > m { + return nil, r.newErrCorruptedBH(bh, "invalid data-offsets offset") + } + b := &filterBlock{ + bpool: r.bpool, + data: data, + oOffset: oOffset, + baseLg: uint(data[n-1]), + filtersNum: (m - oOffset) / 4, + } + return b, nil +} + +func (r *Reader) readFilterBlockCached(bh blockHandle, fillCache bool) (*filterBlock, util.Releaser, error) { + if r.cache != nil { + var ( + err error + ch *cache.Handle + ) + if fillCache { + ch = r.cache.Get(bh.offset, func() (size int, value cache.Value) { + var b *filterBlock + b, err = r.readFilterBlock(bh) + if err != nil { + return 0, nil + } + return cap(b.data), b + }) + } else { + ch = r.cache.Get(bh.offset, nil) + } + if ch != nil { + b, ok := ch.Value().(*filterBlock) + if !ok { + ch.Release() + return nil, nil, errors.New("leveldb/table: inconsistent block type") + } + return b, ch, err + } else if err != nil { + return nil, nil, err + } + } + + b, err := r.readFilterBlock(bh) + return b, b, err +} + +func (r *Reader) getIndexBlock(fillCache bool) (b *block, rel util.Releaser, err error) { + if r.indexBlock == nil { + return r.readBlockCached(r.indexBH, true, fillCache) + } + return r.indexBlock, util.NoopReleaser{}, nil +} + +func (r *Reader) getFilterBlock(fillCache bool) (*filterBlock, util.Releaser, error) { + if r.filterBlock == nil { + return r.readFilterBlockCached(r.filterBH, fillCache) + } + return r.filterBlock, util.NoopReleaser{}, nil +} + +func (r *Reader) newBlockIter(b *block, bReleaser util.Releaser, slice *util.Range, inclLimit bool) *blockIter { + bi := &blockIter{ + tr: r, + block: b, + blockReleaser: bReleaser, + // Valid key should never be nil. + key: make([]byte, 0), + dir: dirSOI, + riStart: 0, + riLimit: b.restartsLen, + offsetStart: 0, + offsetRealStart: 0, + offsetLimit: b.restartsOffset, + } + if slice != nil { + if slice.Start != nil { + if bi.Seek(slice.Start) { + bi.riStart = b.restartIndex(bi.restartIndex, b.restartsLen, bi.prevOffset) + bi.offsetStart = b.restartOffset(bi.riStart) + bi.offsetRealStart = bi.prevOffset + } else { + bi.riStart = b.restartsLen + bi.offsetStart = b.restartsOffset + bi.offsetRealStart = b.restartsOffset + } + } + if slice.Limit != nil { + if bi.Seek(slice.Limit) && (!inclLimit || bi.Next()) { + bi.offsetLimit = bi.prevOffset + bi.riLimit = bi.restartIndex + 1 + } + } + bi.reset() + if bi.offsetStart > bi.offsetLimit { + bi.sErr(errors.New("leveldb/table: invalid slice range")) + } + } + return bi +} + +func (r *Reader) getDataIter(dataBH blockHandle, slice *util.Range, verifyChecksum, fillCache bool) iterator.Iterator { + b, rel, err := r.readBlockCached(dataBH, verifyChecksum, fillCache) + if err != nil { + return iterator.NewEmptyIterator(err) + } + return r.newBlockIter(b, rel, slice, false) +} + +func (r *Reader) getDataIterErr(dataBH blockHandle, slice *util.Range, verifyChecksum, fillCache bool) iterator.Iterator { + r.mu.RLock() + defer r.mu.RUnlock() + + if r.err != nil { + return iterator.NewEmptyIterator(r.err) + } + + return r.getDataIter(dataBH, slice, verifyChecksum, fillCache) +} + +// NewIterator creates an iterator from the table. +// +// Slice allows slicing the iterator to only contains keys in the given +// range. A nil Range.Start is treated as a key before all keys in the +// table. And a nil Range.Limit is treated as a key after all keys in +// the table. +// +// The returned iterator is not goroutine-safe and should be released +// when not used. +// +// Also read Iterator documentation of the leveldb/iterator package. +func (r *Reader) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { + r.mu.RLock() + defer r.mu.RUnlock() + + if r.err != nil { + return iterator.NewEmptyIterator(r.err) + } + + fillCache := !ro.GetDontFillCache() + indexBlock, rel, err := r.getIndexBlock(fillCache) + if err != nil { + return iterator.NewEmptyIterator(err) + } + index := &indexIter{ + blockIter: r.newBlockIter(indexBlock, rel, slice, true), + tr: r, + slice: slice, + fillCache: !ro.GetDontFillCache(), + } + return iterator.NewIndexedIterator(index, opt.GetStrict(r.o, ro, opt.StrictReader)) +} + +func (r *Reader) find(key []byte, filtered bool, ro *opt.ReadOptions, noValue bool) (rkey, value []byte, err error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if r.err != nil { + err = r.err + return + } + + indexBlock, rel, err := r.getIndexBlock(true) + if err != nil { + return + } + defer rel.Release() + + index := r.newBlockIter(indexBlock, nil, nil, true) + defer index.Release() + if !index.Seek(key) { + err = index.Error() + if err == nil { + err = ErrNotFound + } + return + } + dataBH, n := decodeBlockHandle(index.Value()) + if n == 0 { + r.err = r.newErrCorruptedBH(r.indexBH, "bad data block handle") + return + } + if filtered && r.filter != nil { + filterBlock, frel, ferr := r.getFilterBlock(true) + if ferr == nil { + if !filterBlock.contains(r.filter, dataBH.offset, key) { + frel.Release() + return nil, nil, ErrNotFound + } + frel.Release() + } else if !errors.IsCorrupted(ferr) { + err = ferr + return + } + } + data := r.getDataIter(dataBH, nil, r.verifyChecksum, !ro.GetDontFillCache()) + defer data.Release() + if !data.Seek(key) { + err = data.Error() + if err == nil { + err = ErrNotFound + } + return + } + // Don't use block buffer, no need to copy the buffer. + rkey = data.Key() + if !noValue { + if r.bpool == nil { + value = data.Value() + } else { + // Use block buffer, and since the buffer will be recycled, the buffer + // need to be copied. + value = append([]byte{}, data.Value()...) + } + } + return +} + +// Find finds key/value pair whose key is greater than or equal to the +// given key. It returns ErrNotFound if the table doesn't contain +// such pair. +// If filtered is true then the nearest 'block' will be checked against +// 'filter data' (if present) and will immediately return ErrNotFound if +// 'filter data' indicates that such pair doesn't exist. +// +// The caller may modify the contents of the returned slice as it is its +// own copy. +// It is safe to modify the contents of the argument after Find returns. +func (r *Reader) Find(key []byte, filtered bool, ro *opt.ReadOptions) (rkey, value []byte, err error) { + return r.find(key, filtered, ro, false) +} + +// Find finds key that is greater than or equal to the given key. +// It returns ErrNotFound if the table doesn't contain such key. +// If filtered is true then the nearest 'block' will be checked against +// 'filter data' (if present) and will immediately return ErrNotFound if +// 'filter data' indicates that such key doesn't exist. +// +// The caller may modify the contents of the returned slice as it is its +// own copy. +// It is safe to modify the contents of the argument after Find returns. +func (r *Reader) FindKey(key []byte, filtered bool, ro *opt.ReadOptions) (rkey []byte, err error) { + rkey, _, err = r.find(key, filtered, ro, true) + return +} + +// Get gets the value for the given key. It returns errors.ErrNotFound +// if the table does not contain the key. +// +// The caller may modify the contents of the returned slice as it is its +// own copy. +// It is safe to modify the contents of the argument after Find returns. +func (r *Reader) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if r.err != nil { + err = r.err + return + } + + rkey, value, err := r.find(key, false, ro, false) + if err == nil && r.cmp.Compare(rkey, key) != 0 { + value = nil + err = ErrNotFound + } + return +} + +// OffsetOf returns approximate offset for the given key. +// +// It is safe to modify the contents of the argument after Get returns. +func (r *Reader) OffsetOf(key []byte) (offset int64, err error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if r.err != nil { + err = r.err + return + } + + indexBlock, rel, err := r.readBlockCached(r.indexBH, true, true) + if err != nil { + return + } + defer rel.Release() + + index := r.newBlockIter(indexBlock, nil, nil, true) + defer index.Release() + if index.Seek(key) { + dataBH, n := decodeBlockHandle(index.Value()) + if n == 0 { + r.err = r.newErrCorruptedBH(r.indexBH, "bad data block handle") + return + } + offset = int64(dataBH.offset) + return + } + err = index.Error() + if err == nil { + offset = r.dataEnd + } + return +} + +// Release implements util.Releaser. +// It also close the file if it is an io.Closer. +func (r *Reader) Release() { + r.mu.Lock() + defer r.mu.Unlock() + + if closer, ok := r.reader.(io.Closer); ok { + closer.Close() + } + if r.indexBlock != nil { + r.indexBlock.Release() + r.indexBlock = nil + } + if r.filterBlock != nil { + r.filterBlock.Release() + r.filterBlock = nil + } + r.reader = nil + r.cache = nil + r.bpool = nil + r.err = ErrReaderReleased +} + +// NewReader creates a new initialized table reader for the file. +// The fi, cache and bpool is optional and can be nil. +// +// The returned table reader instance is goroutine-safe. +func NewReader(f io.ReaderAt, size int64, fi *storage.FileInfo, cache *cache.CacheGetter, bpool *util.BufferPool, o *opt.Options) (*Reader, error) { + if f == nil { + return nil, errors.New("leveldb/table: nil file") + } + + r := &Reader{ + fi: fi, + reader: f, + cache: cache, + bpool: bpool, + o: o, + cmp: o.GetComparer(), + verifyChecksum: o.GetStrict(opt.StrictBlockChecksum), + } + + if size < footerLen { + r.err = r.newErrCorrupted(0, size, "table", "too small") + return r, nil + } + + footerPos := size - footerLen + var footer [footerLen]byte + if _, err := r.reader.ReadAt(footer[:], footerPos); err != nil && err != io.EOF { + return nil, err + } + if string(footer[footerLen-len(magic):footerLen]) != magic { + r.err = r.newErrCorrupted(footerPos, footerLen, "table-footer", "bad magic number") + return r, nil + } + + var n int + // Decode the metaindex block handle. + r.metaBH, n = decodeBlockHandle(footer[:]) + if n == 0 { + r.err = r.newErrCorrupted(footerPos, footerLen, "table-footer", "bad metaindex block handle") + return r, nil + } + + // Decode the index block handle. + r.indexBH, n = decodeBlockHandle(footer[n:]) + if n == 0 { + r.err = r.newErrCorrupted(footerPos, footerLen, "table-footer", "bad index block handle") + return r, nil + } + + // Read metaindex block. + metaBlock, err := r.readBlock(r.metaBH, true) + if err != nil { + if errors.IsCorrupted(err) { + r.err = err + return r, nil + } else { + return nil, err + } + } + + // Set data end. + r.dataEnd = int64(r.metaBH.offset) + + // Read metaindex. + metaIter := r.newBlockIter(metaBlock, nil, nil, true) + for metaIter.Next() { + key := string(metaIter.Key()) + if !strings.HasPrefix(key, "filter.") { + continue + } + fn := key[7:] + if f0 := o.GetFilter(); f0 != nil && f0.Name() == fn { + r.filter = f0 + } else { + for _, f0 := range o.GetAltFilters() { + if f0.Name() == fn { + r.filter = f0 + break + } + } + } + if r.filter != nil { + filterBH, n := decodeBlockHandle(metaIter.Value()) + if n == 0 { + continue + } + r.filterBH = filterBH + // Update data end. + r.dataEnd = int64(filterBH.offset) + break + } + } + metaIter.Release() + metaBlock.Release() + + // Cache index and filter block locally, since we don't have global cache. + if cache == nil { + r.indexBlock, err = r.readBlock(r.indexBH, true) + if err != nil { + if errors.IsCorrupted(err) { + r.err = err + return r, nil + } else { + return nil, err + } + } + if r.filter != nil { + r.filterBlock, err = r.readFilterBlock(r.filterBH) + if err != nil { + if !errors.IsCorrupted(err) { + return nil, err + } + + // Don't use filter then. + r.filter = nil + } + } + } + + return r, nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table.go new file mode 100644 index 00000000..beacdc1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table.go @@ -0,0 +1,177 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package table allows read and write sorted key/value. +package table + +import ( + "encoding/binary" +) + +/* +Table: + +Table is consist of one or more data blocks, an optional filter block +a metaindex block, an index block and a table footer. Metaindex block +is a special block used to keep parameters of the table, such as filter +block name and its block handle. Index block is a special block used to +keep record of data blocks offset and length, index block use one as +restart interval. The key used by index block are the last key of preceding +block, shorter separator of adjacent blocks or shorter successor of the +last key of the last block. Filter block is an optional block contains +sequence of filter data generated by a filter generator. + +Table data structure: + + optional + / + +--------------+--------------+--------------+------+-------+-----------------+-------------+--------+ + | data block 1 | ... | data block n | filter block | metaindex block | index block | footer | + +--------------+--------------+--------------+--------------+-----------------+-------------+--------+ + + Each block followed by a 5-bytes trailer contains compression type and checksum. + +Table block trailer: + + +---------------------------+-------------------+ + | compression type (1-byte) | checksum (4-byte) | + +---------------------------+-------------------+ + + The checksum is a CRC-32 computed using Castagnoli's polynomial. Compression + type also included in the checksum. + +Table footer: + + +------------------- 40-bytes -------------------+ + / \ + +------------------------+--------------------+------+-----------------+ + | metaindex block handle / index block handle / ---- | magic (8-bytes) | + +------------------------+--------------------+------+-----------------+ + + The magic are first 64-bit of SHA-1 sum of "http://code.google.com/p/leveldb/". + +NOTE: All fixed-length integer are little-endian. +*/ + +/* +Block: + +Block is consist of one or more key/value entries and a block trailer. +Block entry shares key prefix with its preceding key until a restart +point reached. A block should contains at least one restart point. +First restart point are always zero. + +Block data structure: + + + restart point + restart point (depends on restart interval) + / / + +---------------+---------------+---------------+---------------+---------+ + | block entry 1 | block entry 2 | ... | block entry n | trailer | + +---------------+---------------+---------------+---------------+---------+ + +Key/value entry: + + +---- key len ----+ + / \ + +-------+---------+-----------+---------+--------------------+--------------+----------------+ + | shared (varint) | not shared (varint) | value len (varint) | key (varlen) | value (varlen) | + +-----------------+---------------------+--------------------+--------------+----------------+ + + Block entry shares key prefix with its preceding key: + Conditions: + restart_interval=2 + entry one : key=deck,value=v1 + entry two : key=dock,value=v2 + entry three: key=duck,value=v3 + The entries will be encoded as follow: + + + restart point (offset=0) + restart point (offset=16) + / / + +-----+-----+-----+----------+--------+-----+-----+-----+---------+--------+-----+-----+-----+----------+--------+ + | 0 | 4 | 2 | "deck" | "v1" | 1 | 3 | 2 | "ock" | "v2" | 0 | 4 | 2 | "duck" | "v3" | + +-----+-----+-----+----------+--------+-----+-----+-----+---------+--------+-----+-----+-----+----------+--------+ + \ / \ / \ / + +----------- entry one -----------+ +----------- entry two ----------+ +---------- entry three ----------+ + + The block trailer will contains two restart points: + + +------------+-----------+--------+ + | 0 | 16 | 2 | + +------------+-----------+---+----+ + \ / \ + +-- restart points --+ + restart points length + +Block trailer: + + +-- 4-bytes --+ + / \ + +-----------------+-----------------+-----------------+------------------------------+ + | restart point 1 | .... | restart point n | restart points len (4-bytes) | + +-----------------+-----------------+-----------------+------------------------------+ + + +NOTE: All fixed-length integer are little-endian. +*/ + +/* +Filter block: + +Filter block consist of one or more filter data and a filter block trailer. +The trailer contains filter data offsets, a trailer offset and a 1-byte base Lg. + +Filter block data structure: + + + offset 1 + offset 2 + offset n + trailer offset + / / / / + +---------------+---------------+---------------+---------+ + | filter data 1 | ... | filter data n | trailer | + +---------------+---------------+---------------+---------+ + +Filter block trailer: + + +- 4-bytes -+ + / \ + +---------------+---------------+---------------+-------------------------------+------------------+ + | data 1 offset | .... | data n offset | data-offsets offset (4-bytes) | base Lg (1-byte) | + +-------------- +---------------+---------------+-------------------------------+------------------+ + + +NOTE: All fixed-length integer are little-endian. +*/ + +const ( + blockTrailerLen = 5 + footerLen = 48 + + magic = "\x57\xfb\x80\x8b\x24\x75\x47\xdb" + + // The block type gives the per-block compression format. + // These constants are part of the file format and should not be changed. + blockTypeNoCompression = 0 + blockTypeSnappyCompression = 1 + + // Generate new filter every 2KB of data + filterBaseLg = 11 + filterBase = 1 << filterBaseLg +) + +type blockHandle struct { + offset, length uint64 +} + +func decodeBlockHandle(src []byte) (blockHandle, int) { + offset, n := binary.Uvarint(src) + length, m := binary.Uvarint(src[n:]) + if n == 0 || m == 0 { + return blockHandle{}, 0 + } + return blockHandle{offset, length}, n + m +} + +func encodeBlockHandle(dst []byte, b blockHandle) int { + n := binary.PutUvarint(dst, b.offset) + m := binary.PutUvarint(dst[n:], b.length) + return n + m +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go new file mode 100644 index 00000000..b5a8e458 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go @@ -0,0 +1,11 @@ +package table + +import ( + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" +) + +func TestTable(t *testing.T) { + testutil.RunSuite(t, "Table Suite") +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go new file mode 100644 index 00000000..ac98a9c3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go @@ -0,0 +1,122 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package table + +import ( + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type tableWrapper struct { + *Reader +} + +func (t tableWrapper) TestFind(key []byte) (rkey, rvalue []byte, err error) { + return t.Reader.Find(key, false, nil) +} + +func (t tableWrapper) TestGet(key []byte) (value []byte, err error) { + return t.Reader.Get(key, nil) +} + +func (t tableWrapper) TestNewIterator(slice *util.Range) iterator.Iterator { + return t.Reader.NewIterator(slice, nil) +} + +var _ = testutil.Defer(func() { + Describe("Table", func() { + Describe("approximate offset test", func() { + var ( + buf = &bytes.Buffer{} + o = &opt.Options{ + BlockSize: 1024, + Compression: opt.NoCompression, + } + ) + + // Building the table. + tw := NewWriter(buf, o) + tw.Append([]byte("k01"), []byte("hello")) + tw.Append([]byte("k02"), []byte("hello2")) + tw.Append([]byte("k03"), bytes.Repeat([]byte{'x'}, 10000)) + tw.Append([]byte("k04"), bytes.Repeat([]byte{'x'}, 200000)) + tw.Append([]byte("k05"), bytes.Repeat([]byte{'x'}, 300000)) + tw.Append([]byte("k06"), []byte("hello3")) + tw.Append([]byte("k07"), bytes.Repeat([]byte{'x'}, 100000)) + err := tw.Close() + + It("Should be able to approximate offset of a key correctly", func() { + Expect(err).ShouldNot(HaveOccurred()) + + tr, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()), nil, nil, nil, o) + Expect(err).ShouldNot(HaveOccurred()) + CheckOffset := func(key string, expect, threshold int) { + offset, err := tr.OffsetOf([]byte(key)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(offset).Should(BeNumerically("~", expect, threshold), "Offset of key %q", key) + } + + CheckOffset("k0", 0, 0) + CheckOffset("k01a", 0, 0) + CheckOffset("k02", 0, 0) + CheckOffset("k03", 0, 0) + CheckOffset("k04", 10000, 1000) + CheckOffset("k04a", 210000, 1000) + CheckOffset("k05", 210000, 1000) + CheckOffset("k06", 510000, 1000) + CheckOffset("k07", 510000, 1000) + CheckOffset("xyz", 610000, 2000) + }) + }) + + Describe("read test", func() { + Build := func(kv testutil.KeyValue) testutil.DB { + o := &opt.Options{ + BlockSize: 512, + BlockRestartInterval: 3, + } + buf := &bytes.Buffer{} + + // Building the table. + tw := NewWriter(buf, o) + kv.Iterate(func(i int, key, value []byte) { + tw.Append(key, value) + }) + tw.Close() + + // Opening the table. + tr, _ := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()), nil, nil, nil, o) + return tableWrapper{tr} + } + Test := func(kv *testutil.KeyValue, body func(r *Reader)) func() { + return func() { + db := Build(*kv) + if body != nil { + body(db.(tableWrapper).Reader) + } + testutil.KeyValueTesting(nil, *kv, db, nil, nil) + } + } + + testutil.AllKeyValueTesting(nil, Build, nil, nil) + Describe("with one key per block", Test(testutil.KeyValue_Generate(nil, 9, 1, 10, 512, 512), func(r *Reader) { + It("should have correct blocks number", func() { + indexBlock, err := r.readBlock(r.indexBH, true) + Expect(err).To(BeNil()) + Expect(indexBlock.restartsLen).Should(Equal(9)) + }) + })) + }) + }) +}) diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go new file mode 100644 index 00000000..b6b6b082 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go @@ -0,0 +1,378 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package table + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy" +) + +func sharedPrefixLen(a, b []byte) int { + i, n := 0, len(a) + if n > len(b) { + n = len(b) + } + for i < n && a[i] == b[i] { + i++ + } + return i +} + +type blockWriter struct { + restartInterval int + buf util.Buffer + nEntries int + prevKey []byte + restarts []uint32 + scratch []byte +} + +func (w *blockWriter) append(key, value []byte) { + nShared := 0 + if w.nEntries%w.restartInterval == 0 { + w.restarts = append(w.restarts, uint32(w.buf.Len())) + } else { + nShared = sharedPrefixLen(w.prevKey, key) + } + n := binary.PutUvarint(w.scratch[0:], uint64(nShared)) + n += binary.PutUvarint(w.scratch[n:], uint64(len(key)-nShared)) + n += binary.PutUvarint(w.scratch[n:], uint64(len(value))) + w.buf.Write(w.scratch[:n]) + w.buf.Write(key[nShared:]) + w.buf.Write(value) + w.prevKey = append(w.prevKey[:0], key...) + w.nEntries++ +} + +func (w *blockWriter) finish() { + // Write restarts entry. + if w.nEntries == 0 { + // Must have at least one restart entry. + w.restarts = append(w.restarts, 0) + } + w.restarts = append(w.restarts, uint32(len(w.restarts))) + for _, x := range w.restarts { + buf4 := w.buf.Alloc(4) + binary.LittleEndian.PutUint32(buf4, x) + } +} + +func (w *blockWriter) reset() { + w.buf.Reset() + w.nEntries = 0 + w.restarts = w.restarts[:0] +} + +func (w *blockWriter) bytesLen() int { + restartsLen := len(w.restarts) + if restartsLen == 0 { + restartsLen = 1 + } + return w.buf.Len() + 4*restartsLen + 4 +} + +type filterWriter struct { + generator filter.FilterGenerator + buf util.Buffer + nKeys int + offsets []uint32 +} + +func (w *filterWriter) add(key []byte) { + if w.generator == nil { + return + } + w.generator.Add(key) + w.nKeys++ +} + +func (w *filterWriter) flush(offset uint64) { + if w.generator == nil { + return + } + for x := int(offset / filterBase); x > len(w.offsets); { + w.generate() + } +} + +func (w *filterWriter) finish() { + if w.generator == nil { + return + } + // Generate last keys. + + if w.nKeys > 0 { + w.generate() + } + w.offsets = append(w.offsets, uint32(w.buf.Len())) + for _, x := range w.offsets { + buf4 := w.buf.Alloc(4) + binary.LittleEndian.PutUint32(buf4, x) + } + w.buf.WriteByte(filterBaseLg) +} + +func (w *filterWriter) generate() { + // Record offset. + w.offsets = append(w.offsets, uint32(w.buf.Len())) + // Generate filters. + if w.nKeys > 0 { + w.generator.Generate(&w.buf) + w.nKeys = 0 + } +} + +// Writer is a table writer. +type Writer struct { + writer io.Writer + err error + // Options + cmp comparer.Comparer + filter filter.Filter + compression opt.Compression + blockSize int + + dataBlock blockWriter + indexBlock blockWriter + filterBlock filterWriter + pendingBH blockHandle + offset uint64 + nEntries int + // Scratch allocated enough for 5 uvarint. Block writer should not use + // first 20-bytes since it will be used to encode block handle, which + // then passed to the block writer itself. + scratch [50]byte + comparerScratch []byte + compressionScratch []byte +} + +func (w *Writer) writeBlock(buf *util.Buffer, compression opt.Compression) (bh blockHandle, err error) { + // Compress the buffer if necessary. + var b []byte + if compression == opt.SnappyCompression { + // Allocate scratch enough for compression and block trailer. + if n := snappy.MaxEncodedLen(buf.Len()) + blockTrailerLen; len(w.compressionScratch) < n { + w.compressionScratch = make([]byte, n) + } + var compressed []byte + compressed, err = snappy.Encode(w.compressionScratch, buf.Bytes()) + if err != nil { + return + } + n := len(compressed) + b = compressed[:n+blockTrailerLen] + b[n] = blockTypeSnappyCompression + } else { + tmp := buf.Alloc(blockTrailerLen) + tmp[0] = blockTypeNoCompression + b = buf.Bytes() + } + + // Calculate the checksum. + n := len(b) - 4 + checksum := util.NewCRC(b[:n]).Value() + binary.LittleEndian.PutUint32(b[n:], checksum) + + // Write the buffer to the file. + _, err = w.writer.Write(b) + if err != nil { + return + } + bh = blockHandle{w.offset, uint64(len(b) - blockTrailerLen)} + w.offset += uint64(len(b)) + return +} + +func (w *Writer) flushPendingBH(key []byte) { + if w.pendingBH.length == 0 { + return + } + var separator []byte + if len(key) == 0 { + separator = w.cmp.Successor(w.comparerScratch[:0], w.dataBlock.prevKey) + } else { + separator = w.cmp.Separator(w.comparerScratch[:0], w.dataBlock.prevKey, key) + } + if separator == nil { + separator = w.dataBlock.prevKey + } else { + w.comparerScratch = separator + } + n := encodeBlockHandle(w.scratch[:20], w.pendingBH) + // Append the block handle to the index block. + w.indexBlock.append(separator, w.scratch[:n]) + // Reset prev key of the data block. + w.dataBlock.prevKey = w.dataBlock.prevKey[:0] + // Clear pending block handle. + w.pendingBH = blockHandle{} +} + +func (w *Writer) finishBlock() error { + w.dataBlock.finish() + bh, err := w.writeBlock(&w.dataBlock.buf, w.compression) + if err != nil { + return err + } + w.pendingBH = bh + // Reset the data block. + w.dataBlock.reset() + // Flush the filter block. + w.filterBlock.flush(w.offset) + return nil +} + +// Append appends key/value pair to the table. The keys passed must +// be in increasing order. +// +// It is safe to modify the contents of the arguments after Append returns. +func (w *Writer) Append(key, value []byte) error { + if w.err != nil { + return w.err + } + if w.nEntries > 0 && w.cmp.Compare(w.dataBlock.prevKey, key) >= 0 { + w.err = fmt.Errorf("leveldb/table: Writer: keys are not in increasing order: %q, %q", w.dataBlock.prevKey, key) + return w.err + } + + w.flushPendingBH(key) + // Append key/value pair to the data block. + w.dataBlock.append(key, value) + // Add key to the filter block. + w.filterBlock.add(key) + + // Finish the data block if block size target reached. + if w.dataBlock.bytesLen() >= w.blockSize { + if err := w.finishBlock(); err != nil { + w.err = err + return w.err + } + } + w.nEntries++ + return nil +} + +// BlocksLen returns number of blocks written so far. +func (w *Writer) BlocksLen() int { + n := w.indexBlock.nEntries + if w.pendingBH.length > 0 { + // Includes the pending block. + n++ + } + return n +} + +// EntriesLen returns number of entries added so far. +func (w *Writer) EntriesLen() int { + return w.nEntries +} + +// BytesLen returns number of bytes written so far. +func (w *Writer) BytesLen() int { + return int(w.offset) +} + +// Close will finalize the table. Calling Append is not possible +// after Close, but calling BlocksLen, EntriesLen and BytesLen +// is still possible. +func (w *Writer) Close() error { + if w.err != nil { + return w.err + } + + // Write the last data block. Or empty data block if there + // aren't any data blocks at all. + if w.dataBlock.nEntries > 0 || w.nEntries == 0 { + if err := w.finishBlock(); err != nil { + w.err = err + return w.err + } + } + w.flushPendingBH(nil) + + // Write the filter block. + var filterBH blockHandle + w.filterBlock.finish() + if buf := &w.filterBlock.buf; buf.Len() > 0 { + filterBH, w.err = w.writeBlock(buf, opt.NoCompression) + if w.err != nil { + return w.err + } + } + + // Write the metaindex block. + if filterBH.length > 0 { + key := []byte("filter." + w.filter.Name()) + n := encodeBlockHandle(w.scratch[:20], filterBH) + w.dataBlock.append(key, w.scratch[:n]) + } + w.dataBlock.finish() + metaindexBH, err := w.writeBlock(&w.dataBlock.buf, w.compression) + if err != nil { + w.err = err + return w.err + } + + // Write the index block. + w.indexBlock.finish() + indexBH, err := w.writeBlock(&w.indexBlock.buf, w.compression) + if err != nil { + w.err = err + return w.err + } + + // Write the table footer. + footer := w.scratch[:footerLen] + for i := range footer { + footer[i] = 0 + } + n := encodeBlockHandle(footer, metaindexBH) + encodeBlockHandle(footer[n:], indexBH) + copy(footer[footerLen-len(magic):], magic) + if _, err := w.writer.Write(footer); err != nil { + w.err = err + return w.err + } + w.offset += footerLen + + w.err = errors.New("leveldb/table: writer is closed") + return nil +} + +// NewWriter creates a new initialized table writer for the file. +// +// Table writer is not goroutine-safe. +func NewWriter(f io.Writer, o *opt.Options) *Writer { + w := &Writer{ + writer: f, + cmp: o.GetComparer(), + filter: o.GetFilter(), + compression: o.GetCompression(), + blockSize: o.GetBlockSize(), + comparerScratch: make([]byte, 0), + } + // data block + w.dataBlock.restartInterval = o.GetBlockRestartInterval() + // The first 20-bytes are used for encoding block handle. + w.dataBlock.scratch = w.scratch[20:] + // index block + w.indexBlock.restartInterval = 1 + w.indexBlock.scratch = w.scratch[20:] + // filter block + if w.filter != nil { + w.filterBlock.generator = w.filter.NewGenerator() + w.filterBlock.flush(0) + } + return w +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/db.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/db.go new file mode 100644 index 00000000..124ee7ce --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/db.go @@ -0,0 +1,222 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package testutil + +import ( + "fmt" + "math/rand" + + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type DB interface{} + +type Put interface { + TestPut(key []byte, value []byte) error +} + +type Delete interface { + TestDelete(key []byte) error +} + +type Find interface { + TestFind(key []byte) (rkey, rvalue []byte, err error) +} + +type Get interface { + TestGet(key []byte) (value []byte, err error) +} + +type Has interface { + TestHas(key []byte) (ret bool, err error) +} + +type NewIterator interface { + TestNewIterator(slice *util.Range) iterator.Iterator +} + +type DBAct int + +func (a DBAct) String() string { + switch a { + case DBNone: + return "none" + case DBPut: + return "put" + case DBOverwrite: + return "overwrite" + case DBDelete: + return "delete" + case DBDeleteNA: + return "delete_na" + } + return "unknown" +} + +const ( + DBNone DBAct = iota + DBPut + DBOverwrite + DBDelete + DBDeleteNA +) + +type DBTesting struct { + Rand *rand.Rand + DB interface { + Get + Put + Delete + } + PostFn func(t *DBTesting) + Deleted, Present KeyValue + Act, LastAct DBAct + ActKey, LastActKey []byte +} + +func (t *DBTesting) post() { + if t.PostFn != nil { + t.PostFn(t) + } +} + +func (t *DBTesting) setAct(act DBAct, key []byte) { + t.LastAct, t.Act = t.Act, act + t.LastActKey, t.ActKey = t.ActKey, key +} + +func (t *DBTesting) text() string { + return fmt.Sprintf("last action was <%v> %q, <%v> %q", t.LastAct, t.LastActKey, t.Act, t.ActKey) +} + +func (t *DBTesting) Text() string { + return "DBTesting " + t.text() +} + +func (t *DBTesting) TestPresentKV(key, value []byte) { + rvalue, err := t.DB.TestGet(key) + Expect(err).ShouldNot(HaveOccurred(), "Get on key %q, %s", key, t.text()) + Expect(rvalue).Should(Equal(value), "Value for key %q, %s", key, t.text()) +} + +func (t *DBTesting) TestAllPresent() { + t.Present.IterateShuffled(t.Rand, func(i int, key, value []byte) { + t.TestPresentKV(key, value) + }) +} + +func (t *DBTesting) TestDeletedKey(key []byte) { + _, err := t.DB.TestGet(key) + Expect(err).Should(Equal(errors.ErrNotFound), "Get on deleted key %q, %s", key, t.text()) +} + +func (t *DBTesting) TestAllDeleted() { + t.Deleted.IterateShuffled(t.Rand, func(i int, key, value []byte) { + t.TestDeletedKey(key) + }) +} + +func (t *DBTesting) TestAll() { + dn := t.Deleted.Len() + pn := t.Present.Len() + ShuffledIndex(t.Rand, dn+pn, 1, func(i int) { + if i >= dn { + key, value := t.Present.Index(i - dn) + t.TestPresentKV(key, value) + } else { + t.TestDeletedKey(t.Deleted.KeyAt(i)) + } + }) +} + +func (t *DBTesting) Put(key, value []byte) { + if new := t.Present.PutU(key, value); new { + t.setAct(DBPut, key) + } else { + t.setAct(DBOverwrite, key) + } + t.Deleted.Delete(key) + err := t.DB.TestPut(key, value) + Expect(err).ShouldNot(HaveOccurred(), t.Text()) + t.TestPresentKV(key, value) + t.post() +} + +func (t *DBTesting) PutRandom() bool { + if t.Deleted.Len() > 0 { + i := t.Rand.Intn(t.Deleted.Len()) + key, value := t.Deleted.Index(i) + t.Put(key, value) + return true + } + return false +} + +func (t *DBTesting) Delete(key []byte) { + if exist, value := t.Present.Delete(key); exist { + t.setAct(DBDelete, key) + t.Deleted.PutU(key, value) + } else { + t.setAct(DBDeleteNA, key) + } + err := t.DB.TestDelete(key) + Expect(err).ShouldNot(HaveOccurred(), t.Text()) + t.TestDeletedKey(key) + t.post() +} + +func (t *DBTesting) DeleteRandom() bool { + if t.Present.Len() > 0 { + i := t.Rand.Intn(t.Present.Len()) + t.Delete(t.Present.KeyAt(i)) + return true + } + return false +} + +func (t *DBTesting) RandomAct(round int) { + for i := 0; i < round; i++ { + if t.Rand.Int()%2 == 0 { + t.PutRandom() + } else { + t.DeleteRandom() + } + } +} + +func DoDBTesting(t *DBTesting) { + if t.Rand == nil { + t.Rand = NewRand() + } + + t.DeleteRandom() + t.PutRandom() + t.DeleteRandom() + t.DeleteRandom() + for i := t.Deleted.Len() / 2; i >= 0; i-- { + t.PutRandom() + } + t.RandomAct((t.Deleted.Len() + t.Present.Len()) * 10) + + // Additional iterator testing + if db, ok := t.DB.(NewIterator); ok { + iter := db.TestNewIterator(nil) + Expect(iter.Error()).NotTo(HaveOccurred()) + + it := IteratorTesting{ + KeyValue: t.Present, + Iter: iter, + } + + DoIteratorTesting(&it) + iter.Release() + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go new file mode 100644 index 00000000..82f3d0e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/ginkgo.go @@ -0,0 +1,21 @@ +package testutil + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func RunSuite(t GinkgoTestingT, name string) { + RunDefer() + + SynchronizedBeforeSuite(func() []byte { + RunDefer("setup") + return nil + }, func(data []byte) {}) + SynchronizedAfterSuite(func() { + RunDefer("teardown") + }, func() {}) + + RegisterFailHandler(Fail) + RunSpecs(t, name) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/iter.go new file mode 100644 index 00000000..0f63a967 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/iter.go @@ -0,0 +1,327 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package testutil + +import ( + "fmt" + "math/rand" + + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" +) + +type IterAct int + +func (a IterAct) String() string { + switch a { + case IterNone: + return "none" + case IterFirst: + return "first" + case IterLast: + return "last" + case IterPrev: + return "prev" + case IterNext: + return "next" + case IterSeek: + return "seek" + case IterSOI: + return "soi" + case IterEOI: + return "eoi" + } + return "unknown" +} + +const ( + IterNone IterAct = iota + IterFirst + IterLast + IterPrev + IterNext + IterSeek + IterSOI + IterEOI +) + +type IteratorTesting struct { + KeyValue + Iter iterator.Iterator + Rand *rand.Rand + PostFn func(t *IteratorTesting) + Pos int + Act, LastAct IterAct + + once bool +} + +func (t *IteratorTesting) init() { + if !t.once { + t.Pos = -1 + t.once = true + } +} + +func (t *IteratorTesting) post() { + if t.PostFn != nil { + t.PostFn(t) + } +} + +func (t *IteratorTesting) setAct(act IterAct) { + t.LastAct, t.Act = t.Act, act +} + +func (t *IteratorTesting) text() string { + return fmt.Sprintf("at pos %d and last action was <%v> -> <%v>", t.Pos, t.LastAct, t.Act) +} + +func (t *IteratorTesting) Text() string { + return "IteratorTesting is " + t.text() +} + +func (t *IteratorTesting) IsFirst() bool { + t.init() + return t.Len() > 0 && t.Pos == 0 +} + +func (t *IteratorTesting) IsLast() bool { + t.init() + return t.Len() > 0 && t.Pos == t.Len()-1 +} + +func (t *IteratorTesting) TestKV() { + t.init() + key, value := t.Index(t.Pos) + Expect(t.Iter.Key()).NotTo(BeNil()) + Expect(t.Iter.Key()).Should(Equal(key), "Key is invalid, %s", t.text()) + Expect(t.Iter.Value()).Should(Equal(value), "Value for key %q, %s", key, t.text()) +} + +func (t *IteratorTesting) First() { + t.init() + t.setAct(IterFirst) + + ok := t.Iter.First() + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + if t.Len() > 0 { + t.Pos = 0 + Expect(ok).Should(BeTrue(), t.Text()) + t.TestKV() + } else { + t.Pos = -1 + Expect(ok).ShouldNot(BeTrue(), t.Text()) + } + t.post() +} + +func (t *IteratorTesting) Last() { + t.init() + t.setAct(IterLast) + + ok := t.Iter.Last() + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + if t.Len() > 0 { + t.Pos = t.Len() - 1 + Expect(ok).Should(BeTrue(), t.Text()) + t.TestKV() + } else { + t.Pos = 0 + Expect(ok).ShouldNot(BeTrue(), t.Text()) + } + t.post() +} + +func (t *IteratorTesting) Next() { + t.init() + t.setAct(IterNext) + + ok := t.Iter.Next() + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + if t.Pos < t.Len()-1 { + t.Pos++ + Expect(ok).Should(BeTrue(), t.Text()) + t.TestKV() + } else { + t.Pos = t.Len() + Expect(ok).ShouldNot(BeTrue(), t.Text()) + } + t.post() +} + +func (t *IteratorTesting) Prev() { + t.init() + t.setAct(IterPrev) + + ok := t.Iter.Prev() + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + if t.Pos > 0 { + t.Pos-- + Expect(ok).Should(BeTrue(), t.Text()) + t.TestKV() + } else { + t.Pos = -1 + Expect(ok).ShouldNot(BeTrue(), t.Text()) + } + t.post() +} + +func (t *IteratorTesting) Seek(i int) { + t.init() + t.setAct(IterSeek) + + key, _ := t.Index(i) + oldKey, _ := t.IndexOrNil(t.Pos) + + ok := t.Iter.Seek(key) + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q, to pos %d, %s", oldKey, key, i, t.text())) + + t.Pos = i + t.TestKV() + t.post() +} + +func (t *IteratorTesting) SeekInexact(i int) { + t.init() + t.setAct(IterSeek) + var key0 []byte + key1, _ := t.Index(i) + if i > 0 { + key0, _ = t.Index(i - 1) + } + key := BytesSeparator(key0, key1) + oldKey, _ := t.IndexOrNil(t.Pos) + + ok := t.Iter.Seek(key) + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key1, i, t.text())) + + t.Pos = i + t.TestKV() + t.post() +} + +func (t *IteratorTesting) SeekKey(key []byte) { + t.init() + t.setAct(IterSeek) + oldKey, _ := t.IndexOrNil(t.Pos) + i := t.Search(key) + + ok := t.Iter.Seek(key) + Expect(t.Iter.Error()).ShouldNot(HaveOccurred()) + if i < t.Len() { + key_, _ := t.Index(i) + Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key_, i, t.text())) + t.Pos = i + t.TestKV() + } else { + Expect(ok).ShouldNot(BeTrue(), fmt.Sprintf("Seek from key %q to %q, %s", oldKey, key, t.text())) + } + + t.Pos = i + t.post() +} + +func (t *IteratorTesting) SOI() { + t.init() + t.setAct(IterSOI) + Expect(t.Pos).Should(BeNumerically("<=", 0), t.Text()) + for i := 0; i < 3; i++ { + t.Prev() + } + t.post() +} + +func (t *IteratorTesting) EOI() { + t.init() + t.setAct(IterEOI) + Expect(t.Pos).Should(BeNumerically(">=", t.Len()-1), t.Text()) + for i := 0; i < 3; i++ { + t.Next() + } + t.post() +} + +func (t *IteratorTesting) WalkPrev(fn func(t *IteratorTesting)) { + t.init() + for old := t.Pos; t.Pos > 0; old = t.Pos { + fn(t) + Expect(t.Pos).Should(BeNumerically("<", old), t.Text()) + } +} + +func (t *IteratorTesting) WalkNext(fn func(t *IteratorTesting)) { + t.init() + for old := t.Pos; t.Pos < t.Len()-1; old = t.Pos { + fn(t) + Expect(t.Pos).Should(BeNumerically(">", old), t.Text()) + } +} + +func (t *IteratorTesting) PrevAll() { + t.WalkPrev(func(t *IteratorTesting) { + t.Prev() + }) +} + +func (t *IteratorTesting) NextAll() { + t.WalkNext(func(t *IteratorTesting) { + t.Next() + }) +} + +func DoIteratorTesting(t *IteratorTesting) { + if t.Rand == nil { + t.Rand = NewRand() + } + t.SOI() + t.NextAll() + t.First() + t.SOI() + t.NextAll() + t.EOI() + t.PrevAll() + t.Last() + t.EOI() + t.PrevAll() + t.SOI() + + t.NextAll() + t.PrevAll() + t.NextAll() + t.Last() + t.PrevAll() + t.First() + t.NextAll() + t.EOI() + + ShuffledIndex(t.Rand, t.Len(), 1, func(i int) { + t.Seek(i) + }) + + ShuffledIndex(t.Rand, t.Len(), 1, func(i int) { + t.SeekInexact(i) + }) + + ShuffledIndex(t.Rand, t.Len(), 1, func(i int) { + t.Seek(i) + if i%2 != 0 { + t.PrevAll() + t.SOI() + } else { + t.NextAll() + t.EOI() + } + }) + + for _, key := range []string{"", "foo", "bar", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"} { + t.SeekKey([]byte(key)) + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kv.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kv.go new file mode 100644 index 00000000..3d596a79 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kv.go @@ -0,0 +1,352 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package testutil + +import ( + "fmt" + "math/rand" + "sort" + "strings" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type KeyValueEntry struct { + key, value []byte +} + +type KeyValue struct { + entries []KeyValueEntry + nbytes int +} + +func (kv *KeyValue) Put(key, value []byte) { + if n := len(kv.entries); n > 0 && cmp.Compare(kv.entries[n-1].key, key) >= 0 { + panic(fmt.Sprintf("Put: keys are not in increasing order: %q, %q", kv.entries[n-1].key, key)) + } + kv.entries = append(kv.entries, KeyValueEntry{key, value}) + kv.nbytes += len(key) + len(value) +} + +func (kv *KeyValue) PutString(key, value string) { + kv.Put([]byte(key), []byte(value)) +} + +func (kv *KeyValue) PutU(key, value []byte) bool { + if i, exist := kv.Get(key); !exist { + if i < kv.Len() { + kv.entries = append(kv.entries[:i+1], kv.entries[i:]...) + kv.entries[i] = KeyValueEntry{key, value} + } else { + kv.entries = append(kv.entries, KeyValueEntry{key, value}) + } + kv.nbytes += len(key) + len(value) + return true + } else { + kv.nbytes += len(value) - len(kv.ValueAt(i)) + kv.entries[i].value = value + } + return false +} + +func (kv *KeyValue) PutUString(key, value string) bool { + return kv.PutU([]byte(key), []byte(value)) +} + +func (kv *KeyValue) Delete(key []byte) (exist bool, value []byte) { + i, exist := kv.Get(key) + if exist { + value = kv.entries[i].value + kv.DeleteIndex(i) + } + return +} + +func (kv *KeyValue) DeleteIndex(i int) bool { + if i < kv.Len() { + kv.nbytes -= len(kv.KeyAt(i)) + len(kv.ValueAt(i)) + kv.entries = append(kv.entries[:i], kv.entries[i+1:]...) + return true + } + return false +} + +func (kv KeyValue) Len() int { + return len(kv.entries) +} + +func (kv *KeyValue) Size() int { + return kv.nbytes +} + +func (kv KeyValue) KeyAt(i int) []byte { + return kv.entries[i].key +} + +func (kv KeyValue) ValueAt(i int) []byte { + return kv.entries[i].value +} + +func (kv KeyValue) Index(i int) (key, value []byte) { + if i < 0 || i >= len(kv.entries) { + panic(fmt.Sprintf("Index #%d: out of range", i)) + } + return kv.entries[i].key, kv.entries[i].value +} + +func (kv KeyValue) IndexInexact(i int) (key_, key, value []byte) { + key, value = kv.Index(i) + var key0 []byte + var key1 = kv.KeyAt(i) + if i > 0 { + key0 = kv.KeyAt(i - 1) + } + key_ = BytesSeparator(key0, key1) + return +} + +func (kv KeyValue) IndexOrNil(i int) (key, value []byte) { + if i >= 0 && i < len(kv.entries) { + return kv.entries[i].key, kv.entries[i].value + } + return nil, nil +} + +func (kv KeyValue) IndexString(i int) (key, value string) { + key_, _value := kv.Index(i) + return string(key_), string(_value) +} + +func (kv KeyValue) Search(key []byte) int { + return sort.Search(kv.Len(), func(i int) bool { + return cmp.Compare(kv.KeyAt(i), key) >= 0 + }) +} + +func (kv KeyValue) SearchString(key string) int { + return kv.Search([]byte(key)) +} + +func (kv KeyValue) Get(key []byte) (i int, exist bool) { + i = kv.Search(key) + if i < kv.Len() && cmp.Compare(kv.KeyAt(i), key) == 0 { + exist = true + } + return +} + +func (kv KeyValue) GetString(key string) (i int, exist bool) { + return kv.Get([]byte(key)) +} + +func (kv KeyValue) Iterate(fn func(i int, key, value []byte)) { + for i, x := range kv.entries { + fn(i, x.key, x.value) + } +} + +func (kv KeyValue) IterateString(fn func(i int, key, value string)) { + kv.Iterate(func(i int, key, value []byte) { + fn(i, string(key), string(value)) + }) +} + +func (kv KeyValue) IterateShuffled(rnd *rand.Rand, fn func(i int, key, value []byte)) { + ShuffledIndex(rnd, kv.Len(), 1, func(i int) { + fn(i, kv.entries[i].key, kv.entries[i].value) + }) +} + +func (kv KeyValue) IterateShuffledString(rnd *rand.Rand, fn func(i int, key, value string)) { + kv.IterateShuffled(rnd, func(i int, key, value []byte) { + fn(i, string(key), string(value)) + }) +} + +func (kv KeyValue) IterateInexact(fn func(i int, key_, key, value []byte)) { + for i := range kv.entries { + key_, key, value := kv.IndexInexact(i) + fn(i, key_, key, value) + } +} + +func (kv KeyValue) IterateInexactString(fn func(i int, key_, key, value string)) { + kv.IterateInexact(func(i int, key_, key, value []byte) { + fn(i, string(key_), string(key), string(value)) + }) +} + +func (kv KeyValue) Clone() KeyValue { + return KeyValue{append([]KeyValueEntry{}, kv.entries...), kv.nbytes} +} + +func (kv KeyValue) Slice(start, limit int) KeyValue { + if start < 0 || limit > kv.Len() { + panic(fmt.Sprintf("Slice %d .. %d: out of range", start, limit)) + } else if limit < start { + panic(fmt.Sprintf("Slice %d .. %d: invalid range", start, limit)) + } + return KeyValue{append([]KeyValueEntry{}, kv.entries[start:limit]...), kv.nbytes} +} + +func (kv KeyValue) SliceKey(start, limit []byte) KeyValue { + start_ := 0 + limit_ := kv.Len() + if start != nil { + start_ = kv.Search(start) + } + if limit != nil { + limit_ = kv.Search(limit) + } + return kv.Slice(start_, limit_) +} + +func (kv KeyValue) SliceKeyString(start, limit string) KeyValue { + return kv.SliceKey([]byte(start), []byte(limit)) +} + +func (kv KeyValue) SliceRange(r *util.Range) KeyValue { + if r != nil { + return kv.SliceKey(r.Start, r.Limit) + } + return kv.Clone() +} + +func (kv KeyValue) Range(start, limit int) (r util.Range) { + if kv.Len() > 0 { + if start == kv.Len() { + r.Start = BytesAfter(kv.KeyAt(start - 1)) + } else { + r.Start = kv.KeyAt(start) + } + } + if limit < kv.Len() { + r.Limit = kv.KeyAt(limit) + } + return +} + +func KeyValue_EmptyKey() *KeyValue { + kv := &KeyValue{} + kv.PutString("", "v") + return kv +} + +func KeyValue_EmptyValue() *KeyValue { + kv := &KeyValue{} + kv.PutString("abc", "") + kv.PutString("abcd", "") + return kv +} + +func KeyValue_OneKeyValue() *KeyValue { + kv := &KeyValue{} + kv.PutString("abc", "v") + return kv +} + +func KeyValue_BigValue() *KeyValue { + kv := &KeyValue{} + kv.PutString("big1", strings.Repeat("1", 200000)) + return kv +} + +func KeyValue_SpecialKey() *KeyValue { + kv := &KeyValue{} + kv.PutString("\xff\xff", "v3") + return kv +} + +func KeyValue_MultipleKeyValue() *KeyValue { + kv := &KeyValue{} + kv.PutString("a", "v") + kv.PutString("aa", "v1") + kv.PutString("aaa", "v2") + kv.PutString("aaacccccccccc", "v2") + kv.PutString("aaaccccccccccd", "v3") + kv.PutString("aaaccccccccccf", "v4") + kv.PutString("aaaccccccccccfg", "v5") + kv.PutString("ab", "v6") + kv.PutString("abc", "v7") + kv.PutString("abcd", "v8") + kv.PutString("accccccccccccccc", "v9") + kv.PutString("b", "v10") + kv.PutString("bb", "v11") + kv.PutString("bc", "v12") + kv.PutString("c", "v13") + kv.PutString("c1", "v13") + kv.PutString("czzzzzzzzzzzzzz", "v14") + kv.PutString("fffffffffffffff", "v15") + kv.PutString("g11", "v15") + kv.PutString("g111", "v15") + kv.PutString("g111\xff", "v15") + kv.PutString("zz", "v16") + kv.PutString("zzzzzzz", "v16") + kv.PutString("zzzzzzzzzzzzzzzz", "v16") + return kv +} + +var keymap = []byte("012345678ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy") + +func KeyValue_Generate(rnd *rand.Rand, n, minlen, maxlen, vminlen, vmaxlen int) *KeyValue { + if rnd == nil { + rnd = NewRand() + } + if maxlen < minlen { + panic("max len should >= min len") + } + + rrand := func(min, max int) int { + if min == max { + return max + } + return rnd.Intn(max-min) + min + } + + kv := &KeyValue{} + endC := byte(len(keymap) - 1) + gen := make([]byte, 0, maxlen) + for i := 0; i < n; i++ { + m := rrand(minlen, maxlen) + last := gen + retry: + gen = last[:m] + if k := len(last); m > k { + for j := k; j < m; j++ { + gen[j] = 0 + } + } else { + for j := m - 1; j >= 0; j-- { + c := last[j] + if c == endC { + continue + } + gen[j] = c + 1 + for j += 1; j < m; j++ { + gen[j] = 0 + } + goto ok + } + if m < maxlen { + m++ + goto retry + } + panic(fmt.Sprintf("only able to generate %d keys out of %d keys, try increasing max len", kv.Len(), n)) + ok: + } + key := make([]byte, m) + for j := 0; j < m; j++ { + key[j] = keymap[gen[j]] + } + value := make([]byte, rrand(vminlen, vmaxlen)) + for n := copy(value, []byte(fmt.Sprintf("v%d", i))); n < len(value); n++ { + value[n] = 'x' + } + kv.Put(key, value) + } + return kv +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go new file mode 100644 index 00000000..0a298850 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go @@ -0,0 +1,187 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package testutil + +import ( + "fmt" + "math/rand" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB, teardown func(DB)) { + if rnd == nil { + rnd = NewRand() + } + + if p == nil { + BeforeEach(func() { + p = setup(kv) + }) + if teardown != nil { + AfterEach(func() { + teardown(p) + }) + } + } + + It("Should find all keys with Find", func() { + if db, ok := p.(Find); ok { + ShuffledIndex(nil, kv.Len(), 1, func(i int) { + key_, key, value := kv.IndexInexact(i) + + // Using exact key. + rkey, rvalue, err := db.TestFind(key) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key) + Expect(rkey).Should(Equal(key), "Key") + Expect(rvalue).Should(Equal(value), "Value for key %q", key) + + // Using inexact key. + rkey, rvalue, err = db.TestFind(key_) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q)", key_, key) + Expect(rkey).Should(Equal(key)) + Expect(rvalue).Should(Equal(value), "Value for key %q (%q)", key_, key) + }) + } + }) + + It("Should return error if the key is not present", func() { + if db, ok := p.(Find); ok { + var key []byte + if kv.Len() > 0 { + key_, _ := kv.Index(kv.Len() - 1) + key = BytesAfter(key_) + } + rkey, _, err := db.TestFind(key) + Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey) + Expect(err).Should(Equal(errors.ErrNotFound)) + } + }) + + It("Should only find exact key with Get", func() { + if db, ok := p.(Get); ok { + ShuffledIndex(nil, kv.Len(), 1, func(i int) { + key_, key, value := kv.IndexInexact(i) + + // Using exact key. + rvalue, err := db.TestGet(key) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key) + Expect(rvalue).Should(Equal(value), "Value for key %q", key) + + // Using inexact key. + if len(key_) > 0 { + _, err = db.TestGet(key_) + Expect(err).Should(HaveOccurred(), "Error for key %q", key_) + Expect(err).Should(Equal(errors.ErrNotFound)) + } + }) + } + }) + + It("Should only find present key with Has", func() { + if db, ok := p.(Has); ok { + ShuffledIndex(nil, kv.Len(), 1, func(i int) { + key_, key, _ := kv.IndexInexact(i) + + // Using exact key. + ret, err := db.TestHas(key) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key) + Expect(ret).Should(BeTrue(), "False for key %q", key) + + // Using inexact key. + if len(key_) > 0 { + ret, err = db.TestHas(key_) + Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_) + Expect(ret).ShouldNot(BeTrue(), "True for key %q", key) + } + }) + } + }) + + TestIter := func(r *util.Range, _kv KeyValue) { + if db, ok := p.(NewIterator); ok { + iter := db.TestNewIterator(r) + Expect(iter.Error()).ShouldNot(HaveOccurred()) + + t := IteratorTesting{ + KeyValue: _kv, + Iter: iter, + } + + DoIteratorTesting(&t) + iter.Release() + } + } + + It("Should iterates and seeks correctly", func(done Done) { + TestIter(nil, kv.Clone()) + done <- true + }, 3.0) + + RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) { + type slice struct { + r *util.Range + start, limit int + } + + key_, _, _ := kv.IndexInexact(i) + for _, x := range []slice{ + {&util.Range{Start: key_, Limit: nil}, i, kv.Len()}, + {&util.Range{Start: nil, Limit: key_}, 0, i}, + } { + It(fmt.Sprintf("Should iterates and seeks correctly of a slice %d .. %d", x.start, x.limit), func(done Done) { + TestIter(x.r, kv.Slice(x.start, x.limit)) + done <- true + }, 3.0) + } + }) + + RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) { + It(fmt.Sprintf("Should iterates and seeks correctly of a slice %d .. %d", start, limit), func(done Done) { + r := kv.Range(start, limit) + TestIter(&r, kv.Slice(start, limit)) + done <- true + }, 3.0) + }) +} + +func AllKeyValueTesting(rnd *rand.Rand, body, setup func(KeyValue) DB, teardown func(DB)) { + Test := func(kv *KeyValue) func() { + return func() { + var p DB + if setup != nil { + Defer("setup", func() { + p = setup(*kv) + }) + } + if teardown != nil { + Defer("teardown", func() { + teardown(p) + }) + } + if body != nil { + p = body(*kv) + } + KeyValueTesting(rnd, *kv, p, func(KeyValue) DB { + return p + }, nil) + } + } + + Describe("with no key/value (empty)", Test(&KeyValue{})) + Describe("with empty key", Test(KeyValue_EmptyKey())) + Describe("with empty value", Test(KeyValue_EmptyValue())) + Describe("with one key/value", Test(KeyValue_OneKeyValue())) + Describe("with big value", Test(KeyValue_BigValue())) + Describe("with special key", Test(KeyValue_SpecialKey())) + Describe("with multiple key/value", Test(KeyValue_MultipleKeyValue())) + Describe("with generated key/value", Test(KeyValue_Generate(nil, 120, 1, 50, 10, 120))) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go new file mode 100644 index 00000000..33662019 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go @@ -0,0 +1,586 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package testutil + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +var ( + storageMu sync.Mutex + storageUseFS bool = true + storageKeepFS bool = false + storageNum int +) + +type StorageMode int + +const ( + ModeOpen StorageMode = 1 << iota + ModeCreate + ModeRemove + ModeRead + ModeWrite + ModeSync + ModeClose +) + +const ( + modeOpen = iota + modeCreate + modeRemove + modeRead + modeWrite + modeSync + modeClose + + modeCount +) + +const ( + typeManifest = iota + typeJournal + typeTable + typeTemp + + typeCount +) + +const flattenCount = modeCount * typeCount + +func flattenType(m StorageMode, t storage.FileType) int { + var x int + switch m { + case ModeOpen: + x = modeOpen + case ModeCreate: + x = modeCreate + case ModeRemove: + x = modeRemove + case ModeRead: + x = modeRead + case ModeWrite: + x = modeWrite + case ModeSync: + x = modeSync + case ModeClose: + x = modeClose + default: + panic("invalid storage mode") + } + x *= typeCount + switch t { + case storage.TypeManifest: + return x + typeManifest + case storage.TypeJournal: + return x + typeJournal + case storage.TypeTable: + return x + typeTable + case storage.TypeTemp: + return x + typeTemp + default: + panic("invalid file type") + } +} + +func listFlattenType(m StorageMode, t storage.FileType) []int { + ret := make([]int, 0, flattenCount) + add := func(x int) { + x *= typeCount + switch { + case t&storage.TypeManifest != 0: + ret = append(ret, x+typeManifest) + case t&storage.TypeJournal != 0: + ret = append(ret, x+typeJournal) + case t&storage.TypeTable != 0: + ret = append(ret, x+typeTable) + case t&storage.TypeTemp != 0: + ret = append(ret, x+typeTemp) + } + } + switch { + case m&ModeOpen != 0: + add(modeOpen) + case m&ModeCreate != 0: + add(modeCreate) + case m&ModeRemove != 0: + add(modeRemove) + case m&ModeRead != 0: + add(modeRead) + case m&ModeWrite != 0: + add(modeWrite) + case m&ModeSync != 0: + add(modeSync) + case m&ModeClose != 0: + add(modeClose) + } + return ret +} + +func packFile(num uint64, t storage.FileType) uint64 { + if num>>(64-typeCount) != 0 { + panic("overflow") + } + return num<> typeCount, storage.FileType(x) & storage.TypeAll +} + +type emulatedError struct { + err error +} + +func (err emulatedError) Error() string { + return fmt.Sprintf("emulated storage error: %v", err.err) +} + +type storageLock struct { + s *Storage + r util.Releaser +} + +func (l storageLock) Release() { + l.r.Release() + l.s.logI("storage lock released") +} + +type reader struct { + f *file + storage.Reader +} + +func (r *reader) Read(p []byte) (n int, err error) { + err = r.f.s.emulateError(ModeRead, r.f.Type()) + if err == nil { + r.f.s.stall(ModeRead, r.f.Type()) + n, err = r.Reader.Read(p) + } + r.f.s.count(ModeRead, r.f.Type(), n) + if err != nil && err != io.EOF { + r.f.s.logI("read error, num=%d type=%v n=%d err=%v", r.f.Num(), r.f.Type(), n, err) + } + return +} + +func (r *reader) ReadAt(p []byte, off int64) (n int, err error) { + err = r.f.s.emulateError(ModeRead, r.f.Type()) + if err == nil { + r.f.s.stall(ModeRead, r.f.Type()) + n, err = r.Reader.ReadAt(p, off) + } + r.f.s.count(ModeRead, r.f.Type(), n) + if err != nil && err != io.EOF { + r.f.s.logI("readAt error, num=%d type=%v offset=%d n=%d err=%v", r.f.Num(), r.f.Type(), off, n, err) + } + return +} + +func (r *reader) Close() (err error) { + return r.f.doClose(r.Reader) +} + +type writer struct { + f *file + storage.Writer +} + +func (w *writer) Write(p []byte) (n int, err error) { + err = w.f.s.emulateError(ModeWrite, w.f.Type()) + if err == nil { + w.f.s.stall(ModeWrite, w.f.Type()) + n, err = w.Writer.Write(p) + } + w.f.s.count(ModeWrite, w.f.Type(), n) + if err != nil && err != io.EOF { + w.f.s.logI("write error, num=%d type=%v n=%d err=%v", w.f.Num(), w.f.Type(), n, err) + } + return +} + +func (w *writer) Sync() (err error) { + err = w.f.s.emulateError(ModeSync, w.f.Type()) + if err == nil { + w.f.s.stall(ModeSync, w.f.Type()) + err = w.Writer.Sync() + } + w.f.s.count(ModeSync, w.f.Type(), 0) + if err != nil { + w.f.s.logI("sync error, num=%d type=%v err=%v", w.f.Num(), w.f.Type(), err) + } + return +} + +func (w *writer) Close() (err error) { + return w.f.doClose(w.Writer) +} + +type file struct { + s *Storage + storage.File +} + +func (f *file) pack() uint64 { + return packFile(f.Num(), f.Type()) +} + +func (f *file) assertOpen() { + ExpectWithOffset(2, f.s.opens).NotTo(HaveKey(f.pack()), "File open, num=%d type=%v writer=%v", f.Num(), f.Type(), f.s.opens[f.pack()]) +} + +func (f *file) doClose(closer io.Closer) (err error) { + err = f.s.emulateError(ModeClose, f.Type()) + if err == nil { + f.s.stall(ModeClose, f.Type()) + } + f.s.mu.Lock() + defer f.s.mu.Unlock() + if err == nil { + ExpectWithOffset(2, f.s.opens).To(HaveKey(f.pack()), "File closed, num=%d type=%v", f.Num(), f.Type()) + err = closer.Close() + } + f.s.countNB(ModeClose, f.Type(), 0) + writer := f.s.opens[f.pack()] + if err != nil { + f.s.logISkip(1, "file close failed, num=%d type=%v writer=%v err=%v", f.Num(), f.Type(), writer, err) + } else { + f.s.logISkip(1, "file closed, num=%d type=%v writer=%v", f.Num(), f.Type(), writer) + delete(f.s.opens, f.pack()) + } + return +} + +func (f *file) Open() (r storage.Reader, err error) { + err = f.s.emulateError(ModeOpen, f.Type()) + if err == nil { + f.s.stall(ModeOpen, f.Type()) + } + f.s.mu.Lock() + defer f.s.mu.Unlock() + if err == nil { + f.assertOpen() + f.s.countNB(ModeOpen, f.Type(), 0) + r, err = f.File.Open() + } + if err != nil { + f.s.logI("file open failed, num=%d type=%v err=%v", f.Num(), f.Type(), err) + } else { + f.s.logI("file opened, num=%d type=%v", f.Num(), f.Type()) + f.s.opens[f.pack()] = false + r = &reader{f, r} + } + return +} + +func (f *file) Create() (w storage.Writer, err error) { + err = f.s.emulateError(ModeCreate, f.Type()) + if err == nil { + f.s.stall(ModeCreate, f.Type()) + } + f.s.mu.Lock() + defer f.s.mu.Unlock() + if err == nil { + f.assertOpen() + f.s.countNB(ModeCreate, f.Type(), 0) + w, err = f.File.Create() + } + if err != nil { + f.s.logI("file create failed, num=%d type=%v err=%v", f.Num(), f.Type(), err) + } else { + f.s.logI("file created, num=%d type=%v", f.Num(), f.Type()) + f.s.opens[f.pack()] = true + w = &writer{f, w} + } + return +} + +func (f *file) Remove() (err error) { + err = f.s.emulateError(ModeRemove, f.Type()) + if err == nil { + f.s.stall(ModeRemove, f.Type()) + } + f.s.mu.Lock() + defer f.s.mu.Unlock() + if err == nil { + f.assertOpen() + f.s.countNB(ModeRemove, f.Type(), 0) + err = f.File.Remove() + } + if err != nil { + f.s.logI("file remove failed, num=%d type=%v err=%v", f.Num(), f.Type(), err) + } else { + f.s.logI("file removed, num=%d type=%v", f.Num(), f.Type()) + } + return +} + +type Storage struct { + storage.Storage + closeFn func() error + + lmu sync.Mutex + lb bytes.Buffer + + mu sync.Mutex + // Open files, true=writer, false=reader + opens map[uint64]bool + counters [flattenCount]int + bytesCounter [flattenCount]int64 + emulatedError [flattenCount]error + stallCond sync.Cond + stalled [flattenCount]bool +} + +func (s *Storage) log(skip int, str string) { + s.lmu.Lock() + defer s.lmu.Unlock() + _, file, line, ok := runtime.Caller(skip + 2) + if ok { + // Truncate file name at last file name separator. + if index := strings.LastIndex(file, "/"); index >= 0 { + file = file[index+1:] + } else if index = strings.LastIndex(file, "\\"); index >= 0 { + file = file[index+1:] + } + } else { + file = "???" + line = 1 + } + fmt.Fprintf(&s.lb, "%s:%d: ", file, line) + lines := strings.Split(str, "\n") + if l := len(lines); l > 1 && lines[l-1] == "" { + lines = lines[:l-1] + } + for i, line := range lines { + if i > 0 { + s.lb.WriteString("\n\t") + } + s.lb.WriteString(line) + } + s.lb.WriteByte('\n') +} + +func (s *Storage) logISkip(skip int, format string, args ...interface{}) { + pc, _, _, ok := runtime.Caller(skip + 1) + if ok { + if f := runtime.FuncForPC(pc); f != nil { + fname := f.Name() + if index := strings.LastIndex(fname, "."); index >= 0 { + fname = fname[index+1:] + } + format = fname + ": " + format + } + } + s.log(skip+1, fmt.Sprintf(format, args...)) +} + +func (s *Storage) logI(format string, args ...interface{}) { + s.logISkip(1, format, args...) +} + +func (s *Storage) Log(str string) { + s.log(1, "Log: "+str) + s.Storage.Log(str) +} + +func (s *Storage) Lock() (r util.Releaser, err error) { + r, err = s.Storage.Lock() + if err != nil { + s.logI("storage locking failed, err=%v", err) + } else { + s.logI("storage locked") + r = storageLock{s, r} + } + return +} + +func (s *Storage) GetFile(num uint64, t storage.FileType) storage.File { + return &file{s, s.Storage.GetFile(num, t)} +} + +func (s *Storage) GetFiles(t storage.FileType) (files []storage.File, err error) { + rfiles, err := s.Storage.GetFiles(t) + if err != nil { + s.logI("get files failed, err=%v", err) + return + } + files = make([]storage.File, len(rfiles)) + for i, f := range rfiles { + files[i] = &file{s, f} + } + s.logI("get files, type=0x%x count=%d", int(t), len(files)) + return +} + +func (s *Storage) GetManifest() (f storage.File, err error) { + manifest, err := s.Storage.GetManifest() + if err != nil { + if !os.IsNotExist(err) { + s.logI("get manifest failed, err=%v", err) + } + return + } + s.logI("get manifest, num=%d", manifest.Num()) + return &file{s, manifest}, nil +} + +func (s *Storage) SetManifest(f storage.File) error { + f_, ok := f.(*file) + ExpectWithOffset(1, ok).To(BeTrue()) + ExpectWithOffset(1, f_.Type()).To(Equal(storage.TypeManifest)) + err := s.Storage.SetManifest(f_.File) + if err != nil { + s.logI("set manifest failed, err=%v", err) + } else { + s.logI("set manifest, num=%d", f_.Num()) + } + return err +} + +func (s *Storage) openFiles() string { + out := "Open files:" + for x, writer := range s.opens { + num, t := unpackFile(x) + out += fmt.Sprintf("\n · num=%d type=%v writer=%v", num, t, writer) + } + return out +} + +func (s *Storage) Close() error { + s.mu.Lock() + defer s.mu.Unlock() + ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles()) + err := s.Storage.Close() + if err != nil { + s.logI("storage closing failed, err=%v", err) + } else { + s.logI("storage closed") + } + if s.closeFn != nil { + if err1 := s.closeFn(); err1 != nil { + s.logI("close func error, err=%v", err1) + } + } + return err +} + +func (s *Storage) countNB(m StorageMode, t storage.FileType, n int) { + s.counters[flattenType(m, t)]++ + s.bytesCounter[flattenType(m, t)] += int64(n) +} + +func (s *Storage) count(m StorageMode, t storage.FileType, n int) { + s.mu.Lock() + defer s.mu.Unlock() + s.countNB(m, t, n) +} + +func (s *Storage) ResetCounter(m StorageMode, t storage.FileType) { + for _, x := range listFlattenType(m, t) { + s.counters[x] = 0 + s.bytesCounter[x] = 0 + } +} + +func (s *Storage) Counter(m StorageMode, t storage.FileType) (count int, bytes int64) { + for _, x := range listFlattenType(m, t) { + count += s.counters[x] + bytes += s.bytesCounter[x] + } + return +} + +func (s *Storage) emulateError(m StorageMode, t storage.FileType) error { + s.mu.Lock() + defer s.mu.Unlock() + err := s.emulatedError[flattenType(m, t)] + if err != nil { + return emulatedError{err} + } + return nil +} + +func (s *Storage) EmulateError(m StorageMode, t storage.FileType, err error) { + s.mu.Lock() + defer s.mu.Unlock() + for _, x := range listFlattenType(m, t) { + s.emulatedError[x] = err + } +} + +func (s *Storage) stall(m StorageMode, t storage.FileType) { + x := flattenType(m, t) + s.mu.Lock() + defer s.mu.Unlock() + for s.stalled[x] { + s.stallCond.Wait() + } +} + +func (s *Storage) Stall(m StorageMode, t storage.FileType) { + s.mu.Lock() + defer s.mu.Unlock() + for _, x := range listFlattenType(m, t) { + s.stalled[x] = true + } +} + +func (s *Storage) Release(m StorageMode, t storage.FileType) { + s.mu.Lock() + defer s.mu.Unlock() + for _, x := range listFlattenType(m, t) { + s.stalled[x] = false + } + s.stallCond.Broadcast() +} + +func NewStorage() *Storage { + var stor storage.Storage + var closeFn func() error + if storageUseFS { + for { + storageMu.Lock() + num := storageNum + storageNum++ + storageMu.Unlock() + path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num)) + if _, err := os.Stat(path); os.IsNotExist(err) { + stor, err = storage.OpenFile(path) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "creating storage at %s", path) + closeFn = func() error { + if storageKeepFS { + return nil + } + return os.RemoveAll(path) + } + break + } + } + } else { + stor = storage.NewMemStorage() + } + s := &Storage{ + Storage: stor, + closeFn: closeFn, + opens: make(map[uint64]bool), + } + s.stallCond.L = &s.mu + return s +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/util.go new file mode 100644 index 00000000..82816ac1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/util.go @@ -0,0 +1,171 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package testutil + +import ( + "bytes" + "flag" + "math/rand" + "reflect" + "sync" + + "github.com/onsi/ginkgo/config" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" +) + +var ( + runfn = make(map[string][]func()) + runmu sync.Mutex +) + +func Defer(args ...interface{}) bool { + var ( + group string + fn func() + ) + for _, arg := range args { + v := reflect.ValueOf(arg) + switch v.Kind() { + case reflect.String: + group = v.String() + case reflect.Func: + r := reflect.ValueOf(&fn).Elem() + r.Set(v) + } + } + if fn != nil { + runmu.Lock() + runfn[group] = append(runfn[group], fn) + runmu.Unlock() + } + return true +} + +func RunDefer(groups ...string) bool { + if len(groups) == 0 { + groups = append(groups, "") + } + runmu.Lock() + var runfn_ []func() + for _, group := range groups { + runfn_ = append(runfn_, runfn[group]...) + delete(runfn, group) + } + runmu.Unlock() + for _, fn := range runfn_ { + fn() + } + return runfn_ != nil +} + +func RandomSeed() int64 { + if !flag.Parsed() { + panic("random seed not initialized") + } + return config.GinkgoConfig.RandomSeed +} + +func NewRand() *rand.Rand { + return rand.New(rand.NewSource(RandomSeed())) +} + +var cmp = comparer.DefaultComparer + +func BytesSeparator(a, b []byte) []byte { + if bytes.Equal(a, b) { + return b + } + i, n := 0, len(a) + if n > len(b) { + n = len(b) + } + for ; i < n && (a[i] == b[i]); i++ { + } + x := append([]byte{}, a[:i]...) + if i < n { + if c := a[i] + 1; c < b[i] { + return append(x, c) + } + x = append(x, a[i]) + i++ + } + for ; i < len(a); i++ { + if c := a[i]; c < 0xff { + return append(x, c+1) + } else { + x = append(x, c) + } + } + if len(b) > i && b[i] > 0 { + return append(x, b[i]-1) + } + return append(x, 'x') +} + +func BytesAfter(b []byte) []byte { + var x []byte + for _, c := range b { + if c < 0xff { + return append(x, c+1) + } else { + x = append(x, c) + } + } + return append(x, 'x') +} + +func RandomIndex(rnd *rand.Rand, n, round int, fn func(i int)) { + if rnd == nil { + rnd = NewRand() + } + for x := 0; x < round; x++ { + fn(rnd.Intn(n)) + } + return +} + +func ShuffledIndex(rnd *rand.Rand, n, round int, fn func(i int)) { + if rnd == nil { + rnd = NewRand() + } + for x := 0; x < round; x++ { + for _, i := range rnd.Perm(n) { + fn(i) + } + } + return +} + +func RandomRange(rnd *rand.Rand, n, round int, fn func(start, limit int)) { + if rnd == nil { + rnd = NewRand() + } + for x := 0; x < round; x++ { + start := rnd.Intn(n) + length := 0 + if j := n - start; j > 0 { + length = rnd.Intn(j) + } + fn(start, start+length) + } + return +} + +func Max(x, y int) int { + if x > y { + return x + } + return y +} + +func Min(x, y int) int { + if x < y { + return x + } + return y +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go new file mode 100644 index 00000000..2ec08fdf --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go @@ -0,0 +1,63 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + . "github.com/onsi/gomega" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type testingDB struct { + *DB + ro *opt.ReadOptions + wo *opt.WriteOptions + stor *testutil.Storage +} + +func (t *testingDB) TestPut(key []byte, value []byte) error { + return t.Put(key, value, t.wo) +} + +func (t *testingDB) TestDelete(key []byte) error { + return t.Delete(key, t.wo) +} + +func (t *testingDB) TestGet(key []byte) (value []byte, err error) { + return t.Get(key, t.ro) +} + +func (t *testingDB) TestHas(key []byte) (ret bool, err error) { + return t.Has(key, t.ro) +} + +func (t *testingDB) TestNewIterator(slice *util.Range) iterator.Iterator { + return t.NewIterator(slice, t.ro) +} + +func (t *testingDB) TestClose() { + err := t.Close() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + err = t.stor.Close() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) +} + +func newTestingDB(o *opt.Options, ro *opt.ReadOptions, wo *opt.WriteOptions) *testingDB { + stor := testutil.NewStorage() + db, err := Open(stor, o) + // FIXME: This may be called from outside It, which may cause panic. + Expect(err).NotTo(HaveOccurred()) + return &testingDB{ + DB: db, + ro: ro, + wo: wo, + stor: stor, + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go new file mode 100644 index 00000000..edca5e36 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go @@ -0,0 +1,91 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "fmt" + "sort" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage" +) + +func shorten(str string) string { + if len(str) <= 8 { + return str + } + return str[:3] + ".." + str[len(str)-3:] +} + +var bunits = [...]string{"", "Ki", "Mi", "Gi"} + +func shortenb(bytes int) string { + i := 0 + for ; bytes > 1024 && i < 4; i++ { + bytes /= 1024 + } + return fmt.Sprintf("%d%sB", bytes, bunits[i]) +} + +func sshortenb(bytes int) string { + if bytes == 0 { + return "~" + } + sign := "+" + if bytes < 0 { + sign = "-" + bytes *= -1 + } + i := 0 + for ; bytes > 1024 && i < 4; i++ { + bytes /= 1024 + } + return fmt.Sprintf("%s%d%sB", sign, bytes, bunits[i]) +} + +func sint(x int) string { + if x == 0 { + return "~" + } + sign := "+" + if x < 0 { + sign = "-" + x *= -1 + } + return fmt.Sprintf("%s%d", sign, x) +} + +func minInt(a, b int) int { + if a < b { + return a + } + return b +} + +func maxInt(a, b int) int { + if a > b { + return a + } + return b +} + +type files []storage.File + +func (p files) Len() int { + return len(p) +} + +func (p files) Less(i, j int) bool { + return p[i].Num() < p[j].Num() +} + +func (p files) Swap(i, j int) { + p[i], p[j] = p[j], p[i] +} + +func (p files) sort() { + sort.Sort(p) +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer.go new file mode 100644 index 00000000..21de2425 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer.go @@ -0,0 +1,293 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package util + +// This a copy of Go std bytes.Buffer with some modification +// and some features stripped. + +import ( + "bytes" + "io" +) + +// A Buffer is a variable-sized buffer of bytes with Read and Write methods. +// The zero value for Buffer is an empty buffer ready to use. +type Buffer struct { + buf []byte // contents are the bytes buf[off : len(buf)] + off int // read at &buf[off], write at &buf[len(buf)] + bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation. +} + +// Bytes returns a slice of the contents of the unread portion of the buffer; +// len(b.Bytes()) == b.Len(). If the caller changes the contents of the +// returned slice, the contents of the buffer will change provided there +// are no intervening method calls on the Buffer. +func (b *Buffer) Bytes() []byte { return b.buf[b.off:] } + +// String returns the contents of the unread portion of the buffer +// as a string. If the Buffer is a nil pointer, it returns "". +func (b *Buffer) String() string { + if b == nil { + // Special case, useful in debugging. + return "" + } + return string(b.buf[b.off:]) +} + +// Len returns the number of bytes of the unread portion of the buffer; +// b.Len() == len(b.Bytes()). +func (b *Buffer) Len() int { return len(b.buf) - b.off } + +// Truncate discards all but the first n unread bytes from the buffer. +// It panics if n is negative or greater than the length of the buffer. +func (b *Buffer) Truncate(n int) { + switch { + case n < 0 || n > b.Len(): + panic("leveldb/util.Buffer: truncation out of range") + case n == 0: + // Reuse buffer space. + b.off = 0 + } + b.buf = b.buf[0 : b.off+n] +} + +// Reset resets the buffer so it has no content. +// b.Reset() is the same as b.Truncate(0). +func (b *Buffer) Reset() { b.Truncate(0) } + +// grow grows the buffer to guarantee space for n more bytes. +// It returns the index where bytes should be written. +// If the buffer can't grow it will panic with bytes.ErrTooLarge. +func (b *Buffer) grow(n int) int { + m := b.Len() + // If buffer is empty, reset to recover space. + if m == 0 && b.off != 0 { + b.Truncate(0) + } + if len(b.buf)+n > cap(b.buf) { + var buf []byte + if b.buf == nil && n <= len(b.bootstrap) { + buf = b.bootstrap[0:] + } else if m+n <= cap(b.buf)/2 { + // We can slide things down instead of allocating a new + // slice. We only need m+n <= cap(b.buf) to slide, but + // we instead let capacity get twice as large so we + // don't spend all our time copying. + copy(b.buf[:], b.buf[b.off:]) + buf = b.buf[:m] + } else { + // not enough space anywhere + buf = makeSlice(2*cap(b.buf) + n) + copy(buf, b.buf[b.off:]) + } + b.buf = buf + b.off = 0 + } + b.buf = b.buf[0 : b.off+m+n] + return b.off + m +} + +// Alloc allocs n bytes of slice from the buffer, growing the buffer as +// needed. If n is negative, Alloc will panic. +// If the buffer can't grow it will panic with bytes.ErrTooLarge. +func (b *Buffer) Alloc(n int) []byte { + if n < 0 { + panic("leveldb/util.Buffer.Alloc: negative count") + } + m := b.grow(n) + return b.buf[m:] +} + +// Grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After Grow(n), at least n bytes can be written to the +// buffer without another allocation. +// If n is negative, Grow will panic. +// If the buffer can't grow it will panic with bytes.ErrTooLarge. +func (b *Buffer) Grow(n int) { + if n < 0 { + panic("leveldb/util.Buffer.Grow: negative count") + } + m := b.grow(n) + b.buf = b.buf[0:m] +} + +// Write appends the contents of p to the buffer, growing the buffer as +// needed. The return value n is the length of p; err is always nil. If the +// buffer becomes too large, Write will panic with bytes.ErrTooLarge. +func (b *Buffer) Write(p []byte) (n int, err error) { + m := b.grow(len(p)) + return copy(b.buf[m:], p), nil +} + +// MinRead is the minimum slice size passed to a Read call by +// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond +// what is required to hold the contents of r, ReadFrom will not grow the +// underlying buffer. +const MinRead = 512 + +// ReadFrom reads data from r until EOF and appends it to the buffer, growing +// the buffer as needed. The return value n is the number of bytes read. Any +// error except io.EOF encountered during the read is also returned. If the +// buffer becomes too large, ReadFrom will panic with bytes.ErrTooLarge. +func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { + // If buffer is empty, reset to recover space. + if b.off >= len(b.buf) { + b.Truncate(0) + } + for { + if free := cap(b.buf) - len(b.buf); free < MinRead { + // not enough space at end + newBuf := b.buf + if b.off+free < MinRead { + // not enough space using beginning of buffer; + // double buffer capacity + newBuf = makeSlice(2*cap(b.buf) + MinRead) + } + copy(newBuf, b.buf[b.off:]) + b.buf = newBuf[:len(b.buf)-b.off] + b.off = 0 + } + m, e := r.Read(b.buf[len(b.buf):cap(b.buf)]) + b.buf = b.buf[0 : len(b.buf)+m] + n += int64(m) + if e == io.EOF { + break + } + if e != nil { + return n, e + } + } + return n, nil // err is EOF, so return nil explicitly +} + +// makeSlice allocates a slice of size n. If the allocation fails, it panics +// with bytes.ErrTooLarge. +func makeSlice(n int) []byte { + // If the make fails, give a known error. + defer func() { + if recover() != nil { + panic(bytes.ErrTooLarge) + } + }() + return make([]byte, n) +} + +// WriteTo writes data to w until the buffer is drained or an error occurs. +// The return value n is the number of bytes written; it always fits into an +// int, but it is int64 to match the io.WriterTo interface. Any error +// encountered during the write is also returned. +func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { + if b.off < len(b.buf) { + nBytes := b.Len() + m, e := w.Write(b.buf[b.off:]) + if m > nBytes { + panic("leveldb/util.Buffer.WriteTo: invalid Write count") + } + b.off += m + n = int64(m) + if e != nil { + return n, e + } + // all bytes should have been written, by definition of + // Write method in io.Writer + if m != nBytes { + return n, io.ErrShortWrite + } + } + // Buffer is now empty; reset. + b.Truncate(0) + return +} + +// WriteByte appends the byte c to the buffer, growing the buffer as needed. +// The returned error is always nil, but is included to match bufio.Writer's +// WriteByte. If the buffer becomes too large, WriteByte will panic with +// bytes.ErrTooLarge. +func (b *Buffer) WriteByte(c byte) error { + m := b.grow(1) + b.buf[m] = c + return nil +} + +// Read reads the next len(p) bytes from the buffer or until the buffer +// is drained. The return value n is the number of bytes read. If the +// buffer has no data to return, err is io.EOF (unless len(p) is zero); +// otherwise it is nil. +func (b *Buffer) Read(p []byte) (n int, err error) { + if b.off >= len(b.buf) { + // Buffer is empty, reset to recover space. + b.Truncate(0) + if len(p) == 0 { + return + } + return 0, io.EOF + } + n = copy(p, b.buf[b.off:]) + b.off += n + return +} + +// Next returns a slice containing the next n bytes from the buffer, +// advancing the buffer as if the bytes had been returned by Read. +// If there are fewer than n bytes in the buffer, Next returns the entire buffer. +// The slice is only valid until the next call to a read or write method. +func (b *Buffer) Next(n int) []byte { + m := b.Len() + if n > m { + n = m + } + data := b.buf[b.off : b.off+n] + b.off += n + return data +} + +// ReadByte reads and returns the next byte from the buffer. +// If no byte is available, it returns error io.EOF. +func (b *Buffer) ReadByte() (c byte, err error) { + if b.off >= len(b.buf) { + // Buffer is empty, reset to recover space. + b.Truncate(0) + return 0, io.EOF + } + c = b.buf[b.off] + b.off++ + return c, nil +} + +// ReadBytes reads until the first occurrence of delim in the input, +// returning a slice containing the data up to and including the delimiter. +// If ReadBytes encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often io.EOF). +// ReadBytes returns err != nil if and only if the returned data does not end in +// delim. +func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) { + slice, err := b.readSlice(delim) + // return a copy of slice. The buffer's backing array may + // be overwritten by later calls. + line = append(line, slice...) + return +} + +// readSlice is like ReadBytes but returns a reference to internal buffer data. +func (b *Buffer) readSlice(delim byte) (line []byte, err error) { + i := bytes.IndexByte(b.buf[b.off:], delim) + end := b.off + i + 1 + if i < 0 { + end = len(b.buf) + err = io.EOF + } + line = b.buf[b.off:end] + b.off = end + return line, err +} + +// NewBuffer creates and initializes a new Buffer using buf as its initial +// contents. It is intended to prepare a Buffer to read existing data. It +// can also be used to size the internal buffer for writing. To do that, +// buf should have the desired capacity but a length of zero. +// +// In most cases, new(Buffer) (or just declaring a Buffer variable) is +// sufficient to initialize a Buffer. +func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go new file mode 100644 index 00000000..2b8453d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go @@ -0,0 +1,238 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package util + +import ( + "fmt" + "sync" + "sync/atomic" + "time" +) + +type buffer struct { + b []byte + miss int +} + +// BufferPool is a 'buffer pool'. +type BufferPool struct { + pool [6]chan []byte + size [5]uint32 + sizeMiss [5]uint32 + sizeHalf [5]uint32 + baseline [4]int + baseline0 int + + mu sync.RWMutex + closed bool + closeC chan struct{} + + get uint32 + put uint32 + half uint32 + less uint32 + equal uint32 + greater uint32 + miss uint32 +} + +func (p *BufferPool) poolNum(n int) int { + if n <= p.baseline0 && n > p.baseline0/2 { + return 0 + } + for i, x := range p.baseline { + if n <= x { + return i + 1 + } + } + return len(p.baseline) + 1 +} + +// Get returns buffer with length of n. +func (p *BufferPool) Get(n int) []byte { + if p == nil { + return make([]byte, n) + } + + p.mu.RLock() + defer p.mu.RUnlock() + + if p.closed { + return make([]byte, n) + } + + atomic.AddUint32(&p.get, 1) + + poolNum := p.poolNum(n) + pool := p.pool[poolNum] + if poolNum == 0 { + // Fast path. + select { + case b := <-pool: + switch { + case cap(b) > n: + if cap(b)-n >= n { + atomic.AddUint32(&p.half, 1) + select { + case pool <- b: + default: + } + return make([]byte, n) + } else { + atomic.AddUint32(&p.less, 1) + return b[:n] + } + case cap(b) == n: + atomic.AddUint32(&p.equal, 1) + return b[:n] + default: + atomic.AddUint32(&p.greater, 1) + } + default: + atomic.AddUint32(&p.miss, 1) + } + + return make([]byte, n, p.baseline0) + } else { + sizePtr := &p.size[poolNum-1] + + select { + case b := <-pool: + switch { + case cap(b) > n: + if cap(b)-n >= n { + atomic.AddUint32(&p.half, 1) + sizeHalfPtr := &p.sizeHalf[poolNum-1] + if atomic.AddUint32(sizeHalfPtr, 1) == 20 { + atomic.StoreUint32(sizePtr, uint32(cap(b)/2)) + atomic.StoreUint32(sizeHalfPtr, 0) + } else { + select { + case pool <- b: + default: + } + } + return make([]byte, n) + } else { + atomic.AddUint32(&p.less, 1) + return b[:n] + } + case cap(b) == n: + atomic.AddUint32(&p.equal, 1) + return b[:n] + default: + atomic.AddUint32(&p.greater, 1) + if uint32(cap(b)) >= atomic.LoadUint32(sizePtr) { + select { + case pool <- b: + default: + } + } + } + default: + atomic.AddUint32(&p.miss, 1) + } + + if size := atomic.LoadUint32(sizePtr); uint32(n) > size { + if size == 0 { + atomic.CompareAndSwapUint32(sizePtr, 0, uint32(n)) + } else { + sizeMissPtr := &p.sizeMiss[poolNum-1] + if atomic.AddUint32(sizeMissPtr, 1) == 20 { + atomic.StoreUint32(sizePtr, uint32(n)) + atomic.StoreUint32(sizeMissPtr, 0) + } + } + return make([]byte, n) + } else { + return make([]byte, n, size) + } + } +} + +// Put adds given buffer to the pool. +func (p *BufferPool) Put(b []byte) { + if p == nil { + return + } + + p.mu.RLock() + defer p.mu.RUnlock() + + if p.closed { + return + } + + atomic.AddUint32(&p.put, 1) + + pool := p.pool[p.poolNum(cap(b))] + select { + case pool <- b: + default: + } + +} + +func (p *BufferPool) Close() { + if p == nil { + return + } + + p.mu.Lock() + if !p.closed { + p.closed = true + p.closeC <- struct{}{} + } + p.mu.Unlock() +} + +func (p *BufferPool) String() string { + if p == nil { + return "" + } + + return fmt.Sprintf("BufferPool{B·%d Z·%v Zm·%v Zh·%v G·%d P·%d H·%d <·%d =·%d >·%d M·%d}", + p.baseline0, p.size, p.sizeMiss, p.sizeHalf, p.get, p.put, p.half, p.less, p.equal, p.greater, p.miss) +} + +func (p *BufferPool) drain() { + ticker := time.NewTicker(2 * time.Second) + for { + select { + case <-ticker.C: + for _, ch := range p.pool { + select { + case <-ch: + default: + } + } + case <-p.closeC: + close(p.closeC) + for _, ch := range p.pool { + close(ch) + } + return + } + } +} + +// NewBufferPool creates a new initialized 'buffer pool'. +func NewBufferPool(baseline int) *BufferPool { + if baseline <= 0 { + panic("baseline can't be <= 0") + } + p := &BufferPool{ + baseline0: baseline, + baseline: [...]int{baseline / 4, baseline / 2, baseline * 2, baseline * 4}, + closeC: make(chan struct{}, 1), + } + for i, cap := range []int{2, 2, 4, 4, 2, 1} { + p.pool[i] = make(chan []byte, cap) + } + go p.drain() + return p +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go new file mode 100644 index 00000000..87d96739 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go @@ -0,0 +1,369 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package util + +import ( + "bytes" + "io" + "math/rand" + "runtime" + "testing" +) + +const N = 10000 // make this bigger for a larger (and slower) test +var data string // test data for write tests +var testBytes []byte // test data; same as data but as a slice. + +func init() { + testBytes = make([]byte, N) + for i := 0; i < N; i++ { + testBytes[i] = 'a' + byte(i%26) + } + data = string(testBytes) +} + +// Verify that contents of buf match the string s. +func check(t *testing.T, testname string, buf *Buffer, s string) { + bytes := buf.Bytes() + str := buf.String() + if buf.Len() != len(bytes) { + t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes)) + } + + if buf.Len() != len(str) { + t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str)) + } + + if buf.Len() != len(s) { + t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s)) + } + + if string(bytes) != s { + t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s) + } +} + +// Fill buf through n writes of byte slice fub. +// The initial contents of buf corresponds to the string s; +// the result is the final contents of buf returned as a string. +func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub []byte) string { + check(t, testname+" (fill 1)", buf, s) + for ; n > 0; n-- { + m, err := buf.Write(fub) + if m != len(fub) { + t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub)) + } + if err != nil { + t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err) + } + s += string(fub) + check(t, testname+" (fill 4)", buf, s) + } + return s +} + +func TestNewBuffer(t *testing.T) { + buf := NewBuffer(testBytes) + check(t, "NewBuffer", buf, data) +} + +// Empty buf through repeated reads into fub. +// The initial contents of buf corresponds to the string s. +func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) { + check(t, testname+" (empty 1)", buf, s) + + for { + n, err := buf.Read(fub) + if n == 0 { + break + } + if err != nil { + t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err) + } + s = s[n:] + check(t, testname+" (empty 3)", buf, s) + } + + check(t, testname+" (empty 4)", buf, "") +} + +func TestBasicOperations(t *testing.T) { + var buf Buffer + + for i := 0; i < 5; i++ { + check(t, "TestBasicOperations (1)", &buf, "") + + buf.Reset() + check(t, "TestBasicOperations (2)", &buf, "") + + buf.Truncate(0) + check(t, "TestBasicOperations (3)", &buf, "") + + n, err := buf.Write([]byte(data[0:1])) + if n != 1 { + t.Errorf("wrote 1 byte, but n == %d", n) + } + if err != nil { + t.Errorf("err should always be nil, but err == %s", err) + } + check(t, "TestBasicOperations (4)", &buf, "a") + + buf.WriteByte(data[1]) + check(t, "TestBasicOperations (5)", &buf, "ab") + + n, err = buf.Write([]byte(data[2:26])) + if n != 24 { + t.Errorf("wrote 25 bytes, but n == %d", n) + } + check(t, "TestBasicOperations (6)", &buf, string(data[0:26])) + + buf.Truncate(26) + check(t, "TestBasicOperations (7)", &buf, string(data[0:26])) + + buf.Truncate(20) + check(t, "TestBasicOperations (8)", &buf, string(data[0:20])) + + empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5)) + empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100)) + + buf.WriteByte(data[1]) + c, err := buf.ReadByte() + if err != nil { + t.Error("ReadByte unexpected eof") + } + if c != data[1] { + t.Errorf("ReadByte wrong value c=%v", c) + } + c, err = buf.ReadByte() + if err == nil { + t.Error("ReadByte unexpected not eof") + } + } +} + +func TestLargeByteWrites(t *testing.T) { + var buf Buffer + limit := 30 + if testing.Short() { + limit = 9 + } + for i := 3; i < limit; i += 3 { + s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, testBytes) + empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i)) + } + check(t, "TestLargeByteWrites (3)", &buf, "") +} + +func TestLargeByteReads(t *testing.T) { + var buf Buffer + for i := 3; i < 30; i += 3 { + s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) + empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))) + } + check(t, "TestLargeByteReads (3)", &buf, "") +} + +func TestMixedReadsAndWrites(t *testing.T) { + var buf Buffer + s := "" + for i := 0; i < 50; i++ { + wlen := rand.Intn(len(data)) + s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testBytes[0:wlen]) + rlen := rand.Intn(len(data)) + fub := make([]byte, rlen) + n, _ := buf.Read(fub) + s = s[n:] + } + empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len())) +} + +func TestNil(t *testing.T) { + var b *Buffer + if b.String() != "" { + t.Errorf("expected ; got %q", b.String()) + } +} + +func TestReadFrom(t *testing.T) { + var buf Buffer + for i := 3; i < 30; i += 3 { + s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) + var b Buffer + b.ReadFrom(&buf) + empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data))) + } +} + +func TestWriteTo(t *testing.T) { + var buf Buffer + for i := 3; i < 30; i += 3 { + s := fillBytes(t, "TestWriteTo (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) + var b Buffer + buf.WriteTo(&b) + empty(t, "TestWriteTo (2)", &b, s, make([]byte, len(data))) + } +} + +func TestNext(t *testing.T) { + b := []byte{0, 1, 2, 3, 4} + tmp := make([]byte, 5) + for i := 0; i <= 5; i++ { + for j := i; j <= 5; j++ { + for k := 0; k <= 6; k++ { + // 0 <= i <= j <= 5; 0 <= k <= 6 + // Check that if we start with a buffer + // of length j at offset i and ask for + // Next(k), we get the right bytes. + buf := NewBuffer(b[0:j]) + n, _ := buf.Read(tmp[0:i]) + if n != i { + t.Fatalf("Read %d returned %d", i, n) + } + bb := buf.Next(k) + want := k + if want > j-i { + want = j - i + } + if len(bb) != want { + t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb)) + } + for l, v := range bb { + if v != byte(l+i) { + t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i) + } + } + } + } + } +} + +var readBytesTests = []struct { + buffer string + delim byte + expected []string + err error +}{ + {"", 0, []string{""}, io.EOF}, + {"a\x00", 0, []string{"a\x00"}, nil}, + {"abbbaaaba", 'b', []string{"ab", "b", "b", "aaab"}, nil}, + {"hello\x01world", 1, []string{"hello\x01"}, nil}, + {"foo\nbar", 0, []string{"foo\nbar"}, io.EOF}, + {"alpha\nbeta\ngamma\n", '\n', []string{"alpha\n", "beta\n", "gamma\n"}, nil}, + {"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, io.EOF}, +} + +func TestReadBytes(t *testing.T) { + for _, test := range readBytesTests { + buf := NewBuffer([]byte(test.buffer)) + var err error + for _, expected := range test.expected { + var bytes []byte + bytes, err = buf.ReadBytes(test.delim) + if string(bytes) != expected { + t.Errorf("expected %q, got %q", expected, bytes) + } + if err != nil { + break + } + } + if err != test.err { + t.Errorf("expected error %v, got %v", test.err, err) + } + } +} + +func TestGrow(t *testing.T) { + x := []byte{'x'} + y := []byte{'y'} + tmp := make([]byte, 72) + for _, startLen := range []int{0, 100, 1000, 10000, 100000} { + xBytes := bytes.Repeat(x, startLen) + for _, growLen := range []int{0, 100, 1000, 10000, 100000} { + buf := NewBuffer(xBytes) + // If we read, this affects buf.off, which is good to test. + readBytes, _ := buf.Read(tmp) + buf.Grow(growLen) + yBytes := bytes.Repeat(y, growLen) + // Check no allocation occurs in write, as long as we're single-threaded. + var m1, m2 runtime.MemStats + runtime.ReadMemStats(&m1) + buf.Write(yBytes) + runtime.ReadMemStats(&m2) + if runtime.GOMAXPROCS(-1) == 1 && m1.Mallocs != m2.Mallocs { + t.Errorf("allocation occurred during write") + } + // Check that buffer has correct data. + if !bytes.Equal(buf.Bytes()[0:startLen-readBytes], xBytes[readBytes:]) { + t.Errorf("bad initial data at %d %d", startLen, growLen) + } + if !bytes.Equal(buf.Bytes()[startLen-readBytes:startLen-readBytes+growLen], yBytes) { + t.Errorf("bad written data at %d %d", startLen, growLen) + } + } + } +} + +// Was a bug: used to give EOF reading empty slice at EOF. +func TestReadEmptyAtEOF(t *testing.T) { + b := new(Buffer) + slice := make([]byte, 0) + n, err := b.Read(slice) + if err != nil { + t.Errorf("read error: %v", err) + } + if n != 0 { + t.Errorf("wrong count; got %d want 0", n) + } +} + +// Tests that we occasionally compact. Issue 5154. +func TestBufferGrowth(t *testing.T) { + var b Buffer + buf := make([]byte, 1024) + b.Write(buf[0:1]) + var cap0 int + for i := 0; i < 5<<10; i++ { + b.Write(buf) + b.Read(buf) + if i == 0 { + cap0 = cap(b.buf) + } + } + cap1 := cap(b.buf) + // (*Buffer).grow allows for 2x capacity slop before sliding, + // so set our error threshold at 3x. + if cap1 > cap0*3 { + t.Errorf("buffer cap = %d; too big (grew from %d)", cap1, cap0) + } +} + +// From Issue 5154. +func BenchmarkBufferNotEmptyWriteRead(b *testing.B) { + buf := make([]byte, 1024) + for i := 0; i < b.N; i++ { + var b Buffer + b.Write(buf[0:1]) + for i := 0; i < 5<<10; i++ { + b.Write(buf) + b.Read(buf) + } + } +} + +// Check that we don't compact too often. From Issue 5154. +func BenchmarkBufferFullSmallReads(b *testing.B) { + buf := make([]byte, 1024) + for i := 0; i < b.N; i++ { + var b Buffer + b.Write(buf) + for b.Len()+20 < cap(b.buf) { + b.Write(buf[:10]) + } + for i := 0; i < 5<<10; i++ { + b.Read(buf[:1]) + b.Write(buf[:1]) + } + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/crc32.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/crc32.go new file mode 100644 index 00000000..631c9d61 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/crc32.go @@ -0,0 +1,30 @@ +// Copyright 2011 The LevelDB-Go Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package util + +import ( + "hash/crc32" +) + +var table = crc32.MakeTable(crc32.Castagnoli) + +// CRC is a CRC-32 checksum computed using Castagnoli's polynomial. +type CRC uint32 + +// NewCRC creates a new crc based on the given bytes. +func NewCRC(b []byte) CRC { + return CRC(0).Update(b) +} + +// Update updates the crc with the given bytes. +func (c CRC) Update(b []byte) CRC { + return CRC(crc32.Update(uint32(c), table, b)) +} + +// Value returns a masked crc. +func (c CRC) Value() uint32 { + return uint32(c>>15|c<<17) + 0xa282ead8 +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/hash.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/hash.go new file mode 100644 index 00000000..54903660 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/hash.go @@ -0,0 +1,48 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package util + +import ( + "bytes" + "encoding/binary" +) + +// Hash return hash of the given data. +func Hash(data []byte, seed uint32) uint32 { + // Similar to murmur hash + var m uint32 = 0xc6a4a793 + var r uint32 = 24 + h := seed ^ (uint32(len(data)) * m) + + buf := bytes.NewBuffer(data) + for buf.Len() >= 4 { + var w uint32 + binary.Read(buf, binary.LittleEndian, &w) + h += w + h *= m + h ^= (h >> 16) + } + + rest := buf.Bytes() + switch len(rest) { + default: + panic("not reached") + case 3: + h += uint32(rest[2]) << 16 + fallthrough + case 2: + h += uint32(rest[1]) << 8 + fallthrough + case 1: + h += uint32(rest[0]) + h *= m + h ^= (h >> r) + case 0: + } + + return h +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool.go new file mode 100644 index 00000000..1f7fdd41 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool.go @@ -0,0 +1,21 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build go1.3 + +package util + +import ( + "sync" +) + +type Pool struct { + sync.Pool +} + +func NewPool(cap int) *Pool { + return &Pool{} +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool_legacy.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool_legacy.go new file mode 100644 index 00000000..27b8d03b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/pool_legacy.go @@ -0,0 +1,33 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build !go1.3 + +package util + +type Pool struct { + pool chan interface{} +} + +func (p *Pool) Get() interface{} { + select { + case x := <-p.pool: + return x + default: + return nil + } +} + +func (p *Pool) Put(x interface{}) { + select { + case p.pool <- x: + default: + } +} + +func NewPool(cap int) *Pool { + return &Pool{pool: make(chan interface{}, cap)} +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go new file mode 100644 index 00000000..85159583 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/range.go @@ -0,0 +1,32 @@ +// Copyright (c) 2014, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package util + +// Range is a key range. +type Range struct { + // Start of the key range, include in the range. + Start []byte + + // Limit of the key range, not include in the range. + Limit []byte +} + +// BytesPrefix returns key range that satisfy the given prefix. +// This only applicable for the standard 'bytes comparer'. +func BytesPrefix(prefix []byte) *Range { + var limit []byte + for i := len(prefix) - 1; i >= 0; i-- { + c := prefix[i] + if c < 0xff { + limit = make([]byte, i+1) + copy(limit, prefix) + limit[i] = c + 1 + break + } + } + return &Range{prefix, limit} +} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/util.go new file mode 100644 index 00000000..f3597686 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/util.go @@ -0,0 +1,73 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package util provides utilities used throughout leveldb. +package util + +import ( + "errors" +) + +var ( + ErrReleased = errors.New("leveldb: resource already relesed") + ErrHasReleaser = errors.New("leveldb: releaser already defined") +) + +// Releaser is the interface that wraps the basic Release method. +type Releaser interface { + // Release releases associated resources. Release should always success + // and can be called multipe times without causing error. + Release() +} + +// ReleaseSetter is the interface that wraps the basic SetReleaser method. +type ReleaseSetter interface { + // SetReleaser associates the given releaser to the resources. The + // releaser will be called once coresponding resources released. + // Calling SetReleaser with nil will clear the releaser. + // + // This will panic if a releaser already present or coresponding + // resource is already released. Releaser should be cleared first + // before assigned a new one. + SetReleaser(releaser Releaser) +} + +// BasicReleaser provides basic implementation of Releaser and ReleaseSetter. +type BasicReleaser struct { + releaser Releaser + released bool +} + +// Released returns whether Release method already called. +func (r *BasicReleaser) Released() bool { + return r.released +} + +// Release implements Releaser.Release. +func (r *BasicReleaser) Release() { + if !r.released { + if r.releaser != nil { + r.releaser.Release() + r.releaser = nil + } + r.released = true + } +} + +// SetReleaser implements ReleaseSetter.SetReleaser. +func (r *BasicReleaser) SetReleaser(releaser Releaser) { + if r.released { + panic(ErrReleased) + } + if r.releaser != nil && releaser != nil { + panic(ErrHasReleaser) + } + r.releaser = releaser +} + +type NoopReleaser struct{} + +func (NoopReleaser) Release() {} diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go new file mode 100644 index 00000000..f0eb8c6b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go @@ -0,0 +1,457 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package leveldb + +import ( + "sync/atomic" + "unsafe" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util" +) + +type tSet struct { + level int + table *tFile +} + +type version struct { + s *session + + tables []tFiles + + // Level that should be compacted next and its compaction score. + // Score < 1 means compaction is not strictly needed. These fields + // are initialized by computeCompaction() + cLevel int + cScore float64 + + cSeek unsafe.Pointer + + ref int + // Succeeding version. + next *version +} + +func newVersion(s *session) *version { + return &version{s: s, tables: make([]tFiles, s.o.GetNumLevel())} +} + +func (v *version) releaseNB() { + v.ref-- + if v.ref > 0 { + return + } + if v.ref < 0 { + panic("negative version ref") + } + + tables := make(map[uint64]bool) + for _, tt := range v.next.tables { + for _, t := range tt { + num := t.file.Num() + tables[num] = true + } + } + + for _, tt := range v.tables { + for _, t := range tt { + num := t.file.Num() + if _, ok := tables[num]; !ok { + v.s.tops.remove(t) + } + } + } + + v.next.releaseNB() + v.next = nil +} + +func (v *version) release() { + v.s.vmu.Lock() + v.releaseNB() + v.s.vmu.Unlock() +} + +func (v *version) walkOverlapping(ikey iKey, f func(level int, t *tFile) bool, lf func(level int) bool) { + ukey := ikey.ukey() + + // Walk tables level-by-level. + for level, tables := range v.tables { + if len(tables) == 0 { + continue + } + + if level == 0 { + // Level-0 files may overlap each other. Find all files that + // overlap ukey. + for _, t := range tables { + if t.overlaps(v.s.icmp, ukey, ukey) { + if !f(level, t) { + return + } + } + } + } else { + if i := tables.searchMax(v.s.icmp, ikey); i < len(tables) { + t := tables[i] + if v.s.icmp.uCompare(ukey, t.imin.ukey()) >= 0 { + if !f(level, t) { + return + } + } + } + } + + if lf != nil && !lf(level) { + return + } + } +} + +func (v *version) get(ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byte, tcomp bool, err error) { + ukey := ikey.ukey() + + var ( + tset *tSet + tseek bool + + // Level-0. + zfound bool + zseq uint64 + zkt kType + zval []byte + ) + + err = ErrNotFound + + // Since entries never hope across level, finding key/value + // in smaller level make later levels irrelevant. + v.walkOverlapping(ikey, func(level int, t *tFile) bool { + if !tseek { + if tset == nil { + tset = &tSet{level, t} + } else { + tseek = true + } + } + + var ( + fikey, fval []byte + ferr error + ) + if noValue { + fikey, ferr = v.s.tops.findKey(t, ikey, ro) + } else { + fikey, fval, ferr = v.s.tops.find(t, ikey, ro) + } + switch ferr { + case nil: + case ErrNotFound: + return true + default: + err = ferr + return false + } + + if fukey, fseq, fkt, fkerr := parseIkey(fikey); fkerr == nil { + if v.s.icmp.uCompare(ukey, fukey) == 0 { + if level == 0 { + if fseq >= zseq { + zfound = true + zseq = fseq + zkt = fkt + zval = fval + } + } else { + switch fkt { + case ktVal: + value = fval + err = nil + case ktDel: + default: + panic("leveldb: invalid iKey type") + } + return false + } + } + } else { + err = fkerr + return false + } + + return true + }, func(level int) bool { + if zfound { + switch zkt { + case ktVal: + value = zval + err = nil + case ktDel: + default: + panic("leveldb: invalid iKey type") + } + return false + } + + return true + }) + + if tseek && tset.table.consumeSeek() <= 0 { + tcomp = atomic.CompareAndSwapPointer(&v.cSeek, nil, unsafe.Pointer(tset)) + } + + return +} + +func (v *version) sampleSeek(ikey iKey) (tcomp bool) { + var tset *tSet + + v.walkOverlapping(ikey, func(level int, t *tFile) bool { + if tset == nil { + tset = &tSet{level, t} + return true + } else { + if tset.table.consumeSeek() <= 0 { + tcomp = atomic.CompareAndSwapPointer(&v.cSeek, nil, unsafe.Pointer(tset)) + } + return false + } + }, nil) + + return +} + +func (v *version) getIterators(slice *util.Range, ro *opt.ReadOptions) (its []iterator.Iterator) { + // Merge all level zero files together since they may overlap + for _, t := range v.tables[0] { + it := v.s.tops.newIterator(t, slice, ro) + its = append(its, it) + } + + strict := opt.GetStrict(v.s.o.Options, ro, opt.StrictReader) + for _, tables := range v.tables[1:] { + if len(tables) == 0 { + continue + } + + it := iterator.NewIndexedIterator(tables.newIndexIterator(v.s.tops, v.s.icmp, slice, ro), strict) + its = append(its, it) + } + + return +} + +func (v *version) newStaging() *versionStaging { + return &versionStaging{base: v, tables: make([]tablesScratch, v.s.o.GetNumLevel())} +} + +// Spawn a new version based on this version. +func (v *version) spawn(r *sessionRecord) *version { + staging := v.newStaging() + staging.commit(r) + return staging.finish() +} + +func (v *version) fillRecord(r *sessionRecord) { + for level, ts := range v.tables { + for _, t := range ts { + r.addTableFile(level, t) + } + } +} + +func (v *version) tLen(level int) int { + return len(v.tables[level]) +} + +func (v *version) offsetOf(ikey iKey) (n uint64, err error) { + for level, tables := range v.tables { + for _, t := range tables { + if v.s.icmp.Compare(t.imax, ikey) <= 0 { + // Entire file is before "ikey", so just add the file size + n += t.size + } else if v.s.icmp.Compare(t.imin, ikey) > 0 { + // Entire file is after "ikey", so ignore + if level > 0 { + // Files other than level 0 are sorted by meta->min, so + // no further files in this level will contain data for + // "ikey". + break + } + } else { + // "ikey" falls in the range for this table. Add the + // approximate offset of "ikey" within the table. + var nn uint64 + nn, err = v.s.tops.offsetOf(t, ikey) + if err != nil { + return 0, err + } + n += nn + } + } + } + + return +} + +func (v *version) pickLevel(umin, umax []byte) (level int) { + if !v.tables[0].overlaps(v.s.icmp, umin, umax, true) { + var overlaps tFiles + maxLevel := v.s.o.GetMaxMemCompationLevel() + for ; level < maxLevel; level++ { + if v.tables[level+1].overlaps(v.s.icmp, umin, umax, false) { + break + } + overlaps = v.tables[level+2].getOverlaps(overlaps, v.s.icmp, umin, umax, false) + if overlaps.size() > uint64(v.s.o.GetCompactionGPOverlaps(level)) { + break + } + } + } + + return +} + +func (v *version) computeCompaction() { + // Precomputed best level for next compaction + var bestLevel int = -1 + var bestScore float64 = -1 + + for level, tables := range v.tables { + var score float64 + if level == 0 { + // We treat level-0 specially by bounding the number of files + // instead of number of bytes for two reasons: + // + // (1) With larger write-buffer sizes, it is nice not to do too + // many level-0 compactions. + // + // (2) The files in level-0 are merged on every read and + // therefore we wish to avoid too many files when the individual + // file size is small (perhaps because of a small write-buffer + // setting, or very high compression ratios, or lots of + // overwrites/deletions). + score = float64(len(tables)) / float64(v.s.o.GetCompactionL0Trigger()) + } else { + score = float64(tables.size()) / float64(v.s.o.GetCompactionTotalSize(level)) + } + + if score > bestScore { + bestLevel = level + bestScore = score + } + } + + v.cLevel = bestLevel + v.cScore = bestScore +} + +func (v *version) needCompaction() bool { + return v.cScore >= 1 || atomic.LoadPointer(&v.cSeek) != nil +} + +type tablesScratch struct { + added map[uint64]atRecord + deleted map[uint64]struct{} +} + +type versionStaging struct { + base *version + tables []tablesScratch +} + +func (p *versionStaging) commit(r *sessionRecord) { + // Deleted tables. + for _, r := range r.deletedTables { + tm := &(p.tables[r.level]) + + if len(p.base.tables[r.level]) > 0 { + if tm.deleted == nil { + tm.deleted = make(map[uint64]struct{}) + } + tm.deleted[r.num] = struct{}{} + } + + if tm.added != nil { + delete(tm.added, r.num) + } + } + + // New tables. + for _, r := range r.addedTables { + tm := &(p.tables[r.level]) + + if tm.added == nil { + tm.added = make(map[uint64]atRecord) + } + tm.added[r.num] = r + + if tm.deleted != nil { + delete(tm.deleted, r.num) + } + } +} + +func (p *versionStaging) finish() *version { + // Build new version. + nv := newVersion(p.base.s) + for level, tm := range p.tables { + btables := p.base.tables[level] + + n := len(btables) + len(tm.added) - len(tm.deleted) + if n < 0 { + n = 0 + } + nt := make(tFiles, 0, n) + + // Base tables. + for _, t := range btables { + if _, ok := tm.deleted[t.file.Num()]; ok { + continue + } + if _, ok := tm.added[t.file.Num()]; ok { + continue + } + nt = append(nt, t) + } + + // New tables. + for _, r := range tm.added { + nt = append(nt, p.base.s.tableFileFromRecord(r)) + } + + // Sort tables. + if level == 0 { + nt.sortByNum() + } else { + nt.sortByKey(p.base.s.icmp) + } + nv.tables[level] = nt + } + + // Compute compaction score for new version. + nv.computeCompaction() + + return nv +} + +type versionReleaser struct { + v *version + once bool +} + +func (vr *versionReleaser) Release() { + v := vr.v + v.s.vmu.Lock() + if !vr.once { + v.releaseNB() + vr.once = true + } + v.s.vmu.Unlock() +} diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go new file mode 100644 index 00000000..552a17bf --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go @@ -0,0 +1,292 @@ +// Copyright 2011 The Snappy-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package snappy + +import ( + "encoding/binary" + "errors" + "io" +) + +var ( + // ErrCorrupt reports that the input is invalid. + ErrCorrupt = errors.New("snappy: corrupt input") + // ErrUnsupported reports that the input isn't supported. + ErrUnsupported = errors.New("snappy: unsupported input") +) + +// DecodedLen returns the length of the decoded block. +func DecodedLen(src []byte) (int, error) { + v, _, err := decodedLen(src) + return v, err +} + +// decodedLen returns the length of the decoded block and the number of bytes +// that the length header occupied. +func decodedLen(src []byte) (blockLen, headerLen int, err error) { + v, n := binary.Uvarint(src) + if n == 0 { + return 0, 0, ErrCorrupt + } + if uint64(int(v)) != v { + return 0, 0, errors.New("snappy: decoded block is too large") + } + return int(v), n, nil +} + +// Decode returns the decoded form of src. The returned slice may be a sub- +// slice of dst if dst was large enough to hold the entire decoded block. +// Otherwise, a newly allocated slice will be returned. +// It is valid to pass a nil dst. +func Decode(dst, src []byte) ([]byte, error) { + dLen, s, err := decodedLen(src) + if err != nil { + return nil, err + } + if len(dst) < dLen { + dst = make([]byte, dLen) + } + + var d, offset, length int + for s < len(src) { + switch src[s] & 0x03 { + case tagLiteral: + x := uint(src[s] >> 2) + switch { + case x < 60: + s += 1 + case x == 60: + s += 2 + if s > len(src) { + return nil, ErrCorrupt + } + x = uint(src[s-1]) + case x == 61: + s += 3 + if s > len(src) { + return nil, ErrCorrupt + } + x = uint(src[s-2]) | uint(src[s-1])<<8 + case x == 62: + s += 4 + if s > len(src) { + return nil, ErrCorrupt + } + x = uint(src[s-3]) | uint(src[s-2])<<8 | uint(src[s-1])<<16 + case x == 63: + s += 5 + if s > len(src) { + return nil, ErrCorrupt + } + x = uint(src[s-4]) | uint(src[s-3])<<8 | uint(src[s-2])<<16 | uint(src[s-1])<<24 + } + length = int(x + 1) + if length <= 0 { + return nil, errors.New("snappy: unsupported literal length") + } + if length > len(dst)-d || length > len(src)-s { + return nil, ErrCorrupt + } + copy(dst[d:], src[s:s+length]) + d += length + s += length + continue + + case tagCopy1: + s += 2 + if s > len(src) { + return nil, ErrCorrupt + } + length = 4 + int(src[s-2])>>2&0x7 + offset = int(src[s-2])&0xe0<<3 | int(src[s-1]) + + case tagCopy2: + s += 3 + if s > len(src) { + return nil, ErrCorrupt + } + length = 1 + int(src[s-3])>>2 + offset = int(src[s-2]) | int(src[s-1])<<8 + + case tagCopy4: + return nil, errors.New("snappy: unsupported COPY_4 tag") + } + + end := d + length + if offset > d || end > len(dst) { + return nil, ErrCorrupt + } + for ; d < end; d++ { + dst[d] = dst[d-offset] + } + } + if d != dLen { + return nil, ErrCorrupt + } + return dst[:d], nil +} + +// NewReader returns a new Reader that decompresses from r, using the framing +// format described at +// https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt +func NewReader(r io.Reader) *Reader { + return &Reader{ + r: r, + decoded: make([]byte, maxUncompressedChunkLen), + buf: make([]byte, MaxEncodedLen(maxUncompressedChunkLen)+checksumSize), + } +} + +// Reader is an io.Reader than can read Snappy-compressed bytes. +type Reader struct { + r io.Reader + err error + decoded []byte + buf []byte + // decoded[i:j] contains decoded bytes that have not yet been passed on. + i, j int + readHeader bool +} + +// Reset discards any buffered data, resets all state, and switches the Snappy +// reader to read from r. This permits reusing a Reader rather than allocating +// a new one. +func (r *Reader) Reset(reader io.Reader) { + r.r = reader + r.err = nil + r.i = 0 + r.j = 0 + r.readHeader = false +} + +func (r *Reader) readFull(p []byte) (ok bool) { + if _, r.err = io.ReadFull(r.r, p); r.err != nil { + if r.err == io.ErrUnexpectedEOF { + r.err = ErrCorrupt + } + return false + } + return true +} + +// Read satisfies the io.Reader interface. +func (r *Reader) Read(p []byte) (int, error) { + if r.err != nil { + return 0, r.err + } + for { + if r.i < r.j { + n := copy(p, r.decoded[r.i:r.j]) + r.i += n + return n, nil + } + if !r.readFull(r.buf[:4]) { + return 0, r.err + } + chunkType := r.buf[0] + if !r.readHeader { + if chunkType != chunkTypeStreamIdentifier { + r.err = ErrCorrupt + return 0, r.err + } + r.readHeader = true + } + chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16 + if chunkLen > len(r.buf) { + r.err = ErrUnsupported + return 0, r.err + } + + // The chunk types are specified at + // https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt + switch chunkType { + case chunkTypeCompressedData: + // Section 4.2. Compressed data (chunk type 0x00). + if chunkLen < checksumSize { + r.err = ErrCorrupt + return 0, r.err + } + buf := r.buf[:chunkLen] + if !r.readFull(buf) { + return 0, r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + buf = buf[checksumSize:] + + n, err := DecodedLen(buf) + if err != nil { + r.err = err + return 0, r.err + } + if n > len(r.decoded) { + r.err = ErrCorrupt + return 0, r.err + } + if _, err := Decode(r.decoded, buf); err != nil { + r.err = err + return 0, r.err + } + if crc(r.decoded[:n]) != checksum { + r.err = ErrCorrupt + return 0, r.err + } + r.i, r.j = 0, n + continue + + case chunkTypeUncompressedData: + // Section 4.3. Uncompressed data (chunk type 0x01). + if chunkLen < checksumSize { + r.err = ErrCorrupt + return 0, r.err + } + buf := r.buf[:checksumSize] + if !r.readFull(buf) { + return 0, r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + // Read directly into r.decoded instead of via r.buf. + n := chunkLen - checksumSize + if !r.readFull(r.decoded[:n]) { + return 0, r.err + } + if crc(r.decoded[:n]) != checksum { + r.err = ErrCorrupt + return 0, r.err + } + r.i, r.j = 0, n + continue + + case chunkTypeStreamIdentifier: + // Section 4.1. Stream identifier (chunk type 0xff). + if chunkLen != len(magicBody) { + r.err = ErrCorrupt + return 0, r.err + } + if !r.readFull(r.buf[:len(magicBody)]) { + return 0, r.err + } + for i := 0; i < len(magicBody); i++ { + if r.buf[i] != magicBody[i] { + r.err = ErrCorrupt + return 0, r.err + } + } + continue + } + + if chunkType <= 0x7f { + // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f). + r.err = ErrUnsupported + return 0, r.err + + } else { + // Section 4.4 Padding (chunk type 0xfe). + // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd). + if !r.readFull(r.buf[:chunkLen]) { + return 0, r.err + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go new file mode 100644 index 00000000..dda37242 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go @@ -0,0 +1,258 @@ +// Copyright 2011 The Snappy-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package snappy + +import ( + "encoding/binary" + "io" +) + +// We limit how far copy back-references can go, the same as the C++ code. +const maxOffset = 1 << 15 + +// emitLiteral writes a literal chunk and returns the number of bytes written. +func emitLiteral(dst, lit []byte) int { + i, n := 0, uint(len(lit)-1) + switch { + case n < 60: + dst[0] = uint8(n)<<2 | tagLiteral + i = 1 + case n < 1<<8: + dst[0] = 60<<2 | tagLiteral + dst[1] = uint8(n) + i = 2 + case n < 1<<16: + dst[0] = 61<<2 | tagLiteral + dst[1] = uint8(n) + dst[2] = uint8(n >> 8) + i = 3 + case n < 1<<24: + dst[0] = 62<<2 | tagLiteral + dst[1] = uint8(n) + dst[2] = uint8(n >> 8) + dst[3] = uint8(n >> 16) + i = 4 + case int64(n) < 1<<32: + dst[0] = 63<<2 | tagLiteral + dst[1] = uint8(n) + dst[2] = uint8(n >> 8) + dst[3] = uint8(n >> 16) + dst[4] = uint8(n >> 24) + i = 5 + default: + panic("snappy: source buffer is too long") + } + if copy(dst[i:], lit) != len(lit) { + panic("snappy: destination buffer is too short") + } + return i + len(lit) +} + +// emitCopy writes a copy chunk and returns the number of bytes written. +func emitCopy(dst []byte, offset, length int) int { + i := 0 + for length > 0 { + x := length - 4 + if 0 <= x && x < 1<<3 && offset < 1<<11 { + dst[i+0] = uint8(offset>>8)&0x07<<5 | uint8(x)<<2 | tagCopy1 + dst[i+1] = uint8(offset) + i += 2 + break + } + + x = length + if x > 1<<6 { + x = 1 << 6 + } + dst[i+0] = uint8(x-1)<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + i += 3 + length -= x + } + return i +} + +// Encode returns the encoded form of src. The returned slice may be a sub- +// slice of dst if dst was large enough to hold the entire encoded block. +// Otherwise, a newly allocated slice will be returned. +// It is valid to pass a nil dst. +func Encode(dst, src []byte) ([]byte, error) { + if n := MaxEncodedLen(len(src)); len(dst) < n { + dst = make([]byte, n) + } + + // The block starts with the varint-encoded length of the decompressed bytes. + d := binary.PutUvarint(dst, uint64(len(src))) + + // Return early if src is short. + if len(src) <= 4 { + if len(src) != 0 { + d += emitLiteral(dst[d:], src) + } + return dst[:d], nil + } + + // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. + const maxTableSize = 1 << 14 + shift, tableSize := uint(32-8), 1<<8 + for tableSize < maxTableSize && tableSize < len(src) { + shift-- + tableSize *= 2 + } + var table [maxTableSize]int + + // Iterate over the source bytes. + var ( + s int // The iterator position. + t int // The last position with the same hash as s. + lit int // The start position of any pending literal bytes. + ) + for s+3 < len(src) { + // Update the hash table. + b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3] + h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24 + p := &table[(h*0x1e35a7bd)>>shift] + // We need to to store values in [-1, inf) in table. To save + // some initialization time, (re)use the table's zero value + // and shift the values against this zero: add 1 on writes, + // subtract 1 on reads. + t, *p = *p-1, s+1 + // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte. + if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] { + s++ + continue + } + // Otherwise, we have a match. First, emit any pending literal bytes. + if lit != s { + d += emitLiteral(dst[d:], src[lit:s]) + } + // Extend the match to be as long as possible. + s0 := s + s, t = s+4, t+4 + for s < len(src) && src[s] == src[t] { + s++ + t++ + } + // Emit the copied bytes. + d += emitCopy(dst[d:], s-t, s-s0) + lit = s + } + + // Emit any final pending literal bytes and return. + if lit != len(src) { + d += emitLiteral(dst[d:], src[lit:]) + } + return dst[:d], nil +} + +// MaxEncodedLen returns the maximum length of a snappy block, given its +// uncompressed length. +func MaxEncodedLen(srcLen int) int { + // Compressed data can be defined as: + // compressed := item* literal* + // item := literal* copy + // + // The trailing literal sequence has a space blowup of at most 62/60 + // since a literal of length 60 needs one tag byte + one extra byte + // for length information. + // + // Item blowup is trickier to measure. Suppose the "copy" op copies + // 4 bytes of data. Because of a special check in the encoding code, + // we produce a 4-byte copy only if the offset is < 65536. Therefore + // the copy op takes 3 bytes to encode, and this type of item leads + // to at most the 62/60 blowup for representing literals. + // + // Suppose the "copy" op copies 5 bytes of data. If the offset is big + // enough, it will take 5 bytes to encode the copy op. Therefore the + // worst case here is a one-byte literal followed by a five-byte copy. + // That is, 6 bytes of input turn into 7 bytes of "compressed" data. + // + // This last factor dominates the blowup, so the final estimate is: + return 32 + srcLen + srcLen/6 +} + +// NewWriter returns a new Writer that compresses to w, using the framing +// format described at +// https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt +func NewWriter(w io.Writer) *Writer { + return &Writer{ + w: w, + enc: make([]byte, MaxEncodedLen(maxUncompressedChunkLen)), + } +} + +// Writer is an io.Writer than can write Snappy-compressed bytes. +type Writer struct { + w io.Writer + err error + enc []byte + buf [checksumSize + chunkHeaderSize]byte + wroteHeader bool +} + +// Reset discards the writer's state and switches the Snappy writer to write to +// w. This permits reusing a Writer rather than allocating a new one. +func (w *Writer) Reset(writer io.Writer) { + w.w = writer + w.err = nil + w.wroteHeader = false +} + +// Write satisfies the io.Writer interface. +func (w *Writer) Write(p []byte) (n int, errRet error) { + if w.err != nil { + return 0, w.err + } + if !w.wroteHeader { + copy(w.enc, magicChunk) + if _, err := w.w.Write(w.enc[:len(magicChunk)]); err != nil { + w.err = err + return n, err + } + w.wroteHeader = true + } + for len(p) > 0 { + var uncompressed []byte + if len(p) > maxUncompressedChunkLen { + uncompressed, p = p[:maxUncompressedChunkLen], p[maxUncompressedChunkLen:] + } else { + uncompressed, p = p, nil + } + checksum := crc(uncompressed) + + // Compress the buffer, discarding the result if the improvement + // isn't at least 12.5%. + chunkType := uint8(chunkTypeCompressedData) + chunkBody, err := Encode(w.enc, uncompressed) + if err != nil { + w.err = err + return n, err + } + if len(chunkBody) >= len(uncompressed)-len(uncompressed)/8 { + chunkType, chunkBody = chunkTypeUncompressedData, uncompressed + } + + chunkLen := 4 + len(chunkBody) + w.buf[0] = chunkType + w.buf[1] = uint8(chunkLen >> 0) + w.buf[2] = uint8(chunkLen >> 8) + w.buf[3] = uint8(chunkLen >> 16) + w.buf[4] = uint8(checksum >> 0) + w.buf[5] = uint8(checksum >> 8) + w.buf[6] = uint8(checksum >> 16) + w.buf[7] = uint8(checksum >> 24) + if _, err = w.w.Write(w.buf[:]); err != nil { + w.err = err + return n, err + } + if _, err = w.w.Write(chunkBody); err != nil { + w.err = err + return n, err + } + n += len(uncompressed) + } + return n, nil +} diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go new file mode 100644 index 00000000..043bf3d8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go @@ -0,0 +1,68 @@ +// Copyright 2011 The Snappy-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package snappy implements the snappy block-based compression format. +// It aims for very high speeds and reasonable compression. +// +// The C++ snappy implementation is at http://code.google.com/p/snappy/ +package snappy + +import ( + "hash/crc32" +) + +/* +Each encoded block begins with the varint-encoded length of the decoded data, +followed by a sequence of chunks. Chunks begin and end on byte boundaries. The +first byte of each chunk is broken into its 2 least and 6 most significant bits +called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag. +Zero means a literal tag. All other values mean a copy tag. + +For literal tags: + - If m < 60, the next 1 + m bytes are literal bytes. + - Otherwise, let n be the little-endian unsigned integer denoted by the next + m - 59 bytes. The next 1 + n bytes after that are literal bytes. + +For copy tags, length bytes are copied from offset bytes ago, in the style of +Lempel-Ziv compression algorithms. In particular: + - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12). + The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10 + of the offset. The next byte is bits 0-7 of the offset. + - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65). + The length is 1 + m. The offset is the little-endian unsigned integer + denoted by the next 2 bytes. + - For l == 3, this tag is a legacy format that is no longer supported. +*/ +const ( + tagLiteral = 0x00 + tagCopy1 = 0x01 + tagCopy2 = 0x02 + tagCopy4 = 0x03 +) + +const ( + checksumSize = 4 + chunkHeaderSize = 4 + magicChunk = "\xff\x06\x00\x00" + magicBody + magicBody = "sNaPpY" + // https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt says + // that "the uncompressed data in a chunk must be no longer than 65536 bytes". + maxUncompressedChunkLen = 65536 +) + +const ( + chunkTypeCompressedData = 0x00 + chunkTypeUncompressedData = 0x01 + chunkTypePadding = 0xfe + chunkTypeStreamIdentifier = 0xff +) + +var crcTable = crc32.MakeTable(crc32.Castagnoli) + +// crc implements the checksum specified in section 3 of +// https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt +func crc(b []byte) uint32 { + c := crc32.Update(0, crcTable, b) + return uint32(c>>15|c<<17) + 0xa282ead8 +} diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go new file mode 100644 index 00000000..0623385b --- /dev/null +++ b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go @@ -0,0 +1,364 @@ +// Copyright 2011 The Snappy-Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package snappy + +import ( + "bytes" + "flag" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net/http" + "os" + "path/filepath" + "strings" + "testing" +) + +var ( + download = flag.Bool("download", false, "If true, download any missing files before running benchmarks") + testdata = flag.String("testdata", "testdata", "Directory containing the test data") +) + +func roundtrip(b, ebuf, dbuf []byte) error { + e, err := Encode(ebuf, b) + if err != nil { + return fmt.Errorf("encoding error: %v", err) + } + d, err := Decode(dbuf, e) + if err != nil { + return fmt.Errorf("decoding error: %v", err) + } + if !bytes.Equal(b, d) { + return fmt.Errorf("roundtrip mismatch:\n\twant %v\n\tgot %v", b, d) + } + return nil +} + +func TestEmpty(t *testing.T) { + if err := roundtrip(nil, nil, nil); err != nil { + t.Fatal(err) + } +} + +func TestSmallCopy(t *testing.T) { + for _, ebuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} { + for _, dbuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} { + for i := 0; i < 32; i++ { + s := "aaaa" + strings.Repeat("b", i) + "aaaabbbb" + if err := roundtrip([]byte(s), ebuf, dbuf); err != nil { + t.Errorf("len(ebuf)=%d, len(dbuf)=%d, i=%d: %v", len(ebuf), len(dbuf), i, err) + } + } + } + } +} + +func TestSmallRand(t *testing.T) { + rng := rand.New(rand.NewSource(27354294)) + for n := 1; n < 20000; n += 23 { + b := make([]byte, n) + for i := range b { + b[i] = uint8(rng.Uint32()) + } + if err := roundtrip(b, nil, nil); err != nil { + t.Fatal(err) + } + } +} + +func TestSmallRegular(t *testing.T) { + for n := 1; n < 20000; n += 23 { + b := make([]byte, n) + for i := range b { + b[i] = uint8(i%10 + 'a') + } + if err := roundtrip(b, nil, nil); err != nil { + t.Fatal(err) + } + } +} + +func cmp(a, b []byte) error { + if len(a) != len(b) { + return fmt.Errorf("got %d bytes, want %d", len(a), len(b)) + } + for i := range a { + if a[i] != b[i] { + return fmt.Errorf("byte #%d: got 0x%02x, want 0x%02x", i, a[i], b[i]) + } + } + return nil +} + +func TestFramingFormat(t *testing.T) { + // src is comprised of alternating 1e5-sized sequences of random + // (incompressible) bytes and repeated (compressible) bytes. 1e5 was chosen + // because it is larger than maxUncompressedChunkLen (64k). + src := make([]byte, 1e6) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < 10; i++ { + if i%2 == 0 { + for j := 0; j < 1e5; j++ { + src[1e5*i+j] = uint8(rng.Intn(256)) + } + } else { + for j := 0; j < 1e5; j++ { + src[1e5*i+j] = uint8(i) + } + } + } + + buf := new(bytes.Buffer) + if _, err := NewWriter(buf).Write(src); err != nil { + t.Fatalf("Write: encoding: %v", err) + } + dst, err := ioutil.ReadAll(NewReader(buf)) + if err != nil { + t.Fatalf("ReadAll: decoding: %v", err) + } + if err := cmp(dst, src); err != nil { + t.Fatal(err) + } +} + +func TestReaderReset(t *testing.T) { + gold := bytes.Repeat([]byte("All that is gold does not glitter,\n"), 10000) + buf := new(bytes.Buffer) + if _, err := NewWriter(buf).Write(gold); err != nil { + t.Fatalf("Write: %v", err) + } + encoded, invalid, partial := buf.String(), "invalid", "partial" + r := NewReader(nil) + for i, s := range []string{encoded, invalid, partial, encoded, partial, invalid, encoded, encoded} { + if s == partial { + r.Reset(strings.NewReader(encoded)) + if _, err := r.Read(make([]byte, 101)); err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + continue + } + r.Reset(strings.NewReader(s)) + got, err := ioutil.ReadAll(r) + switch s { + case encoded: + if err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + if err := cmp(got, gold); err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + case invalid: + if err == nil { + t.Errorf("#%d: got nil error, want non-nil", i) + continue + } + } + } +} + +func TestWriterReset(t *testing.T) { + gold := bytes.Repeat([]byte("Not all those who wander are lost;\n"), 10000) + var gots, wants [][]byte + const n = 20 + w, failed := NewWriter(nil), false + for i := 0; i <= n; i++ { + buf := new(bytes.Buffer) + w.Reset(buf) + want := gold[:len(gold)*i/n] + if _, err := w.Write(want); err != nil { + t.Errorf("#%d: Write: %v", i, err) + failed = true + continue + } + got, err := ioutil.ReadAll(NewReader(buf)) + if err != nil { + t.Errorf("#%d: ReadAll: %v", i, err) + failed = true + continue + } + gots = append(gots, got) + wants = append(wants, want) + } + if failed { + return + } + for i := range gots { + if err := cmp(gots[i], wants[i]); err != nil { + t.Errorf("#%d: %v", i, err) + } + } +} + +func benchDecode(b *testing.B, src []byte) { + encoded, err := Encode(nil, src) + if err != nil { + b.Fatal(err) + } + // Bandwidth is in amount of uncompressed data. + b.SetBytes(int64(len(src))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Decode(src, encoded) + } +} + +func benchEncode(b *testing.B, src []byte) { + // Bandwidth is in amount of uncompressed data. + b.SetBytes(int64(len(src))) + dst := make([]byte, MaxEncodedLen(len(src))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Encode(dst, src) + } +} + +func readFile(b testing.TB, filename string) []byte { + src, err := ioutil.ReadFile(filename) + if err != nil { + b.Fatalf("failed reading %s: %s", filename, err) + } + if len(src) == 0 { + b.Fatalf("%s has zero length", filename) + } + return src +} + +// expand returns a slice of length n containing repeated copies of src. +func expand(src []byte, n int) []byte { + dst := make([]byte, n) + for x := dst; len(x) > 0; { + i := copy(x, src) + x = x[i:] + } + return dst +} + +func benchWords(b *testing.B, n int, decode bool) { + // Note: the file is OS-language dependent so the resulting values are not + // directly comparable for non-US-English OS installations. + data := expand(readFile(b, "/usr/share/dict/words"), n) + if decode { + benchDecode(b, data) + } else { + benchEncode(b, data) + } +} + +func BenchmarkWordsDecode1e3(b *testing.B) { benchWords(b, 1e3, true) } +func BenchmarkWordsDecode1e4(b *testing.B) { benchWords(b, 1e4, true) } +func BenchmarkWordsDecode1e5(b *testing.B) { benchWords(b, 1e5, true) } +func BenchmarkWordsDecode1e6(b *testing.B) { benchWords(b, 1e6, true) } +func BenchmarkWordsEncode1e3(b *testing.B) { benchWords(b, 1e3, false) } +func BenchmarkWordsEncode1e4(b *testing.B) { benchWords(b, 1e4, false) } +func BenchmarkWordsEncode1e5(b *testing.B) { benchWords(b, 1e5, false) } +func BenchmarkWordsEncode1e6(b *testing.B) { benchWords(b, 1e6, false) } + +// testFiles' values are copied directly from +// https://raw.githubusercontent.com/google/snappy/master/snappy_unittest.cc +// The label field is unused in snappy-go. +var testFiles = []struct { + label string + filename string +}{ + {"html", "html"}, + {"urls", "urls.10K"}, + {"jpg", "fireworks.jpeg"}, + {"jpg_200", "fireworks.jpeg"}, + {"pdf", "paper-100k.pdf"}, + {"html4", "html_x_4"}, + {"txt1", "alice29.txt"}, + {"txt2", "asyoulik.txt"}, + {"txt3", "lcet10.txt"}, + {"txt4", "plrabn12.txt"}, + {"pb", "geo.protodata"}, + {"gaviota", "kppkn.gtb"}, +} + +// The test data files are present at this canonical URL. +const baseURL = "https://raw.githubusercontent.com/google/snappy/master/testdata/" + +func downloadTestdata(basename string) (errRet error) { + filename := filepath.Join(*testdata, basename) + if stat, err := os.Stat(filename); err == nil && stat.Size() != 0 { + return nil + } + + if !*download { + return fmt.Errorf("test data not found; skipping benchmark without the -download flag") + } + // Download the official snappy C++ implementation reference test data + // files for benchmarking. + if err := os.Mkdir(*testdata, 0777); err != nil && !os.IsExist(err) { + return fmt.Errorf("failed to create testdata: %s", err) + } + + f, err := os.Create(filename) + if err != nil { + return fmt.Errorf("failed to create %s: %s", filename, err) + } + defer f.Close() + defer func() { + if errRet != nil { + os.Remove(filename) + } + }() + url := baseURL + basename + resp, err := http.Get(url) + if err != nil { + return fmt.Errorf("failed to download %s: %s", url, err) + } + defer resp.Body.Close() + if s := resp.StatusCode; s != http.StatusOK { + return fmt.Errorf("downloading %s: HTTP status code %d (%s)", url, s, http.StatusText(s)) + } + _, err = io.Copy(f, resp.Body) + if err != nil { + return fmt.Errorf("failed to download %s to %s: %s", url, filename, err) + } + return nil +} + +func benchFile(b *testing.B, n int, decode bool) { + if err := downloadTestdata(testFiles[n].filename); err != nil { + b.Fatalf("failed to download testdata: %s", err) + } + data := readFile(b, filepath.Join(*testdata, testFiles[n].filename)) + if decode { + benchDecode(b, data) + } else { + benchEncode(b, data) + } +} + +// Naming convention is kept similar to what snappy's C++ implementation uses. +func Benchmark_UFlat0(b *testing.B) { benchFile(b, 0, true) } +func Benchmark_UFlat1(b *testing.B) { benchFile(b, 1, true) } +func Benchmark_UFlat2(b *testing.B) { benchFile(b, 2, true) } +func Benchmark_UFlat3(b *testing.B) { benchFile(b, 3, true) } +func Benchmark_UFlat4(b *testing.B) { benchFile(b, 4, true) } +func Benchmark_UFlat5(b *testing.B) { benchFile(b, 5, true) } +func Benchmark_UFlat6(b *testing.B) { benchFile(b, 6, true) } +func Benchmark_UFlat7(b *testing.B) { benchFile(b, 7, true) } +func Benchmark_UFlat8(b *testing.B) { benchFile(b, 8, true) } +func Benchmark_UFlat9(b *testing.B) { benchFile(b, 9, true) } +func Benchmark_UFlat10(b *testing.B) { benchFile(b, 10, true) } +func Benchmark_UFlat11(b *testing.B) { benchFile(b, 11, true) } +func Benchmark_ZFlat0(b *testing.B) { benchFile(b, 0, false) } +func Benchmark_ZFlat1(b *testing.B) { benchFile(b, 1, false) } +func Benchmark_ZFlat2(b *testing.B) { benchFile(b, 2, false) } +func Benchmark_ZFlat3(b *testing.B) { benchFile(b, 3, false) } +func Benchmark_ZFlat4(b *testing.B) { benchFile(b, 4, false) } +func Benchmark_ZFlat5(b *testing.B) { benchFile(b, 5, false) } +func Benchmark_ZFlat6(b *testing.B) { benchFile(b, 6, false) } +func Benchmark_ZFlat7(b *testing.B) { benchFile(b, 7, false) } +func Benchmark_ZFlat8(b *testing.B) { benchFile(b, 8, false) } +func Benchmark_ZFlat9(b *testing.B) { benchFile(b, 9, false) } +func Benchmark_ZFlat10(b *testing.B) { benchFile(b, 10, false) } +func Benchmark_ZFlat11(b *testing.B) { benchFile(b, 11, false) } diff --git a/Godeps/_workspace/src/github.com/willf/bitset/.gitignore b/Godeps/_workspace/src/github.com/willf/bitset/.gitignore new file mode 100644 index 00000000..6cd1df2b --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/willf/bitset/CHANGELOG b/Godeps/_workspace/src/github.com/willf/bitset/CHANGELOG new file mode 100644 index 00000000..30410d90 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/CHANGELOG @@ -0,0 +1,10 @@ +2014-02-14 Version 1.0.0 💗 + +- First 'released' version +- includes various fixes by: + - Daniel Lemire + - Todd Vierling + - Zellyn Hunter + - Seyi Ogunyemi + - Simon Menke + - Cenk Altı \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/willf/bitset/LICENSE.txt b/Godeps/_workspace/src/github.com/willf/bitset/LICENSE.txt new file mode 100644 index 00000000..59cab8a9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2014 Will Fitzgerald. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/willf/bitset/README.md b/Godeps/_workspace/src/github.com/willf/bitset/README.md new file mode 100644 index 00000000..bbf1ea56 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/README.md @@ -0,0 +1,44 @@ +Package bitset implements bitsets, a mapping +between non-negative integers and boolean values. It should be more +efficient than map[uint] bool. + +It provides methods for setting, clearing, flipping, and testing +individual integers. + +But it also provides set intersection, union, difference, +complement, and symmetric operations, as well as tests to +check whether any, all, or no bits are set, and querying a +bitset's current length and number of postive bits. + +BitSets are expanded to the size of the largest set bit; the +memory allocation is approximately Max bits, where Max is +the largest set bit. BitSets are never shrunk. On creation, +a hint can be given for the number of bits that will be used. + +Many of the methods, including Set, Clear, and Flip, return +a BitSet pointer, which allows for chaining. + +Example use: + + import "bitset" + var b BitSet + b.Set(10).Set(11) + if b.Test(1000) { + b.Clear(1000) + } + for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) { + frmt.Println("The following bit is set:",i); + } + if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { + fmt.Println("Intersection works.") + } + +As an alternative to BitSets, one should check out the 'big' package, +which provides a (less set-theoretical) view of bitsets. + +Discussions golang-nuts Google Group: + +* [Revised BitSet](https://groups.google.com/forum/#!topic/golang-nuts/5i3l0CXDiBg) +* [simple bitset?](https://groups.google.com/d/topic/golang-nuts/7n1VkRTlBf4/discussion) + +Godoc documentation is at: https://godoc.org/github.com/willf/bitset diff --git a/Godeps/_workspace/src/github.com/willf/bitset/bitset.go b/Godeps/_workspace/src/github.com/willf/bitset/bitset.go new file mode 100644 index 00000000..9d539327 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/bitset.go @@ -0,0 +1,614 @@ +/* +Package bitset implements bitsets, a mapping +between non-negative integers and boolean values. It should be more +efficient than map[uint] bool. + +It provides methods for setting, clearing, flipping, and testing +individual integers. + +But it also provides set intersection, union, difference, +complement, and symmetric operations, as well as tests to +check whether any, all, or no bits are set, and querying a +bitset's current length and number of postive bits. + +BitSets are expanded to the size of the largest set bit; the +memory allocation is approximately Max bits, where Max is +the largest set bit. BitSets are never shrunk. On creation, +a hint can be given for the number of bits that will be used. + +Many of the methods, including Set,Clear, and Flip, return +a BitSet pointer, which allows for chaining. + +Example use: + + import "bitset" + var b BitSet + b.Set(10).Set(11) + if b.Test(1000) { + b.Clear(1000) + } + if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { + fmt.Println("Intersection works.") + } + +As an alternative to BitSets, one should check out the 'big' package, +which provides a (less set-theoretical) view of bitsets. + +*/ +package bitset + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "io" +) + +// the wordSize of a bit set +const wordSize = uint(64) + +// log2WordSize is lg(wordSize) +const log2WordSize = uint(6) + +// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. +type BitSet struct { + length uint + set []uint64 +} + +// A BitSetError is used to distinguish errors (panics) generated in this package. +type BitSetError string + +// safeSet will fixup b.set to be non-nil and return the field value +func (b *BitSet) safeSet() []uint64 { + if b.set == nil { + b.set = make([]uint64, wordsNeeded(0)) + } + return b.set +} + +// wordsNeeded calculates the number of words needed for i bits +func wordsNeeded(i uint) int { + if i > ((^uint(0)) - wordSize + 1) { + return int((^uint(0)) >> log2WordSize) + } + return int((i + (wordSize - 1)) >> log2WordSize) +} + +// New creates a new BitSet with a hint that length bits will be required +func New(length uint) *BitSet { + return &BitSet{length, make([]uint64, wordsNeeded(length))} +} + +// Cap returns the total possible capicity, or number of bits +func Cap() uint { + return ^uint(0) +} + +// Len returns the length of the BitSet in words +func (b *BitSet) Len() uint { + return b.length +} + +// extendSetMaybe adds additional words to incorporate new bits if needed +func (b *BitSet) extendSetMaybe(i uint) { + if i >= b.length { // if we need more bits, make 'em + nsize := wordsNeeded(i + 1) + if b.set == nil { + b.set = make([]uint64, nsize) + } else if len(b.set) < nsize { + newset := make([]uint64, nsize) + copy(newset, b.set) + b.set = newset + } + b.length = i + 1 + } +} + +// Test whether bit i is set. +func (b *BitSet) Test(i uint) bool { + if i >= b.length { + return false + } + return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0 +} + +// Set bit i to 1 +func (b *BitSet) Set(i uint) *BitSet { + b.extendSetMaybe(i) + b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1)) + return b +} + +// Clear bit i to 0 +func (b *BitSet) Clear(i uint) *BitSet { + if i >= b.length { + return b + } + b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1)) + return b +} + +// SetTo sets bit i to value +func (b *BitSet) SetTo(i uint, value bool) *BitSet { + if value { + return b.Set(i) + } + return b.Clear(i) +} + +// Flip bit at i +func (b *BitSet) Flip(i uint) *BitSet { + if i >= b.length { + return b.Set(i) + } + b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1)) + return b +} + +// NextSet returns the next bit set from the specified index, +// including possibly the current index +// along with an error code (true = valid, false = no set bit found) +// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} +func (b *BitSet) NextSet(i uint) (uint, bool) { + x := int(i >> log2WordSize) + if x >= len(b.set) { + return 0, false + } + w := b.set[x] + w = w >> (i & (wordSize - 1)) + if w != 0 { + return i + trailingZeroes64(w), true + } + x = x + 1 + for x < len(b.set) { + if b.set[x] != 0 { + return uint(x)*wordSize + trailingZeroes64(b.set[x]), true + } + x = x + 1 + + } + return 0, false +} + +// ClearAll clears the entire BitSet +func (b *BitSet) ClearAll() *BitSet { + if b != nil && b.set != nil { + for i := range b.set { + b.set[i] = 0 + } + } + return b +} + +// wordCount returns the number of words used in a bit set +func (b *BitSet) wordCount() int { + return wordsNeeded(b.length) +} + +// Clone this BitSet +func (b *BitSet) Clone() *BitSet { + c := New(b.length) + if b.set != nil { // Clone should not modify current object + copy(c.set, b.set) + } + return c +} + +// Copy this BitSet into a destination BitSet +// Returning the size of the destination BitSet +// like array copy +func (b *BitSet) Copy(c *BitSet) (count uint) { + if c == nil { + return + } + if b.set != nil { // Copy should not modify current object + copy(c.set, b.set) + } + count = c.length + if b.length < c.length { + count = b.length + } + return +} + +// Count (number of set bits) +func (b *BitSet) Count() uint { + if b != nil && b.set != nil { + return uint(popcntSlice(b.set)) + } + return 0 +} + +var deBruijn = [...]byte{ + 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, + 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, + 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, + 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, +} + +func trailingZeroes64(v uint64) uint { + return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58]) +} + +// Equal tests the equvalence of two BitSets. +// False if they are of different sizes, otherwise true +// only if all the same bits are set +func (b *BitSet) Equal(c *BitSet) bool { + if c == nil { + return false + } + if b.length != c.length { + return false + } + if b.length == 0 { // if they have both length == 0, then could have nil set + return true + } + // testing for equality shoud not transform the bitset (no call to safeSet) + + for p, v := range b.set { + if c.set[p] != v { + return false + } + } + return true +} + +func panicIfNull(b *BitSet) { + if b == nil { + panic(BitSetError("BitSet must not be null")) + } +} + +// Difference of base set and other set +// This is the BitSet equivalent of &^ (and not) +func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + result = b.Clone() // clone b (in case b is bigger than compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + for i := 0; i < l; i++ { + result.set[i] = b.set[i] &^ compare.set[i] + } + return +} + +// DifferenceCardinality computes the cardinality of the differnce +func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + cnt := uint64(0) + cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) + cnt += popcntSlice(b.set[l:]) + return uint(cnt) +} + +// InPlaceDifference computes the difference of base set and other set +// This is the BitSet equivalent of &^ (and not) +func (b *BitSet) InPlaceDifference(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + for i := 0; i < l; i++ { + b.set[i] &^= compare.set[i] + } +} + +// Convenience function: return two bitsets ordered by +// increasing length. Note: neither can be nil +func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { + if a.length <= b.length { + ap, bp = a, b + } else { + ap, bp = b, a + } + return +} + +// Intersection of base set and other set +// This is the BitSet equivalent of & (and) +func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + result = New(b.length) + for i, word := range b.set { + result.set[i] = word & compare.set[i] + } + return +} + +// IntersectionCardinality computes the cardinality of the union +func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntAndSlice(b.set, compare.set) + return uint(cnt) +} + +// InPlaceIntersection destructively computes the intersection of +// base set and the compare set. +// This is the BitSet equivalent of & (and) +func (b *BitSet) InPlaceIntersection(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + for i := 0; i < l; i++ { + b.set[i] &= compare.set[i] + } + for i := l; i < len(b.set); i++ { + b.set[i] = 0 + } + if compare.length > 0 { + b.extendSetMaybe(compare.length - 1) + } + return +} + +// Union of base set and other set +// This is the BitSet equivalent of | (or) +func (b *BitSet) Union(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + result = compare.Clone() + for i, word := range b.set { + result.set[i] = word | compare.set[i] + } + return +} + +// UnionCardinality computes the cardinality of the uniton of the base set +// and the compare set. +func (b *BitSet) UnionCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntOrSlice(b.set, compare.set) + if len(compare.set) > len(b.set) { + cnt += popcntSlice(compare.set[len(b.set):]) + } + return uint(cnt) +} + +// InPlaceUnion creates the destructive union of base set and compare set. +// This is the BitSet equivalent of | (or). +func (b *BitSet) InPlaceUnion(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + if compare.length > 0 { + b.extendSetMaybe(compare.length - 1) + } + for i := 0; i < l; i++ { + b.set[i] |= compare.set[i] + } + if len(compare.set) > l { + for i := l; i < len(compare.set); i++ { + b.set[i] = compare.set[i] + } + } +} + +// SymmetricDifference of base set and other set +// This is the BitSet equivalent of ^ (xor) +func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + // compare is bigger, so clone it + result = compare.Clone() + for i, word := range b.set { + result.set[i] = word ^ compare.set[i] + } + return +} + +// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference +func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntXorSlice(b.set, compare.set) + if len(compare.set) > len(b.set) { + cnt += popcntSlice(compare.set[len(b.set):]) + } + return uint(cnt) +} + +// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set +// This is the BitSet equivalent of ^ (xor) +func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + if compare.length > 0 { + b.extendSetMaybe(compare.length - 1) + } + for i := 0; i < l; i++ { + b.set[i] ^= compare.set[i] + } + if len(compare.set) > l { + for i := l; i < len(compare.set); i++ { + b.set[i] = compare.set[i] + } + } +} + +// Is the length an exact multiple of word sizes? +func (b *BitSet) isEven() bool { + return b.length%wordSize == 0 +} + +// Clean last word by setting unused bits to 0 +func (b *BitSet) cleanLastWord() { + if !b.isEven() { + // Mask for cleaning last word + const allBits uint64 = 0xffffffffffffffff + b.set[wordsNeeded(b.length)-1] &= allBits >> (wordSize - b.length%wordSize) + } +} + +// Complement computes the (local) complement of a biset (up to length bits) +func (b *BitSet) Complement() (result *BitSet) { + panicIfNull(b) + result = New(b.length) + for i, word := range b.set { + result.set[i] = ^word + } + result.cleanLastWord() + return +} + +// All returns true if all bits are set, false otherwise +func (b *BitSet) All() bool { + panicIfNull(b) + return b.Count() == b.length +} + +// None returns true if no bit is set, false otherwise +func (b *BitSet) None() bool { + panicIfNull(b) + if b != nil && b.set != nil { + for _, word := range b.set { + if word > 0 { + return false + } + } + return true + } + return true +} + +// Any returns true if any bit is set, false otherwise +func (b *BitSet) Any() bool { + panicIfNull(b) + return !b.None() +} + +// IsSuperSet returns true if this is a superset of the other set +func (b *BitSet) IsSuperSet(other *BitSet) bool { + for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) { + if !other.Test(i) { + return false + } + } + return true +} + +// IsStrictSuperSet returns true if this is a strict superset of the other set +func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { + return b.Count() > other.Count() && b.IsSuperSet(other) +} + +// DumpAsBits dumps a bit set as a string of bits +func (b *BitSet) DumpAsBits() string { + if b.set == nil { + return "." + } + buffer := bytes.NewBufferString("") + i := len(b.set) - 1 + for ; i >= 0; i-- { + fmt.Fprintf(buffer, "%064b.", b.set[i]) + } + return string(buffer.Bytes()) +} + +// BinaryStorageSize returns the binary storage requirements +func (b *BitSet) BinaryStorageSize() int { + return binary.Size(uint64(0)) + binary.Size(b.set) +} + +// WriteTo writes a BitSet to a stream +func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { + length := uint64(b.length) + + // Write length + err := binary.Write(stream, binary.BigEndian, length) + if err != nil { + return 0, err + } + + // Write set + err = binary.Write(stream, binary.BigEndian, b.set) + return int64(b.BinaryStorageSize()), err +} + +// ReadFrom reads a BitSet from a stream written using WriteTo +func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { + var length uint64 + + // Read length first + err := binary.Read(stream, binary.BigEndian, &length) + if err != nil { + return 0, err + } + newset := New(uint(length)) + + if uint64(newset.length) != length { + return 0, errors.New("Unmarshalling error: type mismatch") + } + + // Read remaining bytes as set + err = binary.Read(stream, binary.BigEndian, newset.set) + if err != nil { + return 0, err + } + + *b = *newset + return int64(b.BinaryStorageSize()), nil +} + +// MarshalJSON marshals a BitSet as a JSON structure +func (b *BitSet) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) + _, err := b.WriteTo(buffer) + if err != nil { + return nil, err + } + + // URLEncode all bytes + return json.Marshal(base64.URLEncoding.EncodeToString(buffer.Bytes())) +} + +// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON +func (b *BitSet) UnmarshalJSON(data []byte) error { + // Unmarshal as string + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + // URLDecode string + buf, err := base64.URLEncoding.DecodeString(s) + if err != nil { + return err + } + + _, err = b.ReadFrom(bytes.NewReader(buf)) + return err +} diff --git a/Godeps/_workspace/src/github.com/willf/bitset/bitset_test.go b/Godeps/_workspace/src/github.com/willf/bitset/bitset_test.go new file mode 100644 index 00000000..3215ab38 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/bitset_test.go @@ -0,0 +1,767 @@ +// Copyright 2014 Will Fitzgerald. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file tests bit sets + +package bitset + +import ( + "encoding/json" + "math" + "math/rand" + "testing" +) + +func TestEmptyBitSet(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Error("A zero-length bitset should be fine") + } + }() + b := New(0) + if b.Len() != 0 { + t.Errorf("Empty set should have capacity 0, not %d", b.Len()) + } +} + +func TestZeroValueBitSet(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Error("A zero-length bitset should be fine") + } + }() + var b BitSet + if b.Len() != 0 { + t.Errorf("Empty set should have capacity 0, not %d", b.Len()) + } +} + +func TestBitSetNew(t *testing.T) { + v := New(16) + if v.Test(0) != false { + t.Errorf("Unable to make a bit set and read its 0th value.") + } +} + +func TestBitSetHuge(t *testing.T) { + v := New(uint(math.MaxUint32)) + if v.Test(0) != false { + t.Errorf("Unable to make a huge bit set and read its 0th value.") + } +} + +func TestLen(t *testing.T) { + v := New(1000) + if v.Len() != 1000 { + t.Errorf("Len should be 1000, but is %d.", v.Len()) + } +} + +func TestBitSetIsClear(t *testing.T) { + v := New(1000) + for i := uint(0); i < 1000; i++ { + if v.Test(i) != false { + t.Errorf("Bit %d is set, and it shouldn't be.", i) + } + } +} + +func TestExendOnBoundary(t *testing.T) { + v := New(32) + defer func() { + if r := recover(); r != nil { + t.Error("Border out of index error should not have caused a panic") + } + }() + v.Set(32) +} + +func TestExpand(t *testing.T) { + v := New(0) + defer func() { + if r := recover(); r != nil { + t.Error("Expansion should not have caused a panic") + } + }() + for i := uint(0); i < 1000; i++ { + v.Set(i) + } +} + +func TestBitSetAndGet(t *testing.T) { + v := New(1000) + v.Set(100) + if v.Test(100) != true { + t.Errorf("Bit %d is clear, and it shouldn't be.", 100) + } +} + +func TestIterate(t *testing.T) { + v := New(10000) + v.Set(0) + v.Set(1) + v.Set(2) + data := make([]uint, 3) + c := 0 + for i, e := v.NextSet(0); e; i, e = v.NextSet(i + 1) { + data[c] = i + c++ + } + if data[0] != 0 { + t.Errorf("bug 0") + } + if data[1] != 1 { + t.Errorf("bug 1") + } + if data[2] != 2 { + t.Errorf("bug 2") + } + v.Set(10) + v.Set(2000) + data = make([]uint, 5) + c = 0 + for i, e := v.NextSet(0); e; i, e = v.NextSet(i + 1) { + data[c] = i + c++ + } + if data[0] != 0 { + t.Errorf("bug 0") + } + if data[1] != 1 { + t.Errorf("bug 1") + } + if data[2] != 2 { + t.Errorf("bug 2") + } + if data[3] != 10 { + t.Errorf("bug 3") + } + if data[4] != 2000 { + t.Errorf("bug 4") + } + +} + +func TestSetTo(t *testing.T) { + v := New(1000) + v.SetTo(100, true) + if v.Test(100) != true { + t.Errorf("Bit %d is clear, and it shouldn't be.", 100) + } + v.SetTo(100, false) + if v.Test(100) != false { + t.Errorf("Bit %d is set, and it shouldn't be.", 100) + } +} + +func TestChain(t *testing.T) { + if New(1000).Set(100).Set(99).Clear(99).Test(100) != true { + t.Errorf("Bit %d is clear, and it shouldn't be.", 100) + } +} + +func TestOutOfBoundsLong(t *testing.T) { + v := New(64) + defer func() { + if r := recover(); r != nil { + t.Error("Long distance out of index error should not have caused a panic") + } + }() + v.Set(1000) +} + +func TestOutOfBoundsClose(t *testing.T) { + v := New(65) + defer func() { + if r := recover(); r != nil { + t.Error("Local out of index error should not have caused a panic") + } + }() + v.Set(66) +} + +func TestCount(t *testing.T) { + tot := uint(64*4 + 11) // just some multi unit64 number + v := New(tot) + checkLast := true + for i := uint(0); i < tot; i++ { + sz := uint(v.Count()) + if sz != i { + t.Errorf("Count reported as %d, but it should be %d", sz, i) + checkLast = false + break + } + v.Set(i) + } + if checkLast { + sz := uint(v.Count()) + if sz != tot { + t.Errorf("After all bits set, size reported as %d, but it should be %d", sz, tot) + } + } +} + +// test setting every 3rd bit, just in case something odd is happening +func TestCount2(t *testing.T) { + tot := uint(64*4 + 11) // just some multi unit64 number + v := New(tot) + for i := uint(0); i < tot; i += 3 { + sz := uint(v.Count()) + if sz != i/3 { + t.Errorf("Count reported as %d, but it should be %d", sz, i) + break + } + v.Set(i) + } +} + +// nil tests +func TestNullTest(t *testing.T) { + var v *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Checking bit of null reference should have caused a panic") + } + }() + v.Test(66) +} + +func TestNullSet(t *testing.T) { + var v *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Setting bit of null reference should have caused a panic") + } + }() + v.Set(66) +} + +func TestNullClear(t *testing.T) { + var v *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Clearning bit of null reference should have caused a panic") + } + }() + v.Clear(66) +} + +func TestNullCount(t *testing.T) { + var v *BitSet = nil + defer func() { + if r := recover(); r != nil { + t.Error("Counting null reference should not have caused a panic") + } + }() + cnt := v.Count() + if cnt != 0 { + t.Errorf("Count reported as %d, but it should be 0", cnt) + } +} + +func TestPanicDifferenceBNil(t *testing.T) { + var b *BitSet = nil + var compare = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil First should should have caused a panic") + } + }() + b.Difference(compare) +} + +func TestPanicDifferenceCompareNil(t *testing.T) { + var compare *BitSet = nil + var b = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil Second should should have caused a panic") + } + }() + b.Difference(compare) +} + +func TestPanicUnionBNil(t *testing.T) { + var b *BitSet = nil + var compare = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil First should should have caused a panic") + } + }() + b.Union(compare) +} + +func TestPanicUnionCompareNil(t *testing.T) { + var compare *BitSet = nil + var b = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil Second should should have caused a panic") + } + }() + b.Union(compare) +} + +func TestPanicIntersectionBNil(t *testing.T) { + var b *BitSet = nil + var compare = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil First should should have caused a panic") + } + }() + b.Intersection(compare) +} + +func TestPanicIntersectionCompareNil(t *testing.T) { + var compare *BitSet = nil + var b = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil Second should should have caused a panic") + } + }() + b.Intersection(compare) +} + +func TestPanicSymmetricDifferenceBNil(t *testing.T) { + var b *BitSet = nil + var compare = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil First should should have caused a panic") + } + }() + b.SymmetricDifference(compare) +} + +func TestPanicSymmetricDifferenceCompareNil(t *testing.T) { + var compare *BitSet = nil + var b = New(10) + defer func() { + if r := recover(); r == nil { + t.Error("Nil Second should should have caused a panic") + } + }() + b.SymmetricDifference(compare) +} + +func TestPanicComplementBNil(t *testing.T) { + var b *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Nil should should have caused a panic") + } + }() + b.Complement() +} + +func TestPanicAnytBNil(t *testing.T) { + var b *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Nil should should have caused a panic") + } + }() + b.Any() +} + +func TestPanicNonetBNil(t *testing.T) { + var b *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Nil should should have caused a panic") + } + }() + b.None() +} + +func TestPanicAlltBNil(t *testing.T) { + var b *BitSet = nil + defer func() { + if r := recover(); r == nil { + t.Error("Nil should should have caused a panic") + } + }() + b.All() +} + +func TestEqual(t *testing.T) { + a := New(100) + b := New(99) + c := New(100) + if a.Equal(b) { + t.Error("Sets of different sizes should be not be equal") + } + if !a.Equal(c) { + t.Error("Two empty sets of the same size should be equal") + } + a.Set(99) + c.Set(0) + if a.Equal(c) { + t.Error("Two sets with differences should not be equal") + } + c.Set(99) + a.Set(0) + if !a.Equal(c) { + t.Error("Two sets with the same bits set should be equal") + } +} + +func TestUnion(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) + b.Set(i - 1) + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + if a.UnionCardinality(b) != 200 { + t.Errorf("Union should have 200 bits set, but had %d", a.UnionCardinality(b)) + } + if a.UnionCardinality(b) != b.UnionCardinality(a) { + t.Errorf("Union should be symmetric") + } + + c := a.Union(b) + d := b.Union(a) + if c.Count() != 200 { + t.Errorf("Union should have 200 bits set, but had %d", c.Count()) + } + if !c.Equal(d) { + t.Errorf("Union should be symmetric") + } +} + +func TestInPlaceUnion(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) + b.Set(i - 1) + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + c := a.Clone() + c.InPlaceUnion(b) + d := b.Clone() + d.InPlaceUnion(a) + if c.Count() != 200 { + t.Errorf("Union should have 200 bits set, but had %d", c.Count()) + } + if d.Count() != 200 { + t.Errorf("Union should have 200 bits set, but had %d", d.Count()) + } + if !c.Equal(d) { + t.Errorf("Union should be symmetric") + } +} + +func TestIntersection(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) + b.Set(i - 1).Set(i) + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + if a.IntersectionCardinality(b) != 50 { + t.Errorf("Intersection should have 50 bits set, but had %d", a.IntersectionCardinality(b)) + } + if a.IntersectionCardinality(b) != b.IntersectionCardinality(a) { + t.Errorf("Intersection should be symmetric") + } + c := a.Intersection(b) + d := b.Intersection(a) + if c.Count() != 50 { + t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) + } + if !c.Equal(d) { + t.Errorf("Intersection should be symmetric") + } +} + +func TestInplaceIntersection(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) + b.Set(i - 1).Set(i) + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + c := a.Clone() + c.InPlaceIntersection(b) + d := b.Clone() + d.InPlaceIntersection(a) + if c.Count() != 50 { + t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) + } + if d.Count() != 50 { + t.Errorf("Intersection should have 50 bits set, but had %d", d.Count()) + } + if !c.Equal(d) { + t.Errorf("Intersection should be symmetric") + } +} + +func TestDifference(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) + b.Set(i - 1) + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + if a.DifferenceCardinality(b) != 50 { + t.Errorf("a-b Difference should have 50 bits set, but had %d", a.DifferenceCardinality(b)) + } + if b.DifferenceCardinality(a) != 150 { + t.Errorf("b-a Difference should have 150 bits set, but had %d", b.DifferenceCardinality(a)) + } + + c := a.Difference(b) + d := b.Difference(a) + if c.Count() != 50 { + t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) + } + if d.Count() != 150 { + t.Errorf("b-a Difference should have 150 bits set, but had %d", d.Count()) + } + if c.Equal(d) { + t.Errorf("Difference, here, should not be symmetric") + } +} + +func TestInPlaceDifference(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) + b.Set(i - 1) + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + c := a.Clone() + c.InPlaceDifference(b) + d := b.Clone() + d.InPlaceDifference(a) + if c.Count() != 50 { + t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) + } + if d.Count() != 150 { + t.Errorf("b-a Difference should have 150 bits set, but had %d", d.Count()) + } + if c.Equal(d) { + t.Errorf("Difference, here, should not be symmetric") + } +} + +func TestSymmetricDifference(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) // 01010101010 ... 0000000 + b.Set(i - 1).Set(i) // 11111111111111111000000 + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + if a.SymmetricDifferenceCardinality(b) != 150 { + t.Errorf("a^b Difference should have 150 bits set, but had %d", a.SymmetricDifferenceCardinality(b)) + } + if b.SymmetricDifferenceCardinality(a) != 150 { + t.Errorf("b^a Difference should have 150 bits set, but had %d", b.SymmetricDifferenceCardinality(a)) + } + + c := a.SymmetricDifference(b) + d := b.SymmetricDifference(a) + if c.Count() != 150 { + t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) + } + if d.Count() != 150 { + t.Errorf("b^a Difference should have 150 bits set, but had %d", d.Count()) + } + if !c.Equal(d) { + t.Errorf("SymmetricDifference should be symmetric") + } +} + +func TestInPlaceSymmetricDifference(t *testing.T) { + a := New(100) + b := New(200) + for i := uint(1); i < 100; i += 2 { + a.Set(i) // 01010101010 ... 0000000 + b.Set(i - 1).Set(i) // 11111111111111111000000 + } + for i := uint(100); i < 200; i++ { + b.Set(i) + } + c := a.Clone() + c.InPlaceSymmetricDifference(b) + d := b.Clone() + d.InPlaceSymmetricDifference(a) + if c.Count() != 150 { + t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) + } + if d.Count() != 150 { + t.Errorf("b^a Difference should have 150 bits set, but had %d", d.Count()) + } + if !c.Equal(d) { + t.Errorf("SymmetricDifference should be symmetric") + } +} + +func TestComplement(t *testing.T) { + a := New(50) + b := a.Complement() + if b.Count() != 50 { + t.Errorf("Complement failed, size should be 50, but was %d", b.Count()) + } + a = New(50) + a.Set(10).Set(20).Set(42) + b = a.Complement() + if b.Count() != 47 { + t.Errorf("Complement failed, size should be 47, but was %d", b.Count()) + } +} + +func TestIsSuperSet(t *testing.T) { + a := New(500) + b := New(300) + for i := uint(0); i < 200; i++ { + a.Set(i) + b.Set(i) + } + if a.IsSuperSet(b) != true { + t.Errorf("IsSuperSet fails") + } + if a.IsStrictSuperSet(b) != false { + t.Errorf("IsStrictSuperSet fails") + } +} + +func TestDumpAsBits(t *testing.T) { + a := New(10).Set(10) + astr := "0000000000000000000000000000000000000000000000000000010000000000." + if a.DumpAsBits() != astr { + t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", astr, a.DumpAsBits()) + } + var b BitSet // zero value (b.set == nil) + bstr := "." + if b.DumpAsBits() != bstr { + t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", bstr, b.DumpAsBits()) + } +} + +func TestMarshalUnmarshalJSON(t *testing.T) { + a := New(1010).Set(10).Set(1001) + data, err := json.Marshal(a) + if err != nil { + t.Errorf(err.Error()) + return + } + + b := new(BitSet) + err = json.Unmarshal(data, b) + if err != nil { + t.Errorf(err.Error()) + return + } + + // Bitsets must be equal after marshalling and unmarshalling + if !a.Equal(b) { + t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) + return + } +} + +// BENCHMARKS + +func BenchmarkSet(b *testing.B) { + b.StopTimer() + r := rand.New(rand.NewSource(0)) + sz := 100000 + s := New(uint(sz)) + b.StartTimer() + for i := 0; i < b.N; i++ { + s.Set(uint(r.Int31n(int32(sz)))) + } +} + +func BenchmarkGetTest(b *testing.B) { + b.StopTimer() + r := rand.New(rand.NewSource(0)) + sz := 100000 + s := New(uint(sz)) + b.StartTimer() + for i := 0; i < b.N; i++ { + s.Test(uint(r.Int31n(int32(sz)))) + } +} + +func BenchmarkSetExpand(b *testing.B) { + b.StopTimer() + sz := uint(100000) + b.StartTimer() + for i := 0; i < b.N; i++ { + var s BitSet + s.Set(sz) + } +} + +// go test -bench=Count +func BenchmarkCount(b *testing.B) { + b.StopTimer() + s := New(100000) + for i := 0; i < 100000; i += 100 { + s.Set(uint(i)) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + s.Count() + } +} + +// go test -bench=Iterate +func BenchmarkIterate(b *testing.B) { + b.StopTimer() + s := New(10000) + for i := 0; i < 10000; i += 3 { + s.Set(uint(i)) + } + b.StartTimer() + for j := 0; j < b.N; j++ { + c := uint(0) + for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { + c++ + } + } +} + +// go test -bench=SparseIterate +func BenchmarkSparseIterate(b *testing.B) { + b.StopTimer() + s := New(100000) + for i := 0; i < 100000; i += 30 { + s.Set(uint(i)) + } + b.StartTimer() + for j := 0; j < b.N; j++ { + c := uint(0) + for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { + c++ + } + } +} diff --git a/Godeps/_workspace/src/github.com/willf/bitset/popcnt.go b/Godeps/_workspace/src/github.com/willf/bitset/popcnt.go new file mode 100644 index 00000000..76577a83 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/popcnt.go @@ -0,0 +1,53 @@ +package bitset + +// bit population count, take from +// https://code.google.com/p/go/issues/detail?id=4988#c11 +// credit: https://code.google.com/u/arnehormann/ +func popcount(x uint64) (n uint64) { + x -= (x >> 1) & 0x5555555555555555 + x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 + x += x >> 4 + x &= 0x0f0f0f0f0f0f0f0f + x *= 0x0101010101010101 + return x >> 56 +} + +func popcntSliceGo(s []uint64) uint64 { + cnt := uint64(0) + for _, x := range s { + cnt += popcount(x) + } + return cnt +} + +func popcntMaskSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] &^ m[i]) + } + return cnt +} + +func popcntAndSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] & m[i]) + } + return cnt +} + +func popcntOrSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] | m[i]) + } + return cnt +} + +func popcntXorSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] ^ m[i]) + } + return cnt +} diff --git a/Godeps/_workspace/src/github.com/willf/bitset/popcnt_amd64.s b/Godeps/_workspace/src/github.com/willf/bitset/popcnt_amd64.s new file mode 100644 index 00000000..ca106f90 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/popcnt_amd64.s @@ -0,0 +1,103 @@ +// +build !appengine +TEXT ·hasAsm(SB),4,$0 +MOVQ $1, AX +CPUID +SHRQ $23, CX +ANDQ $1, CX +MOVB CX, ret+0(FP) +RET + + +#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 + +TEXT ·popcntSliceAsm(SB),4,$0-32 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s+8(FP), CX +TESTQ CX, CX +JZ popcntSliceEnd +popcntSliceLoop: +BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX +ADDQ DX, AX +ADDQ $8, SI +LOOP popcntSliceLoop +popcntSliceEnd: +MOVQ AX, ret+24(FP) +RET + +TEXT ·popcntMaskSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s+8(FP), CX +TESTQ CX, CX +JZ popcntMaskSliceEnd +MOVQ m+24(FP), DI +popcntMaskSliceLoop: +MOVQ (DI), DX +NOTQ DX +ANDQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntMaskSliceLoop +popcntMaskSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntAndSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s+8(FP), CX +TESTQ CX, CX +JZ popcntAndSliceEnd +MOVQ m+24(FP), DI +popcntAndSliceLoop: +MOVQ (DI), DX +ANDQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntAndSliceLoop +popcntAndSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntOrSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s+8(FP), CX +TESTQ CX, CX +JZ popcntOrSliceEnd +MOVQ m+24(FP), DI +popcntOrSliceLoop: +MOVQ (DI), DX +ORQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntOrSliceLoop +popcntOrSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntXorSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s+8(FP), CX +TESTQ CX, CX +JZ popcntXorSliceEnd +MOVQ m+24(FP), DI +popcntXorSliceLoop: +MOVQ (DI), DX +XORQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntXorSliceLoop +popcntXorSliceEnd: +MOVQ AX, ret+48(FP) +RET diff --git a/Godeps/_workspace/src/github.com/willf/bitset/popcnt_asm.go b/Godeps/_workspace/src/github.com/willf/bitset/popcnt_asm.go new file mode 100644 index 00000000..9fe38ca4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/popcnt_asm.go @@ -0,0 +1,64 @@ +// +build amd64,!appengine + +package bitset + +//go:noescape + +func hasAsm() bool + +var useAsm = hasAsm() + +//go:noescape + +func popcntSliceAsm(s []uint64) uint64 + +//go:noescape + +func popcntMaskSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntAndSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntOrSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntXorSliceAsm(s, m []uint64) uint64 + +func popcntSlice(s []uint64) uint64 { + if useAsm { + return popcntSliceAsm(s) + } + return popcntSliceGo(s) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + if useAsm { + return popcntMaskSliceAsm(s, m) + } + return popcntMaskSliceGo(s, m) +} + +func popcntAndSlice(s, m []uint64) uint64 { + if useAsm { + return popcntAndSliceAsm(s, m) + } + return popcntAndSliceGo(s, m) +} + +func popcntOrSlice(s, m []uint64) uint64 { + if useAsm { + return popcntOrSliceAsm(s, m) + } + return popcntOrSliceGo(s, m) +} + +func popcntXorSlice(s, m []uint64) uint64 { + if useAsm { + return popcntXorSliceAsm(s, m) + } + return popcntXorSliceGo(s, m) +} diff --git a/Godeps/_workspace/src/github.com/willf/bitset/popcnt_generic.go b/Godeps/_workspace/src/github.com/willf/bitset/popcnt_generic.go new file mode 100644 index 00000000..6b21cb7a --- /dev/null +++ b/Godeps/_workspace/src/github.com/willf/bitset/popcnt_generic.go @@ -0,0 +1,23 @@ +// +build !amd64 appengine + +package bitset + +func popcntSlice(s []uint64) uint64 { + return popcntSliceGo(s) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + return popcntMaskSliceGo(s, m) +} + +func popcntAndSlice(s, m []uint64) uint64 { + return popcntAndSliceGo(s, m) +} + +func popcntOrSlice(s, m []uint64) uint64 { + return popcntOrSliceGo(s, m) +} + +func popcntXorSlice(s, m []uint64) uint64 { + return popcntXorSliceGo(s, m) +} diff --git a/Godeps/_workspace/src/golang.org/x/text/transform/examples_test.go b/Godeps/_workspace/src/golang.org/x/text/transform/examples_test.go new file mode 100644 index 00000000..2798e6b5 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/transform/examples_test.go @@ -0,0 +1,37 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transform_test + +import ( + "fmt" + "unicode" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/transform" + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/unicode/norm" +) + +func ExampleRemoveFunc() { + input := []byte(`tschüß; до свидания`) + + b := make([]byte, len(input)) + + t := transform.RemoveFunc(unicode.IsSpace) + n, _, _ := t.Transform(b, input, true) + fmt.Println(string(b[:n])) + + t = transform.RemoveFunc(func(r rune) bool { + return !unicode.Is(unicode.Latin, r) + }) + n, _, _ = t.Transform(b, input, true) + fmt.Println(string(b[:n])) + + n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true) + fmt.Println(string(b[:n])) + + // Output: + // tschüß;досвидания + // tschüß + // tschuß +} diff --git a/Godeps/_workspace/src/golang.org/x/text/transform/transform.go b/Godeps/_workspace/src/golang.org/x/text/transform/transform.go new file mode 100644 index 00000000..157ee789 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/transform/transform.go @@ -0,0 +1,616 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package transform provides reader and writer wrappers that transform the +// bytes passing through as well as various transformations. Example +// transformations provided by other packages include normalization and +// conversion between character sets. +package transform + +import ( + "bytes" + "errors" + "io" + "unicode/utf8" +) + +var ( + // ErrShortDst means that the destination buffer was too short to + // receive all of the transformed bytes. + ErrShortDst = errors.New("transform: short destination buffer") + + // ErrShortSrc means that the source buffer has insufficient data to + // complete the transformation. + ErrShortSrc = errors.New("transform: short source buffer") + + // errInconsistentByteCount means that Transform returned success (nil + // error) but also returned nSrc inconsistent with the src argument. + errInconsistentByteCount = errors.New("transform: inconsistent byte count returned") + + // errShortInternal means that an internal buffer is not large enough + // to make progress and the Transform operation must be aborted. + errShortInternal = errors.New("transform: short internal buffer") +) + +// Transformer transforms bytes. +type Transformer interface { + // Transform writes to dst the transformed bytes read from src, and + // returns the number of dst bytes written and src bytes read. The + // atEOF argument tells whether src represents the last bytes of the + // input. + // + // Callers should always process the nDst bytes produced and account + // for the nSrc bytes consumed before considering the error err. + // + // A nil error means that all of the transformed bytes (whether freshly + // transformed from src or left over from previous Transform calls) + // were written to dst. A nil error can be returned regardless of + // whether atEOF is true. If err is nil then nSrc must equal len(src); + // the converse is not necessarily true. + // + // ErrShortDst means that dst was too short to receive all of the + // transformed bytes. ErrShortSrc means that src had insufficient data + // to complete the transformation. If both conditions apply, then + // either error may be returned. Other than the error conditions listed + // here, implementations are free to report other errors that arise. + Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) + + // Reset resets the state and allows a Transformer to be reused. + Reset() +} + +// NopResetter can be embedded by implementations of Transformer to add a nop +// Reset method. +type NopResetter struct{} + +// Reset implements the Reset method of the Transformer interface. +func (NopResetter) Reset() {} + +// Reader wraps another io.Reader by transforming the bytes read. +type Reader struct { + r io.Reader + t Transformer + err error + + // dst[dst0:dst1] contains bytes that have been transformed by t but + // not yet copied out via Read. + dst []byte + dst0, dst1 int + + // src[src0:src1] contains bytes that have been read from r but not + // yet transformed through t. + src []byte + src0, src1 int + + // transformComplete is whether the transformation is complete, + // regardless of whether or not it was successful. + transformComplete bool +} + +const defaultBufSize = 4096 + +// NewReader returns a new Reader that wraps r by transforming the bytes read +// via t. It calls Reset on t. +func NewReader(r io.Reader, t Transformer) *Reader { + t.Reset() + return &Reader{ + r: r, + t: t, + dst: make([]byte, defaultBufSize), + src: make([]byte, defaultBufSize), + } +} + +// Read implements the io.Reader interface. +func (r *Reader) Read(p []byte) (int, error) { + n, err := 0, error(nil) + for { + // Copy out any transformed bytes and return the final error if we are done. + if r.dst0 != r.dst1 { + n = copy(p, r.dst[r.dst0:r.dst1]) + r.dst0 += n + if r.dst0 == r.dst1 && r.transformComplete { + return n, r.err + } + return n, nil + } else if r.transformComplete { + return 0, r.err + } + + // Try to transform some source bytes, or to flush the transformer if we + // are out of source bytes. We do this even if r.r.Read returned an error. + // As the io.Reader documentation says, "process the n > 0 bytes returned + // before considering the error". + if r.src0 != r.src1 || r.err != nil { + r.dst0 = 0 + r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF) + r.src0 += n + + switch { + case err == nil: + if r.src0 != r.src1 { + r.err = errInconsistentByteCount + } + // The Transform call was successful; we are complete if we + // cannot read more bytes into src. + r.transformComplete = r.err != nil + continue + case err == ErrShortDst && (r.dst1 != 0 || n != 0): + // Make room in dst by copying out, and try again. + continue + case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil: + // Read more bytes into src via the code below, and try again. + default: + r.transformComplete = true + // The reader error (r.err) takes precedence over the + // transformer error (err) unless r.err is nil or io.EOF. + if r.err == nil || r.err == io.EOF { + r.err = err + } + continue + } + } + + // Move any untransformed source bytes to the start of the buffer + // and read more bytes. + if r.src0 != 0 { + r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1]) + } + n, r.err = r.r.Read(r.src[r.src1:]) + r.src1 += n + } +} + +// TODO: implement ReadByte (and ReadRune??). + +// Writer wraps another io.Writer by transforming the bytes read. +// The user needs to call Close to flush unwritten bytes that may +// be buffered. +type Writer struct { + w io.Writer + t Transformer + dst []byte + + // src[:n] contains bytes that have not yet passed through t. + src []byte + n int +} + +// NewWriter returns a new Writer that wraps w by transforming the bytes written +// via t. It calls Reset on t. +func NewWriter(w io.Writer, t Transformer) *Writer { + t.Reset() + return &Writer{ + w: w, + t: t, + dst: make([]byte, defaultBufSize), + src: make([]byte, defaultBufSize), + } +} + +// Write implements the io.Writer interface. If there are not enough +// bytes available to complete a Transform, the bytes will be buffered +// for the next write. Call Close to convert the remaining bytes. +func (w *Writer) Write(data []byte) (n int, err error) { + src := data + if w.n > 0 { + // Append bytes from data to the last remainder. + // TODO: limit the amount copied on first try. + n = copy(w.src[w.n:], data) + w.n += n + src = w.src[:w.n] + } + for { + nDst, nSrc, err := w.t.Transform(w.dst, src, false) + if _, werr := w.w.Write(w.dst[:nDst]); werr != nil { + return n, werr + } + src = src[nSrc:] + if w.n > 0 && len(src) <= n { + // Enough bytes from w.src have been consumed. We make src point + // to data instead to reduce the copying. + w.n = 0 + n -= len(src) + src = data[n:] + if n < len(data) && (err == nil || err == ErrShortSrc) { + continue + } + } else { + n += nSrc + } + switch { + case err == ErrShortDst && (nDst > 0 || nSrc > 0): + case err == ErrShortSrc && len(src) < len(w.src): + m := copy(w.src, src) + // If w.n > 0, bytes from data were already copied to w.src and n + // was already set to the number of bytes consumed. + if w.n == 0 { + n += m + } + w.n = m + return n, nil + case err == nil && w.n > 0: + return n, errInconsistentByteCount + default: + return n, err + } + } +} + +// Close implements the io.Closer interface. +func (w *Writer) Close() error { + for src := w.src[:w.n]; len(src) > 0; { + nDst, nSrc, err := w.t.Transform(w.dst, src, true) + if nDst == 0 { + return err + } + if _, werr := w.w.Write(w.dst[:nDst]); werr != nil { + return werr + } + if err != ErrShortDst { + return err + } + src = src[nSrc:] + } + return nil +} + +type nop struct{ NopResetter } + +func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := copy(dst, src) + if n < len(src) { + err = ErrShortDst + } + return n, n, err +} + +type discard struct{ NopResetter } + +func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + return 0, len(src), nil +} + +var ( + // Discard is a Transformer for which all Transform calls succeed + // by consuming all bytes and writing nothing. + Discard Transformer = discard{} + + // Nop is a Transformer that copies src to dst. + Nop Transformer = nop{} +) + +// chain is a sequence of links. A chain with N Transformers has N+1 links and +// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst +// buffers given to chain.Transform and the middle N-1 buffers are intermediate +// buffers owned by the chain. The i'th link transforms bytes from the i'th +// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer +// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N). +type chain struct { + link []link + err error + // errStart is the index at which the error occurred plus 1. Processing + // errStart at this level at the next call to Transform. As long as + // errStart > 0, chain will not consume any more source bytes. + errStart int +} + +func (c *chain) fatalError(errIndex int, err error) { + if i := errIndex + 1; i > c.errStart { + c.errStart = i + c.err = err + } +} + +type link struct { + t Transformer + // b[p:n] holds the bytes to be transformed by t. + b []byte + p int + n int +} + +func (l *link) src() []byte { + return l.b[l.p:l.n] +} + +func (l *link) dst() []byte { + return l.b[l.n:] +} + +// Chain returns a Transformer that applies t in sequence. +func Chain(t ...Transformer) Transformer { + if len(t) == 0 { + return nop{} + } + c := &chain{link: make([]link, len(t)+1)} + for i, tt := range t { + c.link[i].t = tt + } + // Allocate intermediate buffers. + b := make([][defaultBufSize]byte, len(t)-1) + for i := range b { + c.link[i+1].b = b[i][:] + } + return c +} + +// Reset resets the state of Chain. It calls Reset on all the Transformers. +func (c *chain) Reset() { + for i, l := range c.link { + if l.t != nil { + l.t.Reset() + } + c.link[i].p, c.link[i].n = 0, 0 + } +} + +// Transform applies the transformers of c in sequence. +func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + // Set up src and dst in the chain. + srcL := &c.link[0] + dstL := &c.link[len(c.link)-1] + srcL.b, srcL.p, srcL.n = src, 0, len(src) + dstL.b, dstL.n = dst, 0 + var lastFull, needProgress bool // for detecting progress + + // i is the index of the next Transformer to apply, for i in [low, high]. + // low is the lowest index for which c.link[low] may still produce bytes. + // high is the highest index for which c.link[high] has a Transformer. + // The error returned by Transform determines whether to increase or + // decrease i. We try to completely fill a buffer before converting it. + for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; { + in, out := &c.link[i], &c.link[i+1] + nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i) + out.n += nDst + in.p += nSrc + if i > 0 && in.p == in.n { + in.p, in.n = 0, 0 + } + needProgress, lastFull = lastFull, false + switch err0 { + case ErrShortDst: + // Process the destination buffer next. Return if we are already + // at the high index. + if i == high { + return dstL.n, srcL.p, ErrShortDst + } + if out.n != 0 { + i++ + // If the Transformer at the next index is not able to process any + // source bytes there is nothing that can be done to make progress + // and the bytes will remain unprocessed. lastFull is used to + // detect this and break out of the loop with a fatal error. + lastFull = true + continue + } + // The destination buffer was too small, but is completely empty. + // Return a fatal error as this transformation can never complete. + c.fatalError(i, errShortInternal) + case ErrShortSrc: + if i == 0 { + // Save ErrShortSrc in err. All other errors take precedence. + err = ErrShortSrc + break + } + // Source bytes were depleted before filling up the destination buffer. + // Verify we made some progress, move the remaining bytes to the errStart + // and try to get more source bytes. + if needProgress && nSrc == 0 || in.n-in.p == len(in.b) { + // There were not enough source bytes to proceed while the source + // buffer cannot hold any more bytes. Return a fatal error as this + // transformation can never complete. + c.fatalError(i, errShortInternal) + break + } + // in.b is an internal buffer and we can make progress. + in.p, in.n = 0, copy(in.b, in.src()) + fallthrough + case nil: + // if i == low, we have depleted the bytes at index i or any lower levels. + // In that case we increase low and i. In all other cases we decrease i to + // fetch more bytes before proceeding to the next index. + if i > low { + i-- + continue + } + default: + c.fatalError(i, err0) + } + // Exhausted level low or fatal error: increase low and continue + // to process the bytes accepted so far. + i++ + low = i + } + + // If c.errStart > 0, this means we found a fatal error. We will clear + // all upstream buffers. At this point, no more progress can be made + // downstream, as Transform would have bailed while handling ErrShortDst. + if c.errStart > 0 { + for i := 1; i < c.errStart; i++ { + c.link[i].p, c.link[i].n = 0, 0 + } + err, c.errStart, c.err = c.err, 0, nil + } + return dstL.n, srcL.p, err +} + +// RemoveFunc returns a Transformer that removes from the input all runes r for +// which f(r) is true. Illegal bytes in the input are replaced by RuneError. +func RemoveFunc(f func(r rune) bool) Transformer { + return removeF(f) +} + +type removeF func(r rune) bool + +func (removeF) Reset() {} + +// Transform implements the Transformer interface. +func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] { + + if r = rune(src[0]); r < utf8.RuneSelf { + sz = 1 + } else { + r, sz = utf8.DecodeRune(src) + + if sz == 1 { + // Invalid rune. + if !atEOF && !utf8.FullRune(src) { + err = ErrShortSrc + break + } + // We replace illegal bytes with RuneError. Not doing so might + // otherwise turn a sequence of invalid UTF-8 into valid UTF-8. + // The resulting byte sequence may subsequently contain runes + // for which t(r) is true that were passed unnoticed. + if !t(r) { + if nDst+3 > len(dst) { + err = ErrShortDst + break + } + nDst += copy(dst[nDst:], "\uFFFD") + } + nSrc++ + continue + } + } + + if !t(r) { + if nDst+sz > len(dst) { + err = ErrShortDst + break + } + nDst += copy(dst[nDst:], src[:sz]) + } + nSrc += sz + } + return +} + +// grow returns a new []byte that is longer than b, and copies the first n bytes +// of b to the start of the new slice. +func grow(b []byte, n int) []byte { + m := len(b) + if m <= 256 { + m *= 2 + } else { + m += m >> 1 + } + buf := make([]byte, m) + copy(buf, b[:n]) + return buf +} + +const initialBufSize = 128 + +// String returns a string with the result of converting s[:n] using t, where +// n <= len(s). If err == nil, n will be len(s). It calls Reset on t. +func String(t Transformer, s string) (result string, n int, err error) { + if s == "" { + return "", 0, nil + } + + t.Reset() + + // Allocate only once. Note that both dst and src escape when passed to + // Transform. + buf := [2 * initialBufSize]byte{} + dst := buf[:initialBufSize:initialBufSize] + src := buf[initialBufSize : 2*initialBufSize] + + // Avoid allocation if the transformed string is identical to the original. + // After this loop, pDst will point to the furthest point in s for which it + // could be detected that t gives equal results, src[:nSrc] will + // indicated the last processed chunk of s for which the output is not equal + // and dst[:nDst] will be the transform of this chunk. + var nDst, nSrc int + pDst := 0 // Used as index in both src and dst in this loop. + for { + n := copy(src, s[pDst:]) + nDst, nSrc, err = t.Transform(dst, src[:n], pDst+n == len(s)) + + // Note 1: we will not enter the loop with pDst == len(s) and we will + // not end the loop with it either. So if nSrc is 0, this means there is + // some kind of error from which we cannot recover given the current + // buffer sizes. We will give up in this case. + // Note 2: it is not entirely correct to simply do a bytes.Equal as + // a Transformer may buffer internally. It will work in most cases, + // though, and no harm is done if it doesn't work. + // TODO: let transformers implement an optional Spanner interface, akin + // to norm's QuickSpan. This would even allow us to avoid any allocation. + if nSrc == 0 || !bytes.Equal(dst[:nDst], src[:nSrc]) { + break + } + + if pDst += nDst; pDst == len(s) { + return s, pDst, nil + } + } + + // Move the bytes seen so far to dst. + pSrc := pDst + nSrc + if pDst+nDst <= initialBufSize { + copy(dst[pDst:], dst[:nDst]) + } else { + b := make([]byte, len(s)+nDst-nSrc) + copy(b[pDst:], dst[:nDst]) + dst = b + } + copy(dst, s[:pDst]) + pDst += nDst + + if err != nil && err != ErrShortDst && err != ErrShortSrc { + return string(dst[:pDst]), pSrc, err + } + + // Complete the string with the remainder. + for { + n := copy(src, s[pSrc:]) + nDst, nSrc, err = t.Transform(dst[pDst:], src[:n], pSrc+n == len(s)) + pDst += nDst + pSrc += nSrc + + switch err { + case nil: + if pSrc == len(s) { + return string(dst[:pDst]), pSrc, nil + } + case ErrShortDst: + // Do not grow as long as we can make progress. This may avoid + // excessive allocations. + if nDst == 0 { + dst = grow(dst, pDst) + } + case ErrShortSrc: + if nSrc == 0 { + src = grow(src, 0) + } + default: + return string(dst[:pDst]), pSrc, err + } + } +} + +// Bytes returns a new byte slice with the result of converting b[:n] using t, +// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t. +func Bytes(t Transformer, b []byte) (result []byte, n int, err error) { + t.Reset() + dst := make([]byte, len(b)) + pDst, pSrc := 0, 0 + for { + nDst, nSrc, err := t.Transform(dst[pDst:], b[pSrc:], true) + pDst += nDst + pSrc += nSrc + if err != ErrShortDst { + return dst[:pDst], pSrc, err + } + + // Grow the destination buffer, but do not grow as long as we can make + // progress. This may avoid excessive allocations. + if nDst == 0 { + dst = grow(dst, pDst) + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/transform/transform_test.go b/Godeps/_workspace/src/golang.org/x/text/transform/transform_test.go new file mode 100644 index 00000000..b463f4f1 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/transform/transform_test.go @@ -0,0 +1,1082 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transform + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "strconv" + "strings" + "testing" + "time" + "unicode/utf8" +) + +type lowerCaseASCII struct{ NopResetter } + +func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + dst[i] = c + } + return n, n, err +} + +var errYouMentionedX = errors.New("you mentioned X") + +type dontMentionX struct{ NopResetter } + +func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if c == 'X' { + return i, i, errYouMentionedX + } + dst[i] = c + } + return n, n, err +} + +// doublerAtEOF is a strange Transformer that transforms "this" to "tthhiiss", +// but only if atEOF is true. +type doublerAtEOF struct{ NopResetter } + +func (doublerAtEOF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if !atEOF { + return 0, 0, ErrShortSrc + } + for i, c := range src { + if 2*i+2 >= len(dst) { + return 2 * i, i, ErrShortDst + } + dst[2*i+0] = c + dst[2*i+1] = c + } + return 2 * len(src), len(src), nil +} + +// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb" +// is encoded as "2a10b". The decoding is assumed to not contain any numbers. + +type rleDecode struct{ NopResetter } + +func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { +loop: + for len(src) > 0 { + n := 0 + for i, c := range src { + if '0' <= c && c <= '9' { + n = 10*n + int(c-'0') + continue + } + if i == 0 { + return nDst, nSrc, errors.New("rleDecode: bad input") + } + if n > len(dst) { + return nDst, nSrc, ErrShortDst + } + for j := 0; j < n; j++ { + dst[j] = c + } + dst, src = dst[n:], src[i+1:] + nDst, nSrc = nDst+n, nSrc+i+1 + continue loop + } + if atEOF { + return nDst, nSrc, errors.New("rleDecode: bad input") + } + return nDst, nSrc, ErrShortSrc + } + return nDst, nSrc, nil +} + +type rleEncode struct { + NopResetter + + // allowStutter means that "xxxxxxxx" can be encoded as "5x3x" + // instead of always as "8x". + allowStutter bool +} + +func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + for len(src) > 0 { + n, c0 := len(src), src[0] + for i, c := range src[1:] { + if c != c0 { + n = i + 1 + break + } + } + if n == len(src) && !atEOF && !e.allowStutter { + return nDst, nSrc, ErrShortSrc + } + s := strconv.Itoa(n) + if len(s) >= len(dst) { + return nDst, nSrc, ErrShortDst + } + copy(dst, s) + dst[len(s)] = c0 + dst, src = dst[len(s)+1:], src[n:] + nDst, nSrc = nDst+len(s)+1, nSrc+n + } + return nDst, nSrc, nil +} + +// trickler consumes all input bytes, but writes a single byte at a time to dst. +type trickler []byte + +func (t *trickler) Reset() { + *t = nil +} + +func (t *trickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + *t = append(*t, src...) + if len(*t) == 0 { + return 0, 0, nil + } + if len(dst) == 0 { + return 0, len(src), ErrShortDst + } + dst[0] = (*t)[0] + *t = (*t)[1:] + if len(*t) > 0 { + err = ErrShortDst + } + return 1, len(src), err +} + +// delayedTrickler is like trickler, but delays writing output to dst. This is +// highly unlikely to be relevant in practice, but it seems like a good idea +// to have some tolerance as long as progress can be detected. +type delayedTrickler []byte + +func (t *delayedTrickler) Reset() { + *t = nil +} +func (t *delayedTrickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if len(*t) > 0 && len(dst) > 0 { + dst[0] = (*t)[0] + *t = (*t)[1:] + nDst = 1 + } + *t = append(*t, src...) + if len(*t) > 0 { + err = ErrShortDst + } + return nDst, len(src), err +} + +type testCase struct { + desc string + t Transformer + src string + dstSize int + srcSize int + ioSize int + wantStr string + wantErr error + wantIter int // number of iterations taken; 0 means we don't care. +} + +func (t testCase) String() string { + return tstr(t.t) + "; " + t.desc +} + +func tstr(t Transformer) string { + if stringer, ok := t.(fmt.Stringer); ok { + return stringer.String() + } + s := fmt.Sprintf("%T", t) + return s[1+strings.Index(s, "."):] +} + +func (c chain) String() string { + buf := &bytes.Buffer{} + buf.WriteString("Chain(") + for i, l := range c.link[:len(c.link)-1] { + if i != 0 { + fmt.Fprint(buf, ", ") + } + buf.WriteString(tstr(l.t)) + } + buf.WriteString(")") + return buf.String() +} + +var testCases = []testCase{ + { + desc: "empty", + t: lowerCaseASCII{}, + src: "", + dstSize: 100, + srcSize: 100, + wantStr: "", + }, + + { + desc: "basic", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small dst", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small src", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "small buffers", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "very small buffers", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 1, + srcSize: 1, + wantStr: "hello world.", + }, + + { + desc: "basic", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 100, + srcSize: 100, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "small buffers", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 10, + srcSize: 10, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "very small buffers", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 1, + srcSize: 1, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "only transform at EOF", + t: doublerAtEOF{}, + src: "this", + dstSize: 100, + srcSize: 100, + wantStr: "tthhiiss", + }, + + { + desc: "basic", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 100, + wantStr: "abbcccddddddddddeeeeeeeeeeeg", + }, + + { + desc: "long", + t: rleDecode{}, + src: "12a23b34c45d56e99z", + dstSize: 100, + srcSize: 100, + wantStr: strings.Repeat("a", 12) + + strings.Repeat("b", 23) + + strings.Repeat("c", 34) + + strings.Repeat("d", 45) + + strings.Repeat("e", 56) + + strings.Repeat("z", 99), + }, + + { + desc: "tight buffers", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 11, + srcSize: 3, + wantStr: "abbcccddddddddddeeeeeeeeeeeg", + }, + + { + desc: "short dst", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 10, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: ErrShortDst, + }, + + { + desc: "short src", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 11, + srcSize: 2, + ioSize: 2, + wantStr: "abbccc", + wantErr: ErrShortSrc, + }, + + { + desc: "basic", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b3c10d11e1g", + }, + + { + desc: "long", + t: rleEncode{}, + src: strings.Repeat("a", 12) + + strings.Repeat("b", 23) + + strings.Repeat("c", 34) + + strings.Repeat("d", 45) + + strings.Repeat("e", 56) + + strings.Repeat("z", 99), + dstSize: 100, + srcSize: 100, + wantStr: "12a23b34c45d56e99z", + }, + + { + desc: "tight buffers", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 12, + wantStr: "1a2b3c10d11e1g", + }, + + { + desc: "short dst", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 2, + srcSize: 12, + wantStr: "1a2b3c", + wantErr: ErrShortDst, + }, + + { + desc: "short src", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 11, + ioSize: 11, + wantStr: "1a2b3c10d", + wantErr: ErrShortSrc, + }, + + { + desc: "allowStutter = false", + t: rleEncode{allowStutter: false}, + src: "aaaabbbbbbbbccccddddd", + dstSize: 10, + srcSize: 10, + wantStr: "4a8b4c5d", + }, + + { + desc: "allowStutter = true", + t: rleEncode{allowStutter: true}, + src: "aaaabbbbbbbbccccddddd", + dstSize: 10, + srcSize: 10, + ioSize: 10, + wantStr: "4a6b2b4c4d1d", + }, + + { + desc: "trickler", + t: &trickler{}, + src: "abcdefghijklm", + dstSize: 3, + srcSize: 15, + wantStr: "abcdefghijklm", + }, + + { + desc: "delayedTrickler", + t: &delayedTrickler{}, + src: "abcdefghijklm", + dstSize: 3, + srcSize: 15, + wantStr: "abcdefghijklm", + }, +} + +func TestReader(t *testing.T) { + for _, tc := range testCases { + r := NewReader(strings.NewReader(tc.src), tc.t) + // Differently sized dst and src buffers are not part of the + // exported API. We override them manually. + r.dst = make([]byte, tc.dstSize) + r.src = make([]byte, tc.srcSize) + got, err := ioutil.ReadAll(r) + str := string(got) + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:\ngot %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr) + } + } +} + +func TestWriter(t *testing.T) { + tests := append(testCases, chainTests()...) + for _, tc := range tests { + sizes := []int{1, 2, 3, 4, 5, 10, 100, 1000} + if tc.ioSize > 0 { + sizes = []int{tc.ioSize} + } + for _, sz := range sizes { + bb := &bytes.Buffer{} + w := NewWriter(bb, tc.t) + // Differently sized dst and src buffers are not part of the + // exported API. We override them manually. + w.dst = make([]byte, tc.dstSize) + w.src = make([]byte, tc.srcSize) + src := make([]byte, sz) + var err error + for b := tc.src; len(b) > 0 && err == nil; { + n := copy(src, b) + b = b[n:] + m := 0 + m, err = w.Write(src[:n]) + if m != n && err == nil { + t.Errorf("%s:%d: did not consume all bytes %d < %d", tc, sz, m, n) + } + } + if err == nil { + err = w.Close() + } + str := bb.String() + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:%d:\ngot %q, %v\nwant %q, %v", tc, sz, str, err, tc.wantStr, tc.wantErr) + } + } + } +} + +func TestNop(t *testing.T) { + testCases := []struct { + str string + dstSize int + err error + }{ + {"", 0, nil}, + {"", 10, nil}, + {"a", 0, ErrShortDst}, + {"a", 1, nil}, + {"a", 10, nil}, + } + for i, tc := range testCases { + dst := make([]byte, tc.dstSize) + nDst, nSrc, err := Nop.Transform(dst, []byte(tc.str), true) + want := tc.str + if tc.dstSize < len(want) { + want = want[:tc.dstSize] + } + if got := string(dst[:nDst]); got != want || err != tc.err || nSrc != nDst { + t.Errorf("%d:\ngot %q, %d, %v\nwant %q, %d, %v", i, got, nSrc, err, want, nDst, tc.err) + } + } +} + +func TestDiscard(t *testing.T) { + testCases := []struct { + str string + dstSize int + }{ + {"", 0}, + {"", 10}, + {"a", 0}, + {"ab", 10}, + } + for i, tc := range testCases { + nDst, nSrc, err := Discard.Transform(make([]byte, tc.dstSize), []byte(tc.str), true) + if nDst != 0 || nSrc != len(tc.str) || err != nil { + t.Errorf("%d:\ngot %q, %d, %v\nwant 0, %d, nil", i, nDst, nSrc, err, len(tc.str)) + } + } +} + +// mkChain creates a Chain transformer. x must be alternating between transformer +// and bufSize, like T, (sz, T)* +func mkChain(x ...interface{}) *chain { + t := []Transformer{} + for i := 0; i < len(x); i += 2 { + t = append(t, x[i].(Transformer)) + } + c := Chain(t...).(*chain) + for i, j := 1, 1; i < len(x); i, j = i+2, j+1 { + c.link[j].b = make([]byte, x[i].(int)) + } + return c +} + +func chainTests() []testCase { + return []testCase{ + { + desc: "nil error", + t: mkChain(rleEncode{}, 100, lowerCaseASCII{}), + src: "ABB", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b", + wantErr: nil, + wantIter: 1, + }, + + { + desc: "short dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}), + src: "1a2b3c10d11e0f1g", + dstSize: 10, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: ErrShortDst, + }, + + { + desc: "short internal dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop), + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: errShortInternal, + }, + + { + desc: "short internal dst buffer from input", + t: mkChain(rleDecode{}, 10, Nop), + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: errShortInternal, + }, + + { + desc: "empty short internal dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop), + src: "4a7b11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "aaaabbbbbbb", + wantErr: errShortInternal, + }, + + { + desc: "empty short internal dst buffer from input", + t: mkChain(rleDecode{}, 10, Nop), + src: "4a7b11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "aaaabbbbbbb", + wantErr: errShortInternal, + }, + + { + desc: "short internal src buffer after full dst buffer", + t: mkChain(Nop, 5, rleEncode{}, 10, Nop), + src: "cccccddddd", + dstSize: 100, + srcSize: 100, + wantStr: "", + wantErr: errShortInternal, + wantIter: 1, + }, + + { + desc: "short internal src buffer after short dst buffer; test lastFull", + t: mkChain(rleDecode{}, 5, rleEncode{}, 4, Nop), + src: "2a1b4c6d", + dstSize: 100, + srcSize: 100, + wantStr: "2a1b", + wantErr: errShortInternal, + }, + + { + desc: "short internal src buffer after successful complete fill", + t: mkChain(Nop, 3, rleDecode{}), + src: "123a4b", + dstSize: 4, + srcSize: 3, + wantStr: "", + wantErr: errShortInternal, + wantIter: 1, + }, + + { + desc: "short internal src buffer after short dst buffer; test lastFull", + t: mkChain(rleDecode{}, 5, rleEncode{}), + src: "2a1b4c6d", + dstSize: 4, + srcSize: 100, + wantStr: "2a1b", + wantErr: errShortInternal, + }, + + { + desc: "short src buffer", + t: mkChain(rleEncode{}, 5, Nop), + src: "abbcccddddeeeee", + dstSize: 4, + srcSize: 4, + ioSize: 4, + wantStr: "1a2b3c", + wantErr: ErrShortSrc, + }, + + { + desc: "process all in one go", + t: mkChain(rleEncode{}, 5, Nop), + src: "abbcccddddeeeeeffffff", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b3c4d5e6f", + wantErr: nil, + wantIter: 1, + }, + + { + desc: "complete processing downstream after error", + t: mkChain(dontMentionX{}, 2, rleDecode{}, 5, Nop), + src: "3a4b5eX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "aaabbbbeeeee", + wantErr: errYouMentionedX, + }, + + { + desc: "return downstream fatal errors first (followed by short dst)", + t: mkChain(dontMentionX{}, 8, rleDecode{}, 4, Nop), + src: "3a4b5eX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "aaabbbb", + wantErr: errShortInternal, + }, + + { + desc: "return downstream fatal errors first (followed by short src)", + t: mkChain(dontMentionX{}, 5, Nop, 1, rleDecode{}), + src: "1a5bX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "", + wantErr: errShortInternal, + }, + + { + desc: "short internal", + t: mkChain(Nop, 11, rleEncode{}, 3, Nop), + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 100, + wantStr: "1a2b3c10d", + wantErr: errShortInternal, + }, + } +} + +func doTransform(tc testCase) (res string, iter int, err error) { + tc.t.Reset() + dst := make([]byte, tc.dstSize) + out, in := make([]byte, 0, 2*len(tc.src)), []byte(tc.src) + for { + iter++ + src, atEOF := in, true + if len(src) > tc.srcSize { + src, atEOF = src[:tc.srcSize], false + } + nDst, nSrc, err := tc.t.Transform(dst, src, atEOF) + out = append(out, dst[:nDst]...) + in = in[nSrc:] + switch { + case err == nil && len(in) != 0: + case err == ErrShortSrc && nSrc > 0: + case err == ErrShortDst && (nDst > 0 || nSrc > 0): + default: + return string(out), iter, err + } + } +} + +func TestChain(t *testing.T) { + if c, ok := Chain().(nop); !ok { + t.Errorf("empty chain: %v; want Nop", c) + } + + // Test Chain for a single Transformer. + for _, tc := range testCases { + tc.t = Chain(tc.t) + str, _, err := doTransform(tc) + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:\ngot %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr) + } + } + + tests := chainTests() + sizes := []int{1, 2, 3, 4, 5, 7, 10, 100, 1000} + addTest := func(tc testCase, t *chain) { + if t.link[0].t != tc.t && tc.wantErr == ErrShortSrc { + tc.wantErr = errShortInternal + } + if t.link[len(t.link)-2].t != tc.t && tc.wantErr == ErrShortDst { + tc.wantErr = errShortInternal + } + tc.t = t + tests = append(tests, tc) + } + for _, tc := range testCases { + for _, sz := range sizes { + tt := tc + tt.dstSize = sz + addTest(tt, mkChain(tc.t, tc.dstSize, Nop)) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 2, Nop)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop)) + if sz >= tc.dstSize && (tc.wantErr != ErrShortDst || sz == tc.dstSize) { + addTest(tt, mkChain(Nop, tc.srcSize, tc.t)) + addTest(tt, mkChain(Nop, 100, Nop, tc.srcSize, tc.t)) + } + } + } + for _, tc := range testCases { + tt := tc + tt.dstSize = 1 + tt.wantStr = "" + addTest(tt, mkChain(tc.t, tc.dstSize, Discard)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Discard)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, tc.dstSize, Discard)) + } + for _, tc := range testCases { + tt := tc + tt.dstSize = 100 + tt.wantStr = strings.Replace(tc.src, "0f", "", -1) + // Chain encoders and decoders. + if _, ok := tc.t.(rleEncode); ok && tc.wantErr == nil { + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 1000, rleDecode{})) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, tc.dstSize, rleDecode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{})) + // decoding needs larger destinations + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, rleDecode{}, 100, Nop)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}, 100, Nop)) + } else if _, ok := tc.t.(rleDecode); ok && tc.wantErr == nil { + // The internal buffer size may need to be the sum of the maximum segment + // size of the two encoders! + addTest(tt, mkChain(tc.t, 2*tc.dstSize, rleEncode{})) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 101, rleEncode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleEncode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 200, rleEncode{}, 100, Nop)) + } + } + for _, tc := range tests { + str, iter, err := doTransform(tc) + mi := tc.wantIter != 0 && tc.wantIter != iter + if str != tc.wantStr || err != tc.wantErr || mi { + t.Errorf("%s:\ngot iter:%d, %q, %v\nwant iter:%d, %q, %v", tc, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr) + } + break + } +} + +func TestRemoveFunc(t *testing.T) { + filter := RemoveFunc(func(r rune) bool { + return strings.IndexRune("ab\u0300\u1234,", r) != -1 + }) + tests := []testCase{ + { + src: ",", + wantStr: "", + }, + + { + src: "c", + wantStr: "c", + }, + + { + src: "\u2345", + wantStr: "\u2345", + }, + + { + src: "tschüß", + wantStr: "tschüß", + }, + + { + src: ",до,свидания,", + wantStr: "досвидания", + }, + + { + src: "a\xbd\xb2=\xbc ⌘", + wantStr: "\uFFFD\uFFFD=\uFFFD ⌘", + }, + + { + // If we didn't replace illegal bytes with RuneError, the result + // would be \u0300 or the code would need to be more complex. + src: "\xcc\u0300\x80", + wantStr: "\uFFFD\uFFFD", + }, + + { + src: "\xcc\u0300\x80", + dstSize: 3, + wantStr: "\uFFFD\uFFFD", + wantIter: 2, + }, + + { + // Test a long buffer greater than the internal buffer size + src: "hello\xcc\xcc\xccworld", + srcSize: 13, + wantStr: "hello\uFFFD\uFFFD\uFFFDworld", + wantIter: 1, + }, + + { + src: "\u2345", + dstSize: 2, + wantStr: "", + wantErr: ErrShortDst, + }, + + { + src: "\xcc", + dstSize: 2, + wantStr: "", + wantErr: ErrShortDst, + }, + + { + src: "\u0300", + dstSize: 2, + srcSize: 1, + wantStr: "", + wantErr: ErrShortSrc, + }, + + { + t: RemoveFunc(func(r rune) bool { + return r == utf8.RuneError + }), + src: "\xcc\u0300\x80", + wantStr: "\u0300", + }, + } + + for _, tc := range tests { + tc.desc = tc.src + if tc.t == nil { + tc.t = filter + } + if tc.dstSize == 0 { + tc.dstSize = 100 + } + if tc.srcSize == 0 { + tc.srcSize = 100 + } + str, iter, err := doTransform(tc) + mi := tc.wantIter != 0 && tc.wantIter != iter + if str != tc.wantStr || err != tc.wantErr || mi { + t.Errorf("%+q:\ngot iter:%d, %+q, %v\nwant iter:%d, %+q, %v", tc.src, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr) + } + + tc.src = str + idem, _, _ := doTransform(tc) + if str != idem { + t.Errorf("%+q: found %+q; want %+q", tc.src, idem, str) + } + } +} + +func testString(t *testing.T, f func(Transformer, string) (string, int, error)) { + for _, tt := range append(testCases, chainTests()...) { + if tt.desc == "allowStutter = true" { + // We don't have control over the buffer size, so we eliminate tests + // that depend on a specific buffer size being set. + continue + } + if tt.wantErr == ErrShortDst || tt.wantErr == ErrShortSrc { + // The result string will be different. + continue + } + got, n, err := f(tt.t, tt.src) + if tt.wantErr != err { + t.Errorf("%s:error: got %v; want %v", tt.desc, err, tt.wantErr) + } + if got, want := err == nil, n == len(tt.src); got != want { + t.Errorf("%s:n: got %v; want %v", tt.desc, got, want) + } + if got != tt.wantStr { + t.Errorf("%s:string: got %q; want %q", tt.desc, got, tt.wantStr) + } + } +} + +func TestBytes(t *testing.T) { + testString(t, func(z Transformer, s string) (string, int, error) { + b, n, err := Bytes(z, []byte(s)) + return string(b), n, err + }) +} + +func TestString(t *testing.T) { + testString(t, String) + + // Overrun the internal destination buffer. + for i, s := range []string{ + strings.Repeat("a", initialBufSize-1), + strings.Repeat("a", initialBufSize+0), + strings.Repeat("a", initialBufSize+1), + strings.Repeat("A", initialBufSize-1), + strings.Repeat("A", initialBufSize+0), + strings.Repeat("A", initialBufSize+1), + strings.Repeat("A", 2*initialBufSize-1), + strings.Repeat("A", 2*initialBufSize+0), + strings.Repeat("A", 2*initialBufSize+1), + strings.Repeat("a", initialBufSize-2) + "A", + strings.Repeat("a", initialBufSize-1) + "A", + strings.Repeat("a", initialBufSize+0) + "A", + strings.Repeat("a", initialBufSize+1) + "A", + } { + got, _, _ := String(lowerCaseASCII{}, s) + if want := strings.ToLower(s); got != want { + t.Errorf("%d:dst buffer test: got %s (%d); want %s (%d)", i, got, len(got), want, len(want)) + } + } + + // Overrun the internal source buffer. + for i, s := range []string{ + strings.Repeat("a", initialBufSize-1), + strings.Repeat("a", initialBufSize+0), + strings.Repeat("a", initialBufSize+1), + strings.Repeat("a", 2*initialBufSize+1), + strings.Repeat("a", 2*initialBufSize+0), + strings.Repeat("a", 2*initialBufSize+1), + } { + got, _, _ := String(rleEncode{}, s) + if want := fmt.Sprintf("%da", len(s)); got != want { + t.Errorf("%d:src buffer test: got %s (%d); want %s (%d)", i, got, len(got), want, len(want)) + } + } + + // Test allocations for non-changing strings. + // Note we still need to allocate a single buffer. + for i, s := range []string{ + "", + "123", + "123456789", + strings.Repeat("a", initialBufSize), + strings.Repeat("a", 10*initialBufSize), + } { + if n := testing.AllocsPerRun(5, func() { String(&lowerCaseASCII{}, s) }); n > 1 { + t.Errorf("%d: #allocs was %f; want 1", i, n) + } + } +} + +// TestBytesAllocation tests that buffer growth stays limited with the trickler +// transformer, which behaves oddly but within spec. In case buffer growth is +// not correctly handled, the test will either panic with a failed allocation or +// thrash. To ensure the tests terminate under the last condition, we time out +// after some sufficiently long period of time. +func TestBytesAllocation(t *testing.T) { + done := make(chan bool) + go func() { + in := bytes.Repeat([]byte{'a'}, 1000) + tr := trickler(make([]byte, 1)) + Bytes(&tr, in) + done <- true + }() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Error("time out, likely due to excessive allocation") + } +} + +// TestStringAllocation tests that buffer growth stays limited with the trickler +// transformer, which behaves oddly but within spec. In case buffer growth is +// not correctly handled, the test will either panic with a failed allocation or +// thrash. To ensure the tests terminate under the last condition, we time out +// after some sufficiently long period of time. +func TestStringAllocation(t *testing.T) { + done := make(chan bool) + go func() { + in := strings.Repeat("a", 1000) + tr := trickler(make([]byte, 1)) + String(&tr, in) + done <- true + }() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Error("time out, likely due to excessive allocation") + } +} + +func BenchmarkStringLower(b *testing.B) { + in := strings.Repeat("a", 4096) + for i := 0; i < b.N; i++ { + String(&lowerCaseASCII{}, in) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/Makefile b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/Makefile new file mode 100644 index 00000000..b4f5d359 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/Makefile @@ -0,0 +1,23 @@ +# Copyright 2011 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +maketables: maketables.go triegen.go + go build $^ + +normregtest: normregtest.go + go build $^ + +tables: maketables + ./maketables > tables.go + gofmt -w tables.go + +# Downloads from www.unicode.org, so not part +# of standard test scripts. +test: testtables regtest + +testtables: maketables + ./maketables -test > data_test.go && go test -tags=test + +regtest: normregtest + ./normregtest diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition.go new file mode 100644 index 00000000..d17b278a --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition.go @@ -0,0 +1,514 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "unicode/utf8" + +const ( + maxNonStarters = 30 + // The maximum number of characters needed for a buffer is + // maxNonStarters + 1 for the starter + 1 for the GCJ + maxBufferSize = maxNonStarters + 2 + maxNFCExpansion = 3 // NFC(0x1D160) + maxNFKCExpansion = 18 // NFKC(0xFDFA) + + maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128 +) + +// ssState is used for reporting the segment state after inserting a rune. +// It is returned by streamSafe.next. +type ssState int + +const ( + // Indicates a rune was successfully added to the segment. + ssSuccess ssState = iota + // Indicates a rune starts a new segment and should not be added. + ssStarter + // Indicates a rune caused a segment overflow and a CGJ should be inserted. + ssOverflow +) + +// streamSafe implements the policy of when a CGJ should be inserted. +type streamSafe uint8 + +// mkStreamSafe is a shorthand for declaring a streamSafe var and calling +// first on it. +func mkStreamSafe(p Properties) streamSafe { + return streamSafe(p.nTrailingNonStarters()) +} + +// first inserts the first rune of a segment. +func (ss *streamSafe) first(p Properties) { + if *ss != 0 { + panic("!= 0") + } + *ss = streamSafe(p.nTrailingNonStarters()) +} + +// insert returns a ssState value to indicate whether a rune represented by p +// can be inserted. +func (ss *streamSafe) next(p Properties) ssState { + if *ss > maxNonStarters { + panic("streamSafe was not reset") + } + n := p.nLeadingNonStarters() + if *ss += streamSafe(n); *ss > maxNonStarters { + *ss = 0 + return ssOverflow + } + // The Stream-Safe Text Processing prescribes that the counting can stop + // as soon as a starter is encountered. However, there are some starters, + // like Jamo V and T, that can combine with other runes, leaving their + // successive non-starters appended to the previous, possibly causing an + // overflow. We will therefore consider any rune with a non-zero nLead to + // be a non-starter. Note that it always hold that if nLead > 0 then + // nLead == nTrail. + if n == 0 { + *ss = 0 + return ssStarter + } + return ssSuccess +} + +// backwards is used for checking for overflow and segment starts +// when traversing a string backwards. Users do not need to call first +// for the first rune. The state of the streamSafe retains the count of +// the non-starters loaded. +func (ss *streamSafe) backwards(p Properties) ssState { + if *ss > maxNonStarters { + panic("streamSafe was not reset") + } + c := *ss + streamSafe(p.nTrailingNonStarters()) + if c > maxNonStarters { + return ssOverflow + } + *ss = c + if p.nLeadingNonStarters() == 0 { + return ssStarter + } + return ssSuccess +} + +func (ss streamSafe) isMax() bool { + return ss == maxNonStarters +} + +// GraphemeJoiner is inserted after maxNonStarters non-starter runes. +const GraphemeJoiner = "\u034F" + +// reorderBuffer is used to normalize a single segment. Characters inserted with +// insert are decomposed and reordered based on CCC. The compose method can +// be used to recombine characters. Note that the byte buffer does not hold +// the UTF-8 characters in order. Only the rune array is maintained in sorted +// order. flush writes the resulting segment to a byte array. +type reorderBuffer struct { + rune [maxBufferSize]Properties // Per character info. + byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos. + nbyte uint8 // Number or bytes. + ss streamSafe // For limiting length of non-starter sequence. + nrune int // Number of runeInfos. + f formInfo + + src input + nsrc int + tmpBytes input + + out []byte + flushF func(*reorderBuffer) bool +} + +func (rb *reorderBuffer) init(f Form, src []byte) { + rb.f = *formTable[f] + rb.src.setBytes(src) + rb.nsrc = len(src) + rb.ss = 0 +} + +func (rb *reorderBuffer) initString(f Form, src string) { + rb.f = *formTable[f] + rb.src.setString(src) + rb.nsrc = len(src) + rb.ss = 0 +} + +func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) { + rb.out = out + rb.flushF = f +} + +// reset discards all characters from the buffer. +func (rb *reorderBuffer) reset() { + rb.nrune = 0 + rb.nbyte = 0 + rb.ss = 0 +} + +func (rb *reorderBuffer) doFlush() bool { + if rb.f.composing { + rb.compose() + } + res := rb.flushF(rb) + rb.reset() + return res +} + +// appendFlush appends the normalized segment to rb.out. +func appendFlush(rb *reorderBuffer) bool { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + rb.out = append(rb.out, rb.byte[start:end]...) + } + return true +} + +// flush appends the normalized segment to out and resets rb. +func (rb *reorderBuffer) flush(out []byte) []byte { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + out = append(out, rb.byte[start:end]...) + } + rb.reset() + return out +} + +// flushCopy copies the normalized segment to buf and resets rb. +// It returns the number of bytes written to buf. +func (rb *reorderBuffer) flushCopy(buf []byte) int { + p := 0 + for i := 0; i < rb.nrune; i++ { + runep := rb.rune[i] + p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size]) + } + rb.reset() + return p +} + +// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class. +// It returns false if the buffer is not large enough to hold the rune. +// It is used internally by insert and insertString only. +func (rb *reorderBuffer) insertOrdered(info Properties) { + n := rb.nrune + b := rb.rune[:] + cc := info.ccc + if cc > 0 { + // Find insertion position + move elements to make room. + for ; n > 0; n-- { + if b[n-1].ccc <= cc { + break + } + b[n] = b[n-1] + } + } + rb.nrune += 1 + pos := uint8(rb.nbyte) + rb.nbyte += utf8.UTFMax + info.pos = pos + b[n] = info +} + +// insertErr is an error code returned by insert. Using this type instead +// of error improves performance up to 20% for many of the benchmarks. +type insertErr int + +const ( + iSuccess insertErr = -iota + iShortDst + iShortSrc +) + +// insertFlush inserts the given rune in the buffer ordered by CCC. +// If a decomposition with multiple segments are encountered, they leading +// ones are flushed. +// It returns a non-zero error code if the rune was not inserted. +func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr { + if rune := src.hangul(i); rune != 0 { + rb.decomposeHangul(rune) + return iSuccess + } + if info.hasDecomposition() { + return rb.insertDecomposed(info.Decomposition()) + } + rb.insertSingle(src, i, info) + return iSuccess +} + +// insertUnsafe inserts the given rune in the buffer ordered by CCC. +// It is assumed there is sufficient space to hold the runes. It is the +// responsibility of the caller to ensure this. This can be done by checking +// the state returned by the streamSafe type. +func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) { + if rune := src.hangul(i); rune != 0 { + rb.decomposeHangul(rune) + } + if info.hasDecomposition() { + // TODO: inline. + rb.insertDecomposed(info.Decomposition()) + } else { + rb.insertSingle(src, i, info) + } +} + +// insertDecomposed inserts an entry in to the reorderBuffer for each rune +// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes. +// It flushes the buffer on each new segment start. +func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr { + rb.tmpBytes.setBytes(dcomp) + for i := 0; i < len(dcomp); { + info := rb.f.info(rb.tmpBytes, i) + if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() { + return iShortDst + } + i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)]) + rb.insertOrdered(info) + } + return iSuccess +} + +// insertSingle inserts an entry in the reorderBuffer for the rune at +// position i. info is the runeInfo for the rune at position i. +func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) { + src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size)) + rb.insertOrdered(info) +} + +// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb. +func (rb *reorderBuffer) insertCGJ() { + rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))}) +} + +// appendRune inserts a rune at the end of the buffer. It is used for Hangul. +func (rb *reorderBuffer) appendRune(r rune) { + bn := rb.nbyte + sz := utf8.EncodeRune(rb.byte[bn:], rune(r)) + rb.nbyte += utf8.UTFMax + rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)} + rb.nrune++ +} + +// assignRune sets a rune at position pos. It is used for Hangul and recomposition. +func (rb *reorderBuffer) assignRune(pos int, r rune) { + bn := rb.rune[pos].pos + sz := utf8.EncodeRune(rb.byte[bn:], rune(r)) + rb.rune[pos] = Properties{pos: bn, size: uint8(sz)} +} + +// runeAt returns the rune at position n. It is used for Hangul and recomposition. +func (rb *reorderBuffer) runeAt(n int) rune { + inf := rb.rune[n] + r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size]) + return r +} + +// bytesAt returns the UTF-8 encoding of the rune at position n. +// It is used for Hangul and recomposition. +func (rb *reorderBuffer) bytesAt(n int) []byte { + inf := rb.rune[n] + return rb.byte[inf.pos : int(inf.pos)+int(inf.size)] +} + +// For Hangul we combine algorithmically, instead of using tables. +const ( + hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80 + hangulBase0 = 0xEA + hangulBase1 = 0xB0 + hangulBase2 = 0x80 + + hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4 + hangulEnd0 = 0xED + hangulEnd1 = 0x9E + hangulEnd2 = 0xA4 + + jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00 + jamoLBase0 = 0xE1 + jamoLBase1 = 0x84 + jamoLEnd = 0x1113 + jamoVBase = 0x1161 + jamoVEnd = 0x1176 + jamoTBase = 0x11A7 + jamoTEnd = 0x11C3 + + jamoTCount = 28 + jamoVCount = 21 + jamoVTCount = 21 * 28 + jamoLVTCount = 19 * 21 * 28 +) + +const hangulUTF8Size = 3 + +func isHangul(b []byte) bool { + if len(b) < hangulUTF8Size { + return false + } + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +func isHangulString(b string) bool { + if len(b) < hangulUTF8Size { + return false + } + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +// Caller must ensure len(b) >= 2. +func isJamoVT(b []byte) bool { + // True if (rune & 0xff00) == jamoLBase + return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1 +} + +func isHangulWithoutJamoT(b []byte) bool { + c, _ := utf8.DecodeRune(b) + c -= hangulBase + return c < jamoLVTCount && c%jamoTCount == 0 +} + +// decomposeHangul writes the decomposed Hangul to buf and returns the number +// of bytes written. len(buf) should be at least 9. +func decomposeHangul(buf []byte, r rune) int { + const JamoUTF8Len = 3 + r -= hangulBase + x := r % jamoTCount + r /= jamoTCount + utf8.EncodeRune(buf, jamoLBase+r/jamoVCount) + utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount) + if x != 0 { + utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x) + return 3 * JamoUTF8Len + } + return 2 * JamoUTF8Len +} + +// decomposeHangul algorithmically decomposes a Hangul rune into +// its Jamo components. +// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul. +func (rb *reorderBuffer) decomposeHangul(r rune) { + r -= hangulBase + x := r % jamoTCount + r /= jamoTCount + rb.appendRune(jamoLBase + r/jamoVCount) + rb.appendRune(jamoVBase + r%jamoVCount) + if x != 0 { + rb.appendRune(jamoTBase + x) + } +} + +// combineHangul algorithmically combines Jamo character components into Hangul. +// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul. +func (rb *reorderBuffer) combineHangul(s, i, k int) { + b := rb.rune[:] + bn := rb.nrune + for ; i < bn; i++ { + cccB := b[k-1].ccc + cccC := b[i].ccc + if cccB == 0 { + s = k - 1 + } + if s != k-1 && cccB >= cccC { + // b[i] is blocked by greater-equal cccX below it + b[k] = b[i] + k++ + } else { + l := rb.runeAt(s) // also used to compare to hangulBase + v := rb.runeAt(i) // also used to compare to jamoT + switch { + case jamoLBase <= l && l < jamoLEnd && + jamoVBase <= v && v < jamoVEnd: + // 11xx plus 116x to LV + rb.assignRune(s, hangulBase+ + (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount) + case hangulBase <= l && l < hangulEnd && + jamoTBase < v && v < jamoTEnd && + ((l-hangulBase)%jamoTCount) == 0: + // ACxx plus 11Ax to LVT + rb.assignRune(s, l+v-jamoTBase) + default: + b[k] = b[i] + k++ + } + } + } + rb.nrune = k +} + +// compose recombines the runes in the buffer. +// It should only be used to recompose a single segment, as it will not +// handle alternations between Hangul and non-Hangul characters correctly. +func (rb *reorderBuffer) compose() { + // UAX #15, section X5 , including Corrigendum #5 + // "In any character sequence beginning with starter S, a character C is + // blocked from S if and only if there is some character B between S + // and C, and either B is a starter or it has the same or higher + // combining class as C." + bn := rb.nrune + if bn == 0 { + return + } + k := 1 + b := rb.rune[:] + for s, i := 0, 1; i < bn; i++ { + if isJamoVT(rb.bytesAt(i)) { + // Redo from start in Hangul mode. Necessary to support + // U+320E..U+321E in NFKC mode. + rb.combineHangul(s, i, k) + return + } + ii := b[i] + // We can only use combineForward as a filter if we later + // get the info for the combined character. This is more + // expensive than using the filter. Using combinesBackward() + // is safe. + if ii.combinesBackward() { + cccB := b[k-1].ccc + cccC := ii.ccc + blocked := false // b[i] blocked by starter or greater or equal CCC? + if cccB == 0 { + s = k - 1 + } else { + blocked = s != k-1 && cccB >= cccC + } + if !blocked { + combined := combine(rb.runeAt(s), rb.runeAt(i)) + if combined != 0 { + rb.assignRune(s, combined) + continue + } + } + } + b[k] = b[i] + k++ + } + rb.nrune = k +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition_test.go new file mode 100644 index 00000000..11684069 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/composition_test.go @@ -0,0 +1,130 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "testing" + +// TestCase is used for most tests. +type TestCase struct { + in []rune + out []rune +} + +func runTests(t *testing.T, name string, fm Form, tests []TestCase) { + rb := reorderBuffer{} + rb.init(fm, nil) + for i, test := range tests { + rb.setFlusher(nil, appendFlush) + for j, rune := range test.in { + b := []byte(string(rune)) + src := inputBytes(b) + info := rb.f.info(src, 0) + if j == 0 { + rb.ss.first(info) + } else { + rb.ss.next(info) + } + if rb.insertFlush(src, 0, info) < 0 { + t.Errorf("%s:%d: insert failed for rune %d", name, i, j) + } + } + rb.doFlush() + was := string(rb.out) + want := string(test.out) + if len(was) != len(want) { + t.Errorf("%s:%d: length = %d; want %d", name, i, len(was), len(want)) + } + if was != want { + k, pfx := pidx(was, want) + t.Errorf("%s:%d: \nwas %s%+q; \nwant %s%+q", name, i, pfx, was[k:], pfx, want[k:]) + } + } +} + +func TestFlush(t *testing.T) { + const ( + hello = "Hello " + world = "world!" + ) + buf := make([]byte, maxByteBufferSize) + p := copy(buf, hello) + out := buf[p:] + rb := reorderBuffer{} + rb.initString(NFC, world) + if i := rb.flushCopy(out); i != 0 { + t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", i) + } + + for i := range world { + // No need to set streamSafe values for this test. + rb.insertFlush(rb.src, i, rb.f.info(rb.src, i)) + n := rb.flushCopy(out) + out = out[n:] + p += n + } + + was := buf[:p] + want := hello + world + if string(was) != want { + t.Errorf(`output after flush was "%s"; want "%s"`, string(was), want) + } + if rb.nrune != 0 { + t.Errorf("non-null size of info buffer (rb.nrune == %d)", rb.nrune) + } + if rb.nbyte != 0 { + t.Errorf("non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte) + } +} + +var insertTests = []TestCase{ + {[]rune{'a'}, []rune{'a'}}, + {[]rune{0x300}, []rune{0x300}}, + {[]rune{0x300, 0x316}, []rune{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220 + {[]rune{0x316, 0x300}, []rune{0x316, 0x300}}, + {[]rune{0x41, 0x316, 0x300}, []rune{0x41, 0x316, 0x300}}, + {[]rune{0x41, 0x300, 0x316}, []rune{0x41, 0x316, 0x300}}, + {[]rune{0x300, 0x316, 0x41}, []rune{0x316, 0x300, 0x41}}, + {[]rune{0x41, 0x300, 0x40, 0x316}, []rune{0x41, 0x300, 0x40, 0x316}}, +} + +func TestInsert(t *testing.T) { + runTests(t, "TestInsert", NFD, insertTests) +} + +var decompositionNFDTest = []TestCase{ + {[]rune{0xC0}, []rune{0x41, 0x300}}, + {[]rune{0xAC00}, []rune{0x1100, 0x1161}}, + {[]rune{0x01C4}, []rune{0x01C4}}, + {[]rune{0x320E}, []rune{0x320E}}, + {[]rune("음ẻ과"), []rune{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}}, +} + +var decompositionNFKDTest = []TestCase{ + {[]rune{0xC0}, []rune{0x41, 0x300}}, + {[]rune{0xAC00}, []rune{0x1100, 0x1161}}, + {[]rune{0x01C4}, []rune{0x44, 0x5A, 0x030C}}, + {[]rune{0x320E}, []rune{0x28, 0x1100, 0x1161, 0x29}}, +} + +func TestDecomposition(t *testing.T) { + runTests(t, "TestDecompositionNFD", NFD, decompositionNFDTest) + runTests(t, "TestDecompositionNFKD", NFKD, decompositionNFKDTest) +} + +var compositionTest = []TestCase{ + {[]rune{0x41, 0x300}, []rune{0xC0}}, + {[]rune{0x41, 0x316}, []rune{0x41, 0x316}}, + {[]rune{0x41, 0x300, 0x35D}, []rune{0xC0, 0x35D}}, + {[]rune{0x41, 0x316, 0x300}, []rune{0xC0, 0x316}}, + // blocking starter + {[]rune{0x41, 0x316, 0x40, 0x300}, []rune{0x41, 0x316, 0x40, 0x300}}, + {[]rune{0x1100, 0x1161}, []rune{0xAC00}}, + // parenthesized Hangul, alternate between ASCII and Hangul. + {[]rune{0x28, 0x1100, 0x1161, 0x29}, []rune{0x28, 0xAC00, 0x29}}, +} + +func TestComposition(t *testing.T) { + runTests(t, "TestComposition", NFC, compositionTest) +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/example_iter_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/example_iter_test.go new file mode 100644 index 00000000..9b7043e6 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/example_iter_test.go @@ -0,0 +1,82 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm_test + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/unicode/norm" +) + +// EqualSimple uses a norm.Iter to compare two non-normalized +// strings for equivalence. +func EqualSimple(a, b string) bool { + var ia, ib norm.Iter + ia.InitString(norm.NFKD, a) + ib.InitString(norm.NFKD, b) + for !ia.Done() && !ib.Done() { + if !bytes.Equal(ia.Next(), ib.Next()) { + return false + } + } + return ia.Done() && ib.Done() +} + +// FindPrefix finds the longest common prefix of ASCII characters +// of a and b. +func FindPrefix(a, b string) int { + i := 0 + for ; i < len(a) && i < len(b) && a[i] < utf8.RuneSelf && a[i] == b[i]; i++ { + } + return i +} + +// EqualOpt is like EqualSimple, but optimizes the special +// case for ASCII characters. +func EqualOpt(a, b string) bool { + n := FindPrefix(a, b) + a, b = a[n:], b[n:] + var ia, ib norm.Iter + ia.InitString(norm.NFKD, a) + ib.InitString(norm.NFKD, b) + for !ia.Done() && !ib.Done() { + if !bytes.Equal(ia.Next(), ib.Next()) { + return false + } + if n := int64(FindPrefix(a[ia.Pos():], b[ib.Pos():])); n != 0 { + ia.Seek(n, 1) + ib.Seek(n, 1) + } + } + return ia.Done() && ib.Done() +} + +var compareTests = []struct{ a, b string }{ + {"aaa", "aaa"}, + {"aaa", "aab"}, + {"a\u0300a", "\u00E0a"}, + {"a\u0300\u0320b", "a\u0320\u0300b"}, + {"\u1E0A\u0323", "\x44\u0323\u0307"}, + // A character that decomposes into multiple segments + // spans several iterations. + {"\u3304", "\u30A4\u30CB\u30F3\u30AF\u3099"}, +} + +func ExampleIter() { + for i, t := range compareTests { + r0 := EqualSimple(t.a, t.b) + r1 := EqualOpt(t.a, t.b) + fmt.Printf("%d: %v %v\n", i, r0, r1) + } + // Output: + // 0: true true + // 1: false false + // 2: true true + // 3: true true + // 4: true true + // 5: true true +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo.go new file mode 100644 index 00000000..15a67c65 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo.go @@ -0,0 +1,256 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +// This file contains Form-specific logic and wrappers for data in tables.go. + +// Rune info is stored in a separate trie per composing form. A composing form +// and its corresponding decomposing form share the same trie. Each trie maps +// a rune to a uint16. The values take two forms. For v >= 0x8000: +// bits +// 15: 1 (inverse of NFD_QD bit of qcInfo) +// 13..7: qcInfo (see below). isYesD is always true (no decompostion). +// 6..0: ccc (compressed CCC value). +// For v < 0x8000, the respective rune has a decomposition and v is an index +// into a byte array of UTF-8 decomposition sequences and additional info and +// has the form: +//
* [ []] +// The header contains the number of bytes in the decomposition (excluding this +// length byte). The two most significant bits of this length byte correspond +// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1. +// The byte sequence is followed by a trailing and leading CCC if the values +// for these are not zero. The value of v determines which ccc are appended +// to the sequences. For v < firstCCC, there are none, for v >= firstCCC, +// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC +// there is an additional leading ccc. The value of tccc itself is the +// trailing CCC shifted left 2 bits. The two least-significant bits of tccc +// are the number of trailing non-starters. + +const ( + qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo + headerLenMask = 0x3F // extract the length value from the header byte + headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte +) + +// Properties provides access to normalization properties of a rune. +type Properties struct { + pos uint8 // start position in reorderBuffer; used in composition.go + size uint8 // length of UTF-8 encoding of this rune + ccc uint8 // leading canonical combining class (ccc if not decomposition) + tccc uint8 // trailing canonical combining class (ccc if not decomposition) + nLead uint8 // number of leading non-starters. + flags qcInfo // quick check flags + index uint16 +} + +// functions dispatchable per form +type lookupFunc func(b input, i int) Properties + +// formInfo holds Form-specific functions and tables. +type formInfo struct { + form Form + composing, compatibility bool // form type + info lookupFunc + nextMain iterFunc +} + +var formTable []*formInfo + +func init() { + formTable = make([]*formInfo, 4) + + for i := range formTable { + f := &formInfo{} + formTable[i] = f + f.form = Form(i) + if Form(i) == NFKD || Form(i) == NFKC { + f.compatibility = true + f.info = lookupInfoNFKC + } else { + f.info = lookupInfoNFC + } + f.nextMain = nextDecomposed + if Form(i) == NFC || Form(i) == NFKC { + f.nextMain = nextComposed + f.composing = true + } + } +} + +// We do not distinguish between boundaries for NFC, NFD, etc. to avoid +// unexpected behavior for the user. For example, in NFD, there is a boundary +// after 'a'. However, 'a' might combine with modifiers, so from the application's +// perspective it is not a good boundary. We will therefore always use the +// boundaries for the combining variants. + +// BoundaryBefore returns true if this rune starts a new segment and +// cannot combine with any rune on the left. +func (p Properties) BoundaryBefore() bool { + if p.ccc == 0 && !p.combinesBackward() { + return true + } + // We assume that the CCC of the first character in a decomposition + // is always non-zero if different from info.ccc and that we can return + // false at this point. This is verified by maketables. + return false +} + +// BoundaryAfter returns true if runes cannot combine with or otherwise +// interact with this or previous runes. +func (p Properties) BoundaryAfter() bool { + // TODO: loosen these conditions. + return p.isInert() +} + +// We pack quick check data in 4 bits: +// 5: Combines forward (0 == false, 1 == true) +// 4..3: NFC_QC Yes(00), No (10), or Maybe (11) +// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition. +// 1..0: Number of trailing non-starters. +// +// When all 4 bits are zero, the character is inert, meaning it is never +// influenced by normalization. +type qcInfo uint8 + +func (p Properties) isYesC() bool { return p.flags&0x10 == 0 } +func (p Properties) isYesD() bool { return p.flags&0x4 == 0 } + +func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 } +func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe +func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD + +func (p Properties) isInert() bool { + return p.flags&qcInfoMask == 0 && p.ccc == 0 +} + +func (p Properties) multiSegment() bool { + return p.index >= firstMulti && p.index < endMulti +} + +func (p Properties) nLeadingNonStarters() uint8 { + return p.nLead +} + +func (p Properties) nTrailingNonStarters() uint8 { + return uint8(p.flags & 0x03) +} + +// Decomposition returns the decomposition for the underlying rune +// or nil if there is none. +func (p Properties) Decomposition() []byte { + // TODO: create the decomposition for Hangul? + if p.index == 0 { + return nil + } + i := p.index + n := decomps[i] & headerLenMask + i++ + return decomps[i : i+uint16(n)] +} + +// Size returns the length of UTF-8 encoding of the rune. +func (p Properties) Size() int { + return int(p.size) +} + +// CCC returns the canonical combining class of the underlying rune. +func (p Properties) CCC() uint8 { + if p.index >= firstCCCZeroExcept { + return 0 + } + return ccc[p.ccc] +} + +// LeadCCC returns the CCC of the first rune in the decomposition. +// If there is no decomposition, LeadCCC equals CCC. +func (p Properties) LeadCCC() uint8 { + return ccc[p.ccc] +} + +// TrailCCC returns the CCC of the last rune in the decomposition. +// If there is no decomposition, TrailCCC equals CCC. +func (p Properties) TrailCCC() uint8 { + return ccc[p.tccc] +} + +// Recomposition +// We use 32-bit keys instead of 64-bit for the two codepoint keys. +// This clips off the bits of three entries, but we know this will not +// result in a collision. In the unlikely event that changes to +// UnicodeData.txt introduce collisions, the compiler will catch it. +// Note that the recomposition map for NFC and NFKC are identical. + +// combine returns the combined rune or 0 if it doesn't exist. +func combine(a, b rune) rune { + key := uint32(uint16(a))<<16 + uint32(uint16(b)) + return recompMap[key] +} + +func lookupInfoNFC(b input, i int) Properties { + v, sz := b.charinfoNFC(i) + return compInfo(v, sz) +} + +func lookupInfoNFKC(b input, i int) Properties { + v, sz := b.charinfoNFKC(i) + return compInfo(v, sz) +} + +// Properties returns properties for the first rune in s. +func (f Form) Properties(s []byte) Properties { + if f == NFC || f == NFD { + return compInfo(nfcData.lookup(s)) + } + return compInfo(nfkcData.lookup(s)) +} + +// PropertiesString returns properties for the first rune in s. +func (f Form) PropertiesString(s string) Properties { + if f == NFC || f == NFD { + return compInfo(nfcData.lookupString(s)) + } + return compInfo(nfkcData.lookupString(s)) +} + +// compInfo converts the information contained in v and sz +// to a Properties. See the comment at the top of the file +// for more information on the format. +func compInfo(v uint16, sz int) Properties { + if v == 0 { + return Properties{size: uint8(sz)} + } else if v >= 0x8000 { + p := Properties{ + size: uint8(sz), + ccc: uint8(v), + tccc: uint8(v), + flags: qcInfo(v >> 8), + } + if p.ccc > 0 || p.combinesBackward() { + p.nLead = uint8(p.flags & 0x3) + } + return p + } + // has decomposition + h := decomps[v] + f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4 + p := Properties{size: uint8(sz), flags: f, index: v} + if v >= firstCCC { + v += uint16(h&headerLenMask) + 1 + c := decomps[v] + p.tccc = c >> 2 + p.flags |= qcInfo(c & 0x3) + if v >= firstLeadingCCC { + p.nLead = c & 0x3 + if v >= firstStarterWithNLead { + // We were tricked. Remove the decomposition. + p.flags &= 0x03 + p.index = 0 + return p + } + p.ccc = decomps[v+1] + } + } + return p +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo_test.go new file mode 100644 index 00000000..e15ba9be --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/forminfo_test.go @@ -0,0 +1,54 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build test + +package norm + +import "testing" + +func TestProperties(t *testing.T) { + var d runeData + CK := [2]string{"C", "K"} + for k, r := 1, rune(0); r < 0x2ffff; r++ { + if k < len(testData) && r == testData[k].r { + d = testData[k] + k++ + } + s := string(r) + for j, p := range []Properties{NFC.PropertiesString(s), NFKC.PropertiesString(s)} { + f := d.f[j] + if p.CCC() != d.ccc { + t.Errorf("%U: ccc(%s): was %d; want %d %X", r, CK[j], p.CCC(), d.ccc, p.index) + } + if p.isYesC() != (f.qc == Yes) { + t.Errorf("%U: YesC(%s): was %v; want %v", r, CK[j], p.isYesC(), f.qc == Yes) + } + if p.combinesBackward() != (f.qc == Maybe) { + t.Errorf("%U: combines backwards(%s): was %v; want %v", r, CK[j], p.combinesBackward(), f.qc == Maybe) + } + if p.nLeadingNonStarters() != d.nLead { + t.Errorf("%U: nLead(%s): was %d; want %d %#v %#v", r, CK[j], p.nLeadingNonStarters(), d.nLead, p, d) + } + if p.nTrailingNonStarters() != d.nTrail { + t.Errorf("%U: nTrail(%s): was %d; want %d %#v %#v", r, CK[j], p.nTrailingNonStarters(), d.nTrail, p, d) + } + if p.combinesForward() != f.combinesForward { + t.Errorf("%U: combines forward(%s): was %v; want %v %#v", r, CK[j], p.combinesForward(), f.combinesForward, p) + } + // Skip Hangul as it is algorithmically computed. + if r >= hangulBase && r < hangulEnd { + continue + } + if p.hasDecomposition() { + if has := f.decomposition != ""; !has { + t.Errorf("%U: hasDecomposition(%s): was %v; want %v", r, CK[j], p.hasDecomposition(), has) + } + if string(p.Decomposition()) != f.decomposition { + t.Errorf("%U: decomp(%s): was %+q; want %+q", r, CK[j], p.Decomposition(), f.decomposition) + } + } + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/input.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/input.go new file mode 100644 index 00000000..045d4ccc --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/input.go @@ -0,0 +1,105 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "unicode/utf8" + +type input struct { + str string + bytes []byte +} + +func inputBytes(str []byte) input { + return input{bytes: str} +} + +func inputString(str string) input { + return input{str: str} +} + +func (in *input) setBytes(str []byte) { + in.str = "" + in.bytes = str +} + +func (in *input) setString(str string) { + in.str = str + in.bytes = nil +} + +func (in *input) _byte(p int) byte { + if in.bytes == nil { + return in.str[p] + } + return in.bytes[p] +} + +func (in *input) skipASCII(p, max int) int { + if in.bytes == nil { + for ; p < max && in.str[p] < utf8.RuneSelf; p++ { + } + } else { + for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ { + } + } + return p +} + +func (in *input) skipContinuationBytes(p int) int { + if in.bytes == nil { + for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ { + } + } else { + for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ { + } + } + return p +} + +func (in *input) appendSlice(buf []byte, b, e int) []byte { + if in.bytes != nil { + return append(buf, in.bytes[b:e]...) + } + for i := b; i < e; i++ { + buf = append(buf, in.str[i]) + } + return buf +} + +func (in *input) copySlice(buf []byte, b, e int) int { + if in.bytes == nil { + return copy(buf, in.str[b:e]) + } + return copy(buf, in.bytes[b:e]) +} + +func (in *input) charinfoNFC(p int) (uint16, int) { + if in.bytes == nil { + return nfcData.lookupString(in.str[p:]) + } + return nfcData.lookup(in.bytes[p:]) +} + +func (in *input) charinfoNFKC(p int) (uint16, int) { + if in.bytes == nil { + return nfkcData.lookupString(in.str[p:]) + } + return nfkcData.lookup(in.bytes[p:]) +} + +func (in *input) hangul(p int) (r rune) { + if in.bytes == nil { + if !isHangulString(in.str[p:]) { + return 0 + } + r, _ = utf8.DecodeRuneInString(in.str[p:]) + } else { + if !isHangul(in.bytes[p:]) { + return 0 + } + r, _ = utf8.DecodeRune(in.bytes[p:]) + } + return r +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter.go new file mode 100644 index 00000000..0a42a72d --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter.go @@ -0,0 +1,450 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "fmt" + "unicode/utf8" +) + +// MaxSegmentSize is the maximum size of a byte buffer needed to consider any +// sequence of starter and non-starter runes for the purpose of normalization. +const MaxSegmentSize = maxByteBufferSize + +// An Iter iterates over a string or byte slice, while normalizing it +// to a given Form. +type Iter struct { + rb reorderBuffer + buf [maxByteBufferSize]byte + info Properties // first character saved from previous iteration + next iterFunc // implementation of next depends on form + asciiF iterFunc + + p int // current position in input source + multiSeg []byte // remainder of multi-segment decomposition +} + +type iterFunc func(*Iter) []byte + +// Init initializes i to iterate over src after normalizing it to Form f. +func (i *Iter) Init(f Form, src []byte) { + i.p = 0 + if len(src) == 0 { + i.setDone() + i.rb.nsrc = 0 + return + } + i.multiSeg = nil + i.rb.init(f, src) + i.next = i.rb.f.nextMain + i.asciiF = nextASCIIBytes + i.info = i.rb.f.info(i.rb.src, i.p) +} + +// InitString initializes i to iterate over src after normalizing it to Form f. +func (i *Iter) InitString(f Form, src string) { + i.p = 0 + if len(src) == 0 { + i.setDone() + i.rb.nsrc = 0 + return + } + i.multiSeg = nil + i.rb.initString(f, src) + i.next = i.rb.f.nextMain + i.asciiF = nextASCIIString + i.info = i.rb.f.info(i.rb.src, i.p) +} + +// Seek sets the segment to be returned by the next call to Next to start +// at position p. It is the responsibility of the caller to set p to the +// start of a UTF8 rune. +func (i *Iter) Seek(offset int64, whence int) (int64, error) { + var abs int64 + switch whence { + case 0: + abs = offset + case 1: + abs = int64(i.p) + offset + case 2: + abs = int64(i.rb.nsrc) + offset + default: + return 0, fmt.Errorf("norm: invalid whence") + } + if abs < 0 { + return 0, fmt.Errorf("norm: negative position") + } + if int(abs) >= i.rb.nsrc { + i.setDone() + return int64(i.p), nil + } + i.p = int(abs) + i.multiSeg = nil + i.next = i.rb.f.nextMain + i.info = i.rb.f.info(i.rb.src, i.p) + return abs, nil +} + +// returnSlice returns a slice of the underlying input type as a byte slice. +// If the underlying is of type []byte, it will simply return a slice. +// If the underlying is of type string, it will copy the slice to the buffer +// and return that. +func (i *Iter) returnSlice(a, b int) []byte { + if i.rb.src.bytes == nil { + return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])] + } + return i.rb.src.bytes[a:b] +} + +// Pos returns the byte position at which the next call to Next will commence processing. +func (i *Iter) Pos() int { + return i.p +} + +func (i *Iter) setDone() { + i.next = nextDone + i.p = i.rb.nsrc +} + +// Done returns true if there is no more input to process. +func (i *Iter) Done() bool { + return i.p >= i.rb.nsrc +} + +// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input. +// For any input a and b for which f(a) == f(b), subsequent calls +// to Next will return the same segments. +// Modifying runes are grouped together with the preceding starter, if such a starter exists. +// Although not guaranteed, n will typically be the smallest possible n. +func (i *Iter) Next() []byte { + return i.next(i) +} + +func nextASCIIBytes(i *Iter) []byte { + p := i.p + 1 + if p >= i.rb.nsrc { + i.setDone() + return i.rb.src.bytes[i.p:p] + } + if i.rb.src.bytes[p] < utf8.RuneSelf { + p0 := i.p + i.p = p + return i.rb.src.bytes[p0:p] + } + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) +} + +func nextASCIIString(i *Iter) []byte { + p := i.p + 1 + if p >= i.rb.nsrc { + i.buf[0] = i.rb.src.str[i.p] + i.setDone() + return i.buf[:1] + } + if i.rb.src.str[p] < utf8.RuneSelf { + i.buf[0] = i.rb.src.str[i.p] + i.p = p + return i.buf[:1] + } + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) +} + +func nextHangul(i *Iter) []byte { + p := i.p + next := p + hangulUTF8Size + if next >= i.rb.nsrc { + i.setDone() + } else if i.rb.src.hangul(next) == 0 { + i.info = i.rb.f.info(i.rb.src, i.p) + i.next = i.rb.f.nextMain + return i.next(i) + } + i.p = next + return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))] +} + +func nextDone(i *Iter) []byte { + return nil +} + +// nextMulti is used for iterating over multi-segment decompositions +// for decomposing normal forms. +func nextMulti(i *Iter) []byte { + j := 0 + d := i.multiSeg + // skip first rune + for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ { + } + for j < len(d) { + info := i.rb.f.info(input{bytes: d}, j) + if info.BoundaryBefore() { + i.multiSeg = d[j:] + return d[:j] + } + j += int(info.size) + } + // treat last segment as normal decomposition + i.next = i.rb.f.nextMain + return i.next(i) +} + +// nextMultiNorm is used for iterating over multi-segment decompositions +// for composing normal forms. +func nextMultiNorm(i *Iter) []byte { + j := 0 + d := i.multiSeg + for j < len(d) { + info := i.rb.f.info(input{bytes: d}, j) + if info.BoundaryBefore() { + i.rb.compose() + seg := i.buf[:i.rb.flushCopy(i.buf[:])] + i.rb.ss.first(info) + i.rb.insertUnsafe(input{bytes: d}, j, info) + i.multiSeg = d[j+int(info.size):] + return seg + } + i.rb.ss.next(info) + i.rb.insertUnsafe(input{bytes: d}, j, info) + j += int(info.size) + } + i.multiSeg = nil + i.next = nextComposed + return doNormComposed(i) +} + +// nextDecomposed is the implementation of Next for forms NFD and NFKD. +func nextDecomposed(i *Iter) (next []byte) { + outp := 0 + inCopyStart, outCopyStart := i.p, 0 + ss := mkStreamSafe(i.info) + for { + if sz := int(i.info.size); sz <= 1 { + p := i.p + i.p++ // ASCII or illegal byte. Either way, advance by 1. + if i.p >= i.rb.nsrc { + i.setDone() + return i.returnSlice(p, i.p) + } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.next = i.asciiF + return i.returnSlice(p, i.p) + } + outp++ + } else if d := i.info.Decomposition(); d != nil { + // Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero. + // Case 1: there is a leftover to copy. In this case the decomposition + // must begin with a modifier and should always be appended. + // Case 2: no leftover. Simply return d if followed by a ccc == 0 value. + p := outp + len(d) + if outp > 0 { + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + if p > len(i.buf) { + return i.buf[:outp] + } + } else if i.info.multiSegment() { + // outp must be 0 as multi-segment decompositions always + // start a new segment. + if i.multiSeg == nil { + i.multiSeg = d + i.next = nextMulti + return nextMulti(i) + } + // We are in the last segment. Treat as normal decomposition. + d = i.multiSeg + i.multiSeg = nil + p = len(d) + } + prevCC := i.info.tccc + if i.p += sz; i.p >= i.rb.nsrc { + i.setDone() + i.info = Properties{} // Force BoundaryBefore to succeed. + } else { + i.info = i.rb.f.info(i.rb.src, i.p) + } + switch ss.next(i.info) { + case ssOverflow: + i.next = nextCGJDecompose + fallthrough + case ssStarter: + if outp > 0 { + copy(i.buf[outp:], d) + return i.buf[:p] + } + return d + } + copy(i.buf[outp:], d) + outp = p + inCopyStart, outCopyStart = i.p, outp + if i.info.ccc < prevCC { + goto doNorm + } + continue + } else if r := i.rb.src.hangul(i.p); r != 0 { + outp = decomposeHangul(i.buf[:], r) + i.p += hangulUTF8Size + inCopyStart, outCopyStart = i.p, outp + if i.p >= i.rb.nsrc { + i.setDone() + break + } else if i.rb.src.hangul(i.p) != 0 { + i.next = nextHangul + return i.buf[:outp] + } + } else { + p := outp + sz + if p > len(i.buf) { + break + } + outp = p + i.p += sz + } + if i.p >= i.rb.nsrc { + i.setDone() + break + } + prevCC := i.info.tccc + i.info = i.rb.f.info(i.rb.src, i.p) + if v := ss.next(i.info); v == ssStarter { + break + } else if v == ssOverflow { + i.next = nextCGJDecompose + break + } + if i.info.ccc < prevCC { + goto doNorm + } + } + if outCopyStart == 0 { + return i.returnSlice(inCopyStart, i.p) + } else if inCopyStart < i.p { + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + } + return i.buf[:outp] +doNorm: + // Insert what we have decomposed so far in the reorderBuffer. + // As we will only reorder, there will always be enough room. + i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + i.rb.insertDecomposed(i.buf[0:outp]) + return doNormDecomposed(i) +} + +func doNormDecomposed(i *Iter) []byte { + for { + if s := i.rb.ss.next(i.info); s == ssOverflow { + i.next = nextCGJDecompose + break + } + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + if i.p += int(i.info.size); i.p >= i.rb.nsrc { + i.setDone() + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if i.info.ccc == 0 { + break + } + } + // new segment or too many combining characters: exit normalization + return i.buf[:i.rb.flushCopy(i.buf[:])] +} + +func nextCGJDecompose(i *Iter) []byte { + i.rb.ss = 0 + i.rb.insertCGJ() + i.next = nextDecomposed + buf := doNormDecomposed(i) + return buf +} + +// nextComposed is the implementation of Next for forms NFC and NFKC. +func nextComposed(i *Iter) []byte { + outp, startp := 0, i.p + var prevCC uint8 + ss := mkStreamSafe(i.info) + for { + if !i.info.isYesC() { + goto doNorm + } + prevCC = i.info.tccc + sz := int(i.info.size) + if sz == 0 { + sz = 1 // illegal rune: copy byte-by-byte + } + p := outp + sz + if p > len(i.buf) { + break + } + outp = p + i.p += sz + if i.p >= i.rb.nsrc { + i.setDone() + break + } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.next = i.asciiF + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if v := ss.next(i.info); v == ssStarter { + break + } else if v == ssOverflow { + i.next = nextCGJCompose + break + } + if i.info.ccc < prevCC { + goto doNorm + } + } + return i.returnSlice(startp, i.p) +doNorm: + i.p = startp + i.info = i.rb.f.info(i.rb.src, i.p) + if i.info.multiSegment() { + d := i.info.Decomposition() + info := i.rb.f.info(input{bytes: d}, 0) + i.rb.insertUnsafe(input{bytes: d}, 0, info) + i.multiSeg = d[int(info.size):] + i.next = nextMultiNorm + return nextMultiNorm(i) + } + i.rb.ss.first(i.info) + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + return doNormComposed(i) +} + +func doNormComposed(i *Iter) []byte { + // First rune should already be inserted. + for { + if i.p += int(i.info.size); i.p >= i.rb.nsrc { + i.setDone() + break + } + i.info = i.rb.f.info(i.rb.src, i.p) + if s := i.rb.ss.next(i.info); s == ssStarter { + break + } else if s == ssOverflow { + i.next = nextCGJCompose + break + } + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + } + i.rb.compose() + seg := i.buf[:i.rb.flushCopy(i.buf[:])] + return seg +} + +func nextCGJCompose(i *Iter) []byte { + i.rb.ss = 0 // instead of first + i.rb.insertCGJ() + i.next = nextComposed + // Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter, + // even if they are not. This is particularly dubious for U+FF9E and UFF9A. + // If we ever change that, insert a check here. + i.rb.ss.first(i.info) + i.rb.insertUnsafe(i.rb.src, i.p, i.info) + return doNormComposed(i) +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter_test.go new file mode 100644 index 00000000..e2aa6f25 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/iter_test.go @@ -0,0 +1,98 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "strings" + "testing" +) + +func doIterNorm(f Form, s string) []byte { + acc := []byte{} + i := Iter{} + i.InitString(f, s) + for !i.Done() { + acc = append(acc, i.Next()...) + } + return acc +} + +func TestIterNext(t *testing.T) { + runNormTests(t, "IterNext", func(f Form, out []byte, s string) []byte { + return doIterNorm(f, string(append(out, s...))) + }) +} + +type SegmentTest struct { + in string + out []string +} + +var segmentTests = []SegmentTest{ + {"\u1E0A\u0323a", []string{"\x44\u0323\u0307", "a", ""}}, + {rep('a', segSize), append(strings.Split(rep('a', segSize), ""), "")}, + {rep('a', segSize+2), append(strings.Split(rep('a', segSize+2), ""), "")}, + {rep('a', segSize) + "\u0300aa", + append(strings.Split(rep('a', segSize-1), ""), "a\u0300", "a", "a", "")}, + + // U+0f73 is NOT treated as a starter as it is a modifier + {"a" + grave(29) + "\u0f73", []string{"a" + grave(29), cgj + "\u0f73"}}, + {"a\u0f73", []string{"a\u0f73"}}, + + // U+ff9e is treated as a non-starter. + // TODO: should we? Note that this will only affect iteration, as whether + // or not we do so does not affect the normalization output and will either + // way result in consistent iteration output. + {"a" + grave(30) + "\uff9e", []string{"a" + grave(30), cgj + "\uff9e"}}, + {"a\uff9e", []string{"a\uff9e"}}, +} + +var segmentTestsK = []SegmentTest{ + {"\u3332", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u3099", ""}}, + // last segment of multi-segment decomposition needs normalization + {"\u3332\u093C", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u093C\u3099", ""}}, + {"\u320E", []string{"\x28", "\uAC00", "\x29"}}, + + // last segment should be copied to start of buffer. + {"\ufdfa", []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645", ""}}, + {"\ufdfa" + grave(30), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), ""}}, + {"\uFDFA" + grave(64), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), cgj + grave(30), cgj + grave(4), ""}}, + + // Hangul and Jamo are grouped togeter. + {"\uAC00", []string{"\u1100\u1161", ""}}, + {"\uAC01", []string{"\u1100\u1161\u11A8", ""}}, + {"\u1100\u1161", []string{"\u1100\u1161", ""}}, +} + +// Note that, by design, segmentation is equal for composing and decomposing forms. +func TestIterSegmentation(t *testing.T) { + segmentTest(t, "SegmentTestD", NFD, segmentTests) + segmentTest(t, "SegmentTestC", NFC, segmentTests) + segmentTest(t, "SegmentTestKD", NFKD, segmentTestsK) + segmentTest(t, "SegmentTestKC", NFKC, segmentTestsK) +} + +func segmentTest(t *testing.T, name string, f Form, tests []SegmentTest) { + iter := Iter{} + for i, tt := range tests { + iter.InitString(f, tt.in) + for j, seg := range tt.out { + if seg == "" { + if !iter.Done() { + res := string(iter.Next()) + t.Errorf(`%s:%d:%d: expected Done()==true, found segment %+q`, name, i, j, res) + } + continue + } + if iter.Done() { + t.Errorf("%s:%d:%d: Done()==true, want false", name, i, j) + } + seg = f.String(seg) + if res := string(iter.Next()); res != seg { + t.Errorf(`%s:%d:%d" segment was %+q (%d); want %+q (%d)`, name, i, j, pc(res), len(res), pc(seg), len(seg)) + } + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/maketables.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/maketables.go new file mode 100644 index 00000000..3524e8c0 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/maketables.go @@ -0,0 +1,1033 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Normalization table generator. +// Data read from the web. +// See forminfo.go for a description of the trie values associated with each rune. + +package main + +import ( + "bytes" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "regexp" + "sort" + "strconv" + "strings" + "unicode" + + "golang.org/x/text/internal/triegen" + "golang.org/x/text/internal/ucd" +) + +func main() { + flag.Parse() + loadUnicodeData() + compactCCC() + loadCompositionExclusions() + completeCharFields(FCanonical) + completeCharFields(FCompatibility) + computeNonStarterCounts() + verifyComputed() + printChars() + if *test { + testDerived() + printTestdata() + } else { + makeTables() + } +} + +var url = flag.String("url", + "http://www.unicode.org/Public/"+unicode.Version+"/ucd/", + "URL of Unicode database directory") +var tablelist = flag.String("tables", + "all", + "comma-separated list of which tables to generate; "+ + "can be 'decomp', 'recomp', 'info' and 'all'") +var test = flag.Bool("test", + false, + "test existing tables against DerivedNormalizationProps and generate test data for regression testing") +var verbose = flag.Bool("verbose", + false, + "write data to stdout as it is parsed") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") + +var logger = log.New(os.Stderr, "", log.Lshortfile) + +const MaxChar = 0x10FFFF // anything above this shouldn't exist + +// Quick Check properties of runes allow us to quickly +// determine whether a rune may occur in a normal form. +// For a given normal form, a rune may be guaranteed to occur +// verbatim (QC=Yes), may or may not combine with another +// rune (QC=Maybe), or may not occur (QC=No). +type QCResult int + +const ( + QCUnknown QCResult = iota + QCYes + QCNo + QCMaybe +) + +func (r QCResult) String() string { + switch r { + case QCYes: + return "Yes" + case QCNo: + return "No" + case QCMaybe: + return "Maybe" + } + return "***UNKNOWN***" +} + +const ( + FCanonical = iota // NFC or NFD + FCompatibility // NFKC or NFKD + FNumberOfFormTypes +) + +const ( + MComposed = iota // NFC or NFKC + MDecomposed // NFD or NFKD + MNumberOfModes +) + +// This contains only the properties we're interested in. +type Char struct { + name string + codePoint rune // if zero, this index is not a valid code point. + ccc uint8 // canonical combining class + origCCC uint8 + excludeInComp bool // from CompositionExclusions.txt + compatDecomp bool // it has a compatibility expansion + + nTrailingNonStarters uint8 + nLeadingNonStarters uint8 // must be equal to trailing if non-zero + + forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility + + state State +} + +var chars = make([]Char, MaxChar+1) +var cccMap = make(map[uint8]uint8) + +func (c Char) String() string { + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name) + fmt.Fprintf(buf, " ccc: %v\n", c.ccc) + fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp) + fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp) + fmt.Fprintf(buf, " state: %v\n", c.state) + fmt.Fprintf(buf, " NFC:\n") + fmt.Fprint(buf, c.forms[FCanonical]) + fmt.Fprintf(buf, " NFKC:\n") + fmt.Fprint(buf, c.forms[FCompatibility]) + + return buf.String() +} + +// In UnicodeData.txt, some ranges are marked like this: +// 3400;;Lo;0;L;;;;;N;;;;; +// 4DB5;;Lo;0;L;;;;;N;;;;; +// parseCharacter keeps a state variable indicating the weirdness. +type State int + +const ( + SNormal State = iota // known to be zero for the type + SFirst + SLast + SMissing +) + +var lastChar = rune('\u0000') + +func (c Char) isValid() bool { + return c.codePoint != 0 && c.state != SMissing +} + +type FormInfo struct { + quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed + verified [MNumberOfModes]bool // index: MComposed or MDecomposed + + combinesForward bool // May combine with rune on the right + combinesBackward bool // May combine with rune on the left + isOneWay bool // Never appears in result + inDecomp bool // Some decompositions result in this char. + decomp Decomposition + expandedDecomp Decomposition +} + +func (f FormInfo) String() string { + buf := bytes.NewBuffer(make([]byte, 0)) + + fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed]) + fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed]) + fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward) + fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward) + fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay) + fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp) + fmt.Fprintf(buf, " decomposition: %X\n", f.decomp) + fmt.Fprintf(buf, " expandedDecomp: %X\n", f.expandedDecomp) + + return buf.String() +} + +type Decomposition []rune + +func openReader(file string) (input io.ReadCloser) { + if *localFiles { + f, err := os.Open(file) + if err != nil { + logger.Fatal(err) + } + input = f + } else { + path := *url + file + resp, err := http.Get(path) + if err != nil { + logger.Fatal(err) + } + if resp.StatusCode != 200 { + logger.Fatal("bad GET status for "+file, resp.Status) + } + input = resp.Body + } + return +} + +func parseDecomposition(s string, skipfirst bool) (a []rune, err error) { + decomp := strings.Split(s, " ") + if len(decomp) > 0 && skipfirst { + decomp = decomp[1:] + } + for _, d := range decomp { + point, err := strconv.ParseUint(d, 16, 64) + if err != nil { + return a, err + } + a = append(a, rune(point)) + } + return a, nil +} + +func loadUnicodeData() { + f := openReader("UnicodeData.txt") + defer f.Close() + p := ucd.New(f) + for p.Next() { + r := p.Rune(ucd.CodePoint) + char := &chars[r] + + char.ccc = uint8(p.Uint(ucd.CanonicalCombiningClass)) + decmap := p.String(ucd.DecompMapping) + + exp, err := parseDecomposition(decmap, false) + isCompat := false + if err != nil { + if len(decmap) > 0 { + exp, err = parseDecomposition(decmap, true) + if err != nil { + logger.Fatalf(`%U: bad decomp |%v|: "%s"`, r, decmap, err) + } + isCompat = true + } + } + + char.name = p.String(ucd.Name) + char.codePoint = r + char.forms[FCompatibility].decomp = exp + if !isCompat { + char.forms[FCanonical].decomp = exp + } else { + char.compatDecomp = true + } + if len(decmap) > 0 { + char.forms[FCompatibility].decomp = exp + } + } + if err := p.Err(); err != nil { + logger.Fatal(err) + } +} + +// compactCCC converts the sparse set of CCC values to a continguous one, +// reducing the number of bits needed from 8 to 6. +func compactCCC() { + m := make(map[uint8]uint8) + for i := range chars { + c := &chars[i] + m[c.ccc] = 0 + } + cccs := []int{} + for v, _ := range m { + cccs = append(cccs, int(v)) + } + sort.Ints(cccs) + for i, c := range cccs { + cccMap[uint8(i)] = uint8(c) + m[uint8(c)] = uint8(i) + } + for i := range chars { + c := &chars[i] + c.origCCC = c.ccc + c.ccc = m[c.ccc] + } + if len(m) >= 1<<6 { + log.Fatalf("too many difference CCC values: %d >= 64", len(m)) + } +} + +// CompositionExclusions.txt has form: +// 0958 # ... +// See http://unicode.org/reports/tr44/ for full explanation +func loadCompositionExclusions() { + f := openReader("CompositionExclusions.txt") + defer f.Close() + p := ucd.New(f) + for p.Next() { + c := &chars[p.Rune(0)] + if c.excludeInComp { + logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint) + } + c.excludeInComp = true + } + if e := p.Err(); e != nil { + logger.Fatal(e) + } +} + +// hasCompatDecomp returns true if any of the recursive +// decompositions contains a compatibility expansion. +// In this case, the character may not occur in NFK*. +func hasCompatDecomp(r rune) bool { + c := &chars[r] + if c.compatDecomp { + return true + } + for _, d := range c.forms[FCompatibility].decomp { + if hasCompatDecomp(d) { + return true + } + } + return false +} + +// Hangul related constants. +const ( + HangulBase = 0xAC00 + HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28) + + JamoLBase = 0x1100 + JamoLEnd = 0x1113 + JamoVBase = 0x1161 + JamoVEnd = 0x1176 + JamoTBase = 0x11A8 + JamoTEnd = 0x11C3 + + JamoLVTCount = 19 * 21 * 28 + JamoTCount = 28 +) + +func isHangul(r rune) bool { + return HangulBase <= r && r < HangulEnd +} + +func isHangulWithoutJamoT(r rune) bool { + if !isHangul(r) { + return false + } + r -= HangulBase + return r < JamoLVTCount && r%JamoTCount == 0 +} + +func ccc(r rune) uint8 { + return chars[r].ccc +} + +// Insert a rune in a buffer, ordered by Canonical Combining Class. +func insertOrdered(b Decomposition, r rune) Decomposition { + n := len(b) + b = append(b, 0) + cc := ccc(r) + if cc > 0 { + // Use bubble sort. + for ; n > 0; n-- { + if ccc(b[n-1]) <= cc { + break + } + b[n] = b[n-1] + } + } + b[n] = r + return b +} + +// Recursively decompose. +func decomposeRecursive(form int, r rune, d Decomposition) Decomposition { + dcomp := chars[r].forms[form].decomp + if len(dcomp) == 0 { + return insertOrdered(d, r) + } + for _, c := range dcomp { + d = decomposeRecursive(form, c, d) + } + return d +} + +func completeCharFields(form int) { + // Phase 0: pre-expand decomposition. + for i := range chars { + f := &chars[i].forms[form] + if len(f.decomp) == 0 { + continue + } + exp := make(Decomposition, 0) + for _, c := range f.decomp { + exp = decomposeRecursive(form, c, exp) + } + f.expandedDecomp = exp + } + + // Phase 1: composition exclusion, mark decomposition. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + // Marks script-specific exclusions and version restricted. + f.isOneWay = c.excludeInComp + + // Singletons + f.isOneWay = f.isOneWay || len(f.decomp) == 1 + + // Non-starter decompositions + if len(f.decomp) > 1 { + chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0 + f.isOneWay = f.isOneWay || chk + } + + // Runes that decompose into more than two runes. + f.isOneWay = f.isOneWay || len(f.decomp) > 2 + + if form == FCompatibility { + f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint) + } + + for _, r := range f.decomp { + chars[r].forms[form].inDecomp = true + } + } + + // Phase 2: forward and backward combining. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + if !f.isOneWay && len(f.decomp) == 2 { + f0 := &chars[f.decomp[0]].forms[form] + f1 := &chars[f.decomp[1]].forms[form] + if !f0.isOneWay { + f0.combinesForward = true + } + if !f1.isOneWay { + f1.combinesBackward = true + } + } + if isHangulWithoutJamoT(rune(i)) { + f.combinesForward = true + } + } + + // Phase 3: quick check values. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + switch { + case len(f.decomp) > 0: + f.quickCheck[MDecomposed] = QCNo + case isHangul(rune(i)): + f.quickCheck[MDecomposed] = QCNo + default: + f.quickCheck[MDecomposed] = QCYes + } + switch { + case f.isOneWay: + f.quickCheck[MComposed] = QCNo + case (i & 0xffff00) == JamoLBase: + f.quickCheck[MComposed] = QCYes + if JamoLBase <= i && i < JamoLEnd { + f.combinesForward = true + } + if JamoVBase <= i && i < JamoVEnd { + f.quickCheck[MComposed] = QCMaybe + f.combinesBackward = true + f.combinesForward = true + } + if JamoTBase <= i && i < JamoTEnd { + f.quickCheck[MComposed] = QCMaybe + f.combinesBackward = true + } + case !f.combinesBackward: + f.quickCheck[MComposed] = QCYes + default: + f.quickCheck[MComposed] = QCMaybe + } + } +} + +func computeNonStarterCounts() { + // Phase 4: leading and trailing non-starter count + for i := range chars { + c := &chars[i] + + runes := []rune{rune(i)} + // We always use FCompatibility so that the CGJ insertion points do not + // change for repeated normalizations with different forms. + if exp := c.forms[FCompatibility].expandedDecomp; len(exp) > 0 { + runes = exp + } + for _, r := range runes { + if chars[r].ccc == 0 { + break + } + c.nLeadingNonStarters++ + } + for i := len(runes) - 1; i >= 0; i-- { + if chars[runes[i]].ccc == 0 { + break + } + c.nTrailingNonStarters++ + } + + // We consider runes that combine backwards to be non-starters for the + // purpose of Stream-Safe Text Processing. + for _, f := range c.forms { + if c.ccc == 0 && f.combinesBackward { + if len(c.forms[FCompatibility].expandedDecomp) > 0 { + log.Fatalf("%U: CCC==0 modifier with an expansion is not supported.", i) + } + c.nTrailingNonStarters = 1 + c.nLeadingNonStarters = 1 + } + } + + if isHangul(rune(i)) { + c.nTrailingNonStarters = 2 + if isHangulWithoutJamoT(rune(i)) { + c.nTrailingNonStarters = 1 + } + } + + if l, t := c.nLeadingNonStarters, c.nTrailingNonStarters; l > 0 && l != t { + log.Fatalf("%U: number of leading and trailing non-starters should be equal (%d vs %d)", i, l, t) + } + if t := c.nTrailingNonStarters; t > 3 { + log.Fatalf("%U: number of trailing non-starters is %d > 3", t) + } + } +} + +func printBytes(b []byte, name string) { + fmt.Printf("// %s: %d bytes\n", name, len(b)) + fmt.Printf("var %s = [...]byte {", name) + for i, c := range b { + switch { + case i%64 == 0: + fmt.Printf("\n// Bytes %x - %x\n", i, i+63) + case i%8 == 0: + fmt.Printf("\n") + } + fmt.Printf("0x%.2X, ", c) + } + fmt.Print("\n}\n\n") +} + +// See forminfo.go for format. +func makeEntry(f *FormInfo, c *Char) uint16 { + e := uint16(0) + if r := c.codePoint; HangulBase <= r && r < HangulEnd { + e |= 0x40 + } + if f.combinesForward { + e |= 0x20 + } + if f.quickCheck[MDecomposed] == QCNo { + e |= 0x4 + } + switch f.quickCheck[MComposed] { + case QCYes: + case QCNo: + e |= 0x10 + case QCMaybe: + e |= 0x18 + default: + log.Fatalf("Illegal quickcheck value %v.", f.quickCheck[MComposed]) + } + e |= uint16(c.nTrailingNonStarters) + return e +} + +// decompSet keeps track of unique decompositions, grouped by whether +// the decomposition is followed by a trailing and/or leading CCC. +type decompSet [7]map[string]bool + +const ( + normalDecomp = iota + firstMulti + firstCCC + endMulti + firstLeadingCCC + firstCCCZeroExcept + firstStarterWithNLead + lastDecomp +) + +var cname = []string{"firstMulti", "firstCCC", "endMulti", "firstLeadingCCC", "firstCCCZeroExcept", "firstStarterWithNLead", "lastDecomp"} + +func makeDecompSet() decompSet { + m := decompSet{} + for i := range m { + m[i] = make(map[string]bool) + } + return m +} +func (m *decompSet) insert(key int, s string) { + m[key][s] = true +} + +func printCharInfoTables() int { + mkstr := func(r rune, f *FormInfo) (int, string) { + d := f.expandedDecomp + s := string([]rune(d)) + if max := 1 << 6; len(s) >= max { + const msg = "%U: too many bytes in decomposition: %d >= %d" + logger.Fatalf(msg, r, len(s), max) + } + head := uint8(len(s)) + if f.quickCheck[MComposed] != QCYes { + head |= 0x40 + } + if f.combinesForward { + head |= 0x80 + } + s = string([]byte{head}) + s + + lccc := ccc(d[0]) + tccc := ccc(d[len(d)-1]) + cc := ccc(r) + if cc != 0 && lccc == 0 && tccc == 0 { + logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc) + } + if tccc < lccc && lccc != 0 { + const msg = "%U: lccc (%d) must be <= tcc (%d)" + logger.Fatalf(msg, r, lccc, tccc) + } + index := normalDecomp + nTrail := chars[r].nTrailingNonStarters + if tccc > 0 || lccc > 0 || nTrail > 0 { + tccc <<= 2 + tccc |= nTrail + s += string([]byte{tccc}) + index = endMulti + for _, r := range d[1:] { + if ccc(r) == 0 { + index = firstCCC + } + } + if lccc > 0 { + s += string([]byte{lccc}) + if index == firstCCC { + logger.Fatalf("%U: multi-segment decomposition not supported for decompositions with leading CCC != 0", r) + } + index = firstLeadingCCC + } + if cc != lccc { + if cc != 0 { + logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc) + } + index = firstCCCZeroExcept + } + } else if len(d) > 1 { + index = firstMulti + } + return index, s + } + + decompSet := makeDecompSet() + const nLeadStr = "\x00\x01" // 0-byte length and tccc with nTrail. + decompSet.insert(firstStarterWithNLead, nLeadStr) + + // Store the uniqued decompositions in a byte buffer, + // preceded by their byte length. + for _, c := range chars { + for _, f := range c.forms { + if len(f.expandedDecomp) == 0 { + continue + } + if f.combinesBackward { + logger.Fatalf("%U: combinesBackward and decompose", c.codePoint) + } + index, s := mkstr(c.codePoint, &f) + decompSet.insert(index, s) + } + } + + decompositions := bytes.NewBuffer(make([]byte, 0, 10000)) + size := 0 + positionMap := make(map[string]uint16) + decompositions.WriteString("\000") + fmt.Println("const (") + for i, m := range decompSet { + sa := []string{} + for s := range m { + sa = append(sa, s) + } + sort.Strings(sa) + for _, s := range sa { + p := decompositions.Len() + decompositions.WriteString(s) + positionMap[s] = uint16(p) + } + if cname[i] != "" { + fmt.Printf("%s = 0x%X\n", cname[i], decompositions.Len()) + } + } + fmt.Println("maxDecomp = 0x8000") + fmt.Println(")") + b := decompositions.Bytes() + printBytes(b, "decomps") + size += len(b) + + varnames := []string{"nfc", "nfkc"} + for i := 0; i < FNumberOfFormTypes; i++ { + trie := triegen.NewTrie(varnames[i]) + + for r, c := range chars { + f := c.forms[i] + d := f.expandedDecomp + if len(d) != 0 { + _, key := mkstr(c.codePoint, &f) + trie.Insert(rune(r), uint64(positionMap[key])) + if c.ccc != ccc(d[0]) { + // We assume the lead ccc of a decomposition !=0 in this case. + if ccc(d[0]) == 0 { + logger.Fatalf("Expected leading CCC to be non-zero; ccc is %d", c.ccc) + } + } + } else if c.nLeadingNonStarters > 0 && len(f.expandedDecomp) == 0 && c.ccc == 0 && !f.combinesBackward { + // Handle cases where it can't be detected that the nLead should be equal + // to nTrail. + trie.Insert(c.codePoint, uint64(positionMap[nLeadStr])) + } else if v := makeEntry(&f, &c)<<8 | uint16(c.ccc); v != 0 { + trie.Insert(c.codePoint, uint64(0x8000|v)) + } + } + sz, err := trie.Gen(os.Stdout, triegen.Compact(&normCompacter{name: varnames[i]})) + if err != nil { + logger.Fatal(err) + } + size += sz + } + return size +} + +func contains(sa []string, s string) bool { + for _, a := range sa { + if a == s { + return true + } + } + return false +} + +// Extract the version number from the URL. +func version() string { + // From http://www.unicode.org/standard/versions/#Version_Numbering: + // for the later Unicode versions, data files are located in + // versioned directories. + fields := strings.Split(*url, "/") + for _, f := range fields { + if match, _ := regexp.MatchString(`[0-9]\.[0-9]\.[0-9]`, f); match { + return f + } + } + logger.Fatal("unknown version") + return "Unknown" +} + +const fileHeader = `// Generated by running +// maketables --tables=%s --url=%s +// DO NOT EDIT + +package norm + +` + +func makeTables() { + size := 0 + if *tablelist == "" { + return + } + list := strings.Split(*tablelist, ",") + if *tablelist == "all" { + list = []string{"recomp", "info"} + } + fmt.Printf(fileHeader, *tablelist, *url) + + // Compute maximum decomposition size. + max := 0 + for _, c := range chars { + if n := len(string(c.forms[FCompatibility].expandedDecomp)); n > max { + max = n + } + } + + fmt.Println("const (") + fmt.Println("\t// Version is the Unicode edition from which the tables are derived.") + fmt.Printf("\tVersion = %q\n", version()) + fmt.Println() + fmt.Println("\t// MaxTransformChunkSize indicates the maximum number of bytes that Transform") + fmt.Println("\t// may need to write atomically for any Form. Making a destination buffer at") + fmt.Println("\t// least this size ensures that Transform can always make progress and that") + fmt.Println("\t// the user does not need to grow the buffer on an ErrShortDst.") + fmt.Printf("\tMaxTransformChunkSize = %d+maxNonStarters*4\n", len(string(0x034F))+max) + fmt.Println(")\n") + + // Print the CCC remap table. + size += len(cccMap) + fmt.Printf("var ccc = [%d]uint8{", len(cccMap)) + for i := 0; i < len(cccMap); i++ { + if i%8 == 0 { + fmt.Println() + } + fmt.Printf("%3d, ", cccMap[uint8(i)]) + } + fmt.Println("\n}\n") + + if contains(list, "info") { + size += printCharInfoTables() + } + + if contains(list, "recomp") { + // Note that we use 32 bit keys, instead of 64 bit. + // This clips the bits of three entries, but we know + // this won't cause a collision. The compiler will catch + // any changes made to UnicodeData.txt that introduces + // a collision. + // Note that the recomposition map for NFC and NFKC + // are identical. + + // Recomposition map + nrentries := 0 + for _, c := range chars { + f := c.forms[FCanonical] + if !f.isOneWay && len(f.decomp) > 0 { + nrentries++ + } + } + sz := nrentries * 8 + size += sz + fmt.Printf("// recompMap: %d bytes (entries only)\n", sz) + fmt.Println("var recompMap = map[uint32]rune{") + for i, c := range chars { + f := c.forms[FCanonical] + d := f.decomp + if !f.isOneWay && len(d) > 0 { + key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1])) + fmt.Printf("0x%.8X: 0x%.4X,\n", key, i) + } + } + fmt.Printf("}\n\n") + } + + fmt.Printf("// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size) +} + +func printChars() { + if *verbose { + for _, c := range chars { + if !c.isValid() || c.state == SMissing { + continue + } + fmt.Println(c) + } + } +} + +// verifyComputed does various consistency tests. +func verifyComputed() { + for i, c := range chars { + for _, f := range c.forms { + isNo := (f.quickCheck[MDecomposed] == QCNo) + if (len(f.decomp) > 0) != isNo && !isHangul(rune(i)) { + log.Fatalf("%U: NF*D QC must be No if rune decomposes", i) + } + + isMaybe := f.quickCheck[MComposed] == QCMaybe + if f.combinesBackward != isMaybe { + log.Fatalf("%U: NF*C QC must be Maybe if combinesBackward", i) + } + if len(f.decomp) > 0 && f.combinesForward && isMaybe { + log.Fatalf("%U: NF*C QC must be Yes or No if combinesForward and decomposes", i) + } + + if len(f.expandedDecomp) != 0 { + continue + } + if a, b := c.nLeadingNonStarters > 0, (c.ccc > 0 || f.combinesBackward); a != b { + // We accept these two runes to be treated differently (it only affects + // segment breaking in iteration, most likely on inproper use), but + // reconsider if more characters are added. + if i != 0xFF9E && i != 0xFF9F { + log.Fatalf("%U: nLead was %v; want %v", i, a, b) + } + } + } + nfc := c.forms[FCanonical] + nfkc := c.forms[FCompatibility] + if nfc.combinesBackward != nfkc.combinesBackward { + logger.Fatalf("%U: Cannot combine combinesBackward\n", c.codePoint) + } + } +} + +// Use values in DerivedNormalizationProps.txt to compare against the +// values we computed. +// DerivedNormalizationProps.txt has form: +// 00C0..00C5 ; NFD_QC; N # ... +// 0374 ; NFD_QC; N # ... +// See http://unicode.org/reports/tr44/ for full explanation +func testDerived() { + f := openReader("DerivedNormalizationProps.txt") + defer f.Close() + p := ucd.New(f) + for p.Next() { + r := p.Rune(0) + c := &chars[r] + + var ftype, mode int + qt := p.String(1) + switch qt { + case "NFC_QC": + ftype, mode = FCanonical, MComposed + case "NFD_QC": + ftype, mode = FCanonical, MDecomposed + case "NFKC_QC": + ftype, mode = FCompatibility, MComposed + case "NFKD_QC": + ftype, mode = FCompatibility, MDecomposed + default: + continue + } + var qr QCResult + switch p.String(2) { + case "Y": + qr = QCYes + case "N": + qr = QCNo + case "M": + qr = QCMaybe + default: + log.Fatalf(`Unexpected quick check value "%s"`, p.String(2)) + } + if got := c.forms[ftype].quickCheck[mode]; got != qr { + logger.Printf("%U: FAILED %s (was %v need %v)\n", r, qt, got, qr) + } + c.forms[ftype].verified[mode] = true + } + if err := p.Err(); err != nil { + logger.Fatal(err) + } + // Any unspecified value must be QCYes. Verify this. + for i, c := range chars { + for j, fd := range c.forms { + for k, qr := range fd.quickCheck { + if !fd.verified[k] && qr != QCYes { + m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n" + logger.Printf(m, i, j, k, qr, c.name) + } + } + } + } +} + +var testHeader = `// Generated by running +// maketables --test --url=%s +// +build test + +package norm + +const ( + Yes = iota + No + Maybe +) + +type formData struct { + qc uint8 + combinesForward bool + decomposition string +} + +type runeData struct { + r rune + ccc uint8 + nLead uint8 + nTrail uint8 + f [2]formData // 0: canonical; 1: compatibility +} + +func f(qc uint8, cf bool, dec string) [2]formData { + return [2]formData{{qc, cf, dec}, {qc, cf, dec}} +} + +func g(qc, qck uint8, cf, cfk bool, d, dk string) [2]formData { + return [2]formData{{qc, cf, d}, {qck, cfk, dk}} +} + +var testData = []runeData{ +` + +func printTestdata() { + type lastInfo struct { + ccc uint8 + nLead uint8 + nTrail uint8 + f string + } + last := lastInfo{} + fmt.Printf(testHeader, *url) + for r, c := range chars { + f := c.forms[FCanonical] + qc, cf, d := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp) + f = c.forms[FCompatibility] + qck, cfk, dk := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp) + s := "" + if d == dk && qc == qck && cf == cfk { + s = fmt.Sprintf("f(%s, %v, %q)", qc, cf, d) + } else { + s = fmt.Sprintf("g(%s, %s, %v, %v, %q, %q)", qc, qck, cf, cfk, d, dk) + } + current := lastInfo{c.ccc, c.nLeadingNonStarters, c.nTrailingNonStarters, s} + if last != current { + fmt.Printf("\t{0x%x, %d, %d, %d, %s},\n", r, c.origCCC, c.nLeadingNonStarters, c.nTrailingNonStarters, s) + last = current + } + } + fmt.Println("}") +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/norm_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/norm_test.go new file mode 100644 index 00000000..12dacfcf --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/norm_test.go @@ -0,0 +1,14 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm_test + +import ( + "testing" +) + +func TestPlaceHolder(t *testing.T) { + // Does nothing, just allows the Makefile to be canonical + // while waiting for the package itself to be written. +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize.go new file mode 100644 index 00000000..d8172849 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize.go @@ -0,0 +1,524 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package norm contains types and functions for normalizing Unicode strings. +package norm + +import "unicode/utf8" + +// A Form denotes a canonical representation of Unicode code points. +// The Unicode-defined normalization and equivalence forms are: +// +// NFC Unicode Normalization Form C +// NFD Unicode Normalization Form D +// NFKC Unicode Normalization Form KC +// NFKD Unicode Normalization Form KD +// +// For a Form f, this documentation uses the notation f(x) to mean +// the bytes or string x converted to the given form. +// A position n in x is called a boundary if conversion to the form can +// proceed independently on both sides: +// f(x) == append(f(x[0:n]), f(x[n:])...) +// +// References: http://unicode.org/reports/tr15/ and +// http://unicode.org/notes/tn5/. +type Form int + +const ( + NFC Form = iota + NFD + NFKC + NFKD +) + +// Bytes returns f(b). May return b if f(b) = b. +func (f Form) Bytes(b []byte) []byte { + src := inputBytes(b) + ft := formTable[f] + n, ok := ft.quickSpan(src, 0, len(b), true) + if ok { + return b + } + out := make([]byte, n, len(b)) + copy(out, b[0:n]) + rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush} + return doAppendInner(&rb, n) +} + +// String returns f(s). +func (f Form) String(s string) string { + src := inputString(s) + ft := formTable[f] + n, ok := ft.quickSpan(src, 0, len(s), true) + if ok { + return s + } + out := make([]byte, n, len(s)) + copy(out, s[0:n]) + rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush} + return string(doAppendInner(&rb, n)) +} + +// IsNormal returns true if b == f(b). +func (f Form) IsNormal(b []byte) bool { + src := inputBytes(b) + ft := formTable[f] + bp, ok := ft.quickSpan(src, 0, len(b), true) + if ok { + return true + } + rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)} + rb.setFlusher(nil, cmpNormalBytes) + for bp < len(b) { + rb.out = b[bp:] + if bp = decomposeSegment(&rb, bp, true); bp < 0 { + return false + } + bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true) + } + return true +} + +func cmpNormalBytes(rb *reorderBuffer) bool { + b := rb.out + for i := 0; i < rb.nrune; i++ { + info := rb.rune[i] + if int(info.size) > len(b) { + return false + } + p := info.pos + pe := p + info.size + for ; p < pe; p++ { + if b[0] != rb.byte[p] { + return false + } + b = b[1:] + } + } + return true +} + +// IsNormalString returns true if s == f(s). +func (f Form) IsNormalString(s string) bool { + src := inputString(s) + ft := formTable[f] + bp, ok := ft.quickSpan(src, 0, len(s), true) + if ok { + return true + } + rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)} + rb.setFlusher(nil, func(rb *reorderBuffer) bool { + for i := 0; i < rb.nrune; i++ { + info := rb.rune[i] + if bp+int(info.size) > len(s) { + return false + } + p := info.pos + pe := p + info.size + for ; p < pe; p++ { + if s[bp] != rb.byte[p] { + return false + } + bp++ + } + } + return true + }) + for bp < len(s) { + if bp = decomposeSegment(&rb, bp, true); bp < 0 { + return false + } + bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true) + } + return true +} + +// patchTail fixes a case where a rune may be incorrectly normalized +// if it is followed by illegal continuation bytes. It returns the +// patched buffer and whether the decomposition is still in progress. +func patchTail(rb *reorderBuffer) bool { + info, p := lastRuneStart(&rb.f, rb.out) + if p == -1 || info.size == 0 { + return true + } + end := p + int(info.size) + extra := len(rb.out) - end + if extra > 0 { + // Potentially allocating memory. However, this only + // happens with ill-formed UTF-8. + x := make([]byte, 0) + x = append(x, rb.out[len(rb.out)-extra:]...) + rb.out = rb.out[:end] + decomposeToLastBoundary(rb) + rb.doFlush() + rb.out = append(rb.out, x...) + return false + } + buf := rb.out[p:] + rb.out = rb.out[:p] + decomposeToLastBoundary(rb) + if s := rb.ss.next(info); s == ssStarter { + rb.doFlush() + rb.ss.first(info) + } else if s == ssOverflow { + rb.doFlush() + rb.insertCGJ() + rb.ss = 0 + } + rb.insertUnsafe(inputBytes(buf), 0, info) + return true +} + +func appendQuick(rb *reorderBuffer, i int) int { + if rb.nsrc == i { + return i + } + end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true) + rb.out = rb.src.appendSlice(rb.out, i, end) + return end +} + +// Append returns f(append(out, b...)). +// The buffer out must be nil, empty, or equal to f(out). +func (f Form) Append(out []byte, src ...byte) []byte { + return f.doAppend(out, inputBytes(src), len(src)) +} + +func (f Form) doAppend(out []byte, src input, n int) []byte { + if n == 0 { + return out + } + ft := formTable[f] + // Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer. + if len(out) == 0 { + p, _ := ft.quickSpan(src, 0, n, true) + out = src.appendSlice(out, 0, p) + if p == n { + return out + } + rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush} + return doAppendInner(&rb, p) + } + rb := reorderBuffer{f: *ft, src: src, nsrc: n} + return doAppend(&rb, out, 0) +} + +func doAppend(rb *reorderBuffer, out []byte, p int) []byte { + rb.setFlusher(out, appendFlush) + src, n := rb.src, rb.nsrc + doMerge := len(out) > 0 + if q := src.skipContinuationBytes(p); q > p { + // Move leading non-starters to destination. + rb.out = src.appendSlice(rb.out, p, q) + p = q + doMerge = patchTail(rb) + } + fd := &rb.f + if doMerge { + var info Properties + if p < n { + info = fd.info(src, p) + if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 { + if p == 0 { + decomposeToLastBoundary(rb) + } + p = decomposeSegment(rb, p, true) + } + } + if info.size == 0 { + rb.doFlush() + // Append incomplete UTF-8 encoding. + return src.appendSlice(rb.out, p, n) + } + if rb.nrune > 0 { + return doAppendInner(rb, p) + } + } + p = appendQuick(rb, p) + return doAppendInner(rb, p) +} + +func doAppendInner(rb *reorderBuffer, p int) []byte { + for n := rb.nsrc; p < n; { + p = decomposeSegment(rb, p, true) + p = appendQuick(rb, p) + } + return rb.out +} + +// AppendString returns f(append(out, []byte(s))). +// The buffer out must be nil, empty, or equal to f(out). +func (f Form) AppendString(out []byte, src string) []byte { + return f.doAppend(out, inputString(src), len(src)) +} + +// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpan(b []byte) int { + n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true) + return n +} + +// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and +// whether any non-normalized parts were found. If atEOF is false, n will +// not point past the last segment if this segment might be become +// non-normalized by appending other runes. +func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) { + var lastCC uint8 + ss := streamSafe(0) + lastSegStart := i + for n = end; i < n; { + if j := src.skipASCII(i, n); i != j { + i = j + lastSegStart = i - 1 + lastCC = 0 + ss = 0 + continue + } + info := f.info(src, i) + if info.size == 0 { + if atEOF { + // include incomplete runes + return n, true + } + return lastSegStart, true + } + // This block needs to be before the next, because it is possible to + // have an overflow for runes that are starters (e.g. with U+FF9E). + switch ss.next(info) { + case ssStarter: + ss.first(info) + lastSegStart = i + case ssOverflow: + return lastSegStart, false + case ssSuccess: + if lastCC > info.ccc { + return lastSegStart, false + } + } + if f.composing { + if !info.isYesC() { + break + } + } else { + if !info.isYesD() { + break + } + } + lastCC = info.ccc + i += int(info.size) + } + if i == n { + if !atEOF { + n = lastSegStart + } + return n, true + } + return lastSegStart, false +} + +// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpanString(s string) int { + n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true) + return n +} + +// FirstBoundary returns the position i of the first boundary in b +// or -1 if b contains no boundary. +func (f Form) FirstBoundary(b []byte) int { + return f.firstBoundary(inputBytes(b), len(b)) +} + +func (f Form) firstBoundary(src input, nsrc int) int { + i := src.skipContinuationBytes(0) + if i >= nsrc { + return -1 + } + fd := formTable[f] + ss := streamSafe(0) + // We should call ss.first here, but we can't as the first rune is + // skipped already. This means FirstBoundary can't really determine + // CGJ insertion points correctly. Luckily it doesn't have to. + // TODO: consider adding NextBoundary + for { + info := fd.info(src, i) + if info.size == 0 { + return -1 + } + if s := ss.next(info); s != ssSuccess { + return i + } + i += int(info.size) + if i >= nsrc { + if !info.BoundaryAfter() && !ss.isMax() { + return -1 + } + return nsrc + } + } +} + +// FirstBoundaryInString returns the position i of the first boundary in s +// or -1 if s contains no boundary. +func (f Form) FirstBoundaryInString(s string) int { + return f.firstBoundary(inputString(s), len(s)) +} + +// LastBoundary returns the position i of the last boundary in b +// or -1 if b contains no boundary. +func (f Form) LastBoundary(b []byte) int { + return lastBoundary(formTable[f], b) +} + +func lastBoundary(fd *formInfo, b []byte) int { + i := len(b) + info, p := lastRuneStart(fd, b) + if p == -1 { + return -1 + } + if info.size == 0 { // ends with incomplete rune + if p == 0 { // starts with incomplete rune + return -1 + } + i = p + info, p = lastRuneStart(fd, b[:i]) + if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter + return i + } + } + if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8 + return i + } + if info.BoundaryAfter() { + return i + } + ss := streamSafe(0) + v := ss.backwards(info) + for i = p; i >= 0 && v != ssStarter; i = p { + info, p = lastRuneStart(fd, b[:i]) + if v = ss.backwards(info); v == ssOverflow { + break + } + if p+int(info.size) != i { + if p == -1 { // no boundary found + return -1 + } + return i // boundary after an illegal UTF-8 encoding + } + } + return i +} + +// decomposeSegment scans the first segment in src into rb. It inserts 0x034f +// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters +// and returns the number of bytes consumed from src or iShortDst or iShortSrc. +func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { + // Force one character to be consumed. + info := rb.f.info(rb.src, sp) + if info.size == 0 { + return 0 + } + if rb.nrune > 0 { + if s := rb.ss.next(info); s == ssStarter { + goto end + } else if s == ssOverflow { + rb.insertCGJ() + goto end + } + } else { + rb.ss.first(info) + } + if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { + return int(err) + } + for { + sp += int(info.size) + if sp >= rb.nsrc { + if !atEOF && !info.BoundaryAfter() { + return int(iShortSrc) + } + break + } + info = rb.f.info(rb.src, sp) + if info.size == 0 { + if !atEOF { + return int(iShortSrc) + } + break + } + if s := rb.ss.next(info); s == ssStarter { + break + } else if s == ssOverflow { + rb.insertCGJ() + break + } + if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { + return int(err) + } + } +end: + if !rb.doFlush() { + return int(iShortDst) + } + return sp +} + +// lastRuneStart returns the runeInfo and position of the last +// rune in buf or the zero runeInfo and -1 if no rune was found. +func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) { + p := len(buf) - 1 + for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- { + } + if p < 0 { + return Properties{}, -1 + } + return fd.info(inputBytes(buf), p), p +} + +// decomposeToLastBoundary finds an open segment at the end of the buffer +// and scans it into rb. Returns the buffer minus the last segment. +func decomposeToLastBoundary(rb *reorderBuffer) { + fd := &rb.f + info, i := lastRuneStart(fd, rb.out) + if int(info.size) != len(rb.out)-i { + // illegal trailing continuation bytes + return + } + if info.BoundaryAfter() { + return + } + var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order + padd := 0 + ss := streamSafe(0) + p := len(rb.out) + for { + add[padd] = info + v := ss.backwards(info) + if v == ssOverflow { + // Note that if we have an overflow, it the string we are appending to + // is not correctly normalized. In this case the behavior is undefined. + break + } + padd++ + p -= int(info.size) + if v == ssStarter || p < 0 { + break + } + info, i = lastRuneStart(fd, rb.out[:p]) + if int(info.size) != p-i { + break + } + } + rb.ss = ss + // Copy bytes for insertion as we may need to overwrite rb.out. + var buf [maxBufferSize * utf8.UTFMax]byte + cp := buf[:copy(buf[:], rb.out[p:])] + rb.out = rb.out[:p] + for padd--; padd >= 0; padd-- { + info = add[padd] + rb.insertUnsafe(inputBytes(cp), 0, info) + cp = cp[info.size:] + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize_test.go new file mode 100644 index 00000000..643d11ed --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normalize_test.go @@ -0,0 +1,1086 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bytes" + "flag" + "fmt" + "io" + "log" + "strings" + "testing" + "unicode/utf8" +) + +var ( + testn = flag.Int("testn", -1, "specific test number to run or -1 for all") +) + +// pc replaces any rune r that is repeated n times, for n > 1, with r{n}. +func pc(s string) []byte { + b := bytes.NewBuffer(make([]byte, 0, len(s))) + for i := 0; i < len(s); { + r, sz := utf8.DecodeRuneInString(s[i:]) + n := 0 + if sz == 1 { + // Special-case one-byte case to handle repetition for invalid UTF-8. + for c := s[i]; i+n < len(s) && s[i+n] == c; n++ { + } + } else { + for _, r2 := range s[i:] { + if r2 != r { + break + } + n++ + } + } + b.WriteString(s[i : i+sz]) + if n > 1 { + fmt.Fprintf(b, "{%d}", n) + } + i += sz * n + } + return b.Bytes() +} + +// pidx finds the index from which two strings start to differ, plus context. +// It returns the index and ellipsis if the index is greater than 0. +func pidx(a, b string) (i int, prefix string) { + for ; i < len(a) && i < len(b) && a[i] == b[i]; i++ { + } + if i < 8 { + return 0, "" + } + i -= 3 // ensure taking at least one full rune before the difference. + for k := i - 7; i > k && !utf8.RuneStart(a[i]); i-- { + } + return i, "..." +} + +type PositionTest struct { + input string + pos int + buffer string // expected contents of reorderBuffer, if applicable +} + +type positionFunc func(rb *reorderBuffer, s string) (int, []byte) + +func runPosTests(t *testing.T, name string, f Form, fn positionFunc, tests []PositionTest) { + rb := reorderBuffer{} + rb.init(f, nil) + for i, test := range tests { + rb.reset() + rb.src = inputString(test.input) + rb.nsrc = len(test.input) + pos, out := fn(&rb, test.input) + if pos != test.pos { + t.Errorf("%s:%d: position is %d; want %d", name, i, pos, test.pos) + } + if outs := string(out); outs != test.buffer { + k, pfx := pidx(outs, test.buffer) + t.Errorf("%s:%d: buffer \nwas %s%+q; \nwant %s%+q", name, i, pfx, pc(outs[k:]), pfx, pc(test.buffer[k:])) + } + } +} + +func grave(n int) string { + return rep(0x0300, n) +} + +func rep(r rune, n int) string { + return strings.Repeat(string(r), n) +} + +const segSize = maxByteBufferSize + +var cgj = GraphemeJoiner + +var decomposeSegmentTests = []PositionTest{ + // illegal runes + {"\xC0", 0, ""}, + {"\u00E0\x80", 2, "\u0061\u0300"}, + // starter + {"a", 1, "a"}, + {"ab", 1, "a"}, + // starter + composing + {"a\u0300", 3, "a\u0300"}, + {"a\u0300b", 3, "a\u0300"}, + // with decomposition + {"\u00C0", 2, "A\u0300"}, + {"\u00C0b", 2, "A\u0300"}, + // long + {grave(31), 60, grave(30) + cgj}, + {grave(30), 60, grave(30)}, + {grave(30) + "\uff9e", 60, grave(30) + cgj}, + // ends with incomplete UTF-8 encoding + {"\xCC", 0, ""}, + {"\u0300\xCC", 2, "\u0300"}, +} + +func decomposeSegmentF(rb *reorderBuffer, s string) (int, []byte) { + rb.initString(NFD, s) + rb.setFlusher(nil, appendFlush) + p := decomposeSegment(rb, 0, true) + return p, rb.out +} + +func TestDecomposeSegment(t *testing.T) { + runPosTests(t, "TestDecomposeSegment", NFC, decomposeSegmentF, decomposeSegmentTests) +} + +var firstBoundaryTests = []PositionTest{ + // no boundary + {"", -1, ""}, + {"\u0300", -1, ""}, + {"\x80\x80", -1, ""}, + // illegal runes + {"\xff", 0, ""}, + {"\u0300\xff", 2, ""}, + {"\u0300\xc0\x80\x80", 2, ""}, + // boundaries + {"a", 0, ""}, + {"\u0300a", 2, ""}, + // Hangul + {"\u1103\u1161", 0, ""}, + {"\u110B\u1173\u11B7", 0, ""}, + {"\u1161\u110B\u1173\u11B7", 3, ""}, + {"\u1173\u11B7\u1103\u1161", 6, ""}, + // too many combining characters. + {grave(maxNonStarters - 1), -1, ""}, + {grave(maxNonStarters), 60, ""}, + {grave(maxNonStarters + 1), 60, ""}, +} + +func firstBoundaryF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.FirstBoundary([]byte(s)), nil +} + +func firstBoundaryStringF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.FirstBoundaryInString(s), nil +} + +func TestFirstBoundary(t *testing.T) { + runPosTests(t, "TestFirstBoundary", NFC, firstBoundaryF, firstBoundaryTests) + runPosTests(t, "TestFirstBoundaryInString", NFC, firstBoundaryStringF, firstBoundaryTests) +} + +var decomposeToLastTests = []PositionTest{ + // ends with inert character + {"Hello!", 6, ""}, + {"\u0632", 2, ""}, + {"a\u0301\u0635", 5, ""}, + // ends with non-inert starter + {"a", 0, "a"}, + {"a\u0301a", 3, "a"}, + {"a\u0301\u03B9", 3, "\u03B9"}, + {"a\u0327", 0, "a\u0327"}, + // illegal runes + {"\xFF", 1, ""}, + {"aa\xFF", 3, ""}, + {"\xC0\x80\x80", 3, ""}, + {"\xCC\x80\x80", 3, ""}, + // ends with incomplete UTF-8 encoding + {"a\xCC", 2, ""}, + // ends with combining characters + {"\u0300\u0301", 0, "\u0300\u0301"}, + {"a\u0300\u0301", 0, "a\u0300\u0301"}, + {"a\u0301\u0308", 0, "a\u0301\u0308"}, + {"a\u0308\u0301", 0, "a\u0308\u0301"}, + {"aaaa\u0300\u0301", 3, "a\u0300\u0301"}, + {"\u0300a\u0300\u0301", 2, "a\u0300\u0301"}, + {"\u00C0", 0, "A\u0300"}, + {"a\u00C0", 1, "A\u0300"}, + // decomposing + {"a\u0300\u00E0", 3, "a\u0300"}, + // multisegment decompositions (flushes leading segments) + {"a\u0300\uFDC0", 7, "\u064A"}, + {"\uFDC0" + grave(29), 4, "\u064A" + grave(29)}, + {"\uFDC0" + grave(30), 4, "\u064A" + grave(30)}, + {"\uFDC0" + grave(31), 5, grave(30)}, + {"\uFDFA" + grave(14), 31, "\u0645" + grave(14)}, + // Overflow + {"\u00E0" + grave(29), 0, "a" + grave(30)}, + {"\u00E0" + grave(30), 2, grave(30)}, + // Hangul + {"a\u1103", 1, "\u1103"}, + {"a\u110B", 1, "\u110B"}, + {"a\u110B\u1173", 1, "\u110B\u1173"}, + // See comment in composition.go:compBoundaryAfter. + {"a\u110B\u1173\u11B7", 1, "\u110B\u1173\u11B7"}, + {"a\uC73C", 1, "\u110B\u1173"}, + {"다음", 3, "\u110B\u1173\u11B7"}, + {"다", 0, "\u1103\u1161"}, + {"\u1103\u1161\u110B\u1173\u11B7", 6, "\u110B\u1173\u11B7"}, + {"\u110B\u1173\u11B7\u1103\u1161", 9, "\u1103\u1161"}, + {"다음음", 6, "\u110B\u1173\u11B7"}, + {"음다다", 6, "\u1103\u1161"}, + // maximized buffer + {"a" + grave(30), 0, "a" + grave(30)}, + // Buffer overflow + {"a" + grave(31), 3, grave(30)}, + // weird UTF-8 + {"a\u0300\u11B7", 0, "a\u0300\u11B7"}, +} + +func decomposeToLast(rb *reorderBuffer, s string) (int, []byte) { + rb.setFlusher([]byte(s), appendFlush) + decomposeToLastBoundary(rb) + buf := rb.flush(nil) + return len(rb.out), buf +} + +func TestDecomposeToLastBoundary(t *testing.T) { + runPosTests(t, "TestDecomposeToLastBoundary", NFKC, decomposeToLast, decomposeToLastTests) +} + +var lastBoundaryTests = []PositionTest{ + // ends with inert character + {"Hello!", 6, ""}, + {"\u0632", 2, ""}, + // ends with non-inert starter + {"a", 0, ""}, + // illegal runes + {"\xff", 1, ""}, + {"aa\xff", 3, ""}, + {"a\xff\u0300", 1, ""}, + {"\xc0\x80\x80", 3, ""}, + {"\xc0\x80\x80\u0300", 3, ""}, + // ends with incomplete UTF-8 encoding + {"\xCC", -1, ""}, + {"\xE0\x80", -1, ""}, + {"\xF0\x80\x80", -1, ""}, + {"a\xCC", 0, ""}, + {"\x80\xCC", 1, ""}, + {"\xCC\xCC", 1, ""}, + // ends with combining characters + {"a\u0300\u0301", 0, ""}, + {"aaaa\u0300\u0301", 3, ""}, + {"\u0300a\u0300\u0301", 2, ""}, + {"\u00C0", 0, ""}, + {"a\u00C0", 1, ""}, + // decomposition may recombine + {"\u0226", 0, ""}, + // no boundary + {"", -1, ""}, + {"\u0300\u0301", -1, ""}, + {"\u0300", -1, ""}, + {"\x80\x80", -1, ""}, + {"\x80\x80\u0301", -1, ""}, + // Hangul + {"다음", 3, ""}, + {"다", 0, ""}, + {"\u1103\u1161\u110B\u1173\u11B7", 6, ""}, + {"\u110B\u1173\u11B7\u1103\u1161", 9, ""}, + // too many combining characters. + {grave(maxNonStarters - 1), -1, ""}, + // May still be preceded with a non-starter. + {grave(maxNonStarters), -1, ""}, + // May still need to insert a cgj after the last combiner. + {grave(maxNonStarters + 1), 2, ""}, + {grave(maxNonStarters + 2), 4, ""}, + + {"a" + grave(maxNonStarters-1), 0, ""}, + {"a" + grave(maxNonStarters), 0, ""}, + // May still need to insert a cgj after the last combiner. + {"a" + grave(maxNonStarters+1), 3, ""}, + {"a" + grave(maxNonStarters+2), 5, ""}, +} + +func lastBoundaryF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.LastBoundary([]byte(s)), nil +} + +func TestLastBoundary(t *testing.T) { + runPosTests(t, "TestLastBoundary", NFC, lastBoundaryF, lastBoundaryTests) +} + +var quickSpanTests = []PositionTest{ + {"", 0, ""}, + // starters + {"a", 1, ""}, + {"abc", 3, ""}, + {"\u043Eb", 3, ""}, + // incomplete last rune. + {"\xCC", 1, ""}, + {"a\xCC", 2, ""}, + // incorrectly ordered combining characters + {"\u0300\u0316", 0, ""}, + {"\u0300\u0316cd", 0, ""}, + // have a maximum number of combining characters. + {rep(0x035D, 30) + "\u035B", 0, ""}, + {"a" + rep(0x035D, 30) + "\u035B", 0, ""}, + {"Ɵ" + rep(0x035D, 30) + "\u035B", 0, ""}, + {"aa" + rep(0x035D, 30) + "\u035B", 1, ""}, + {rep(0x035D, 30) + cgj + "\u035B", 64, ""}, + {"a" + rep(0x035D, 30) + cgj + "\u035B", 65, ""}, + {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", 66, ""}, + {"aa" + rep(0x035D, 30) + cgj + "\u035B", 66, ""}, +} + +var quickSpanNFDTests = []PositionTest{ + // needs decomposing + {"\u00C0", 0, ""}, + {"abc\u00C0", 3, ""}, + // correctly ordered combining characters + {"\u0300", 2, ""}, + {"ab\u0300", 4, ""}, + {"ab\u0300cd", 6, ""}, + {"\u0300cd", 4, ""}, + {"\u0316\u0300", 4, ""}, + {"ab\u0316\u0300", 6, ""}, + {"ab\u0316\u0300cd", 8, ""}, + {"ab\u0316\u0300\u00C0", 6, ""}, + {"\u0316\u0300cd", 6, ""}, + {"\u043E\u0308b", 5, ""}, + // incorrectly ordered combining characters + {"ab\u0300\u0316", 1, ""}, // TODO: we could skip 'b' as well. + {"ab\u0300\u0316cd", 1, ""}, + // Hangul + {"같은", 0, ""}, +} + +var quickSpanNFCTests = []PositionTest{ + // okay composed + {"\u00C0", 2, ""}, + {"abc\u00C0", 5, ""}, + // correctly ordered combining characters + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u00C0\u035D", 4, ""}, + // we do not special case leading combining characters + {"\u0300cd", 0, ""}, + {"\u0300", 0, ""}, + {"\u0316\u0300", 0, ""}, + {"\u0316\u0300cd", 0, ""}, + // incorrectly ordered combining characters + {"ab\u0300\u0316", 1, ""}, + {"ab\u0300\u0316cd", 1, ""}, + // Hangul + {"같은", 6, ""}, + // We return the start of the violating segment in case of overflow. + {grave(30) + "\uff9e", 0, ""}, + {grave(30), 0, ""}, +} + +func doQuickSpan(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.QuickSpan([]byte(s)), nil +} + +func doQuickSpanString(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.QuickSpanString(s), nil +} + +func TestQuickSpan(t *testing.T) { + runPosTests(t, "TestQuickSpanNFD1", NFD, doQuickSpan, quickSpanTests) + runPosTests(t, "TestQuickSpanNFD2", NFD, doQuickSpan, quickSpanNFDTests) + runPosTests(t, "TestQuickSpanNFC1", NFC, doQuickSpan, quickSpanTests) + runPosTests(t, "TestQuickSpanNFC2", NFC, doQuickSpan, quickSpanNFCTests) + + runPosTests(t, "TestQuickSpanStringNFD1", NFD, doQuickSpanString, quickSpanTests) + runPosTests(t, "TestQuickSpanStringNFD2", NFD, doQuickSpanString, quickSpanNFDTests) + runPosTests(t, "TestQuickSpanStringNFC1", NFC, doQuickSpanString, quickSpanTests) + runPosTests(t, "TestQuickSpanStringNFC2", NFC, doQuickSpanString, quickSpanNFCTests) +} + +var isNormalTests = []PositionTest{ + {"", 1, ""}, + // illegal runes + {"\xff", 1, ""}, + // starters + {"a", 1, ""}, + {"abc", 1, ""}, + {"\u043Eb", 1, ""}, + // incorrectly ordered combining characters + {"\u0300\u0316", 0, ""}, + {"ab\u0300\u0316", 0, ""}, + {"ab\u0300\u0316cd", 0, ""}, + {"\u0300\u0316cd", 0, ""}, +} +var isNormalNFDTests = []PositionTest{ + // needs decomposing + {"\u00C0", 0, ""}, + {"abc\u00C0", 0, ""}, + // correctly ordered combining characters + {"\u0300", 1, ""}, + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"\u0300cd", 1, ""}, + {"\u0316\u0300", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u0316\u0300cd", 1, ""}, + {"\u043E\u0308b", 1, ""}, + // Hangul + {"같은", 0, ""}, +} +var isNormalNFCTests = []PositionTest{ + // okay composed + {"\u00C0", 1, ""}, + {"abc\u00C0", 1, ""}, + // need reordering + {"a\u0300", 0, ""}, + {"a\u0300cd", 0, ""}, + {"a\u0316\u0300", 0, ""}, + {"a\u0316\u0300cd", 0, ""}, + // correctly ordered combining characters + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u00C0\u035D", 1, ""}, + {"\u0300", 1, ""}, + {"\u0316\u0300cd", 1, ""}, + // Hangul + {"같은", 1, ""}, +} + +var isNormalNFKXTests = []PositionTest{ + // Special case. + {"\u00BC", 0, ""}, +} + +func isNormalF(rb *reorderBuffer, s string) (int, []byte) { + if rb.f.form.IsNormal([]byte(s)) { + return 1, nil + } + return 0, nil +} + +func isNormalStringF(rb *reorderBuffer, s string) (int, []byte) { + if rb.f.form.IsNormalString(s) { + return 1, nil + } + return 0, nil +} + +func TestIsNormal(t *testing.T) { + runPosTests(t, "TestIsNormalNFD1", NFD, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFD2", NFD, isNormalF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFC1", NFC, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFC2", NFC, isNormalF, isNormalNFCTests) + runPosTests(t, "TestIsNormalNFKD1", NFKD, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFKD2", NFKD, isNormalF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFKD3", NFKD, isNormalF, isNormalNFKXTests) + runPosTests(t, "TestIsNormalNFKC1", NFKC, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFKC2", NFKC, isNormalF, isNormalNFCTests) + runPosTests(t, "TestIsNormalNFKC3", NFKC, isNormalF, isNormalNFKXTests) +} + +func TestIsNormalString(t *testing.T) { + runPosTests(t, "TestIsNormalNFD1", NFD, isNormalStringF, isNormalTests) + runPosTests(t, "TestIsNormalNFD2", NFD, isNormalStringF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFC1", NFC, isNormalStringF, isNormalTests) + runPosTests(t, "TestIsNormalNFC2", NFC, isNormalStringF, isNormalNFCTests) +} + +type AppendTest struct { + left string + right string + out string +} + +type appendFunc func(f Form, out []byte, s string) []byte + +var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"} + +func runNormTests(t *testing.T, name string, fn appendFunc) { + for f := NFC; f <= NFKD; f++ { + runAppendTests(t, name, f, fn, normTests[f]) + } +} + +func runAppendTests(t *testing.T, name string, f Form, fn appendFunc, tests []AppendTest) { + for i, test := range tests { + if *testn >= 0 && i != *testn { + continue + } + out := []byte(test.left) + have := string(fn(f, out, test.right)) + if len(have) != len(test.out) { + t.Errorf("%s.%s:%d: length is %d; want %d (%+q vs %+q)", fstr[f], name, i, len(have), len(test.out), pc(have), pc(test.out)) + } + if have != test.out { + k, pf := pidx(have, test.out) + t.Errorf("%s.%s:%d: \nwas %s%+q; \nwant %s%+q", fstr[f], name, i, pf, pc(have[k:]), pf, pc(test.out[k:])) + } + + // Bootstrap by normalizing input. Ensures that the various variants + // behave the same. + for g := NFC; g <= NFKD; g++ { + if f == g { + continue + } + want := g.String(test.left + test.right) + have := string(fn(g, g.AppendString(nil, test.left), test.right)) + if len(have) != len(want) { + t.Errorf("%s(%s.%s):%d: length is %d; want %d (%+q vs %+q)", fstr[g], fstr[f], name, i, len(have), len(want), pc(have), pc(want)) + } + if have != want { + k, pf := pidx(have, want) + t.Errorf("%s(%s.%s):%d: \nwas %s%+q; \nwant %s%+q", fstr[g], fstr[f], name, i, pf, pc(have[k:]), pf, pc(want[k:])) + } + } + } +} + +var normTests = [][]AppendTest{ + appendTestsNFC, + appendTestsNFD, + appendTestsNFKC, + appendTestsNFKD, +} + +var appendTestsNFC = []AppendTest{ + {"", ascii, ascii}, + {"", txt_all, txt_all}, + {"\uff9e", grave(30), "\uff9e" + grave(29) + cgj + grave(1)}, + {grave(30), "\uff9e", grave(30) + cgj + "\uff9e"}, + + // Tests designed for Iter. + { // ordering of non-composing combining characters + "", + "\u0305\u0316", + "\u0316\u0305", + }, + { // segment overflow + "", + "a" + rep(0x0305, maxNonStarters+4) + "\u0316", + "a" + rep(0x0305, maxNonStarters) + cgj + "\u0316" + rep(0x305, 4), + }, +} + +var appendTestsNFD = []AppendTest{ +// TODO: Move some of the tests here. +} + +var appendTestsNFKC = []AppendTest{ + // empty buffers + {"", "", ""}, + {"a", "", "a"}, + {"", "a", "a"}, + {"", "\u0041\u0307\u0304", "\u01E0"}, + // segment split across buffers + {"", "a\u0300b", "\u00E0b"}, + {"a", "\u0300b", "\u00E0b"}, + {"a", "\u0300\u0316", "\u00E0\u0316"}, + {"a", "\u0316\u0300", "\u00E0\u0316"}, + {"a", "\u0300a\u0300", "\u00E0\u00E0"}, + {"a", "\u0300a\u0300a\u0300", "\u00E0\u00E0\u00E0"}, + {"a", "\u0300aaa\u0300aaa\u0300", "\u00E0aa\u00E0aa\u00E0"}, + {"a\u0300", "\u0327", "\u00E0\u0327"}, + {"a\u0327", "\u0300", "\u00E0\u0327"}, + {"a\u0316", "\u0300", "\u00E0\u0316"}, + {"\u0041\u0307", "\u0304", "\u01E0"}, + // Hangul + {"", "\u110B\u1173", "\uC73C"}, + {"", "\u1103\u1161", "\uB2E4"}, + {"", "\u110B\u1173\u11B7", "\uC74C"}, + {"", "\u320E", "\x28\uAC00\x29"}, + {"", "\x28\u1100\u1161\x29", "\x28\uAC00\x29"}, + {"\u1103", "\u1161", "\uB2E4"}, + {"\u110B", "\u1173\u11B7", "\uC74C"}, + {"\u110B\u1173", "\u11B7", "\uC74C"}, + {"\uC73C", "\u11B7", "\uC74C"}, + // UTF-8 encoding split across buffers + {"a\xCC", "\x80", "\u00E0"}, + {"a\xCC", "\x80b", "\u00E0b"}, + {"a\xCC", "\x80a\u0300", "\u00E0\u00E0"}, + {"a\xCC", "\x80\x80", "\u00E0\x80"}, + {"a\xCC", "\x80\xCC", "\u00E0\xCC"}, + {"a\u0316\xCC", "\x80a\u0316\u0300", "\u00E0\u0316\u00E0\u0316"}, + // ending in incomplete UTF-8 encoding + {"", "\xCC", "\xCC"}, + {"a", "\xCC", "a\xCC"}, + {"a", "b\xCC", "ab\xCC"}, + {"\u0226", "\xCC", "\u0226\xCC"}, + // illegal runes + {"", "\x80", "\x80"}, + {"", "\x80\x80\x80", "\x80\x80\x80"}, + {"", "\xCC\x80\x80\x80", "\xCC\x80\x80\x80"}, + {"", "a\x80", "a\x80"}, + {"", "a\x80\x80\x80", "a\x80\x80\x80"}, + {"", "a\x80\x80\x80\x80\x80\x80", "a\x80\x80\x80\x80\x80\x80"}, + {"a", "\x80\x80\x80", "a\x80\x80\x80"}, + // overflow + {"", strings.Repeat("\x80", 33), strings.Repeat("\x80", 33)}, + {strings.Repeat("\x80", 33), "", strings.Repeat("\x80", 33)}, + {strings.Repeat("\x80", 33), strings.Repeat("\x80", 33), strings.Repeat("\x80", 66)}, + // overflow of combining characters + {"", grave(34), grave(30) + cgj + grave(4)}, + {"", grave(36), grave(30) + cgj + grave(6)}, + {grave(29), grave(5), grave(30) + cgj + grave(4)}, + {grave(30), grave(4), grave(30) + cgj + grave(4)}, + {grave(30), grave(3), grave(30) + cgj + grave(3)}, + {grave(30) + "\xCC", "\x80", grave(30) + cgj + grave(1)}, + {"", "\uFDFA" + grave(14), "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645" + grave(14)}, + {"", "\uFDFA" + grave(28) + "\u0316", "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645\u0316" + grave(28)}, + // - First rune has a trailing non-starter. + {"\u00d5", grave(30), "\u00d5" + grave(29) + cgj + grave(1)}, + // - U+FF9E decomposes into a non-starter in compatibility mode. A CGJ must be + // inserted even when FF9E starts a new segment. + {"\uff9e", grave(30), "\u3099" + grave(29) + cgj + grave(1)}, + {grave(30), "\uff9e", grave(30) + cgj + "\u3099"}, + // - Many non-starter decompositions in a row causing overflow. + {"", rep(0x340, 31), rep(0x300, 30) + cgj + "\u0300"}, + {"", rep(0xFF9E, 31), rep(0x3099, 30) + cgj + "\u3099"}, + // weird UTF-8 + {"\u00E0\xE1", "\x86", "\u00E0\xE1\x86"}, + {"a\u0300\u11B7", "\u0300", "\u00E0\u11B7\u0300"}, + {"a\u0300\u11B7\u0300", "\u0300", "\u00E0\u11B7\u0300\u0300"}, + {"\u0300", "\xF8\x80\x80\x80\x80\u0300", "\u0300\xF8\x80\x80\x80\x80\u0300"}, + {"\u0300", "\xFC\x80\x80\x80\x80\x80\u0300", "\u0300\xFC\x80\x80\x80\x80\x80\u0300"}, + {"\xF8\x80\x80\x80\x80\u0300", "\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"}, + {"\xFC\x80\x80\x80\x80\x80\u0300", "\u0300", "\xFC\x80\x80\x80\x80\x80\u0300\u0300"}, + {"\xF8\x80\x80\x80", "\x80\u0300\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"}, + + {"", strings.Repeat("a\u0316\u0300", 6), strings.Repeat("\u00E0\u0316", 6)}, + // large input. + {"", strings.Repeat("a\u0300\u0316", 4000), strings.Repeat("\u00E0\u0316", 4000)}, + {"", strings.Repeat("\x80\x80", 4000), strings.Repeat("\x80\x80", 4000)}, + {"", "\u0041\u0307\u0304", "\u01E0"}, +} + +var appendTestsNFKD = []AppendTest{ + {"", "a" + grave(64), "a" + grave(30) + cgj + grave(30) + cgj + grave(4)}, + + { // segment overflow on unchanged character + "", + "a" + grave(64) + "\u0316", + "a" + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(4), + }, + { // segment overflow on unchanged character + start value + "", + "a" + grave(98) + "\u0316", + "a" + grave(30) + cgj + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(8), + }, + { // segment overflow on decomposition. (U+0340 decomposes to U+0300.) + "", + "a" + grave(59) + "\u0340", + "a" + grave(30) + cgj + grave(30), + }, + { // segment overflow on non-starter decomposition + "", + "a" + grave(33) + "\u0340" + grave(30) + "\u0320", + "a" + grave(30) + cgj + grave(30) + cgj + "\u0320" + grave(4), + }, + { // start value after ASCII overflow + "", + rep('a', segSize) + grave(32) + "\u0320", + rep('a', segSize) + grave(30) + cgj + "\u0320" + grave(2), + }, + { // Jamo overflow + "", + "\u1100\u1161" + grave(30) + "\u0320" + grave(2), + "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul + "", + "\uac00", + "\u1100\u1161", + }, + { // Hangul overflow + "", + "\uac00" + grave(32) + "\u0320", + "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul overflow in Hangul mode. + "", + "\uac00\uac00" + grave(32) + "\u0320", + "\u1100\u1161\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul overflow in Hangul mode. + "", + strings.Repeat("\uac00", 3) + grave(32) + "\u0320", + strings.Repeat("\u1100\u1161", 3) + grave(29) + cgj + "\u0320" + grave(3), + }, + { // start value after cc=0 + "", + "您您" + grave(34) + "\u0320", + "您您" + grave(30) + cgj + "\u0320" + grave(4), + }, + { // start value after normalization + "", + "\u0300\u0320a" + grave(34) + "\u0320", + "\u0320\u0300a" + grave(30) + cgj + "\u0320" + grave(4), + }, +} + +func TestAppend(t *testing.T) { + runNormTests(t, "Append", func(f Form, out []byte, s string) []byte { + return f.Append(out, []byte(s)...) + }) +} + +func TestAppendString(t *testing.T) { + runNormTests(t, "AppendString", func(f Form, out []byte, s string) []byte { + return f.AppendString(out, s) + }) +} + +func TestBytes(t *testing.T) { + runNormTests(t, "Bytes", func(f Form, out []byte, s string) []byte { + buf := []byte{} + buf = append(buf, out...) + buf = append(buf, s...) + return f.Bytes(buf) + }) +} + +func TestString(t *testing.T) { + runNormTests(t, "String", func(f Form, out []byte, s string) []byte { + outs := string(out) + s + return []byte(f.String(outs)) + }) +} + +func appendBench(f Form, in []byte) func() { + buf := make([]byte, 0, 4*len(in)) + return func() { + f.Append(buf, in...) + } +} + +func bytesBench(f Form, in []byte) func() { + return func() { + f.Bytes(in) + } +} + +func iterBench(f Form, in []byte) func() { + iter := Iter{} + return func() { + iter.Init(f, in) + for !iter.Done() { + iter.Next() + } + } +} + +func transformBench(f Form, in []byte) func() { + buf := make([]byte, 4*len(in)) + return func() { + if _, n, err := f.Transform(buf, in, true); err != nil || len(in) != n { + log.Panic(n, len(in), err) + } + } +} + +func readerBench(f Form, in []byte) func() { + buf := make([]byte, 4*len(in)) + return func() { + r := f.Reader(bytes.NewReader(in)) + var err error + for err == nil { + _, err = r.Read(buf) + } + if err != io.EOF { + panic("") + } + } +} + +func writerBench(f Form, in []byte) func() { + buf := make([]byte, 0, 4*len(in)) + return func() { + r := f.Writer(bytes.NewBuffer(buf)) + if _, err := r.Write(in); err != nil { + panic("") + } + } +} + +func appendBenchmarks(bm []func(), f Form, in []byte) []func() { + bm = append(bm, appendBench(f, in)) + bm = append(bm, iterBench(f, in)) + bm = append(bm, transformBench(f, in)) + bm = append(bm, readerBench(f, in)) + bm = append(bm, writerBench(f, in)) + return bm +} + +func doFormBenchmark(b *testing.B, inf, f Form, s string) { + b.StopTimer() + in := inf.Bytes([]byte(s)) + bm := appendBenchmarks(nil, f, in) + b.SetBytes(int64(len(in) * len(bm))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for _, fn := range bm { + fn() + } + } +} + +func doSingle(b *testing.B, f func(Form, []byte) func(), s []byte) { + b.StopTimer() + fn := f(NFC, s) + b.SetBytes(int64(len(s))) + b.StartTimer() + for i := 0; i < b.N; i++ { + fn() + } +} + +var ( + smallNoChange = []byte("nörmalization") + smallChange = []byte("No\u0308rmalization") + ascii = strings.Repeat("There is nothing to change here! ", 500) +) + +func lowerBench(f Form, in []byte) func() { + // Use package strings instead of bytes as it doesn't allocate memory + // if there aren't any changes. + s := string(in) + return func() { + strings.ToLower(s) + } +} + +func BenchmarkLowerCaseNoChange(b *testing.B) { + doSingle(b, lowerBench, smallNoChange) +} +func BenchmarkLowerCaseChange(b *testing.B) { + doSingle(b, lowerBench, smallChange) +} + +func quickSpanBench(f Form, in []byte) func() { + return func() { + f.QuickSpan(in) + } +} + +func BenchmarkQuickSpanChangeNFC(b *testing.B) { + doSingle(b, quickSpanBench, smallNoChange) +} + +func BenchmarkBytesNoChangeNFC(b *testing.B) { + doSingle(b, bytesBench, smallNoChange) +} +func BenchmarkBytesChangeNFC(b *testing.B) { + doSingle(b, bytesBench, smallChange) +} + +func BenchmarkAppendNoChangeNFC(b *testing.B) { + doSingle(b, appendBench, smallNoChange) +} +func BenchmarkAppendChangeNFC(b *testing.B) { + doSingle(b, appendBench, smallChange) +} +func BenchmarkAppendLargeNFC(b *testing.B) { + doSingle(b, appendBench, txt_all_bytes) +} + +func BenchmarkIterNoChangeNFC(b *testing.B) { + doSingle(b, iterBench, smallNoChange) +} +func BenchmarkIterChangeNFC(b *testing.B) { + doSingle(b, iterBench, smallChange) +} +func BenchmarkIterLargeNFC(b *testing.B) { + doSingle(b, iterBench, txt_all_bytes) +} + +func BenchmarkTransformNoChangeNFC(b *testing.B) { + doSingle(b, transformBench, smallNoChange) +} +func BenchmarkTransformChangeNFC(b *testing.B) { + doSingle(b, transformBench, smallChange) +} +func BenchmarkTransformLargeNFC(b *testing.B) { + doSingle(b, transformBench, txt_all_bytes) +} + +func BenchmarkNormalizeAsciiNFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, ascii) +} +func BenchmarkNormalizeAsciiNFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, ascii) +} +func BenchmarkNormalizeAsciiNFKC(b *testing.B) { + doFormBenchmark(b, NFC, NFKC, ascii) +} +func BenchmarkNormalizeAsciiNFKD(b *testing.B) { + doFormBenchmark(b, NFC, NFKD, ascii) +} + +func BenchmarkNormalizeNFC2NFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, txt_all) +} +func BenchmarkNormalizeNFC2NFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, txt_all) +} +func BenchmarkNormalizeNFD2NFC(b *testing.B) { + doFormBenchmark(b, NFD, NFC, txt_all) +} +func BenchmarkNormalizeNFD2NFD(b *testing.B) { + doFormBenchmark(b, NFD, NFD, txt_all) +} + +// Hangul is often special-cased, so we test it separately. +func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, txt_kr) +} +func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, txt_kr) +} +func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) { + doFormBenchmark(b, NFD, NFC, txt_kr) +} +func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) { + doFormBenchmark(b, NFD, NFD, txt_kr) +} + +var forms = []Form{NFC, NFD, NFKC, NFKD} + +func doTextBenchmark(b *testing.B, s string) { + b.StopTimer() + in := []byte(s) + bm := []func(){} + for _, f := range forms { + bm = appendBenchmarks(bm, f, in) + } + b.SetBytes(int64(len(s) * len(bm))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for _, f := range bm { + f() + } + } +} + +func BenchmarkCanonicalOrdering(b *testing.B) { + doTextBenchmark(b, txt_canon) +} +func BenchmarkExtendedLatin(b *testing.B) { + doTextBenchmark(b, txt_vn) +} +func BenchmarkMiscTwoByteUtf8(b *testing.B) { + doTextBenchmark(b, twoByteUtf8) +} +func BenchmarkMiscThreeByteUtf8(b *testing.B) { + doTextBenchmark(b, threeByteUtf8) +} +func BenchmarkHangul(b *testing.B) { + doTextBenchmark(b, txt_kr) +} +func BenchmarkJapanese(b *testing.B) { + doTextBenchmark(b, txt_jp) +} +func BenchmarkChinese(b *testing.B) { + doTextBenchmark(b, txt_cn) +} +func BenchmarkOverflow(b *testing.B) { + doTextBenchmark(b, overflow) +} + +var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B" + +// Tests sampled from the Canonical ordering tests (Part 2) of +// http://unicode.org/Public/UNIDATA/NormalizationTest.txt +const txt_canon = `\u0061\u0315\u0300\u05AE\u0300\u0062 \u0061\u0300\u0315\u0300\u05AE\u0062 +\u0061\u0302\u0315\u0300\u05AE\u0062 \u0061\u0307\u0315\u0300\u05AE\u0062 +\u0061\u0315\u0300\u05AE\u030A\u0062 \u0061\u059A\u0316\u302A\u031C\u0062 +\u0061\u032E\u059A\u0316\u302A\u0062 \u0061\u0338\u093C\u0334\u0062 +\u0061\u059A\u0316\u302A\u0339 \u0061\u0341\u0315\u0300\u05AE\u0062 +\u0061\u0348\u059A\u0316\u302A\u0062 \u0061\u0361\u0345\u035D\u035C\u0062 +\u0061\u0366\u0315\u0300\u05AE\u0062 \u0061\u0315\u0300\u05AE\u0486\u0062 +\u0061\u05A4\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0613\u0062 +\u0061\u0315\u0300\u05AE\u0615\u0062 \u0061\u0617\u0315\u0300\u05AE\u0062 +\u0061\u0619\u0618\u064D\u064E\u0062 \u0061\u0315\u0300\u05AE\u0654\u0062 +\u0061\u0315\u0300\u05AE\u06DC\u0062 \u0061\u0733\u0315\u0300\u05AE\u0062 +\u0061\u0744\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0745\u0062 +\u0061\u09CD\u05B0\u094D\u3099\u0062 \u0061\u0E38\u0E48\u0E38\u0C56\u0062 +\u0061\u0EB8\u0E48\u0E38\u0E49\u0062 \u0061\u0F72\u0F71\u0EC8\u0F71\u0062 +\u0061\u1039\u05B0\u094D\u3099\u0062 \u0061\u05B0\u094D\u3099\u1A60\u0062 +\u0061\u3099\u093C\u0334\u1BE6\u0062 \u0061\u3099\u093C\u0334\u1C37\u0062 +\u0061\u1CD9\u059A\u0316\u302A\u0062 \u0061\u2DED\u0315\u0300\u05AE\u0062 +\u0061\u2DEF\u0315\u0300\u05AE\u0062 \u0061\u302D\u302E\u059A\u0316\u0062` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/ +const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả. +Nếu bạn sử dụng, chuyển đổi, hoặc xây dựng dự án từ +nội dung được chia sẻ này, bạn phải áp dụng giấy phép này hoặc +một giấy phép khác có các điều khoản tương tự như giấy phép này +cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào +trên đây cũng có thể được miễn bỏ nếu bạn được sự cho phép của +người sở hữu bản quyền. Phạm vi công chúng — Khi tác phẩm hoặc +bất kỳ chương nào của tác phẩm đã trong vùng dành cho công +chúng theo quy định của pháp luật thì tình trạng của nó không +bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.` + +// Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru +const txt_ru = `При обязательном соблюдении следующих условий: +Attribution — Вы должны атрибутировать произведение (указывать +автора и источник) в порядке, предусмотренном автором или +лицензиаром (но только так, чтобы никоим образом не подразумевалось, +что они поддерживают вас или использование вами данного произведения). +Υπό τις ακόλουθες προϋποθέσεις:` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/ +const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με τον +τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια +(χωρίς όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή +τη χρήση του έργου από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε, +τροποποιήσετε ή δημιουργήσετε περαιτέρω βασισμένοι στο έργο θα +μπορείτε να διανέμετε το έργο που θα προκύψει μόνο με την ίδια ή +παρόμοια άδεια.` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/deed.ar +const txt_ar = `بموجب الشروط التالية نسب المصنف — يجب عليك أن +تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من +الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل). +المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة +من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد +لهذا الترخيص.` + +// Taken from http://creativecommons.org/licenses/by-sa/1.0/il/ +const txt_il = `בכפוף לתנאים הבאים: ייחוס — עליך לייחס את היצירה (לתת קרדיט) באופן +המצויין על-ידי היוצר או מעניק הרישיון (אך לא בשום אופן המרמז על כך +שהם תומכים בך או בשימוש שלך ביצירה). שיתוף זהה — אם תחליט/י לשנות, +לעבד או ליצור יצירה נגזרת בהסתמך על יצירה זו, תוכל/י להפיץ את יצירתך +החדשה רק תחת אותו הרישיון או רישיון דומה לרישיון זה.` + +const twoByteUtf8 = txt_ru + txt_gr + txt_ar + txt_il + +// Taken from http://creativecommons.org/licenses/by-sa/2.0/kr/ +const txt_kr = `다음과 같은 조건을 따라야 합니다: 저작자표시 +(Attribution) — 저작자나 이용허락자가 정한 방법으로 저작물의 +원저작자를 표시하여야 합니다(그러나 원저작자가 이용자나 이용자의 +이용을 보증하거나 추천한다는 의미로 표시해서는 안됩니다). +동일조건변경허락 — 이 저작물을 이용하여 만든 이차적 저작물에는 본 +라이선스와 동일한 라이선스를 적용해야 합니다.` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/th/ +const txt_th = `ภายใต้เงื่อนไข ดังต่อไปนี้ : แสดงที่มา — คุณต้องแสดงที่ +มาของงานดังกล่าว ตามรูปแบบที่ผู้สร้างสรรค์หรือผู้อนุญาตกำหนด (แต่ +ไม่ใช่ในลักษณะที่ว่า พวกเขาสนับสนุนคุณหรือสนับสนุนการที่ +คุณนำงานไปใช้) อนุญาตแบบเดียวกัน — หากคุณดัดแปลง เปลี่ยนรูป หรื +อต่อเติมงานนี้ คุณต้องใช้สัญญาอนุญาตแบบเดียวกันหรือแบบที่เหมื +อนกับสัญญาอนุญาตที่ใช้กับงานนี้เท่านั้น` + +const threeByteUtf8 = txt_th + +// Taken from http://creativecommons.org/licenses/by-sa/2.0/jp/ +const txt_jp = `あなたの従うべき条件は以下の通りです。 +表示 — あなたは原著作者のクレジットを表示しなければなりません。 +継承 — もしあなたがこの作品を改変、変形または加工した場合、 +あなたはその結果生じた作品をこの作品と同一の許諾条件の下でのみ +頒布することができます。` + +// http://creativecommons.org/licenses/by-sa/2.5/cn/ +const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、 +广播或通过信息网络传播本作品 创作演绎作品 +对本作品进行商业性使用 惟须遵守下列条件: +署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。 +相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作, +您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。` + +const txt_cjk = txt_cn + txt_jp + txt_kr +const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk + +var txt_all_bytes = []byte(txt_all) diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normregtest.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normregtest.go new file mode 100644 index 00000000..49f81cf5 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/normregtest.go @@ -0,0 +1,318 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "log" + "net/http" + "os" + "path" + "regexp" + "runtime" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/unicode/norm" +) + +func main() { + flag.Parse() + loadTestData() + CharacterByCharacterTests() + StandardTests() + PerformanceTest() + if errorCount == 0 { + fmt.Println("PASS") + } +} + +const file = "NormalizationTest.txt" + +var url = flag.String("url", + "http://www.unicode.org/Public/"+unicode.Version+"/ucd/"+file, + "URL of Unicode database directory") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") + +var logger = log.New(os.Stderr, "", log.Lshortfile) + +// This regression test runs the test set in NormalizationTest.txt +// (taken from http://www.unicode.org/Public//ucd/). +// +// NormalizationTest.txt has form: +// @Part0 # Specific cases +// # +// 1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +// 1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +// +// Each test has 5 columns (c1, c2, c3, c4, c5), where +// (c1, c2, c3, c4, c5) == (c1, NFC(c1), NFD(c1), NFKC(c1), NFKD(c1)) +// +// CONFORMANCE: +// 1. The following invariants must be true for all conformant implementations +// +// NFC +// c2 == NFC(c1) == NFC(c2) == NFC(c3) +// c4 == NFC(c4) == NFC(c5) +// +// NFD +// c3 == NFD(c1) == NFD(c2) == NFD(c3) +// c5 == NFD(c4) == NFD(c5) +// +// NFKC +// c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) +// +// NFKD +// c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) +// +// 2. For every code point X assigned in this version of Unicode that is not +// specifically listed in Part 1, the following invariants must be true +// for all conformant implementations: +// +// X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X) +// + +// Column types. +const ( + cRaw = iota + cNFC + cNFD + cNFKC + cNFKD + cMaxColumns +) + +// Holds data from NormalizationTest.txt +var part []Part + +type Part struct { + name string + number int + tests []Test +} + +type Test struct { + name string + partnr int + number int + r rune // used for character by character test + cols [cMaxColumns]string // Each has 5 entries, see below. +} + +func (t Test) Name() string { + if t.number < 0 { + return part[t.partnr].name + } + return fmt.Sprintf("%s:%d", part[t.partnr].name, t.number) +} + +var partRe = regexp.MustCompile(`@Part(\d) # (.*)$`) +var testRe = regexp.MustCompile(`^` + strings.Repeat(`([\dA-F ]+);`, 5) + ` # (.*)$`) + +var counter int + +// Load the data form NormalizationTest.txt +func loadTestData() { + if *localFiles { + pwd, _ := os.Getwd() + *url = "file://" + path.Join(pwd, file) + } + t := &http.Transport{} + t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/"))) + c := &http.Client{Transport: t} + resp, err := c.Get(*url) + if err != nil { + logger.Fatal(err) + } + if resp.StatusCode != 200 { + logger.Fatal("bad GET status for "+file, resp.Status) + } + f := resp.Body + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + m := partRe.FindStringSubmatch(line) + if m != nil { + if len(m) < 3 { + logger.Fatal("Failed to parse Part: ", line) + } + i, err := strconv.Atoi(m[1]) + if err != nil { + logger.Fatal(err) + } + name := m[2] + part = append(part, Part{name: name[:len(name)-1], number: i}) + continue + } + m = testRe.FindStringSubmatch(line) + if m == nil || len(m) < 7 { + logger.Fatalf(`Failed to parse: "%s" result: %#v`, line, m) + } + test := Test{name: m[6], partnr: len(part) - 1, number: counter} + counter++ + for j := 1; j < len(m)-1; j++ { + for _, split := range strings.Split(m[j], " ") { + r, err := strconv.ParseUint(split, 16, 64) + if err != nil { + logger.Fatal(err) + } + if test.r == 0 { + // save for CharacterByCharacterTests + test.r = rune(r) + } + var buf [utf8.UTFMax]byte + sz := utf8.EncodeRune(buf[:], rune(r)) + test.cols[j-1] += string(buf[:sz]) + } + } + part := &part[len(part)-1] + part.tests = append(part.tests, test) + } + if scanner.Err() != nil { + logger.Fatal(scanner.Err()) + } +} + +var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"} + +var errorCount int + +func cmpResult(t *Test, name string, f norm.Form, gold, test, result string) { + if gold != result { + errorCount++ + if errorCount > 20 { + return + } + logger.Printf("%s:%s: %s(%+q)=%+q; want %+q: %s", + t.Name(), name, fstr[f], test, result, gold, t.name) + } +} + +func cmpIsNormal(t *Test, name string, f norm.Form, test string, result, want bool) { + if result != want { + errorCount++ + if errorCount > 20 { + return + } + logger.Printf("%s:%s: %s(%+q)=%v; want %v", t.Name(), name, fstr[f], test, result, want) + } +} + +func doTest(t *Test, f norm.Form, gold, test string) { + testb := []byte(test) + result := f.Bytes(testb) + cmpResult(t, "Bytes", f, gold, test, string(result)) + + sresult := f.String(test) + cmpResult(t, "String", f, gold, test, sresult) + + acc := []byte{} + i := norm.Iter{} + i.InitString(f, test) + for !i.Done() { + acc = append(acc, i.Next()...) + } + cmpResult(t, "Iter.Next", f, gold, test, string(acc)) + + buf := make([]byte, 128) + acc = nil + for p := 0; p < len(testb); { + nDst, nSrc, _ := f.Transform(buf, testb[p:], true) + acc = append(acc, buf[:nDst]...) + p += nSrc + } + cmpResult(t, "Transform", f, gold, test, string(acc)) + + for i := range test { + out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...) + cmpResult(t, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out)) + } + cmpIsNormal(t, "IsNormal", f, test, f.IsNormal([]byte(test)), test == gold) + cmpIsNormal(t, "IsNormalString", f, test, f.IsNormalString(test), test == gold) +} + +func doConformanceTests(t *Test, partn int) { + for i := 0; i <= 2; i++ { + doTest(t, norm.NFC, t.cols[1], t.cols[i]) + doTest(t, norm.NFD, t.cols[2], t.cols[i]) + doTest(t, norm.NFKC, t.cols[3], t.cols[i]) + doTest(t, norm.NFKD, t.cols[4], t.cols[i]) + } + for i := 3; i <= 4; i++ { + doTest(t, norm.NFC, t.cols[3], t.cols[i]) + doTest(t, norm.NFD, t.cols[4], t.cols[i]) + doTest(t, norm.NFKC, t.cols[3], t.cols[i]) + doTest(t, norm.NFKD, t.cols[4], t.cols[i]) + } +} + +func CharacterByCharacterTests() { + tests := part[1].tests + var last rune = 0 + for i := 0; i <= len(tests); i++ { // last one is special case + var r rune + if i == len(tests) { + r = 0x2FA1E // Don't have to go to 0x10FFFF + } else { + r = tests[i].r + } + for last++; last < r; last++ { + // Check all characters that were not explicitly listed in the test. + t := &Test{partnr: 1, number: -1} + char := string(last) + doTest(t, norm.NFC, char, char) + doTest(t, norm.NFD, char, char) + doTest(t, norm.NFKC, char, char) + doTest(t, norm.NFKD, char, char) + } + if i < len(tests) { + doConformanceTests(&tests[i], 1) + } + } +} + +func StandardTests() { + for _, j := range []int{0, 2, 3} { + for _, test := range part[j].tests { + doConformanceTests(&test, j) + } + } +} + +// PerformanceTest verifies that normalization is O(n). If any of the +// code does not properly check for maxCombiningChars, normalization +// may exhibit O(n**2) behavior. +func PerformanceTest() { + runtime.GOMAXPROCS(2) + success := make(chan bool, 1) + go func() { + buf := bytes.Repeat([]byte("\u035D"), 1024*1024) + buf = append(buf, "\u035B"...) + norm.NFC.Append(nil, buf...) + success <- true + }() + timeout := time.After(1 * time.Second) + select { + case <-success: + // test completed before the timeout + case <-timeout: + errorCount++ + logger.Printf(`unexpectedly long time to complete PerformanceTest`) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter.go new file mode 100644 index 00000000..4fa0e04b --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter.go @@ -0,0 +1,126 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "io" + +type normWriter struct { + rb reorderBuffer + w io.Writer + buf []byte +} + +// Write implements the standard write interface. If the last characters are +// not at a normalization boundary, the bytes will be buffered for the next +// write. The remaining bytes will be written on close. +func (w *normWriter) Write(data []byte) (n int, err error) { + // Process data in pieces to keep w.buf size bounded. + const chunk = 4000 + + for len(data) > 0 { + // Normalize into w.buf. + m := len(data) + if m > chunk { + m = chunk + } + w.rb.src = inputBytes(data[:m]) + w.rb.nsrc = m + w.buf = doAppend(&w.rb, w.buf, 0) + data = data[m:] + n += m + + // Write out complete prefix, save remainder. + // Note that lastBoundary looks back at most 31 runes. + i := lastBoundary(&w.rb.f, w.buf) + if i == -1 { + i = 0 + } + if i > 0 { + if _, err = w.w.Write(w.buf[:i]); err != nil { + break + } + bn := copy(w.buf, w.buf[i:]) + w.buf = w.buf[:bn] + } + } + return n, err +} + +// Close forces data that remains in the buffer to be written. +func (w *normWriter) Close() error { + if len(w.buf) > 0 { + _, err := w.w.Write(w.buf) + if err != nil { + return err + } + } + return nil +} + +// Writer returns a new writer that implements Write(b) +// by writing f(b) to w. The returned writer may use an +// an internal buffer to maintain state across Write calls. +// Calling its Close method writes any buffered data to w. +func (f Form) Writer(w io.Writer) io.WriteCloser { + wr := &normWriter{rb: reorderBuffer{}, w: w} + wr.rb.init(f, nil) + return wr +} + +type normReader struct { + rb reorderBuffer + r io.Reader + inbuf []byte + outbuf []byte + bufStart int + lastBoundary int + err error +} + +// Read implements the standard read interface. +func (r *normReader) Read(p []byte) (int, error) { + for { + if r.lastBoundary-r.bufStart > 0 { + n := copy(p, r.outbuf[r.bufStart:r.lastBoundary]) + r.bufStart += n + if r.lastBoundary-r.bufStart > 0 { + return n, nil + } + return n, r.err + } + if r.err != nil { + return 0, r.err + } + outn := copy(r.outbuf, r.outbuf[r.lastBoundary:]) + r.outbuf = r.outbuf[0:outn] + r.bufStart = 0 + + n, err := r.r.Read(r.inbuf) + r.rb.src = inputBytes(r.inbuf[0:n]) + r.rb.nsrc, r.err = n, err + if n > 0 { + r.outbuf = doAppend(&r.rb, r.outbuf, 0) + } + if err == io.EOF { + r.lastBoundary = len(r.outbuf) + } else { + r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf) + if r.lastBoundary == -1 { + r.lastBoundary = 0 + } + } + } + panic("should not reach here") +} + +// Reader returns a new reader that implements Read +// by reading data from r and returning f(data). +func (f Form) Reader(r io.Reader) io.Reader { + const chunk = 4000 + buf := make([]byte, chunk) + rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf} + rr.rb.init(f, buf) + return rr +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter_test.go new file mode 100644 index 00000000..b7756ba2 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/readwriter_test.go @@ -0,0 +1,56 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bytes" + "fmt" + "testing" +) + +var bufSizes = []int{1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 102, 103, 4000, 4001, 4002, 4003} + +func readFunc(size int) appendFunc { + return func(f Form, out []byte, s string) []byte { + out = append(out, s...) + r := f.Reader(bytes.NewBuffer(out)) + buf := make([]byte, size) + result := []byte{} + for n, err := 0, error(nil); err == nil; { + n, err = r.Read(buf) + result = append(result, buf[:n]...) + } + return result + } +} + +func TestReader(t *testing.T) { + for _, s := range bufSizes { + name := fmt.Sprintf("TestReader%d", s) + runNormTests(t, name, readFunc(s)) + } +} + +func writeFunc(size int) appendFunc { + return func(f Form, out []byte, s string) []byte { + in := append(out, s...) + result := new(bytes.Buffer) + w := f.Writer(result) + buf := make([]byte, size) + for n := 0; len(in) > 0; in = in[n:] { + n = copy(buf, in) + _, _ = w.Write(buf[:n]) + } + w.Close() + return result.Bytes() + } +} + +func TestWriter(t *testing.T) { + for _, s := range bufSizes { + name := fmt.Sprintf("TestWriter%d", s) + runNormTests(t, name, writeFunc(s)) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/tables.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/tables.go new file mode 100644 index 00000000..932c4ec5 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/tables.go @@ -0,0 +1,7549 @@ +// Generated by running +// maketables --tables=all --url=http://www.unicode.org/Public/7.0.0/ucd/ +// DO NOT EDIT + +package norm + +const ( + // Version is the Unicode edition from which the tables are derived. + Version = "7.0.0" + + // MaxTransformChunkSize indicates the maximum number of bytes that Transform + // may need to write atomically for any Form. Making a destination buffer at + // least this size ensures that Transform can always make progress and that + // the user does not need to grow the buffer on an ErrShortDst. + MaxTransformChunkSize = 35 + maxNonStarters*4 +) + +var ccc = [55]uint8{ + 0, 1, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 84, 91, 103, 107, 118, 122, 129, 130, + 132, 202, 214, 216, 218, 220, 222, 224, + 226, 228, 230, 232, 233, 234, 240, +} + +const ( + firstMulti = 0x18E1 + firstCCC = 0x2EC5 + endMulti = 0x2F9B + firstLeadingCCC = 0x49E9 + firstCCCZeroExcept = 0x49FF + firstStarterWithNLead = 0x4A26 + lastDecomp = 0x4A28 + maxDecomp = 0x8000 +) + +// decomps: 18984 bytes +var decomps = [...]byte{ + // Bytes 0 - 3f + 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41, + 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, + 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41, + 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41, + 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41, + 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41, + 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41, + 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41, + // Bytes 40 - 7f + 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41, + 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41, + 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41, + 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41, + 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, + 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, + 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, + 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, + // Bytes 80 - bf + 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41, + 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41, + 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41, + 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41, + 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41, + 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41, + 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41, + 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42, + // Bytes c0 - ff + 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5, + 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2, + 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42, + 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1, + 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6, + 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42, + 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90, + 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9, + // Bytes 100 - 13f + 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42, + 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F, + 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9, + 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42, + 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAB, + 0x42, 0xC9, 0xAD, 0x42, 0xC9, 0xAF, 0x42, 0xC9, + 0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42, + 0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5, + // Bytes 140 - 17f + 0x42, 0xC9, 0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9, + 0xBB, 0x42, 0xCA, 0x81, 0x42, 0xCA, 0x82, 0x42, + 0xCA, 0x83, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A, + 0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA, + 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92, 0x42, + 0xCA, 0x95, 0x42, 0xCA, 0x9D, 0x42, 0xCA, 0x9F, + 0x42, 0xCA, 0xB9, 0x42, 0xCE, 0x91, 0x42, 0xCE, + 0x92, 0x42, 0xCE, 0x93, 0x42, 0xCE, 0x94, 0x42, + // Bytes 180 - 1bf + 0xCE, 0x95, 0x42, 0xCE, 0x96, 0x42, 0xCE, 0x97, + 0x42, 0xCE, 0x98, 0x42, 0xCE, 0x99, 0x42, 0xCE, + 0x9A, 0x42, 0xCE, 0x9B, 0x42, 0xCE, 0x9C, 0x42, + 0xCE, 0x9D, 0x42, 0xCE, 0x9E, 0x42, 0xCE, 0x9F, + 0x42, 0xCE, 0xA0, 0x42, 0xCE, 0xA1, 0x42, 0xCE, + 0xA3, 0x42, 0xCE, 0xA4, 0x42, 0xCE, 0xA5, 0x42, + 0xCE, 0xA6, 0x42, 0xCE, 0xA7, 0x42, 0xCE, 0xA8, + 0x42, 0xCE, 0xA9, 0x42, 0xCE, 0xB1, 0x42, 0xCE, + // Bytes 1c0 - 1ff + 0xB2, 0x42, 0xCE, 0xB3, 0x42, 0xCE, 0xB4, 0x42, + 0xCE, 0xB5, 0x42, 0xCE, 0xB6, 0x42, 0xCE, 0xB7, + 0x42, 0xCE, 0xB8, 0x42, 0xCE, 0xB9, 0x42, 0xCE, + 0xBA, 0x42, 0xCE, 0xBB, 0x42, 0xCE, 0xBC, 0x42, + 0xCE, 0xBD, 0x42, 0xCE, 0xBE, 0x42, 0xCE, 0xBF, + 0x42, 0xCF, 0x80, 0x42, 0xCF, 0x81, 0x42, 0xCF, + 0x82, 0x42, 0xCF, 0x83, 0x42, 0xCF, 0x84, 0x42, + 0xCF, 0x85, 0x42, 0xCF, 0x86, 0x42, 0xCF, 0x87, + // Bytes 200 - 23f + 0x42, 0xCF, 0x88, 0x42, 0xCF, 0x89, 0x42, 0xCF, + 0x9C, 0x42, 0xCF, 0x9D, 0x42, 0xD0, 0xBD, 0x42, + 0xD1, 0x8A, 0x42, 0xD1, 0x8C, 0x42, 0xD7, 0x90, + 0x42, 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7, + 0x93, 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42, + 0xD7, 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2, + 0x42, 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8, + 0xA1, 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42, + // Bytes 240 - 27f + 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB, + 0x42, 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8, + 0xAE, 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42, + 0xD8, 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3, + 0x42, 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8, + 0xB6, 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42, + 0xD8, 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81, + 0x42, 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9, + // Bytes 280 - 2bf + 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42, + 0xD9, 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89, + 0x42, 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9, + 0xAF, 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42, + 0xD9, 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE, + 0x42, 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA, + 0x83, 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42, + 0xDA, 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C, + // Bytes 2c0 - 2ff + 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA, + 0x91, 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42, + 0xDA, 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9, + 0x42, 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA, + 0xB1, 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42, + 0xDA, 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81, + 0x42, 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB, + 0x87, 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42, + // Bytes 300 - 33f + 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90, + 0x42, 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43, + 0xE1, 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43, + 0xE1, 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43, + 0xE1, 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43, + 0xE1, 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43, + 0xE1, 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43, + 0xE1, 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43, + // Bytes 340 - 37f + 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43, + 0xE1, 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43, + 0xE1, 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43, + 0xE1, 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43, + 0xE1, 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43, + 0xE1, 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43, + 0xE1, 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43, + 0xE1, 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43, + // Bytes 380 - 3bf + 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43, + 0xE1, 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43, + 0xE1, 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43, + 0xE1, 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43, + 0xE1, 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43, + 0xE1, 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43, + 0xE1, 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43, + 0xE1, 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43, + // Bytes 3c0 - 3ff + 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43, + 0xE1, 0x85, 0xA1, 0x43, 0xE1, 0x85, 0xA2, 0x43, + 0xE1, 0x85, 0xA3, 0x43, 0xE1, 0x85, 0xA4, 0x43, + 0xE1, 0x85, 0xA5, 0x43, 0xE1, 0x85, 0xA6, 0x43, + 0xE1, 0x85, 0xA7, 0x43, 0xE1, 0x85, 0xA8, 0x43, + 0xE1, 0x85, 0xA9, 0x43, 0xE1, 0x85, 0xAA, 0x43, + 0xE1, 0x85, 0xAB, 0x43, 0xE1, 0x85, 0xAC, 0x43, + 0xE1, 0x85, 0xAD, 0x43, 0xE1, 0x85, 0xAE, 0x43, + // Bytes 400 - 43f + 0xE1, 0x85, 0xAF, 0x43, 0xE1, 0x85, 0xB0, 0x43, + 0xE1, 0x85, 0xB1, 0x43, 0xE1, 0x85, 0xB2, 0x43, + 0xE1, 0x85, 0xB3, 0x43, 0xE1, 0x85, 0xB4, 0x43, + 0xE1, 0x85, 0xB5, 0x43, 0xE1, 0x86, 0x84, 0x43, + 0xE1, 0x86, 0x85, 0x43, 0xE1, 0x86, 0x88, 0x43, + 0xE1, 0x86, 0x91, 0x43, 0xE1, 0x86, 0x92, 0x43, + 0xE1, 0x86, 0x94, 0x43, 0xE1, 0x86, 0x9E, 0x43, + 0xE1, 0x86, 0xA1, 0x43, 0xE1, 0x86, 0xAA, 0x43, + // Bytes 440 - 47f + 0xE1, 0x86, 0xAC, 0x43, 0xE1, 0x86, 0xAD, 0x43, + 0xE1, 0x86, 0xB0, 0x43, 0xE1, 0x86, 0xB1, 0x43, + 0xE1, 0x86, 0xB2, 0x43, 0xE1, 0x86, 0xB3, 0x43, + 0xE1, 0x86, 0xB4, 0x43, 0xE1, 0x86, 0xB5, 0x43, + 0xE1, 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43, + 0xE1, 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43, + 0xE1, 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43, + 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43, + // Bytes 480 - 4bf + 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43, + 0xE1, 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43, + 0xE1, 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43, + 0xE1, 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43, + 0xE1, 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43, + 0xE1, 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43, + 0xE2, 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43, + 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43, + // Bytes 4c0 - 4ff + 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43, + 0xE2, 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43, + 0xE2, 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43, + 0xE2, 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43, + 0xE2, 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43, + 0xE2, 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43, + 0xE2, 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43, + 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43, + // Bytes 500 - 53f + 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43, + 0xE3, 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43, + 0xE3, 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43, + 0xE3, 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43, + 0xE3, 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43, + 0xE3, 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43, + 0xE3, 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43, + 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43, + // Bytes 540 - 57f + 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43, + 0xE3, 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43, + 0xE3, 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43, + 0xE3, 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43, + 0xE3, 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43, + 0xE3, 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43, + 0xE3, 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43, + 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43, + // Bytes 580 - 5bf + 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43, + 0xE3, 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43, + 0xE3, 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43, + 0xE3, 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43, + 0xE3, 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43, + 0xE3, 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43, + 0xE3, 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43, + 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43, + // Bytes 5c0 - 5ff + 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43, + 0xE3, 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43, + 0xE3, 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43, + 0xE3, 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43, + 0xE3, 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43, + 0xE3, 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43, + 0xE3, 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43, + 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43, + // Bytes 600 - 63f + 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43, + 0xE3, 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43, + 0xE3, 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43, + 0xE3, 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43, + 0xE3, 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43, + 0xE3, 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43, + 0xE3, 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43, + 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43, + // Bytes 640 - 67f + 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43, + 0xE3, 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43, + 0xE3, 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43, + 0xE3, 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43, + 0xE3, 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43, + 0xE3, 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43, + 0xE3, 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43, + 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43, + // Bytes 680 - 6bf + 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43, + 0xE3, 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43, + 0xE3, 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43, + 0xE3, 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43, + 0xE3, 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43, + 0xE4, 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43, + 0xE4, 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43, + 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43, + // Bytes 6c0 - 6ff + 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43, + 0xE4, 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43, + 0xE4, 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43, + 0xE4, 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43, + 0xE4, 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43, + 0xE4, 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43, + 0xE4, 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43, + 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43, + // Bytes 700 - 73f + 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43, + 0xE4, 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43, + 0xE4, 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43, + 0xE4, 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43, + 0xE4, 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43, + 0xE4, 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43, + 0xE4, 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43, + 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43, + // Bytes 740 - 77f + 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43, + 0xE4, 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43, + 0xE4, 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43, + 0xE4, 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43, + 0xE4, 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43, + 0xE4, 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43, + 0xE4, 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43, + 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43, + // Bytes 780 - 7bf + 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43, + 0xE4, 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43, + 0xE4, 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43, + 0xE4, 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43, + 0xE4, 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43, + 0xE4, 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43, + 0xE4, 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43, + 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43, + // Bytes 7c0 - 7ff + 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43, + 0xE4, 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43, + 0xE4, 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43, + 0xE4, 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43, + 0xE5, 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43, + 0xE5, 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43, + 0xE5, 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43, + 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43, + // Bytes 800 - 83f + 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43, + 0xE5, 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43, + 0xE5, 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43, + 0xE5, 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43, + 0xE5, 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43, + 0xE5, 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43, + 0xE5, 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43, + 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43, + // Bytes 840 - 87f + 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43, + 0xE5, 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43, + 0xE5, 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43, + 0xE5, 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43, + 0xE5, 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43, + 0xE5, 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43, + 0xE5, 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43, + 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43, + // Bytes 880 - 8bf + 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43, + 0xE5, 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43, + 0xE5, 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43, + 0xE5, 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43, + 0xE5, 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43, + 0xE5, 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43, + 0xE5, 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43, + 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43, + // Bytes 8c0 - 8ff + 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43, + 0xE5, 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43, + 0xE5, 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43, + 0xE5, 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43, + 0xE5, 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43, + 0xE5, 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43, + 0xE5, 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43, + 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43, + // Bytes 900 - 93f + 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43, + 0xE5, 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43, + 0xE5, 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43, + 0xE5, 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43, + 0xE5, 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43, + 0xE5, 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43, + 0xE5, 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43, + 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43, + // Bytes 940 - 97f + 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43, + 0xE5, 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43, + 0xE5, 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43, + 0xE5, 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43, + 0xE5, 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43, + 0xE5, 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43, + 0xE5, 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43, + 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43, + // Bytes 980 - 9bf + 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43, + 0xE5, 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43, + 0xE5, 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43, + 0xE5, 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43, + 0xE5, 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43, + 0xE5, 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43, + 0xE5, 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43, + 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43, + // Bytes 9c0 - 9ff + 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43, + 0xE5, 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43, + 0xE5, 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43, + 0xE5, 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43, + 0xE5, 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43, + 0xE5, 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43, + 0xE5, 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43, + 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43, + // Bytes a00 - a3f + 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43, + 0xE5, 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43, + 0xE5, 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43, + 0xE5, 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43, + 0xE5, 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43, + 0xE5, 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43, + 0xE5, 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43, + 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43, + // Bytes a40 - a7f + 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43, + 0xE5, 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43, + 0xE5, 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43, + 0xE5, 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43, + 0xE5, 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43, + 0xE5, 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43, + 0xE5, 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43, + 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43, + // Bytes a80 - abf + 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43, + 0xE5, 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43, + 0xE5, 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43, + 0xE5, 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43, + 0xE5, 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43, + 0xE5, 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43, + 0xE5, 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43, + 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43, + // Bytes ac0 - aff + 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43, + 0xE5, 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43, + 0xE5, 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43, + 0xE5, 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43, + 0xE5, 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43, + 0xE5, 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43, + 0xE5, 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43, + 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43, + // Bytes b00 - b3f + 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43, + 0xE5, 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43, + 0xE5, 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43, + 0xE5, 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43, + 0xE5, 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43, + 0xE5, 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43, + 0xE5, 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43, + 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43, + // Bytes b40 - b7f + 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43, + 0xE5, 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43, + 0xE5, 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43, + 0xE5, 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43, + 0xE5, 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43, + 0xE5, 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43, + 0xE5, 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43, + 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43, + // Bytes b80 - bbf + 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43, + 0xE5, 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43, + 0xE5, 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43, + 0xE5, 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43, + 0xE5, 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43, + 0xE5, 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43, + 0xE5, 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43, + 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43, + // Bytes bc0 - bff + 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43, + 0xE5, 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43, + 0xE5, 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43, + 0xE5, 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43, + 0xE5, 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43, + 0xE5, 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43, + 0xE5, 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43, + 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43, + // Bytes c00 - c3f + 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43, + 0xE5, 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43, + 0xE6, 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43, + 0xE6, 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43, + 0xE6, 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43, + 0xE6, 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43, + 0xE6, 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43, + 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43, + // Bytes c40 - c7f + 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43, + 0xE6, 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43, + 0xE6, 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43, + 0xE6, 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43, + 0xE6, 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43, + 0xE6, 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43, + 0xE6, 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43, + 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43, + // Bytes c80 - cbf + 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43, + 0xE6, 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43, + 0xE6, 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43, + 0xE6, 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43, + 0xE6, 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43, + 0xE6, 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43, + 0xE6, 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43, + 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43, + // Bytes cc0 - cff + 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43, + 0xE6, 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43, + 0xE6, 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43, + 0xE6, 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43, + 0xE6, 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43, + 0xE6, 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43, + 0xE6, 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43, + 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43, + // Bytes d00 - d3f + 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43, + 0xE6, 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43, + 0xE6, 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43, + 0xE6, 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43, + 0xE6, 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43, + 0xE6, 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43, + 0xE6, 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43, + 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43, + // Bytes d40 - d7f + 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43, + 0xE6, 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43, + 0xE6, 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43, + 0xE6, 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43, + 0xE6, 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43, + 0xE6, 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43, + 0xE6, 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43, + 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43, + // Bytes d80 - dbf + 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43, + 0xE6, 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43, + 0xE6, 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43, + 0xE6, 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43, + 0xE6, 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43, + 0xE6, 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43, + 0xE6, 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43, + 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43, + // Bytes dc0 - dff + 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43, + 0xE6, 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43, + 0xE6, 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43, + 0xE6, 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43, + 0xE6, 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43, + 0xE6, 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43, + 0xE6, 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43, + 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43, + // Bytes e00 - e3f + 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43, + 0xE6, 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43, + 0xE6, 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43, + 0xE6, 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43, + 0xE6, 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43, + 0xE6, 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43, + 0xE6, 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43, + 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43, + // Bytes e40 - e7f + 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43, + 0xE6, 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43, + 0xE6, 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43, + 0xE6, 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43, + 0xE6, 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43, + 0xE6, 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43, + 0xE6, 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43, + 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43, + // Bytes e80 - ebf + 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43, + 0xE6, 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43, + 0xE6, 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43, + 0xE6, 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43, + 0xE6, 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43, + 0xE6, 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43, + 0xE6, 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43, + 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43, + // Bytes ec0 - eff + 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43, + 0xE6, 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43, + 0xE6, 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43, + 0xE6, 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43, + 0xE6, 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43, + 0xE6, 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43, + 0xE6, 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43, + 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43, + // Bytes f00 - f3f + 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43, + 0xE7, 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43, + 0xE7, 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43, + 0xE7, 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43, + 0xE7, 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43, + 0xE7, 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43, + 0xE7, 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43, + 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43, + // Bytes f40 - f7f + 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43, + 0xE7, 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43, + 0xE7, 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43, + 0xE7, 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43, + 0xE7, 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43, + 0xE7, 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43, + 0xE7, 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43, + 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43, + // Bytes f80 - fbf + 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43, + 0xE7, 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43, + 0xE7, 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43, + 0xE7, 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43, + 0xE7, 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43, + 0xE7, 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43, + 0xE7, 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43, + 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43, + // Bytes fc0 - fff + 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43, + 0xE7, 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43, + 0xE7, 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43, + 0xE7, 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43, + 0xE7, 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43, + 0xE7, 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43, + 0xE7, 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43, + 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43, + // Bytes 1000 - 103f + 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43, + 0xE7, 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43, + 0xE7, 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43, + 0xE7, 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43, + 0xE7, 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43, + 0xE7, 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43, + 0xE7, 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43, + 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43, + // Bytes 1040 - 107f + 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43, + 0xE7, 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43, + 0xE7, 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43, + 0xE7, 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43, + 0xE7, 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43, + 0xE7, 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43, + 0xE7, 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43, + 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43, + // Bytes 1080 - 10bf + 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43, + 0xE7, 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43, + 0xE7, 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43, + 0xE7, 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43, + 0xE7, 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43, + 0xE7, 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43, + 0xE7, 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43, + 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43, + // Bytes 10c0 - 10ff + 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43, + 0xE7, 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43, + 0xE7, 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43, + 0xE7, 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43, + 0xE7, 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43, + 0xE7, 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43, + 0xE7, 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43, + 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43, + // Bytes 1100 - 113f + 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43, + 0xE7, 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43, + 0xE7, 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43, + 0xE7, 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43, + 0xE7, 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43, + 0xE7, 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43, + 0xE7, 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43, + 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43, + // Bytes 1140 - 117f + 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43, + 0xE7, 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43, + 0xE7, 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43, + 0xE7, 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43, + 0xE7, 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43, + 0xE7, 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43, + 0xE7, 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43, + 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43, + // Bytes 1180 - 11bf + 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43, + 0xE7, 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43, + 0xE7, 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43, + 0xE7, 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43, + 0xE7, 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43, + 0xE7, 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43, + 0xE7, 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43, + 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43, + // Bytes 11c0 - 11ff + 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43, + 0xE7, 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43, + 0xE7, 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43, + 0xE7, 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43, + 0xE7, 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43, + 0xE7, 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43, + 0xE8, 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43, + 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43, + // Bytes 1200 - 123f + 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43, + 0xE8, 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43, + 0xE8, 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43, + 0xE8, 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43, + 0xE8, 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43, + 0xE8, 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43, + 0xE8, 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43, + 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43, + // Bytes 1240 - 127f + 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43, + 0xE8, 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43, + 0xE8, 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43, + 0xE8, 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43, + 0xE8, 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43, + 0xE8, 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43, + 0xE8, 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43, + 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43, + // Bytes 1280 - 12bf + 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43, + 0xE8, 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43, + 0xE8, 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43, + 0xE8, 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43, + 0xE8, 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43, + 0xE8, 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43, + 0xE8, 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43, + 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43, + // Bytes 12c0 - 12ff + 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43, + 0xE8, 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43, + 0xE8, 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43, + 0xE8, 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43, + 0xE8, 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43, + 0xE8, 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43, + 0xE8, 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43, + 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43, + // Bytes 1300 - 133f + 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43, + 0xE8, 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43, + 0xE8, 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43, + 0xE8, 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43, + 0xE8, 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43, + 0xE8, 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43, + 0xE8, 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43, + 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43, + // Bytes 1340 - 137f + 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43, + 0xE8, 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43, + 0xE8, 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43, + 0xE8, 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43, + 0xE8, 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43, + 0xE8, 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43, + 0xE8, 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43, + 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43, + // Bytes 1380 - 13bf + 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43, + 0xE8, 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43, + 0xE8, 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43, + 0xE8, 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43, + 0xE8, 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43, + 0xE8, 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43, + 0xE8, 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43, + 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43, + // Bytes 13c0 - 13ff + 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43, + 0xE8, 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43, + 0xE8, 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43, + 0xE8, 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43, + 0xE8, 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43, + 0xE8, 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43, + 0xE8, 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43, + 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43, + // Bytes 1400 - 143f + 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43, + 0xE8, 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43, + 0xE8, 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43, + 0xE8, 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43, + 0xE8, 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43, + 0xE8, 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43, + 0xE8, 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43, + 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43, + // Bytes 1440 - 147f + 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43, + 0xE8, 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43, + 0xE8, 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43, + 0xE8, 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43, + 0xE8, 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43, + 0xE8, 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43, + 0xE8, 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43, + 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43, + // Bytes 1480 - 14bf + 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43, + 0xE9, 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43, + 0xE9, 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43, + 0xE9, 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43, + 0xE9, 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43, + 0xE9, 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43, + 0xE9, 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43, + 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85, 0xAA, 0x43, + // Bytes 14c0 - 14ff + 0xE9, 0x86, 0x99, 0x43, 0xE9, 0x86, 0xB4, 0x43, + 0xE9, 0x87, 0x86, 0x43, 0xE9, 0x87, 0x8C, 0x43, + 0xE9, 0x87, 0x8F, 0x43, 0xE9, 0x87, 0x91, 0x43, + 0xE9, 0x88, 0xB4, 0x43, 0xE9, 0x88, 0xB8, 0x43, + 0xE9, 0x89, 0xB6, 0x43, 0xE9, 0x89, 0xBC, 0x43, + 0xE9, 0x8B, 0x97, 0x43, 0xE9, 0x8B, 0x98, 0x43, + 0xE9, 0x8C, 0x84, 0x43, 0xE9, 0x8D, 0x8A, 0x43, + 0xE9, 0x8F, 0xB9, 0x43, 0xE9, 0x90, 0x95, 0x43, + // Bytes 1500 - 153f + 0xE9, 0x95, 0xB7, 0x43, 0xE9, 0x96, 0x80, 0x43, + 0xE9, 0x96, 0x8B, 0x43, 0xE9, 0x96, 0xAD, 0x43, + 0xE9, 0x96, 0xB7, 0x43, 0xE9, 0x98, 0x9C, 0x43, + 0xE9, 0x98, 0xAE, 0x43, 0xE9, 0x99, 0x8B, 0x43, + 0xE9, 0x99, 0x8D, 0x43, 0xE9, 0x99, 0xB5, 0x43, + 0xE9, 0x99, 0xB8, 0x43, 0xE9, 0x99, 0xBC, 0x43, + 0xE9, 0x9A, 0x86, 0x43, 0xE9, 0x9A, 0xA3, 0x43, + 0xE9, 0x9A, 0xB6, 0x43, 0xE9, 0x9A, 0xB7, 0x43, + // Bytes 1540 - 157f + 0xE9, 0x9A, 0xB8, 0x43, 0xE9, 0x9A, 0xB9, 0x43, + 0xE9, 0x9B, 0x83, 0x43, 0xE9, 0x9B, 0xA2, 0x43, + 0xE9, 0x9B, 0xA3, 0x43, 0xE9, 0x9B, 0xA8, 0x43, + 0xE9, 0x9B, 0xB6, 0x43, 0xE9, 0x9B, 0xB7, 0x43, + 0xE9, 0x9C, 0xA3, 0x43, 0xE9, 0x9C, 0xB2, 0x43, + 0xE9, 0x9D, 0x88, 0x43, 0xE9, 0x9D, 0x91, 0x43, + 0xE9, 0x9D, 0x96, 0x43, 0xE9, 0x9D, 0x9E, 0x43, + 0xE9, 0x9D, 0xA2, 0x43, 0xE9, 0x9D, 0xA9, 0x43, + // Bytes 1580 - 15bf + 0xE9, 0x9F, 0x8B, 0x43, 0xE9, 0x9F, 0x9B, 0x43, + 0xE9, 0x9F, 0xA0, 0x43, 0xE9, 0x9F, 0xAD, 0x43, + 0xE9, 0x9F, 0xB3, 0x43, 0xE9, 0x9F, 0xBF, 0x43, + 0xE9, 0xA0, 0x81, 0x43, 0xE9, 0xA0, 0x85, 0x43, + 0xE9, 0xA0, 0x8B, 0x43, 0xE9, 0xA0, 0x98, 0x43, + 0xE9, 0xA0, 0xA9, 0x43, 0xE9, 0xA0, 0xBB, 0x43, + 0xE9, 0xA1, 0x9E, 0x43, 0xE9, 0xA2, 0xA8, 0x43, + 0xE9, 0xA3, 0x9B, 0x43, 0xE9, 0xA3, 0x9F, 0x43, + // Bytes 15c0 - 15ff + 0xE9, 0xA3, 0xA2, 0x43, 0xE9, 0xA3, 0xAF, 0x43, + 0xE9, 0xA3, 0xBC, 0x43, 0xE9, 0xA4, 0xA8, 0x43, + 0xE9, 0xA4, 0xA9, 0x43, 0xE9, 0xA6, 0x96, 0x43, + 0xE9, 0xA6, 0x99, 0x43, 0xE9, 0xA6, 0xA7, 0x43, + 0xE9, 0xA6, 0xAC, 0x43, 0xE9, 0xA7, 0x82, 0x43, + 0xE9, 0xA7, 0xB1, 0x43, 0xE9, 0xA7, 0xBE, 0x43, + 0xE9, 0xA9, 0xAA, 0x43, 0xE9, 0xAA, 0xA8, 0x43, + 0xE9, 0xAB, 0x98, 0x43, 0xE9, 0xAB, 0x9F, 0x43, + // Bytes 1600 - 163f + 0xE9, 0xAC, 0x92, 0x43, 0xE9, 0xAC, 0xA5, 0x43, + 0xE9, 0xAC, 0xAF, 0x43, 0xE9, 0xAC, 0xB2, 0x43, + 0xE9, 0xAC, 0xBC, 0x43, 0xE9, 0xAD, 0x9A, 0x43, + 0xE9, 0xAD, 0xAF, 0x43, 0xE9, 0xB1, 0x80, 0x43, + 0xE9, 0xB1, 0x97, 0x43, 0xE9, 0xB3, 0xA5, 0x43, + 0xE9, 0xB3, 0xBD, 0x43, 0xE9, 0xB5, 0xA7, 0x43, + 0xE9, 0xB6, 0xB4, 0x43, 0xE9, 0xB7, 0xBA, 0x43, + 0xE9, 0xB8, 0x9E, 0x43, 0xE9, 0xB9, 0xB5, 0x43, + // Bytes 1640 - 167f + 0xE9, 0xB9, 0xBF, 0x43, 0xE9, 0xBA, 0x97, 0x43, + 0xE9, 0xBA, 0x9F, 0x43, 0xE9, 0xBA, 0xA5, 0x43, + 0xE9, 0xBA, 0xBB, 0x43, 0xE9, 0xBB, 0x83, 0x43, + 0xE9, 0xBB, 0x8D, 0x43, 0xE9, 0xBB, 0x8E, 0x43, + 0xE9, 0xBB, 0x91, 0x43, 0xE9, 0xBB, 0xB9, 0x43, + 0xE9, 0xBB, 0xBD, 0x43, 0xE9, 0xBB, 0xBE, 0x43, + 0xE9, 0xBC, 0x85, 0x43, 0xE9, 0xBC, 0x8E, 0x43, + 0xE9, 0xBC, 0x8F, 0x43, 0xE9, 0xBC, 0x93, 0x43, + // Bytes 1680 - 16bf + 0xE9, 0xBC, 0x96, 0x43, 0xE9, 0xBC, 0xA0, 0x43, + 0xE9, 0xBC, 0xBB, 0x43, 0xE9, 0xBD, 0x83, 0x43, + 0xE9, 0xBD, 0x8A, 0x43, 0xE9, 0xBD, 0x92, 0x43, + 0xE9, 0xBE, 0x8D, 0x43, 0xE9, 0xBE, 0x8E, 0x43, + 0xE9, 0xBE, 0x9C, 0x43, 0xE9, 0xBE, 0x9F, 0x43, + 0xE9, 0xBE, 0xA0, 0x43, 0xEA, 0x9C, 0xA7, 0x43, + 0xEA, 0x9D, 0xAF, 0x43, 0xEA, 0xAC, 0xB7, 0x43, + 0xEA, 0xAD, 0x92, 0x44, 0xF0, 0xA0, 0x84, 0xA2, + // Bytes 16c0 - 16ff + 0x44, 0xF0, 0xA0, 0x94, 0x9C, 0x44, 0xF0, 0xA0, + 0x94, 0xA5, 0x44, 0xF0, 0xA0, 0x95, 0x8B, 0x44, + 0xF0, 0xA0, 0x98, 0xBA, 0x44, 0xF0, 0xA0, 0xA0, + 0x84, 0x44, 0xF0, 0xA0, 0xA3, 0x9E, 0x44, 0xF0, + 0xA0, 0xA8, 0xAC, 0x44, 0xF0, 0xA0, 0xAD, 0xA3, + 0x44, 0xF0, 0xA1, 0x93, 0xA4, 0x44, 0xF0, 0xA1, + 0x9A, 0xA8, 0x44, 0xF0, 0xA1, 0x9B, 0xAA, 0x44, + 0xF0, 0xA1, 0xA7, 0x88, 0x44, 0xF0, 0xA1, 0xAC, + // Bytes 1700 - 173f + 0x98, 0x44, 0xF0, 0xA1, 0xB4, 0x8B, 0x44, 0xF0, + 0xA1, 0xB7, 0xA4, 0x44, 0xF0, 0xA1, 0xB7, 0xA6, + 0x44, 0xF0, 0xA2, 0x86, 0x83, 0x44, 0xF0, 0xA2, + 0x86, 0x9F, 0x44, 0xF0, 0xA2, 0x8C, 0xB1, 0x44, + 0xF0, 0xA2, 0x9B, 0x94, 0x44, 0xF0, 0xA2, 0xA1, + 0x84, 0x44, 0xF0, 0xA2, 0xA1, 0x8A, 0x44, 0xF0, + 0xA2, 0xAC, 0x8C, 0x44, 0xF0, 0xA2, 0xAF, 0xB1, + 0x44, 0xF0, 0xA3, 0x80, 0x8A, 0x44, 0xF0, 0xA3, + // Bytes 1740 - 177f + 0x8A, 0xB8, 0x44, 0xF0, 0xA3, 0x8D, 0x9F, 0x44, + 0xF0, 0xA3, 0x8E, 0x93, 0x44, 0xF0, 0xA3, 0x8E, + 0x9C, 0x44, 0xF0, 0xA3, 0x8F, 0x83, 0x44, 0xF0, + 0xA3, 0x8F, 0x95, 0x44, 0xF0, 0xA3, 0x91, 0xAD, + 0x44, 0xF0, 0xA3, 0x9A, 0xA3, 0x44, 0xF0, 0xA3, + 0xA2, 0xA7, 0x44, 0xF0, 0xA3, 0xAA, 0x8D, 0x44, + 0xF0, 0xA3, 0xAB, 0xBA, 0x44, 0xF0, 0xA3, 0xB2, + 0xBC, 0x44, 0xF0, 0xA3, 0xB4, 0x9E, 0x44, 0xF0, + // Bytes 1780 - 17bf + 0xA3, 0xBB, 0x91, 0x44, 0xF0, 0xA3, 0xBD, 0x9E, + 0x44, 0xF0, 0xA3, 0xBE, 0x8E, 0x44, 0xF0, 0xA4, + 0x89, 0xA3, 0x44, 0xF0, 0xA4, 0x8B, 0xAE, 0x44, + 0xF0, 0xA4, 0x8E, 0xAB, 0x44, 0xF0, 0xA4, 0x98, + 0x88, 0x44, 0xF0, 0xA4, 0x9C, 0xB5, 0x44, 0xF0, + 0xA4, 0xA0, 0x94, 0x44, 0xF0, 0xA4, 0xB0, 0xB6, + 0x44, 0xF0, 0xA4, 0xB2, 0x92, 0x44, 0xF0, 0xA4, + 0xBE, 0xA1, 0x44, 0xF0, 0xA4, 0xBE, 0xB8, 0x44, + // Bytes 17c0 - 17ff + 0xF0, 0xA5, 0x81, 0x84, 0x44, 0xF0, 0xA5, 0x83, + 0xB2, 0x44, 0xF0, 0xA5, 0x83, 0xB3, 0x44, 0xF0, + 0xA5, 0x84, 0x99, 0x44, 0xF0, 0xA5, 0x84, 0xB3, + 0x44, 0xF0, 0xA5, 0x89, 0x89, 0x44, 0xF0, 0xA5, + 0x90, 0x9D, 0x44, 0xF0, 0xA5, 0x98, 0xA6, 0x44, + 0xF0, 0xA5, 0x9A, 0x9A, 0x44, 0xF0, 0xA5, 0x9B, + 0x85, 0x44, 0xF0, 0xA5, 0xA5, 0xBC, 0x44, 0xF0, + 0xA5, 0xAA, 0xA7, 0x44, 0xF0, 0xA5, 0xAE, 0xAB, + // Bytes 1800 - 183f + 0x44, 0xF0, 0xA5, 0xB2, 0x80, 0x44, 0xF0, 0xA5, + 0xB3, 0x90, 0x44, 0xF0, 0xA5, 0xBE, 0x86, 0x44, + 0xF0, 0xA6, 0x87, 0x9A, 0x44, 0xF0, 0xA6, 0x88, + 0xA8, 0x44, 0xF0, 0xA6, 0x89, 0x87, 0x44, 0xF0, + 0xA6, 0x8B, 0x99, 0x44, 0xF0, 0xA6, 0x8C, 0xBE, + 0x44, 0xF0, 0xA6, 0x93, 0x9A, 0x44, 0xF0, 0xA6, + 0x94, 0xA3, 0x44, 0xF0, 0xA6, 0x96, 0xA8, 0x44, + 0xF0, 0xA6, 0x9E, 0xA7, 0x44, 0xF0, 0xA6, 0x9E, + // Bytes 1840 - 187f + 0xB5, 0x44, 0xF0, 0xA6, 0xAC, 0xBC, 0x44, 0xF0, + 0xA6, 0xB0, 0xB6, 0x44, 0xF0, 0xA6, 0xB3, 0x95, + 0x44, 0xF0, 0xA6, 0xB5, 0xAB, 0x44, 0xF0, 0xA6, + 0xBC, 0xAC, 0x44, 0xF0, 0xA6, 0xBE, 0xB1, 0x44, + 0xF0, 0xA7, 0x83, 0x92, 0x44, 0xF0, 0xA7, 0x8F, + 0x8A, 0x44, 0xF0, 0xA7, 0x99, 0xA7, 0x44, 0xF0, + 0xA7, 0xA2, 0xAE, 0x44, 0xF0, 0xA7, 0xA5, 0xA6, + 0x44, 0xF0, 0xA7, 0xB2, 0xA8, 0x44, 0xF0, 0xA7, + // Bytes 1880 - 18bf + 0xBB, 0x93, 0x44, 0xF0, 0xA7, 0xBC, 0xAF, 0x44, + 0xF0, 0xA8, 0x97, 0x92, 0x44, 0xF0, 0xA8, 0x97, + 0xAD, 0x44, 0xF0, 0xA8, 0x9C, 0xAE, 0x44, 0xF0, + 0xA8, 0xAF, 0xBA, 0x44, 0xF0, 0xA8, 0xB5, 0xB7, + 0x44, 0xF0, 0xA9, 0x85, 0x85, 0x44, 0xF0, 0xA9, + 0x87, 0x9F, 0x44, 0xF0, 0xA9, 0x88, 0x9A, 0x44, + 0xF0, 0xA9, 0x90, 0x8A, 0x44, 0xF0, 0xA9, 0x92, + 0x96, 0x44, 0xF0, 0xA9, 0x96, 0xB6, 0x44, 0xF0, + // Bytes 18c0 - 18ff + 0xA9, 0xAC, 0xB0, 0x44, 0xF0, 0xAA, 0x83, 0x8E, + 0x44, 0xF0, 0xAA, 0x84, 0x85, 0x44, 0xF0, 0xAA, + 0x88, 0x8E, 0x44, 0xF0, 0xAA, 0x8A, 0x91, 0x44, + 0xF0, 0xAA, 0x8E, 0x92, 0x44, 0xF0, 0xAA, 0x98, + 0x80, 0x06, 0xE0, 0xA7, 0x87, 0xE0, 0xA6, 0xBE, + 0x06, 0xE0, 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x06, + 0xE0, 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x06, 0xE0, + 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x06, 0xE0, 0xAD, + // Bytes 1900 - 193f + 0x87, 0xE0, 0xAD, 0x97, 0x06, 0xE0, 0xAE, 0x92, + 0xE0, 0xAF, 0x97, 0x06, 0xE0, 0xAF, 0x86, 0xE0, + 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x86, 0xE0, 0xAF, + 0x97, 0x06, 0xE0, 0xAF, 0x87, 0xE0, 0xAE, 0xBE, + 0x06, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x06, + 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x06, 0xE0, + 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x06, 0xE0, 0xB5, + 0x86, 0xE0, 0xB4, 0xBE, 0x06, 0xE0, 0xB5, 0x86, + // Bytes 1940 - 197f + 0xE0, 0xB5, 0x97, 0x06, 0xE0, 0xB5, 0x87, 0xE0, + 0xB4, 0xBE, 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, + 0x9F, 0x06, 0xE1, 0x80, 0xA5, 0xE1, 0x80, 0xAE, + 0x06, 0xE1, 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x06, + 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, + 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, + 0x8B, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x8D, + 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x91, 0xE1, + // Bytes 1980 - 19bf + 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBA, 0xE1, 0xAC, + 0xB5, 0x06, 0xE1, 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, + 0x06, 0xE1, 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x06, + 0xE1, 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, + 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x08, 0xF0, 0x91, + 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x08, 0xF0, + 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84, 0xA7, 0x08, + 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91, 0x8C, 0xBE, + // Bytes 19c0 - 19ff + 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91, 0x8D, + 0x97, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, + 0x92, 0xB0, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, + 0x91, 0x92, 0xBA, 0x08, 0xF0, 0x91, 0x92, 0xB9, + 0xF0, 0x91, 0x92, 0xBD, 0x08, 0xF0, 0x91, 0x96, + 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x08, 0xF0, 0x91, + 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x09, 0xE0, + 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95, + // Bytes 1a00 - 1a3f + 0x42, 0x21, 0x21, 0x42, 0x21, 0x3F, 0x42, 0x2E, + 0x2E, 0x42, 0x30, 0x2C, 0x42, 0x30, 0x2E, 0x42, + 0x31, 0x2C, 0x42, 0x31, 0x2E, 0x42, 0x31, 0x30, + 0x42, 0x31, 0x31, 0x42, 0x31, 0x32, 0x42, 0x31, + 0x33, 0x42, 0x31, 0x34, 0x42, 0x31, 0x35, 0x42, + 0x31, 0x36, 0x42, 0x31, 0x37, 0x42, 0x31, 0x38, + 0x42, 0x31, 0x39, 0x42, 0x32, 0x2C, 0x42, 0x32, + 0x2E, 0x42, 0x32, 0x30, 0x42, 0x32, 0x31, 0x42, + // Bytes 1a40 - 1a7f + 0x32, 0x32, 0x42, 0x32, 0x33, 0x42, 0x32, 0x34, + 0x42, 0x32, 0x35, 0x42, 0x32, 0x36, 0x42, 0x32, + 0x37, 0x42, 0x32, 0x38, 0x42, 0x32, 0x39, 0x42, + 0x33, 0x2C, 0x42, 0x33, 0x2E, 0x42, 0x33, 0x30, + 0x42, 0x33, 0x31, 0x42, 0x33, 0x32, 0x42, 0x33, + 0x33, 0x42, 0x33, 0x34, 0x42, 0x33, 0x35, 0x42, + 0x33, 0x36, 0x42, 0x33, 0x37, 0x42, 0x33, 0x38, + 0x42, 0x33, 0x39, 0x42, 0x34, 0x2C, 0x42, 0x34, + // Bytes 1a80 - 1abf + 0x2E, 0x42, 0x34, 0x30, 0x42, 0x34, 0x31, 0x42, + 0x34, 0x32, 0x42, 0x34, 0x33, 0x42, 0x34, 0x34, + 0x42, 0x34, 0x35, 0x42, 0x34, 0x36, 0x42, 0x34, + 0x37, 0x42, 0x34, 0x38, 0x42, 0x34, 0x39, 0x42, + 0x35, 0x2C, 0x42, 0x35, 0x2E, 0x42, 0x35, 0x30, + 0x42, 0x36, 0x2C, 0x42, 0x36, 0x2E, 0x42, 0x37, + 0x2C, 0x42, 0x37, 0x2E, 0x42, 0x38, 0x2C, 0x42, + 0x38, 0x2E, 0x42, 0x39, 0x2C, 0x42, 0x39, 0x2E, + // Bytes 1ac0 - 1aff + 0x42, 0x3D, 0x3D, 0x42, 0x3F, 0x21, 0x42, 0x3F, + 0x3F, 0x42, 0x41, 0x55, 0x42, 0x42, 0x71, 0x42, + 0x43, 0x44, 0x42, 0x44, 0x4A, 0x42, 0x44, 0x5A, + 0x42, 0x44, 0x7A, 0x42, 0x47, 0x42, 0x42, 0x47, + 0x79, 0x42, 0x48, 0x50, 0x42, 0x48, 0x56, 0x42, + 0x48, 0x67, 0x42, 0x48, 0x7A, 0x42, 0x49, 0x49, + 0x42, 0x49, 0x4A, 0x42, 0x49, 0x55, 0x42, 0x49, + 0x56, 0x42, 0x49, 0x58, 0x42, 0x4B, 0x42, 0x42, + // Bytes 1b00 - 1b3f + 0x4B, 0x4B, 0x42, 0x4B, 0x4D, 0x42, 0x4C, 0x4A, + 0x42, 0x4C, 0x6A, 0x42, 0x4D, 0x42, 0x42, 0x4D, + 0x43, 0x42, 0x4D, 0x44, 0x42, 0x4D, 0x56, 0x42, + 0x4D, 0x57, 0x42, 0x4E, 0x4A, 0x42, 0x4E, 0x6A, + 0x42, 0x4E, 0x6F, 0x42, 0x50, 0x48, 0x42, 0x50, + 0x52, 0x42, 0x50, 0x61, 0x42, 0x52, 0x73, 0x42, + 0x53, 0x44, 0x42, 0x53, 0x4D, 0x42, 0x53, 0x53, + 0x42, 0x53, 0x76, 0x42, 0x54, 0x4D, 0x42, 0x56, + // Bytes 1b40 - 1b7f + 0x49, 0x42, 0x57, 0x43, 0x42, 0x57, 0x5A, 0x42, + 0x57, 0x62, 0x42, 0x58, 0x49, 0x42, 0x63, 0x63, + 0x42, 0x63, 0x64, 0x42, 0x63, 0x6D, 0x42, 0x64, + 0x42, 0x42, 0x64, 0x61, 0x42, 0x64, 0x6C, 0x42, + 0x64, 0x6D, 0x42, 0x64, 0x7A, 0x42, 0x65, 0x56, + 0x42, 0x66, 0x66, 0x42, 0x66, 0x69, 0x42, 0x66, + 0x6C, 0x42, 0x66, 0x6D, 0x42, 0x68, 0x61, 0x42, + 0x69, 0x69, 0x42, 0x69, 0x6A, 0x42, 0x69, 0x6E, + // Bytes 1b80 - 1bbf + 0x42, 0x69, 0x76, 0x42, 0x69, 0x78, 0x42, 0x6B, + 0x41, 0x42, 0x6B, 0x56, 0x42, 0x6B, 0x57, 0x42, + 0x6B, 0x67, 0x42, 0x6B, 0x6C, 0x42, 0x6B, 0x6D, + 0x42, 0x6B, 0x74, 0x42, 0x6C, 0x6A, 0x42, 0x6C, + 0x6D, 0x42, 0x6C, 0x6E, 0x42, 0x6C, 0x78, 0x42, + 0x6D, 0x32, 0x42, 0x6D, 0x33, 0x42, 0x6D, 0x41, + 0x42, 0x6D, 0x56, 0x42, 0x6D, 0x57, 0x42, 0x6D, + 0x62, 0x42, 0x6D, 0x67, 0x42, 0x6D, 0x6C, 0x42, + // Bytes 1bc0 - 1bff + 0x6D, 0x6D, 0x42, 0x6D, 0x73, 0x42, 0x6E, 0x41, + 0x42, 0x6E, 0x46, 0x42, 0x6E, 0x56, 0x42, 0x6E, + 0x57, 0x42, 0x6E, 0x6A, 0x42, 0x6E, 0x6D, 0x42, + 0x6E, 0x73, 0x42, 0x6F, 0x56, 0x42, 0x70, 0x41, + 0x42, 0x70, 0x46, 0x42, 0x70, 0x56, 0x42, 0x70, + 0x57, 0x42, 0x70, 0x63, 0x42, 0x70, 0x73, 0x42, + 0x73, 0x72, 0x42, 0x73, 0x74, 0x42, 0x76, 0x69, + 0x42, 0x78, 0x69, 0x43, 0x28, 0x31, 0x29, 0x43, + // Bytes 1c00 - 1c3f + 0x28, 0x32, 0x29, 0x43, 0x28, 0x33, 0x29, 0x43, + 0x28, 0x34, 0x29, 0x43, 0x28, 0x35, 0x29, 0x43, + 0x28, 0x36, 0x29, 0x43, 0x28, 0x37, 0x29, 0x43, + 0x28, 0x38, 0x29, 0x43, 0x28, 0x39, 0x29, 0x43, + 0x28, 0x41, 0x29, 0x43, 0x28, 0x42, 0x29, 0x43, + 0x28, 0x43, 0x29, 0x43, 0x28, 0x44, 0x29, 0x43, + 0x28, 0x45, 0x29, 0x43, 0x28, 0x46, 0x29, 0x43, + 0x28, 0x47, 0x29, 0x43, 0x28, 0x48, 0x29, 0x43, + // Bytes 1c40 - 1c7f + 0x28, 0x49, 0x29, 0x43, 0x28, 0x4A, 0x29, 0x43, + 0x28, 0x4B, 0x29, 0x43, 0x28, 0x4C, 0x29, 0x43, + 0x28, 0x4D, 0x29, 0x43, 0x28, 0x4E, 0x29, 0x43, + 0x28, 0x4F, 0x29, 0x43, 0x28, 0x50, 0x29, 0x43, + 0x28, 0x51, 0x29, 0x43, 0x28, 0x52, 0x29, 0x43, + 0x28, 0x53, 0x29, 0x43, 0x28, 0x54, 0x29, 0x43, + 0x28, 0x55, 0x29, 0x43, 0x28, 0x56, 0x29, 0x43, + 0x28, 0x57, 0x29, 0x43, 0x28, 0x58, 0x29, 0x43, + // Bytes 1c80 - 1cbf + 0x28, 0x59, 0x29, 0x43, 0x28, 0x5A, 0x29, 0x43, + 0x28, 0x61, 0x29, 0x43, 0x28, 0x62, 0x29, 0x43, + 0x28, 0x63, 0x29, 0x43, 0x28, 0x64, 0x29, 0x43, + 0x28, 0x65, 0x29, 0x43, 0x28, 0x66, 0x29, 0x43, + 0x28, 0x67, 0x29, 0x43, 0x28, 0x68, 0x29, 0x43, + 0x28, 0x69, 0x29, 0x43, 0x28, 0x6A, 0x29, 0x43, + 0x28, 0x6B, 0x29, 0x43, 0x28, 0x6C, 0x29, 0x43, + 0x28, 0x6D, 0x29, 0x43, 0x28, 0x6E, 0x29, 0x43, + // Bytes 1cc0 - 1cff + 0x28, 0x6F, 0x29, 0x43, 0x28, 0x70, 0x29, 0x43, + 0x28, 0x71, 0x29, 0x43, 0x28, 0x72, 0x29, 0x43, + 0x28, 0x73, 0x29, 0x43, 0x28, 0x74, 0x29, 0x43, + 0x28, 0x75, 0x29, 0x43, 0x28, 0x76, 0x29, 0x43, + 0x28, 0x77, 0x29, 0x43, 0x28, 0x78, 0x29, 0x43, + 0x28, 0x79, 0x29, 0x43, 0x28, 0x7A, 0x29, 0x43, + 0x2E, 0x2E, 0x2E, 0x43, 0x31, 0x30, 0x2E, 0x43, + 0x31, 0x31, 0x2E, 0x43, 0x31, 0x32, 0x2E, 0x43, + // Bytes 1d00 - 1d3f + 0x31, 0x33, 0x2E, 0x43, 0x31, 0x34, 0x2E, 0x43, + 0x31, 0x35, 0x2E, 0x43, 0x31, 0x36, 0x2E, 0x43, + 0x31, 0x37, 0x2E, 0x43, 0x31, 0x38, 0x2E, 0x43, + 0x31, 0x39, 0x2E, 0x43, 0x32, 0x30, 0x2E, 0x43, + 0x3A, 0x3A, 0x3D, 0x43, 0x3D, 0x3D, 0x3D, 0x43, + 0x43, 0x6F, 0x2E, 0x43, 0x46, 0x41, 0x58, 0x43, + 0x47, 0x48, 0x7A, 0x43, 0x47, 0x50, 0x61, 0x43, + 0x49, 0x49, 0x49, 0x43, 0x4C, 0x54, 0x44, 0x43, + // Bytes 1d40 - 1d7f + 0x4C, 0xC2, 0xB7, 0x43, 0x4D, 0x48, 0x7A, 0x43, + 0x4D, 0x50, 0x61, 0x43, 0x4D, 0xCE, 0xA9, 0x43, + 0x50, 0x50, 0x4D, 0x43, 0x50, 0x50, 0x56, 0x43, + 0x50, 0x54, 0x45, 0x43, 0x54, 0x45, 0x4C, 0x43, + 0x54, 0x48, 0x7A, 0x43, 0x56, 0x49, 0x49, 0x43, + 0x58, 0x49, 0x49, 0x43, 0x61, 0x2F, 0x63, 0x43, + 0x61, 0x2F, 0x73, 0x43, 0x61, 0xCA, 0xBE, 0x43, + 0x62, 0x61, 0x72, 0x43, 0x63, 0x2F, 0x6F, 0x43, + // Bytes 1d80 - 1dbf + 0x63, 0x2F, 0x75, 0x43, 0x63, 0x61, 0x6C, 0x43, + 0x63, 0x6D, 0x32, 0x43, 0x63, 0x6D, 0x33, 0x43, + 0x64, 0x6D, 0x32, 0x43, 0x64, 0x6D, 0x33, 0x43, + 0x65, 0x72, 0x67, 0x43, 0x66, 0x66, 0x69, 0x43, + 0x66, 0x66, 0x6C, 0x43, 0x67, 0x61, 0x6C, 0x43, + 0x68, 0x50, 0x61, 0x43, 0x69, 0x69, 0x69, 0x43, + 0x6B, 0x48, 0x7A, 0x43, 0x6B, 0x50, 0x61, 0x43, + 0x6B, 0x6D, 0x32, 0x43, 0x6B, 0x6D, 0x33, 0x43, + // Bytes 1dc0 - 1dff + 0x6B, 0xCE, 0xA9, 0x43, 0x6C, 0x6F, 0x67, 0x43, + 0x6C, 0xC2, 0xB7, 0x43, 0x6D, 0x69, 0x6C, 0x43, + 0x6D, 0x6D, 0x32, 0x43, 0x6D, 0x6D, 0x33, 0x43, + 0x6D, 0x6F, 0x6C, 0x43, 0x72, 0x61, 0x64, 0x43, + 0x76, 0x69, 0x69, 0x43, 0x78, 0x69, 0x69, 0x43, + 0xC2, 0xB0, 0x43, 0x43, 0xC2, 0xB0, 0x46, 0x43, + 0xCA, 0xBC, 0x6E, 0x43, 0xCE, 0xBC, 0x41, 0x43, + 0xCE, 0xBC, 0x46, 0x43, 0xCE, 0xBC, 0x56, 0x43, + // Bytes 1e00 - 1e3f + 0xCE, 0xBC, 0x57, 0x43, 0xCE, 0xBC, 0x67, 0x43, + 0xCE, 0xBC, 0x6C, 0x43, 0xCE, 0xBC, 0x6D, 0x43, + 0xCE, 0xBC, 0x73, 0x44, 0x28, 0x31, 0x30, 0x29, + 0x44, 0x28, 0x31, 0x31, 0x29, 0x44, 0x28, 0x31, + 0x32, 0x29, 0x44, 0x28, 0x31, 0x33, 0x29, 0x44, + 0x28, 0x31, 0x34, 0x29, 0x44, 0x28, 0x31, 0x35, + 0x29, 0x44, 0x28, 0x31, 0x36, 0x29, 0x44, 0x28, + 0x31, 0x37, 0x29, 0x44, 0x28, 0x31, 0x38, 0x29, + // Bytes 1e40 - 1e7f + 0x44, 0x28, 0x31, 0x39, 0x29, 0x44, 0x28, 0x32, + 0x30, 0x29, 0x44, 0x30, 0xE7, 0x82, 0xB9, 0x44, + 0x31, 0xE2, 0x81, 0x84, 0x44, 0x31, 0xE6, 0x97, + 0xA5, 0x44, 0x31, 0xE6, 0x9C, 0x88, 0x44, 0x31, + 0xE7, 0x82, 0xB9, 0x44, 0x32, 0xE6, 0x97, 0xA5, + 0x44, 0x32, 0xE6, 0x9C, 0x88, 0x44, 0x32, 0xE7, + 0x82, 0xB9, 0x44, 0x33, 0xE6, 0x97, 0xA5, 0x44, + 0x33, 0xE6, 0x9C, 0x88, 0x44, 0x33, 0xE7, 0x82, + // Bytes 1e80 - 1ebf + 0xB9, 0x44, 0x34, 0xE6, 0x97, 0xA5, 0x44, 0x34, + 0xE6, 0x9C, 0x88, 0x44, 0x34, 0xE7, 0x82, 0xB9, + 0x44, 0x35, 0xE6, 0x97, 0xA5, 0x44, 0x35, 0xE6, + 0x9C, 0x88, 0x44, 0x35, 0xE7, 0x82, 0xB9, 0x44, + 0x36, 0xE6, 0x97, 0xA5, 0x44, 0x36, 0xE6, 0x9C, + 0x88, 0x44, 0x36, 0xE7, 0x82, 0xB9, 0x44, 0x37, + 0xE6, 0x97, 0xA5, 0x44, 0x37, 0xE6, 0x9C, 0x88, + 0x44, 0x37, 0xE7, 0x82, 0xB9, 0x44, 0x38, 0xE6, + // Bytes 1ec0 - 1eff + 0x97, 0xA5, 0x44, 0x38, 0xE6, 0x9C, 0x88, 0x44, + 0x38, 0xE7, 0x82, 0xB9, 0x44, 0x39, 0xE6, 0x97, + 0xA5, 0x44, 0x39, 0xE6, 0x9C, 0x88, 0x44, 0x39, + 0xE7, 0x82, 0xB9, 0x44, 0x56, 0x49, 0x49, 0x49, + 0x44, 0x61, 0x2E, 0x6D, 0x2E, 0x44, 0x6B, 0x63, + 0x61, 0x6C, 0x44, 0x70, 0x2E, 0x6D, 0x2E, 0x44, + 0x76, 0x69, 0x69, 0x69, 0x44, 0xD5, 0xA5, 0xD6, + 0x82, 0x44, 0xD5, 0xB4, 0xD5, 0xA5, 0x44, 0xD5, + // Bytes 1f00 - 1f3f + 0xB4, 0xD5, 0xAB, 0x44, 0xD5, 0xB4, 0xD5, 0xAD, + 0x44, 0xD5, 0xB4, 0xD5, 0xB6, 0x44, 0xD5, 0xBE, + 0xD5, 0xB6, 0x44, 0xD7, 0x90, 0xD7, 0x9C, 0x44, + 0xD8, 0xA7, 0xD9, 0xB4, 0x44, 0xD8, 0xA8, 0xD8, + 0xAC, 0x44, 0xD8, 0xA8, 0xD8, 0xAD, 0x44, 0xD8, + 0xA8, 0xD8, 0xAE, 0x44, 0xD8, 0xA8, 0xD8, 0xB1, + 0x44, 0xD8, 0xA8, 0xD8, 0xB2, 0x44, 0xD8, 0xA8, + 0xD9, 0x85, 0x44, 0xD8, 0xA8, 0xD9, 0x86, 0x44, + // Bytes 1f40 - 1f7f + 0xD8, 0xA8, 0xD9, 0x87, 0x44, 0xD8, 0xA8, 0xD9, + 0x89, 0x44, 0xD8, 0xA8, 0xD9, 0x8A, 0x44, 0xD8, + 0xAA, 0xD8, 0xAC, 0x44, 0xD8, 0xAA, 0xD8, 0xAD, + 0x44, 0xD8, 0xAA, 0xD8, 0xAE, 0x44, 0xD8, 0xAA, + 0xD8, 0xB1, 0x44, 0xD8, 0xAA, 0xD8, 0xB2, 0x44, + 0xD8, 0xAA, 0xD9, 0x85, 0x44, 0xD8, 0xAA, 0xD9, + 0x86, 0x44, 0xD8, 0xAA, 0xD9, 0x87, 0x44, 0xD8, + 0xAA, 0xD9, 0x89, 0x44, 0xD8, 0xAA, 0xD9, 0x8A, + // Bytes 1f80 - 1fbf + 0x44, 0xD8, 0xAB, 0xD8, 0xAC, 0x44, 0xD8, 0xAB, + 0xD8, 0xB1, 0x44, 0xD8, 0xAB, 0xD8, 0xB2, 0x44, + 0xD8, 0xAB, 0xD9, 0x85, 0x44, 0xD8, 0xAB, 0xD9, + 0x86, 0x44, 0xD8, 0xAB, 0xD9, 0x87, 0x44, 0xD8, + 0xAB, 0xD9, 0x89, 0x44, 0xD8, 0xAB, 0xD9, 0x8A, + 0x44, 0xD8, 0xAC, 0xD8, 0xAD, 0x44, 0xD8, 0xAC, + 0xD9, 0x85, 0x44, 0xD8, 0xAC, 0xD9, 0x89, 0x44, + 0xD8, 0xAC, 0xD9, 0x8A, 0x44, 0xD8, 0xAD, 0xD8, + // Bytes 1fc0 - 1fff + 0xAC, 0x44, 0xD8, 0xAD, 0xD9, 0x85, 0x44, 0xD8, + 0xAD, 0xD9, 0x89, 0x44, 0xD8, 0xAD, 0xD9, 0x8A, + 0x44, 0xD8, 0xAE, 0xD8, 0xAC, 0x44, 0xD8, 0xAE, + 0xD8, 0xAD, 0x44, 0xD8, 0xAE, 0xD9, 0x85, 0x44, + 0xD8, 0xAE, 0xD9, 0x89, 0x44, 0xD8, 0xAE, 0xD9, + 0x8A, 0x44, 0xD8, 0xB3, 0xD8, 0xAC, 0x44, 0xD8, + 0xB3, 0xD8, 0xAD, 0x44, 0xD8, 0xB3, 0xD8, 0xAE, + 0x44, 0xD8, 0xB3, 0xD8, 0xB1, 0x44, 0xD8, 0xB3, + // Bytes 2000 - 203f + 0xD9, 0x85, 0x44, 0xD8, 0xB3, 0xD9, 0x87, 0x44, + 0xD8, 0xB3, 0xD9, 0x89, 0x44, 0xD8, 0xB3, 0xD9, + 0x8A, 0x44, 0xD8, 0xB4, 0xD8, 0xAC, 0x44, 0xD8, + 0xB4, 0xD8, 0xAD, 0x44, 0xD8, 0xB4, 0xD8, 0xAE, + 0x44, 0xD8, 0xB4, 0xD8, 0xB1, 0x44, 0xD8, 0xB4, + 0xD9, 0x85, 0x44, 0xD8, 0xB4, 0xD9, 0x87, 0x44, + 0xD8, 0xB4, 0xD9, 0x89, 0x44, 0xD8, 0xB4, 0xD9, + 0x8A, 0x44, 0xD8, 0xB5, 0xD8, 0xAD, 0x44, 0xD8, + // Bytes 2040 - 207f + 0xB5, 0xD8, 0xAE, 0x44, 0xD8, 0xB5, 0xD8, 0xB1, + 0x44, 0xD8, 0xB5, 0xD9, 0x85, 0x44, 0xD8, 0xB5, + 0xD9, 0x89, 0x44, 0xD8, 0xB5, 0xD9, 0x8A, 0x44, + 0xD8, 0xB6, 0xD8, 0xAC, 0x44, 0xD8, 0xB6, 0xD8, + 0xAD, 0x44, 0xD8, 0xB6, 0xD8, 0xAE, 0x44, 0xD8, + 0xB6, 0xD8, 0xB1, 0x44, 0xD8, 0xB6, 0xD9, 0x85, + 0x44, 0xD8, 0xB6, 0xD9, 0x89, 0x44, 0xD8, 0xB6, + 0xD9, 0x8A, 0x44, 0xD8, 0xB7, 0xD8, 0xAD, 0x44, + // Bytes 2080 - 20bf + 0xD8, 0xB7, 0xD9, 0x85, 0x44, 0xD8, 0xB7, 0xD9, + 0x89, 0x44, 0xD8, 0xB7, 0xD9, 0x8A, 0x44, 0xD8, + 0xB8, 0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD8, 0xAC, + 0x44, 0xD8, 0xB9, 0xD9, 0x85, 0x44, 0xD8, 0xB9, + 0xD9, 0x89, 0x44, 0xD8, 0xB9, 0xD9, 0x8A, 0x44, + 0xD8, 0xBA, 0xD8, 0xAC, 0x44, 0xD8, 0xBA, 0xD9, + 0x85, 0x44, 0xD8, 0xBA, 0xD9, 0x89, 0x44, 0xD8, + 0xBA, 0xD9, 0x8A, 0x44, 0xD9, 0x81, 0xD8, 0xAC, + // Bytes 20c0 - 20ff + 0x44, 0xD9, 0x81, 0xD8, 0xAD, 0x44, 0xD9, 0x81, + 0xD8, 0xAE, 0x44, 0xD9, 0x81, 0xD9, 0x85, 0x44, + 0xD9, 0x81, 0xD9, 0x89, 0x44, 0xD9, 0x81, 0xD9, + 0x8A, 0x44, 0xD9, 0x82, 0xD8, 0xAD, 0x44, 0xD9, + 0x82, 0xD9, 0x85, 0x44, 0xD9, 0x82, 0xD9, 0x89, + 0x44, 0xD9, 0x82, 0xD9, 0x8A, 0x44, 0xD9, 0x83, + 0xD8, 0xA7, 0x44, 0xD9, 0x83, 0xD8, 0xAC, 0x44, + 0xD9, 0x83, 0xD8, 0xAD, 0x44, 0xD9, 0x83, 0xD8, + // Bytes 2100 - 213f + 0xAE, 0x44, 0xD9, 0x83, 0xD9, 0x84, 0x44, 0xD9, + 0x83, 0xD9, 0x85, 0x44, 0xD9, 0x83, 0xD9, 0x89, + 0x44, 0xD9, 0x83, 0xD9, 0x8A, 0x44, 0xD9, 0x84, + 0xD8, 0xA7, 0x44, 0xD9, 0x84, 0xD8, 0xAC, 0x44, + 0xD9, 0x84, 0xD8, 0xAD, 0x44, 0xD9, 0x84, 0xD8, + 0xAE, 0x44, 0xD9, 0x84, 0xD9, 0x85, 0x44, 0xD9, + 0x84, 0xD9, 0x87, 0x44, 0xD9, 0x84, 0xD9, 0x89, + 0x44, 0xD9, 0x84, 0xD9, 0x8A, 0x44, 0xD9, 0x85, + // Bytes 2140 - 217f + 0xD8, 0xA7, 0x44, 0xD9, 0x85, 0xD8, 0xAC, 0x44, + 0xD9, 0x85, 0xD8, 0xAD, 0x44, 0xD9, 0x85, 0xD8, + 0xAE, 0x44, 0xD9, 0x85, 0xD9, 0x85, 0x44, 0xD9, + 0x85, 0xD9, 0x89, 0x44, 0xD9, 0x85, 0xD9, 0x8A, + 0x44, 0xD9, 0x86, 0xD8, 0xAC, 0x44, 0xD9, 0x86, + 0xD8, 0xAD, 0x44, 0xD9, 0x86, 0xD8, 0xAE, 0x44, + 0xD9, 0x86, 0xD8, 0xB1, 0x44, 0xD9, 0x86, 0xD8, + 0xB2, 0x44, 0xD9, 0x86, 0xD9, 0x85, 0x44, 0xD9, + // Bytes 2180 - 21bf + 0x86, 0xD9, 0x86, 0x44, 0xD9, 0x86, 0xD9, 0x87, + 0x44, 0xD9, 0x86, 0xD9, 0x89, 0x44, 0xD9, 0x86, + 0xD9, 0x8A, 0x44, 0xD9, 0x87, 0xD8, 0xAC, 0x44, + 0xD9, 0x87, 0xD9, 0x85, 0x44, 0xD9, 0x87, 0xD9, + 0x89, 0x44, 0xD9, 0x87, 0xD9, 0x8A, 0x44, 0xD9, + 0x88, 0xD9, 0xB4, 0x44, 0xD9, 0x8A, 0xD8, 0xAC, + 0x44, 0xD9, 0x8A, 0xD8, 0xAD, 0x44, 0xD9, 0x8A, + 0xD8, 0xAE, 0x44, 0xD9, 0x8A, 0xD8, 0xB1, 0x44, + // Bytes 21c0 - 21ff + 0xD9, 0x8A, 0xD8, 0xB2, 0x44, 0xD9, 0x8A, 0xD9, + 0x85, 0x44, 0xD9, 0x8A, 0xD9, 0x86, 0x44, 0xD9, + 0x8A, 0xD9, 0x87, 0x44, 0xD9, 0x8A, 0xD9, 0x89, + 0x44, 0xD9, 0x8A, 0xD9, 0x8A, 0x44, 0xD9, 0x8A, + 0xD9, 0xB4, 0x44, 0xDB, 0x87, 0xD9, 0xB4, 0x45, + 0x28, 0xE1, 0x84, 0x80, 0x29, 0x45, 0x28, 0xE1, + 0x84, 0x82, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x83, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x85, 0x29, 0x45, + // Bytes 2200 - 223f + 0x28, 0xE1, 0x84, 0x86, 0x29, 0x45, 0x28, 0xE1, + 0x84, 0x87, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x89, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8B, 0x29, 0x45, + 0x28, 0xE1, 0x84, 0x8C, 0x29, 0x45, 0x28, 0xE1, + 0x84, 0x8E, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8F, + 0x29, 0x45, 0x28, 0xE1, 0x84, 0x90, 0x29, 0x45, + 0x28, 0xE1, 0x84, 0x91, 0x29, 0x45, 0x28, 0xE1, + 0x84, 0x92, 0x29, 0x45, 0x28, 0xE4, 0xB8, 0x80, + // Bytes 2240 - 227f + 0x29, 0x45, 0x28, 0xE4, 0xB8, 0x83, 0x29, 0x45, + 0x28, 0xE4, 0xB8, 0x89, 0x29, 0x45, 0x28, 0xE4, + 0xB9, 0x9D, 0x29, 0x45, 0x28, 0xE4, 0xBA, 0x8C, + 0x29, 0x45, 0x28, 0xE4, 0xBA, 0x94, 0x29, 0x45, + 0x28, 0xE4, 0xBB, 0xA3, 0x29, 0x45, 0x28, 0xE4, + 0xBC, 0x81, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x91, + 0x29, 0x45, 0x28, 0xE5, 0x85, 0xAB, 0x29, 0x45, + 0x28, 0xE5, 0x85, 0xAD, 0x29, 0x45, 0x28, 0xE5, + // Bytes 2280 - 22bf + 0x8A, 0xB4, 0x29, 0x45, 0x28, 0xE5, 0x8D, 0x81, + 0x29, 0x45, 0x28, 0xE5, 0x8D, 0x94, 0x29, 0x45, + 0x28, 0xE5, 0x90, 0x8D, 0x29, 0x45, 0x28, 0xE5, + 0x91, 0xBC, 0x29, 0x45, 0x28, 0xE5, 0x9B, 0x9B, + 0x29, 0x45, 0x28, 0xE5, 0x9C, 0x9F, 0x29, 0x45, + 0x28, 0xE5, 0xAD, 0xA6, 0x29, 0x45, 0x28, 0xE6, + 0x97, 0xA5, 0x29, 0x45, 0x28, 0xE6, 0x9C, 0x88, + 0x29, 0x45, 0x28, 0xE6, 0x9C, 0x89, 0x29, 0x45, + // Bytes 22c0 - 22ff + 0x28, 0xE6, 0x9C, 0xA8, 0x29, 0x45, 0x28, 0xE6, + 0xA0, 0xAA, 0x29, 0x45, 0x28, 0xE6, 0xB0, 0xB4, + 0x29, 0x45, 0x28, 0xE7, 0x81, 0xAB, 0x29, 0x45, + 0x28, 0xE7, 0x89, 0xB9, 0x29, 0x45, 0x28, 0xE7, + 0x9B, 0xA3, 0x29, 0x45, 0x28, 0xE7, 0xA4, 0xBE, + 0x29, 0x45, 0x28, 0xE7, 0xA5, 0x9D, 0x29, 0x45, + 0x28, 0xE7, 0xA5, 0xAD, 0x29, 0x45, 0x28, 0xE8, + 0x87, 0xAA, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xB3, + // Bytes 2300 - 233f + 0x29, 0x45, 0x28, 0xE8, 0xB2, 0xA1, 0x29, 0x45, + 0x28, 0xE8, 0xB3, 0x87, 0x29, 0x45, 0x28, 0xE9, + 0x87, 0x91, 0x29, 0x45, 0x30, 0xE2, 0x81, 0x84, + 0x33, 0x45, 0x31, 0x30, 0xE6, 0x97, 0xA5, 0x45, + 0x31, 0x30, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x30, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x31, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x31, 0xE6, 0x9C, 0x88, 0x45, + 0x31, 0x31, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x32, + // Bytes 2340 - 237f + 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x32, 0xE6, 0x9C, + 0x88, 0x45, 0x31, 0x32, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x33, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x33, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x34, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x34, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x35, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x35, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x36, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x36, 0xE7, 0x82, 0xB9, 0x45, + // Bytes 2380 - 23bf + 0x31, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x37, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x38, 0xE6, 0x97, + 0xA5, 0x45, 0x31, 0x38, 0xE7, 0x82, 0xB9, 0x45, + 0x31, 0x39, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x39, + 0xE7, 0x82, 0xB9, 0x45, 0x31, 0xE2, 0x81, 0x84, + 0x32, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x33, 0x45, + 0x31, 0xE2, 0x81, 0x84, 0x34, 0x45, 0x31, 0xE2, + 0x81, 0x84, 0x35, 0x45, 0x31, 0xE2, 0x81, 0x84, + // Bytes 23c0 - 23ff + 0x36, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x37, 0x45, + 0x31, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x31, 0xE2, + 0x81, 0x84, 0x39, 0x45, 0x32, 0x30, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0x30, 0xE7, 0x82, 0xB9, 0x45, + 0x32, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x31, + 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x32, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0x32, 0xE7, 0x82, 0xB9, 0x45, + 0x32, 0x33, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x33, + // Bytes 2400 - 243f + 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x34, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0x34, 0xE7, 0x82, 0xB9, 0x45, + 0x32, 0x35, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x36, + 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x37, 0xE6, 0x97, + 0xA5, 0x45, 0x32, 0x38, 0xE6, 0x97, 0xA5, 0x45, + 0x32, 0x39, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0xE2, + 0x81, 0x84, 0x33, 0x45, 0x32, 0xE2, 0x81, 0x84, + 0x35, 0x45, 0x33, 0x30, 0xE6, 0x97, 0xA5, 0x45, + // Bytes 2440 - 247f + 0x33, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0xE2, + 0x81, 0x84, 0x34, 0x45, 0x33, 0xE2, 0x81, 0x84, + 0x35, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x38, 0x45, + 0x34, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x35, 0xE2, + 0x81, 0x84, 0x36, 0x45, 0x35, 0xE2, 0x81, 0x84, + 0x38, 0x45, 0x37, 0xE2, 0x81, 0x84, 0x38, 0x45, + 0x41, 0xE2, 0x88, 0x95, 0x6D, 0x45, 0x56, 0xE2, + 0x88, 0x95, 0x6D, 0x45, 0x6D, 0xE2, 0x88, 0x95, + // Bytes 2480 - 24bf + 0x73, 0x46, 0x31, 0xE2, 0x81, 0x84, 0x31, 0x30, + 0x46, 0x43, 0xE2, 0x88, 0x95, 0x6B, 0x67, 0x46, + 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x46, 0xD8, + 0xA8, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xA8, + 0xD8, 0xAE, 0xD9, 0x8A, 0x46, 0xD8, 0xAA, 0xD8, + 0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, + 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, + 0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, + // Bytes 24c0 - 24ff + 0x46, 0xD8, 0xAA, 0xD8, 0xAD, 0xD9, 0x85, 0x46, + 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD8, + 0xAA, 0xD8, 0xAE, 0xD9, 0x89, 0x46, 0xD8, 0xAA, + 0xD8, 0xAE, 0xD9, 0x8A, 0x46, 0xD8, 0xAA, 0xD9, + 0x85, 0xD8, 0xAC, 0x46, 0xD8, 0xAA, 0xD9, 0x85, + 0xD8, 0xAD, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, + 0xAE, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x89, + 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + // Bytes 2500 - 253f + 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x89, 0x46, 0xD8, + 0xAC, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, + 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xAC, 0xD9, + 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD9, 0x85, + 0xD9, 0x8A, 0x46, 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, + 0x8A, 0x46, 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x89, + 0x46, 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD8, 0xB3, 0xD8, 0xAC, 0xD8, 0xAD, 0x46, 0xD8, + // Bytes 2540 - 257f + 0xB3, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD8, 0xB3, + 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xB3, 0xD8, + 0xAE, 0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, + 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, + 0xAC, 0x46, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAD, + 0x46, 0xD8, 0xB3, 0xD9, 0x85, 0xD9, 0x85, 0x46, + 0xD8, 0xB4, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8, + 0xB4, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xB4, + // Bytes 2580 - 25bf + 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD9, + 0x85, 0xD8, 0xAE, 0x46, 0xD8, 0xB4, 0xD9, 0x85, + 0xD9, 0x85, 0x46, 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, + 0xAD, 0x46, 0xD8, 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, + 0x46, 0xD8, 0xB5, 0xD9, 0x84, 0xD9, 0x89, 0x46, + 0xD8, 0xB5, 0xD9, 0x84, 0xDB, 0x92, 0x46, 0xD8, + 0xB5, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB6, + 0xD8, 0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xB6, 0xD8, + // Bytes 25c0 - 25ff + 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB6, 0xD8, 0xAE, + 0xD9, 0x85, 0x46, 0xD8, 0xB7, 0xD9, 0x85, 0xD8, + 0xAD, 0x46, 0xD8, 0xB7, 0xD9, 0x85, 0xD9, 0x85, + 0x46, 0xD8, 0xB7, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD8, 0xB9, 0xD8, 0xAC, 0xD9, 0x85, 0x46, 0xD8, + 0xB9, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB9, + 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xB9, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xBA, 0xD9, 0x85, + // Bytes 2600 - 263f + 0xD9, 0x85, 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, + 0x89, 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x8A, + 0x46, 0xD9, 0x81, 0xD8, 0xAE, 0xD9, 0x85, 0x46, + 0xD9, 0x81, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, + 0x82, 0xD9, 0x84, 0xDB, 0x92, 0x46, 0xD9, 0x82, + 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x82, 0xD9, + 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x82, 0xD9, 0x85, + 0xD9, 0x8A, 0x46, 0xD9, 0x83, 0xD9, 0x85, 0xD9, + // Bytes 2640 - 267f + 0x85, 0x46, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x8A, + 0x46, 0xD9, 0x84, 0xD8, 0xAC, 0xD8, 0xAC, 0x46, + 0xD9, 0x84, 0xD8, 0xAC, 0xD9, 0x85, 0x46, 0xD9, + 0x84, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x84, + 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, + 0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x84, 0xD8, 0xAD, + 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAE, 0xD9, + 0x85, 0x46, 0xD9, 0x84, 0xD9, 0x85, 0xD8, 0xAD, + // Bytes 2680 - 26bf + 0x46, 0xD9, 0x84, 0xD9, 0x85, 0xD9, 0x8A, 0x46, + 0xD9, 0x85, 0xD8, 0xAC, 0xD8, 0xAD, 0x46, 0xD9, + 0x85, 0xD8, 0xAC, 0xD8, 0xAE, 0x46, 0xD9, 0x85, + 0xD8, 0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, + 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8, 0xAD, + 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, + 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x8A, + 0x46, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0x46, + // Bytes 26c0 - 26ff + 0xD9, 0x85, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, + 0x85, 0xD8, 0xAE, 0xD9, 0x8A, 0x46, 0xD9, 0x85, + 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD8, + 0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x86, 0xD8, 0xAC, + 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, + 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x8A, + 0x46, 0xD9, 0x86, 0xD8, 0xAD, 0xD9, 0x85, 0x46, + 0xD9, 0x86, 0xD8, 0xAD, 0xD9, 0x89, 0x46, 0xD9, + // Bytes 2700 - 273f + 0x86, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x86, + 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD9, + 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x87, 0xD9, 0x85, + 0xD8, 0xAC, 0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD9, + 0x85, 0x46, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9, 0x8A, + 0x46, 0xD9, 0x8A, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, + 0xD9, 0x8A, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9, + 0x8A, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, + // Bytes 2740 - 277f + 0xD9, 0x94, 0xD8, 0xA7, 0x46, 0xD9, 0x8A, 0xD9, + 0x94, 0xD8, 0xAC, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xD8, 0xAD, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, + 0xAE, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xB1, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xB2, 0x46, + 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x85, 0x46, 0xD9, + 0x8A, 0xD9, 0x94, 0xD9, 0x86, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xD9, 0x87, 0x46, 0xD9, 0x8A, 0xD9, + // Bytes 2780 - 27bf + 0x94, 0xD9, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94, + 0xD9, 0x89, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, + 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x86, + 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x87, 0x46, + 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x88, 0x46, 0xD9, + 0x8A, 0xD9, 0x94, 0xDB, 0x90, 0x46, 0xD9, 0x8A, + 0xD9, 0x94, 0xDB, 0x95, 0x46, 0xE0, 0xB9, 0x8D, + 0xE0, 0xB8, 0xB2, 0x46, 0xE0, 0xBA, 0xAB, 0xE0, + // Bytes 27c0 - 27ff + 0xBA, 0x99, 0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, + 0xA1, 0x46, 0xE0, 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, + 0x46, 0xE0, 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0x46, + 0xE0, 0xBD, 0x82, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, + 0xBD, 0x8C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, + 0x91, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x96, + 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x9B, 0xE0, + 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0x90, 0xE0, 0xBE, + // Bytes 2800 - 283f + 0xB5, 0x46, 0xE0, 0xBE, 0x92, 0xE0, 0xBE, 0xB7, + 0x46, 0xE0, 0xBE, 0x9C, 0xE0, 0xBE, 0xB7, 0x46, + 0xE0, 0xBE, 0xA1, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, + 0xBE, 0xA6, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, + 0xAB, 0xE0, 0xBE, 0xB7, 0x46, 0xE1, 0x84, 0x80, + 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x82, 0xE1, + 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, + 0xA1, 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, + // Bytes 2840 - 287f + 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x46, + 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x46, 0xE1, + 0x84, 0x89, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, + 0x8B, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x8B, + 0xE1, 0x85, 0xAE, 0x46, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, + 0xA1, 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, + 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x46, + // Bytes 2880 - 28bf + 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x46, 0xE1, + 0x84, 0x92, 0xE1, 0x85, 0xA1, 0x46, 0xE2, 0x80, + 0xB2, 0xE2, 0x80, 0xB2, 0x46, 0xE2, 0x80, 0xB5, + 0xE2, 0x80, 0xB5, 0x46, 0xE2, 0x88, 0xAB, 0xE2, + 0x88, 0xAB, 0x46, 0xE2, 0x88, 0xAE, 0xE2, 0x88, + 0xAE, 0x46, 0xE3, 0x81, 0xBB, 0xE3, 0x81, 0x8B, + 0x46, 0xE3, 0x82, 0x88, 0xE3, 0x82, 0x8A, 0x46, + 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0x46, 0xE3, + // Bytes 28c0 - 28ff + 0x82, 0xB3, 0xE3, 0x82, 0xB3, 0x46, 0xE3, 0x82, + 0xB3, 0xE3, 0x83, 0x88, 0x46, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83, 0x8A, 0xE3, + 0x83, 0x8E, 0x46, 0xE3, 0x83, 0x9B, 0xE3, 0x83, + 0xB3, 0x46, 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA, + 0x46, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xA9, 0x46, + 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xA0, 0x46, 0xE5, + 0xA4, 0xA7, 0xE6, 0xAD, 0xA3, 0x46, 0xE5, 0xB9, + // Bytes 2900 - 293f + 0xB3, 0xE6, 0x88, 0x90, 0x46, 0xE6, 0x98, 0x8E, + 0xE6, 0xB2, 0xBB, 0x46, 0xE6, 0x98, 0xAD, 0xE5, + 0x92, 0x8C, 0x47, 0x72, 0x61, 0x64, 0xE2, 0x88, + 0x95, 0x73, 0x47, 0xE3, 0x80, 0x94, 0x53, 0xE3, + 0x80, 0x95, 0x48, 0x28, 0xE1, 0x84, 0x80, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x82, + 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, + 0x83, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, + // Bytes 2940 - 297f + 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, + 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x29, + 0x48, 0x28, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1, + 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8B, 0xE1, 0x85, + 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8C, + 0xE1, 0x85, 0xAE, 0x29, 0x48, 0x28, 0xE1, 0x84, + // Bytes 2980 - 29bf + 0x8E, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, + 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, + 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x29, 0x48, + 0x28, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x29, + 0x48, 0x28, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, + 0x29, 0x48, 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, + 0x73, 0x32, 0x48, 0xD8, 0xA7, 0xD9, 0x83, 0xD8, + 0xA8, 0xD8, 0xB1, 0x48, 0xD8, 0xA7, 0xD9, 0x84, + // Bytes 29c0 - 29ff + 0xD9, 0x84, 0xD9, 0x87, 0x48, 0xD8, 0xB1, 0xD8, + 0xB3, 0xD9, 0x88, 0xD9, 0x84, 0x48, 0xD8, 0xB1, + 0xDB, 0x8C, 0xD8, 0xA7, 0xD9, 0x84, 0x48, 0xD8, + 0xB5, 0xD9, 0x84, 0xD8, 0xB9, 0xD9, 0x85, 0x48, + 0xD8, 0xB9, 0xD9, 0x84, 0xD9, 0x8A, 0xD9, 0x87, + 0x48, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, + 0xAF, 0x48, 0xD9, 0x88, 0xD8, 0xB3, 0xD9, 0x84, + 0xD9, 0x85, 0x49, 0xE2, 0x80, 0xB2, 0xE2, 0x80, + // Bytes 2a00 - 2a3f + 0xB2, 0xE2, 0x80, 0xB2, 0x49, 0xE2, 0x80, 0xB5, + 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x49, 0xE2, + 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, + 0x49, 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0xE2, + 0x88, 0xAE, 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xB8, + 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE4, 0xBA, 0x8C, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE5, 0x8B, 0x9D, 0xE3, 0x80, 0x95, + // Bytes 2a40 - 2a7f + 0x49, 0xE3, 0x80, 0x94, 0xE5, 0xAE, 0x89, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x89, + 0x93, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, + 0xE6, 0x95, 0x97, 0xE3, 0x80, 0x95, 0x49, 0xE3, + 0x80, 0x94, 0xE6, 0x9C, 0xAC, 0xE3, 0x80, 0x95, + 0x49, 0xE3, 0x80, 0x94, 0xE7, 0x82, 0xB9, 0xE3, + 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE7, 0x9B, + 0x97, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x82, 0xA2, + // Bytes 2a80 - 2abf + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x49, 0xE3, + 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, + 0x49, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0xA9, 0xE3, + 0x83, 0xB3, 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, + 0xB3, 0xE3, 0x82, 0xB9, 0x49, 0xE3, 0x82, 0xAA, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0x49, 0xE3, + 0x82, 0xAB, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAA, + 0x49, 0xE3, 0x82, 0xB1, 0xE3, 0x83, 0xBC, 0xE3, + // Bytes 2ac0 - 2aff + 0x82, 0xB9, 0x49, 0xE3, 0x82, 0xB3, 0xE3, 0x83, + 0xAB, 0xE3, 0x83, 0x8A, 0x49, 0xE3, 0x82, 0xBB, + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, + 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, + 0x49, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0xE3, + 0x82, 0xB7, 0x49, 0xE3, 0x83, 0x88, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x8E, + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x49, 0xE3, + // Bytes 2b00 - 2b3f + 0x83, 0x8F, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x84, + 0x49, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x92, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xB3, 0x49, 0xE3, 0x83, 0x95, + 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3, + 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xBD, + 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x83, 0xAB, 0xE3, + 0x83, 0x84, 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, + // Bytes 2b40 - 2b7f + 0xBC, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9B, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xB3, 0x49, 0xE3, + 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAB, + 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x83, 0xE3, + 0x83, 0x8F, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x83, + 0xAB, 0xE3, 0x82, 0xAF, 0x49, 0xE3, 0x83, 0xA4, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x49, 0xE3, + 0x83, 0xA6, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xB3, + // Bytes 2b80 - 2bbf + 0x49, 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, + 0x83, 0x88, 0x4C, 0xE1, 0x84, 0x8C, 0xE1, 0x85, + 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4, 0x4C, + 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, + 0xB2, 0xE2, 0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, + 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, + 0xAB, 0x4C, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, + 0xE3, 0x83, 0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, + // Bytes 2bc0 - 2bff + 0x82, 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, + 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, + 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xB3, 0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, + 0xAB, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, + 0x83, 0x88, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, + 0xAD, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, + // Bytes 2c00 - 2c3f + 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0x8B, 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, + 0xBC, 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, + 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, + 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, + 0xE3, 0x83, 0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, + 0x82, 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, + // Bytes 2c40 - 2c7f + 0x4C, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, + 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0x84, 0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, + 0xE3, 0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, + // Bytes 2c80 - 2cbf + 0xBF, 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, + 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, + 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, + 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, + 0x4C, 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, + 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, + 0x9F, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, + // Bytes 2cc0 - 2cff + 0x83, 0xB3, 0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, + 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, + 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, + 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, + 0xBC, 0x4C, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, + 0xE4, 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, + 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, + // Bytes 2d00 - 2d3f + 0x92, 0xE1, 0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, + 0xD9, 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, + 0xA7, 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE1, 0x84, + 0x8E, 0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, + 0x84, 0x80, 0xE1, 0x85, 0xA9, 0x4F, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, + 0x83, 0xBC, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, + // Bytes 2d40 - 2d7f + 0x82, 0x9A, 0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, + 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, + 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, + 0xB5, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, + 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, + 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, + 0x98, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, + // Bytes 2d80 - 2dbf + 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, + 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, + 0x83, 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, + 0x9E, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, + 0x83, 0xA7, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, + 0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, + 0xAB, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, + // Bytes 2dc0 - 2dff + 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, + 0xE1, 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, + 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xAB, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xBC, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, + 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, + // Bytes 2e00 - 2e3f + 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, + 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, + 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, + 0x83, 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, + 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, + 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, + // Bytes 2e40 - 2e7f + 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, + 0x88, 0x52, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, + 0xE3, 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, + 0x88, 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, + 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, + 0xB7, 0xE3, 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, + 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, + 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, + // Bytes 2e80 - 2ebf + 0x83, 0xAB, 0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, + 0xD9, 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, + 0x84, 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, + 0xD9, 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, + 0x88, 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x86, + 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x86, 0xE0, + // Bytes 2ec0 - 2eff + 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x09, 0xE0, 0xB7, + 0x99, 0xE0, 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x11, + 0x44, 0x44, 0x5A, 0xCC, 0x8C, 0xC9, 0x44, 0x44, + 0x7A, 0xCC, 0x8C, 0xC9, 0x44, 0x64, 0x7A, 0xCC, + 0x8C, 0xC9, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, + 0x93, 0xC9, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, + 0x94, 0xC9, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, + 0x95, 0xB5, 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, + // Bytes 2f00 - 2f3f + 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C, 0xE3, 0x82, + 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xAB, 0xE3, + 0x82, 0x99, 0x0D, 0x4C, 0xE3, 0x82, 0xB3, 0xE3, + 0x83, 0xBC, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, + 0x0D, 0x4C, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, 0x4F, + 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x8B, 0xE3, 0x83, + 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, + // Bytes 2f40 - 2f7f + 0x4F, 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, + 0x83, 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, + 0x0D, 0x4F, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, + 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB7, 0xE3, 0x82, + 0x99, 0x0D, 0x4F, 0xE3, 0x83, 0x9B, 0xE3, 0x82, + 0x9A, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x82, 0xA8, 0xE3, + 0x82, 0xB9, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xBC, + // Bytes 2f80 - 2fbf + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D, 0x52, + 0xE3, 0x83, 0x95, 0xE3, 0x82, 0xA1, 0xE3, 0x83, + 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x03, 0x3C, 0xCC, 0xB8, 0x05, + 0x03, 0x3D, 0xCC, 0xB8, 0x05, 0x03, 0x3E, 0xCC, + 0xB8, 0x05, 0x03, 0x41, 0xCC, 0x80, 0xC9, 0x03, + 0x41, 0xCC, 0x81, 0xC9, 0x03, 0x41, 0xCC, 0x83, + 0xC9, 0x03, 0x41, 0xCC, 0x84, 0xC9, 0x03, 0x41, + // Bytes 2fc0 - 2fff + 0xCC, 0x89, 0xC9, 0x03, 0x41, 0xCC, 0x8C, 0xC9, + 0x03, 0x41, 0xCC, 0x8F, 0xC9, 0x03, 0x41, 0xCC, + 0x91, 0xC9, 0x03, 0x41, 0xCC, 0xA5, 0xB5, 0x03, + 0x41, 0xCC, 0xA8, 0xA5, 0x03, 0x42, 0xCC, 0x87, + 0xC9, 0x03, 0x42, 0xCC, 0xA3, 0xB5, 0x03, 0x42, + 0xCC, 0xB1, 0xB5, 0x03, 0x43, 0xCC, 0x81, 0xC9, + 0x03, 0x43, 0xCC, 0x82, 0xC9, 0x03, 0x43, 0xCC, + 0x87, 0xC9, 0x03, 0x43, 0xCC, 0x8C, 0xC9, 0x03, + // Bytes 3000 - 303f + 0x44, 0xCC, 0x87, 0xC9, 0x03, 0x44, 0xCC, 0x8C, + 0xC9, 0x03, 0x44, 0xCC, 0xA3, 0xB5, 0x03, 0x44, + 0xCC, 0xA7, 0xA5, 0x03, 0x44, 0xCC, 0xAD, 0xB5, + 0x03, 0x44, 0xCC, 0xB1, 0xB5, 0x03, 0x45, 0xCC, + 0x80, 0xC9, 0x03, 0x45, 0xCC, 0x81, 0xC9, 0x03, + 0x45, 0xCC, 0x83, 0xC9, 0x03, 0x45, 0xCC, 0x86, + 0xC9, 0x03, 0x45, 0xCC, 0x87, 0xC9, 0x03, 0x45, + 0xCC, 0x88, 0xC9, 0x03, 0x45, 0xCC, 0x89, 0xC9, + // Bytes 3040 - 307f + 0x03, 0x45, 0xCC, 0x8C, 0xC9, 0x03, 0x45, 0xCC, + 0x8F, 0xC9, 0x03, 0x45, 0xCC, 0x91, 0xC9, 0x03, + 0x45, 0xCC, 0xA8, 0xA5, 0x03, 0x45, 0xCC, 0xAD, + 0xB5, 0x03, 0x45, 0xCC, 0xB0, 0xB5, 0x03, 0x46, + 0xCC, 0x87, 0xC9, 0x03, 0x47, 0xCC, 0x81, 0xC9, + 0x03, 0x47, 0xCC, 0x82, 0xC9, 0x03, 0x47, 0xCC, + 0x84, 0xC9, 0x03, 0x47, 0xCC, 0x86, 0xC9, 0x03, + 0x47, 0xCC, 0x87, 0xC9, 0x03, 0x47, 0xCC, 0x8C, + // Bytes 3080 - 30bf + 0xC9, 0x03, 0x47, 0xCC, 0xA7, 0xA5, 0x03, 0x48, + 0xCC, 0x82, 0xC9, 0x03, 0x48, 0xCC, 0x87, 0xC9, + 0x03, 0x48, 0xCC, 0x88, 0xC9, 0x03, 0x48, 0xCC, + 0x8C, 0xC9, 0x03, 0x48, 0xCC, 0xA3, 0xB5, 0x03, + 0x48, 0xCC, 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0xAE, + 0xB5, 0x03, 0x49, 0xCC, 0x80, 0xC9, 0x03, 0x49, + 0xCC, 0x81, 0xC9, 0x03, 0x49, 0xCC, 0x82, 0xC9, + 0x03, 0x49, 0xCC, 0x83, 0xC9, 0x03, 0x49, 0xCC, + // Bytes 30c0 - 30ff + 0x84, 0xC9, 0x03, 0x49, 0xCC, 0x86, 0xC9, 0x03, + 0x49, 0xCC, 0x87, 0xC9, 0x03, 0x49, 0xCC, 0x89, + 0xC9, 0x03, 0x49, 0xCC, 0x8C, 0xC9, 0x03, 0x49, + 0xCC, 0x8F, 0xC9, 0x03, 0x49, 0xCC, 0x91, 0xC9, + 0x03, 0x49, 0xCC, 0xA3, 0xB5, 0x03, 0x49, 0xCC, + 0xA8, 0xA5, 0x03, 0x49, 0xCC, 0xB0, 0xB5, 0x03, + 0x4A, 0xCC, 0x82, 0xC9, 0x03, 0x4B, 0xCC, 0x81, + 0xC9, 0x03, 0x4B, 0xCC, 0x8C, 0xC9, 0x03, 0x4B, + // Bytes 3100 - 313f + 0xCC, 0xA3, 0xB5, 0x03, 0x4B, 0xCC, 0xA7, 0xA5, + 0x03, 0x4B, 0xCC, 0xB1, 0xB5, 0x03, 0x4C, 0xCC, + 0x81, 0xC9, 0x03, 0x4C, 0xCC, 0x8C, 0xC9, 0x03, + 0x4C, 0xCC, 0xA7, 0xA5, 0x03, 0x4C, 0xCC, 0xAD, + 0xB5, 0x03, 0x4C, 0xCC, 0xB1, 0xB5, 0x03, 0x4D, + 0xCC, 0x81, 0xC9, 0x03, 0x4D, 0xCC, 0x87, 0xC9, + 0x03, 0x4D, 0xCC, 0xA3, 0xB5, 0x03, 0x4E, 0xCC, + 0x80, 0xC9, 0x03, 0x4E, 0xCC, 0x81, 0xC9, 0x03, + // Bytes 3140 - 317f + 0x4E, 0xCC, 0x83, 0xC9, 0x03, 0x4E, 0xCC, 0x87, + 0xC9, 0x03, 0x4E, 0xCC, 0x8C, 0xC9, 0x03, 0x4E, + 0xCC, 0xA3, 0xB5, 0x03, 0x4E, 0xCC, 0xA7, 0xA5, + 0x03, 0x4E, 0xCC, 0xAD, 0xB5, 0x03, 0x4E, 0xCC, + 0xB1, 0xB5, 0x03, 0x4F, 0xCC, 0x80, 0xC9, 0x03, + 0x4F, 0xCC, 0x81, 0xC9, 0x03, 0x4F, 0xCC, 0x86, + 0xC9, 0x03, 0x4F, 0xCC, 0x89, 0xC9, 0x03, 0x4F, + 0xCC, 0x8B, 0xC9, 0x03, 0x4F, 0xCC, 0x8C, 0xC9, + // Bytes 3180 - 31bf + 0x03, 0x4F, 0xCC, 0x8F, 0xC9, 0x03, 0x4F, 0xCC, + 0x91, 0xC9, 0x03, 0x50, 0xCC, 0x81, 0xC9, 0x03, + 0x50, 0xCC, 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x81, + 0xC9, 0x03, 0x52, 0xCC, 0x87, 0xC9, 0x03, 0x52, + 0xCC, 0x8C, 0xC9, 0x03, 0x52, 0xCC, 0x8F, 0xC9, + 0x03, 0x52, 0xCC, 0x91, 0xC9, 0x03, 0x52, 0xCC, + 0xA7, 0xA5, 0x03, 0x52, 0xCC, 0xB1, 0xB5, 0x03, + 0x53, 0xCC, 0x82, 0xC9, 0x03, 0x53, 0xCC, 0x87, + // Bytes 31c0 - 31ff + 0xC9, 0x03, 0x53, 0xCC, 0xA6, 0xB5, 0x03, 0x53, + 0xCC, 0xA7, 0xA5, 0x03, 0x54, 0xCC, 0x87, 0xC9, + 0x03, 0x54, 0xCC, 0x8C, 0xC9, 0x03, 0x54, 0xCC, + 0xA3, 0xB5, 0x03, 0x54, 0xCC, 0xA6, 0xB5, 0x03, + 0x54, 0xCC, 0xA7, 0xA5, 0x03, 0x54, 0xCC, 0xAD, + 0xB5, 0x03, 0x54, 0xCC, 0xB1, 0xB5, 0x03, 0x55, + 0xCC, 0x80, 0xC9, 0x03, 0x55, 0xCC, 0x81, 0xC9, + 0x03, 0x55, 0xCC, 0x82, 0xC9, 0x03, 0x55, 0xCC, + // Bytes 3200 - 323f + 0x86, 0xC9, 0x03, 0x55, 0xCC, 0x89, 0xC9, 0x03, + 0x55, 0xCC, 0x8A, 0xC9, 0x03, 0x55, 0xCC, 0x8B, + 0xC9, 0x03, 0x55, 0xCC, 0x8C, 0xC9, 0x03, 0x55, + 0xCC, 0x8F, 0xC9, 0x03, 0x55, 0xCC, 0x91, 0xC9, + 0x03, 0x55, 0xCC, 0xA3, 0xB5, 0x03, 0x55, 0xCC, + 0xA4, 0xB5, 0x03, 0x55, 0xCC, 0xA8, 0xA5, 0x03, + 0x55, 0xCC, 0xAD, 0xB5, 0x03, 0x55, 0xCC, 0xB0, + 0xB5, 0x03, 0x56, 0xCC, 0x83, 0xC9, 0x03, 0x56, + // Bytes 3240 - 327f + 0xCC, 0xA3, 0xB5, 0x03, 0x57, 0xCC, 0x80, 0xC9, + 0x03, 0x57, 0xCC, 0x81, 0xC9, 0x03, 0x57, 0xCC, + 0x82, 0xC9, 0x03, 0x57, 0xCC, 0x87, 0xC9, 0x03, + 0x57, 0xCC, 0x88, 0xC9, 0x03, 0x57, 0xCC, 0xA3, + 0xB5, 0x03, 0x58, 0xCC, 0x87, 0xC9, 0x03, 0x58, + 0xCC, 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x80, 0xC9, + 0x03, 0x59, 0xCC, 0x81, 0xC9, 0x03, 0x59, 0xCC, + 0x82, 0xC9, 0x03, 0x59, 0xCC, 0x83, 0xC9, 0x03, + // Bytes 3280 - 32bf + 0x59, 0xCC, 0x84, 0xC9, 0x03, 0x59, 0xCC, 0x87, + 0xC9, 0x03, 0x59, 0xCC, 0x88, 0xC9, 0x03, 0x59, + 0xCC, 0x89, 0xC9, 0x03, 0x59, 0xCC, 0xA3, 0xB5, + 0x03, 0x5A, 0xCC, 0x81, 0xC9, 0x03, 0x5A, 0xCC, + 0x82, 0xC9, 0x03, 0x5A, 0xCC, 0x87, 0xC9, 0x03, + 0x5A, 0xCC, 0x8C, 0xC9, 0x03, 0x5A, 0xCC, 0xA3, + 0xB5, 0x03, 0x5A, 0xCC, 0xB1, 0xB5, 0x03, 0x61, + 0xCC, 0x80, 0xC9, 0x03, 0x61, 0xCC, 0x81, 0xC9, + // Bytes 32c0 - 32ff + 0x03, 0x61, 0xCC, 0x83, 0xC9, 0x03, 0x61, 0xCC, + 0x84, 0xC9, 0x03, 0x61, 0xCC, 0x89, 0xC9, 0x03, + 0x61, 0xCC, 0x8C, 0xC9, 0x03, 0x61, 0xCC, 0x8F, + 0xC9, 0x03, 0x61, 0xCC, 0x91, 0xC9, 0x03, 0x61, + 0xCC, 0xA5, 0xB5, 0x03, 0x61, 0xCC, 0xA8, 0xA5, + 0x03, 0x62, 0xCC, 0x87, 0xC9, 0x03, 0x62, 0xCC, + 0xA3, 0xB5, 0x03, 0x62, 0xCC, 0xB1, 0xB5, 0x03, + 0x63, 0xCC, 0x81, 0xC9, 0x03, 0x63, 0xCC, 0x82, + // Bytes 3300 - 333f + 0xC9, 0x03, 0x63, 0xCC, 0x87, 0xC9, 0x03, 0x63, + 0xCC, 0x8C, 0xC9, 0x03, 0x64, 0xCC, 0x87, 0xC9, + 0x03, 0x64, 0xCC, 0x8C, 0xC9, 0x03, 0x64, 0xCC, + 0xA3, 0xB5, 0x03, 0x64, 0xCC, 0xA7, 0xA5, 0x03, + 0x64, 0xCC, 0xAD, 0xB5, 0x03, 0x64, 0xCC, 0xB1, + 0xB5, 0x03, 0x65, 0xCC, 0x80, 0xC9, 0x03, 0x65, + 0xCC, 0x81, 0xC9, 0x03, 0x65, 0xCC, 0x83, 0xC9, + 0x03, 0x65, 0xCC, 0x86, 0xC9, 0x03, 0x65, 0xCC, + // Bytes 3340 - 337f + 0x87, 0xC9, 0x03, 0x65, 0xCC, 0x88, 0xC9, 0x03, + 0x65, 0xCC, 0x89, 0xC9, 0x03, 0x65, 0xCC, 0x8C, + 0xC9, 0x03, 0x65, 0xCC, 0x8F, 0xC9, 0x03, 0x65, + 0xCC, 0x91, 0xC9, 0x03, 0x65, 0xCC, 0xA8, 0xA5, + 0x03, 0x65, 0xCC, 0xAD, 0xB5, 0x03, 0x65, 0xCC, + 0xB0, 0xB5, 0x03, 0x66, 0xCC, 0x87, 0xC9, 0x03, + 0x67, 0xCC, 0x81, 0xC9, 0x03, 0x67, 0xCC, 0x82, + 0xC9, 0x03, 0x67, 0xCC, 0x84, 0xC9, 0x03, 0x67, + // Bytes 3380 - 33bf + 0xCC, 0x86, 0xC9, 0x03, 0x67, 0xCC, 0x87, 0xC9, + 0x03, 0x67, 0xCC, 0x8C, 0xC9, 0x03, 0x67, 0xCC, + 0xA7, 0xA5, 0x03, 0x68, 0xCC, 0x82, 0xC9, 0x03, + 0x68, 0xCC, 0x87, 0xC9, 0x03, 0x68, 0xCC, 0x88, + 0xC9, 0x03, 0x68, 0xCC, 0x8C, 0xC9, 0x03, 0x68, + 0xCC, 0xA3, 0xB5, 0x03, 0x68, 0xCC, 0xA7, 0xA5, + 0x03, 0x68, 0xCC, 0xAE, 0xB5, 0x03, 0x68, 0xCC, + 0xB1, 0xB5, 0x03, 0x69, 0xCC, 0x80, 0xC9, 0x03, + // Bytes 33c0 - 33ff + 0x69, 0xCC, 0x81, 0xC9, 0x03, 0x69, 0xCC, 0x82, + 0xC9, 0x03, 0x69, 0xCC, 0x83, 0xC9, 0x03, 0x69, + 0xCC, 0x84, 0xC9, 0x03, 0x69, 0xCC, 0x86, 0xC9, + 0x03, 0x69, 0xCC, 0x89, 0xC9, 0x03, 0x69, 0xCC, + 0x8C, 0xC9, 0x03, 0x69, 0xCC, 0x8F, 0xC9, 0x03, + 0x69, 0xCC, 0x91, 0xC9, 0x03, 0x69, 0xCC, 0xA3, + 0xB5, 0x03, 0x69, 0xCC, 0xA8, 0xA5, 0x03, 0x69, + 0xCC, 0xB0, 0xB5, 0x03, 0x6A, 0xCC, 0x82, 0xC9, + // Bytes 3400 - 343f + 0x03, 0x6A, 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, + 0x81, 0xC9, 0x03, 0x6B, 0xCC, 0x8C, 0xC9, 0x03, + 0x6B, 0xCC, 0xA3, 0xB5, 0x03, 0x6B, 0xCC, 0xA7, + 0xA5, 0x03, 0x6B, 0xCC, 0xB1, 0xB5, 0x03, 0x6C, + 0xCC, 0x81, 0xC9, 0x03, 0x6C, 0xCC, 0x8C, 0xC9, + 0x03, 0x6C, 0xCC, 0xA7, 0xA5, 0x03, 0x6C, 0xCC, + 0xAD, 0xB5, 0x03, 0x6C, 0xCC, 0xB1, 0xB5, 0x03, + 0x6D, 0xCC, 0x81, 0xC9, 0x03, 0x6D, 0xCC, 0x87, + // Bytes 3440 - 347f + 0xC9, 0x03, 0x6D, 0xCC, 0xA3, 0xB5, 0x03, 0x6E, + 0xCC, 0x80, 0xC9, 0x03, 0x6E, 0xCC, 0x81, 0xC9, + 0x03, 0x6E, 0xCC, 0x83, 0xC9, 0x03, 0x6E, 0xCC, + 0x87, 0xC9, 0x03, 0x6E, 0xCC, 0x8C, 0xC9, 0x03, + 0x6E, 0xCC, 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0xA7, + 0xA5, 0x03, 0x6E, 0xCC, 0xAD, 0xB5, 0x03, 0x6E, + 0xCC, 0xB1, 0xB5, 0x03, 0x6F, 0xCC, 0x80, 0xC9, + 0x03, 0x6F, 0xCC, 0x81, 0xC9, 0x03, 0x6F, 0xCC, + // Bytes 3480 - 34bf + 0x86, 0xC9, 0x03, 0x6F, 0xCC, 0x89, 0xC9, 0x03, + 0x6F, 0xCC, 0x8B, 0xC9, 0x03, 0x6F, 0xCC, 0x8C, + 0xC9, 0x03, 0x6F, 0xCC, 0x8F, 0xC9, 0x03, 0x6F, + 0xCC, 0x91, 0xC9, 0x03, 0x70, 0xCC, 0x81, 0xC9, + 0x03, 0x70, 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, + 0x81, 0xC9, 0x03, 0x72, 0xCC, 0x87, 0xC9, 0x03, + 0x72, 0xCC, 0x8C, 0xC9, 0x03, 0x72, 0xCC, 0x8F, + 0xC9, 0x03, 0x72, 0xCC, 0x91, 0xC9, 0x03, 0x72, + // Bytes 34c0 - 34ff + 0xCC, 0xA7, 0xA5, 0x03, 0x72, 0xCC, 0xB1, 0xB5, + 0x03, 0x73, 0xCC, 0x82, 0xC9, 0x03, 0x73, 0xCC, + 0x87, 0xC9, 0x03, 0x73, 0xCC, 0xA6, 0xB5, 0x03, + 0x73, 0xCC, 0xA7, 0xA5, 0x03, 0x74, 0xCC, 0x87, + 0xC9, 0x03, 0x74, 0xCC, 0x88, 0xC9, 0x03, 0x74, + 0xCC, 0x8C, 0xC9, 0x03, 0x74, 0xCC, 0xA3, 0xB5, + 0x03, 0x74, 0xCC, 0xA6, 0xB5, 0x03, 0x74, 0xCC, + 0xA7, 0xA5, 0x03, 0x74, 0xCC, 0xAD, 0xB5, 0x03, + // Bytes 3500 - 353f + 0x74, 0xCC, 0xB1, 0xB5, 0x03, 0x75, 0xCC, 0x80, + 0xC9, 0x03, 0x75, 0xCC, 0x81, 0xC9, 0x03, 0x75, + 0xCC, 0x82, 0xC9, 0x03, 0x75, 0xCC, 0x86, 0xC9, + 0x03, 0x75, 0xCC, 0x89, 0xC9, 0x03, 0x75, 0xCC, + 0x8A, 0xC9, 0x03, 0x75, 0xCC, 0x8B, 0xC9, 0x03, + 0x75, 0xCC, 0x8C, 0xC9, 0x03, 0x75, 0xCC, 0x8F, + 0xC9, 0x03, 0x75, 0xCC, 0x91, 0xC9, 0x03, 0x75, + 0xCC, 0xA3, 0xB5, 0x03, 0x75, 0xCC, 0xA4, 0xB5, + // Bytes 3540 - 357f + 0x03, 0x75, 0xCC, 0xA8, 0xA5, 0x03, 0x75, 0xCC, + 0xAD, 0xB5, 0x03, 0x75, 0xCC, 0xB0, 0xB5, 0x03, + 0x76, 0xCC, 0x83, 0xC9, 0x03, 0x76, 0xCC, 0xA3, + 0xB5, 0x03, 0x77, 0xCC, 0x80, 0xC9, 0x03, 0x77, + 0xCC, 0x81, 0xC9, 0x03, 0x77, 0xCC, 0x82, 0xC9, + 0x03, 0x77, 0xCC, 0x87, 0xC9, 0x03, 0x77, 0xCC, + 0x88, 0xC9, 0x03, 0x77, 0xCC, 0x8A, 0xC9, 0x03, + 0x77, 0xCC, 0xA3, 0xB5, 0x03, 0x78, 0xCC, 0x87, + // Bytes 3580 - 35bf + 0xC9, 0x03, 0x78, 0xCC, 0x88, 0xC9, 0x03, 0x79, + 0xCC, 0x80, 0xC9, 0x03, 0x79, 0xCC, 0x81, 0xC9, + 0x03, 0x79, 0xCC, 0x82, 0xC9, 0x03, 0x79, 0xCC, + 0x83, 0xC9, 0x03, 0x79, 0xCC, 0x84, 0xC9, 0x03, + 0x79, 0xCC, 0x87, 0xC9, 0x03, 0x79, 0xCC, 0x88, + 0xC9, 0x03, 0x79, 0xCC, 0x89, 0xC9, 0x03, 0x79, + 0xCC, 0x8A, 0xC9, 0x03, 0x79, 0xCC, 0xA3, 0xB5, + 0x03, 0x7A, 0xCC, 0x81, 0xC9, 0x03, 0x7A, 0xCC, + // Bytes 35c0 - 35ff + 0x82, 0xC9, 0x03, 0x7A, 0xCC, 0x87, 0xC9, 0x03, + 0x7A, 0xCC, 0x8C, 0xC9, 0x03, 0x7A, 0xCC, 0xA3, + 0xB5, 0x03, 0x7A, 0xCC, 0xB1, 0xB5, 0x04, 0xC2, + 0xA8, 0xCC, 0x80, 0xCA, 0x04, 0xC2, 0xA8, 0xCC, + 0x81, 0xCA, 0x04, 0xC2, 0xA8, 0xCD, 0x82, 0xCA, + 0x04, 0xC3, 0x86, 0xCC, 0x81, 0xC9, 0x04, 0xC3, + 0x86, 0xCC, 0x84, 0xC9, 0x04, 0xC3, 0x98, 0xCC, + 0x81, 0xC9, 0x04, 0xC3, 0xA6, 0xCC, 0x81, 0xC9, + // Bytes 3600 - 363f + 0x04, 0xC3, 0xA6, 0xCC, 0x84, 0xC9, 0x04, 0xC3, + 0xB8, 0xCC, 0x81, 0xC9, 0x04, 0xC5, 0xBF, 0xCC, + 0x87, 0xC9, 0x04, 0xC6, 0xB7, 0xCC, 0x8C, 0xC9, + 0x04, 0xCA, 0x92, 0xCC, 0x8C, 0xC9, 0x04, 0xCE, + 0x91, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x91, 0xCC, + 0x81, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x84, 0xC9, + 0x04, 0xCE, 0x91, 0xCC, 0x86, 0xC9, 0x04, 0xCE, + 0x91, 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0x95, 0xCC, + // Bytes 3640 - 367f + 0x80, 0xC9, 0x04, 0xCE, 0x95, 0xCC, 0x81, 0xC9, + 0x04, 0xCE, 0x97, 0xCC, 0x80, 0xC9, 0x04, 0xCE, + 0x97, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97, 0xCD, + 0x85, 0xD9, 0x04, 0xCE, 0x99, 0xCC, 0x80, 0xC9, + 0x04, 0xCE, 0x99, 0xCC, 0x81, 0xC9, 0x04, 0xCE, + 0x99, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x99, 0xCC, + 0x86, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x88, 0xC9, + 0x04, 0xCE, 0x9F, 0xCC, 0x80, 0xC9, 0x04, 0xCE, + // Bytes 3680 - 36bf + 0x9F, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA1, 0xCC, + 0x94, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x80, 0xC9, + 0x04, 0xCE, 0xA5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, + 0xA5, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, + 0x86, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, + 0x04, 0xCE, 0xA9, 0xCC, 0x80, 0xC9, 0x04, 0xCE, + 0xA9, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA9, 0xCD, + 0x85, 0xD9, 0x04, 0xCE, 0xB1, 0xCC, 0x84, 0xC9, + // Bytes 36c0 - 36ff + 0x04, 0xCE, 0xB1, 0xCC, 0x86, 0xC9, 0x04, 0xCE, + 0xB1, 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0xB5, 0xCC, + 0x80, 0xC9, 0x04, 0xCE, 0xB5, 0xCC, 0x81, 0xC9, + 0x04, 0xCE, 0xB7, 0xCD, 0x85, 0xD9, 0x04, 0xCE, + 0xB9, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xB9, 0xCC, + 0x81, 0xC9, 0x04, 0xCE, 0xB9, 0xCC, 0x84, 0xC9, + 0x04, 0xCE, 0xB9, 0xCC, 0x86, 0xC9, 0x04, 0xCE, + 0xB9, 0xCD, 0x82, 0xC9, 0x04, 0xCE, 0xBF, 0xCC, + // Bytes 3700 - 373f + 0x80, 0xC9, 0x04, 0xCE, 0xBF, 0xCC, 0x81, 0xC9, + 0x04, 0xCF, 0x81, 0xCC, 0x93, 0xC9, 0x04, 0xCF, + 0x81, 0xCC, 0x94, 0xC9, 0x04, 0xCF, 0x85, 0xCC, + 0x80, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x81, 0xC9, + 0x04, 0xCF, 0x85, 0xCC, 0x84, 0xC9, 0x04, 0xCF, + 0x85, 0xCC, 0x86, 0xC9, 0x04, 0xCF, 0x85, 0xCD, + 0x82, 0xC9, 0x04, 0xCF, 0x89, 0xCD, 0x85, 0xD9, + 0x04, 0xCF, 0x92, 0xCC, 0x81, 0xC9, 0x04, 0xCF, + // Bytes 3740 - 377f + 0x92, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x86, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0x90, 0xCC, 0x86, 0xC9, + 0x04, 0xD0, 0x90, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0x93, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0x95, 0xCC, + 0x80, 0xC9, 0x04, 0xD0, 0x95, 0xCC, 0x86, 0xC9, + 0x04, 0xD0, 0x95, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0x96, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x96, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0x97, 0xCC, 0x88, 0xC9, + // Bytes 3780 - 37bf + 0x04, 0xD0, 0x98, 0xCC, 0x80, 0xC9, 0x04, 0xD0, + 0x98, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0x98, 0xCC, + 0x86, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x88, 0xC9, + 0x04, 0xD0, 0x9A, 0xCC, 0x81, 0xC9, 0x04, 0xD0, + 0x9E, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, + 0x84, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x86, 0xC9, + 0x04, 0xD0, 0xA3, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0xA3, 0xCC, 0x8B, 0xC9, 0x04, 0xD0, 0xA7, 0xCC, + // Bytes 37c0 - 37ff + 0x88, 0xC9, 0x04, 0xD0, 0xAB, 0xCC, 0x88, 0xC9, + 0x04, 0xD0, 0xAD, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + 0xB0, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0xB3, 0xCC, 0x81, 0xC9, + 0x04, 0xD0, 0xB5, 0xCC, 0x80, 0xC9, 0x04, 0xD0, + 0xB5, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, + 0x88, 0xC9, 0x04, 0xD0, 0xB6, 0xCC, 0x86, 0xC9, + 0x04, 0xD0, 0xB6, 0xCC, 0x88, 0xC9, 0x04, 0xD0, + // Bytes 3800 - 383f + 0xB7, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, + 0x80, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x84, 0xC9, + 0x04, 0xD0, 0xB8, 0xCC, 0x86, 0xC9, 0x04, 0xD0, + 0xB8, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xBA, 0xCC, + 0x81, 0xC9, 0x04, 0xD0, 0xBE, 0xCC, 0x88, 0xC9, + 0x04, 0xD1, 0x83, 0xCC, 0x84, 0xC9, 0x04, 0xD1, + 0x83, 0xCC, 0x86, 0xC9, 0x04, 0xD1, 0x83, 0xCC, + 0x88, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x8B, 0xC9, + // Bytes 3840 - 387f + 0x04, 0xD1, 0x87, 0xCC, 0x88, 0xC9, 0x04, 0xD1, + 0x8B, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x8D, 0xCC, + 0x88, 0xC9, 0x04, 0xD1, 0x96, 0xCC, 0x88, 0xC9, + 0x04, 0xD1, 0xB4, 0xCC, 0x8F, 0xC9, 0x04, 0xD1, + 0xB5, 0xCC, 0x8F, 0xC9, 0x04, 0xD3, 0x98, 0xCC, + 0x88, 0xC9, 0x04, 0xD3, 0x99, 0xCC, 0x88, 0xC9, + 0x04, 0xD3, 0xA8, 0xCC, 0x88, 0xC9, 0x04, 0xD3, + 0xA9, 0xCC, 0x88, 0xC9, 0x04, 0xD8, 0xA7, 0xD9, + // Bytes 3880 - 38bf + 0x93, 0xC9, 0x04, 0xD8, 0xA7, 0xD9, 0x94, 0xC9, + 0x04, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, 0x04, 0xD9, + 0x88, 0xD9, 0x94, 0xC9, 0x04, 0xD9, 0x8A, 0xD9, + 0x94, 0xC9, 0x04, 0xDB, 0x81, 0xD9, 0x94, 0xC9, + 0x04, 0xDB, 0x92, 0xD9, 0x94, 0xC9, 0x04, 0xDB, + 0x95, 0xD9, 0x94, 0xC9, 0x05, 0x41, 0xCC, 0x82, + 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x82, 0xCC, + 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x83, + // Bytes 38c0 - 38ff + 0xCA, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x89, 0xCA, + 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x80, 0xCA, 0x05, + 0x41, 0xCC, 0x86, 0xCC, 0x81, 0xCA, 0x05, 0x41, + 0xCC, 0x86, 0xCC, 0x83, 0xCA, 0x05, 0x41, 0xCC, + 0x86, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC, 0x87, + 0xCC, 0x84, 0xCA, 0x05, 0x41, 0xCC, 0x88, 0xCC, + 0x84, 0xCA, 0x05, 0x41, 0xCC, 0x8A, 0xCC, 0x81, + 0xCA, 0x05, 0x41, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, + // Bytes 3900 - 393f + 0x05, 0x41, 0xCC, 0xA3, 0xCC, 0x86, 0xCA, 0x05, + 0x43, 0xCC, 0xA7, 0xCC, 0x81, 0xCA, 0x05, 0x45, + 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05, 0x45, 0xCC, + 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, + 0xCC, 0x83, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, + 0x89, 0xCA, 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x80, + 0xCA, 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x81, 0xCA, + 0x05, 0x45, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, + // Bytes 3940 - 397f + 0x45, 0xCC, 0xA7, 0xCC, 0x86, 0xCA, 0x05, 0x49, + 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x4C, 0xCC, + 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x82, + 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, + 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x83, + 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0xCA, + 0x05, 0x4F, 0xCC, 0x83, 0xCC, 0x81, 0xCA, 0x05, + 0x4F, 0xCC, 0x83, 0xCC, 0x84, 0xCA, 0x05, 0x4F, + // Bytes 3980 - 39bf + 0xCC, 0x83, 0xCC, 0x88, 0xCA, 0x05, 0x4F, 0xCC, + 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC, 0x84, + 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x87, 0xCC, + 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x88, 0xCC, 0x84, + 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0xCA, + 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0x81, 0xCA, 0x05, + 0x4F, 0xCC, 0x9B, 0xCC, 0x83, 0xCA, 0x05, 0x4F, + 0xCC, 0x9B, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC, + // Bytes 39c0 - 39ff + 0x9B, 0xCC, 0xA3, 0xB6, 0x05, 0x4F, 0xCC, 0xA3, + 0xCC, 0x82, 0xCA, 0x05, 0x4F, 0xCC, 0xA8, 0xCC, + 0x84, 0xCA, 0x05, 0x52, 0xCC, 0xA3, 0xCC, 0x84, + 0xCA, 0x05, 0x53, 0xCC, 0x81, 0xCC, 0x87, 0xCA, + 0x05, 0x53, 0xCC, 0x8C, 0xCC, 0x87, 0xCA, 0x05, + 0x53, 0xCC, 0xA3, 0xCC, 0x87, 0xCA, 0x05, 0x55, + 0xCC, 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x55, 0xCC, + 0x84, 0xCC, 0x88, 0xCA, 0x05, 0x55, 0xCC, 0x88, + // Bytes 3a00 - 3a3f + 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, + 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x84, + 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x8C, 0xCA, + 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, + 0x55, 0xCC, 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x55, + 0xCC, 0x9B, 0xCC, 0x83, 0xCA, 0x05, 0x55, 0xCC, + 0x9B, 0xCC, 0x89, 0xCA, 0x05, 0x55, 0xCC, 0x9B, + 0xCC, 0xA3, 0xB6, 0x05, 0x61, 0xCC, 0x82, 0xCC, + // Bytes 3a40 - 3a7f + 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x81, + 0xCA, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x83, 0xCA, + 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, + 0x61, 0xCC, 0x86, 0xCC, 0x80, 0xCA, 0x05, 0x61, + 0xCC, 0x86, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC, + 0x86, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC, 0x86, + 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x87, 0xCC, + 0x84, 0xCA, 0x05, 0x61, 0xCC, 0x88, 0xCC, 0x84, + // Bytes 3a80 - 3abf + 0xCA, 0x05, 0x61, 0xCC, 0x8A, 0xCC, 0x81, 0xCA, + 0x05, 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, + 0x61, 0xCC, 0xA3, 0xCC, 0x86, 0xCA, 0x05, 0x63, + 0xCC, 0xA7, 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, + 0x82, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC, 0x82, + 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, + 0x83, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x89, + 0xCA, 0x05, 0x65, 0xCC, 0x84, 0xCC, 0x80, 0xCA, + // Bytes 3ac0 - 3aff + 0x05, 0x65, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, + 0x65, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x65, + 0xCC, 0xA7, 0xCC, 0x86, 0xCA, 0x05, 0x69, 0xCC, + 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x6C, 0xCC, 0xA3, + 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x82, 0xCC, + 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x81, + 0xCA, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0xCA, + 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, + // Bytes 3b00 - 3b3f + 0x6F, 0xCC, 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x6F, + 0xCC, 0x83, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC, + 0x83, 0xCC, 0x88, 0xCA, 0x05, 0x6F, 0xCC, 0x84, + 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x84, 0xCC, + 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x87, 0xCC, 0x84, + 0xCA, 0x05, 0x6F, 0xCC, 0x88, 0xCC, 0x84, 0xCA, + 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, + 0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x6F, + // Bytes 3b40 - 3b7f + 0xCC, 0x9B, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC, + 0x9B, 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, + 0xCC, 0xA3, 0xB6, 0x05, 0x6F, 0xCC, 0xA3, 0xCC, + 0x82, 0xCA, 0x05, 0x6F, 0xCC, 0xA8, 0xCC, 0x84, + 0xCA, 0x05, 0x72, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, + 0x05, 0x73, 0xCC, 0x81, 0xCC, 0x87, 0xCA, 0x05, + 0x73, 0xCC, 0x8C, 0xCC, 0x87, 0xCA, 0x05, 0x73, + 0xCC, 0xA3, 0xCC, 0x87, 0xCA, 0x05, 0x75, 0xCC, + // Bytes 3b80 - 3bbf + 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x75, 0xCC, 0x84, + 0xCC, 0x88, 0xCA, 0x05, 0x75, 0xCC, 0x88, 0xCC, + 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x81, + 0xCA, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0xCA, + 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0xCA, 0x05, + 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x75, + 0xCC, 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x75, 0xCC, + 0x9B, 0xCC, 0x83, 0xCA, 0x05, 0x75, 0xCC, 0x9B, + // Bytes 3bc0 - 3bff + 0xCC, 0x89, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, + 0xA3, 0xB6, 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x80, + 0xCA, 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0xCA, + 0x05, 0xE1, 0xBE, 0xBF, 0xCD, 0x82, 0xCA, 0x05, + 0xE1, 0xBF, 0xBE, 0xCC, 0x80, 0xCA, 0x05, 0xE1, + 0xBF, 0xBE, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBF, + 0xBE, 0xCD, 0x82, 0xCA, 0x05, 0xE2, 0x86, 0x90, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x86, 0x92, 0xCC, + // Bytes 3c00 - 3c3f + 0xB8, 0x05, 0x05, 0xE2, 0x86, 0x94, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x87, 0x92, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x87, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x88, 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, + 0x88, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x8B, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0xA3, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x88, 0xA5, 0xCC, 0xB8, + // Bytes 3c40 - 3c7f + 0x05, 0x05, 0xE2, 0x88, 0xBC, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x89, 0x83, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0x85, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x89, 0x88, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0x8D, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xA1, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xA4, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x05, + // Bytes 3c80 - 3cbf + 0x05, 0xE2, 0x89, 0xB3, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x89, 0xB6, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x89, 0xB7, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, + 0xBA, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBB, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBC, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0x82, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x05, 0x05, + // Bytes 3cc0 - 3cff + 0xE2, 0x8A, 0x86, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + 0x8A, 0x87, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + 0x91, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x92, + 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xA2, 0xCC, + 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, + 0x05, 0x05, 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x05, + 0x05, 0xE2, 0x8A, 0xAB, 0xCC, 0xB8, 0x05, 0x05, + 0xE2, 0x8A, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, + // Bytes 3d00 - 3d3f + 0x8A, 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, + 0xB4, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB5, + 0xCC, 0xB8, 0x05, 0x06, 0xCE, 0x91, 0xCC, 0x93, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0x91, 0xCC, 0x94, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0x95, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0x95, 0xCC, 0x93, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0x95, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0x95, 0xCC, 0x94, + // Bytes 3d40 - 3d7f + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0x97, 0xCC, 0x93, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0x97, 0xCC, 0x94, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0x99, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0x99, 0xCC, 0x93, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0x99, 0xCC, 0x93, + 0xCD, 0x82, 0xCA, 0x06, 0xCE, 0x99, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0x99, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0x99, 0xCC, 0x94, + // Bytes 3d80 - 3dbf + 0xCD, 0x82, 0xCA, 0x06, 0xCE, 0x9F, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0x9F, 0xCC, 0x93, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0x9F, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0x9F, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xA5, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xA5, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xA5, 0xCC, 0x94, + 0xCD, 0x82, 0xCA, 0x06, 0xCE, 0xA9, 0xCC, 0x93, + // Bytes 3dc0 - 3dff + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xA9, 0xCC, 0x94, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB1, 0xCC, 0x80, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB1, 0xCC, 0x81, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB1, 0xCC, 0x93, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB1, 0xCC, 0x94, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB1, 0xCD, 0x82, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB5, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xB5, 0xCC, 0x93, + // Bytes 3e00 - 3e3f + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xB5, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xB5, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xB7, 0xCC, 0x80, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB7, 0xCC, 0x81, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB7, 0xCC, 0x93, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB7, 0xCC, 0x94, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB7, 0xCD, 0x82, + 0xCD, 0x85, 0xDA, 0x06, 0xCE, 0xB9, 0xCC, 0x88, + // Bytes 3e40 - 3e7f + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x88, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x88, + 0xCD, 0x82, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x93, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x93, + 0xCD, 0x82, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xB9, 0xCC, 0x94, + // Bytes 3e80 - 3ebf + 0xCD, 0x82, 0xCA, 0x06, 0xCE, 0xBF, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xBF, 0xCC, 0x93, + 0xCC, 0x81, 0xCA, 0x06, 0xCE, 0xBF, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCE, 0xBF, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x88, + 0xCC, 0x80, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x88, + 0xCC, 0x81, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x88, + 0xCD, 0x82, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x93, + // Bytes 3ec0 - 3eff + 0xCC, 0x80, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x93, + 0xCC, 0x81, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x93, + 0xCD, 0x82, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x94, + 0xCC, 0x80, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x94, + 0xCC, 0x81, 0xCA, 0x06, 0xCF, 0x85, 0xCC, 0x94, + 0xCD, 0x82, 0xCA, 0x06, 0xCF, 0x89, 0xCC, 0x80, + 0xCD, 0x85, 0xDA, 0x06, 0xCF, 0x89, 0xCC, 0x81, + 0xCD, 0x85, 0xDA, 0x06, 0xCF, 0x89, 0xCC, 0x93, + // Bytes 3f00 - 3f3f + 0xCD, 0x85, 0xDA, 0x06, 0xCF, 0x89, 0xCC, 0x94, + 0xCD, 0x85, 0xDA, 0x06, 0xCF, 0x89, 0xCD, 0x82, + 0xCD, 0x85, 0xDA, 0x06, 0xE0, 0xA4, 0xA8, 0xE0, + 0xA4, 0xBC, 0x09, 0x06, 0xE0, 0xA4, 0xB0, 0xE0, + 0xA4, 0xBC, 0x09, 0x06, 0xE0, 0xA4, 0xB3, 0xE0, + 0xA4, 0xBC, 0x09, 0x06, 0xE0, 0xB1, 0x86, 0xE0, + 0xB1, 0x96, 0x85, 0x06, 0xE0, 0xB7, 0x99, 0xE0, + 0xB7, 0x8A, 0x11, 0x06, 0xE3, 0x81, 0x86, 0xE3, + // Bytes 3f40 - 3f7f + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x8B, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x8D, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x8F, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x91, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x93, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x95, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x97, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x99, 0xE3, + // Bytes 3f80 - 3fbf + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x9B, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x9D, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0x9F, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xA1, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xA4, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xA6, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xA8, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xAF, 0xE3, + // Bytes 3fc0 - 3fff + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xAF, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x81, 0xB2, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xB2, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x81, 0xB5, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xB5, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x81, 0xB8, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xB8, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x81, 0xBB, 0xE3, + // Bytes 4000 - 403f + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x81, 0xBB, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x82, 0x9D, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xA6, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xAB, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xAD, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xAF, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xB1, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xB3, 0xE3, + // Bytes 4040 - 407f + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xB5, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xB7, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xB9, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xBB, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xBD, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x82, 0xBF, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x81, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x84, 0xE3, + // Bytes 4080 - 40bf + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x86, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x88, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x8F, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x8F, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x83, 0x92, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x92, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x95, 0xE3, + // Bytes 40c0 - 40ff + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x83, 0x98, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x98, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x83, 0x9B, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0x9B, 0xE3, + 0x82, 0x9A, 0x0D, 0x06, 0xE3, 0x83, 0xAF, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0xB0, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0xB1, 0xE3, + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0xB2, 0xE3, + // Bytes 4100 - 413f + 0x82, 0x99, 0x0D, 0x06, 0xE3, 0x83, 0xBD, 0xE3, + 0x82, 0x99, 0x0D, 0x08, 0xCE, 0x91, 0xCC, 0x93, + 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, + 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, + 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, + // Bytes 4140 - 417f + 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x93, + 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, + 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, + // Bytes 4180 - 41bf + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, + 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, + 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, + 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, + 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, + // Bytes 41c0 - 41ff + 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x93, + 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, + 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, + // Bytes 4200 - 423f + 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, + 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, + 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, + 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, + 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, + 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, + 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, + 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, + // Bytes 4240 - 427f + 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, + 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x93, + 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, + 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, + 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, + 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, + 0xCD, 0x85, 0xDB, 0x08, 0xF0, 0x91, 0x82, 0x99, + 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, + // Bytes 4280 - 42bf + 0x82, 0x9B, 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x08, + 0xF0, 0x91, 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, + 0x09, 0x42, 0xC2, 0xB4, 0x01, 0x43, 0x20, 0xCC, + 0x81, 0xC9, 0x43, 0x20, 0xCC, 0x83, 0xC9, 0x43, + 0x20, 0xCC, 0x84, 0xC9, 0x43, 0x20, 0xCC, 0x85, + 0xC9, 0x43, 0x20, 0xCC, 0x86, 0xC9, 0x43, 0x20, + 0xCC, 0x87, 0xC9, 0x43, 0x20, 0xCC, 0x88, 0xC9, + 0x43, 0x20, 0xCC, 0x8A, 0xC9, 0x43, 0x20, 0xCC, + // Bytes 42c0 - 42ff + 0x8B, 0xC9, 0x43, 0x20, 0xCC, 0x93, 0xC9, 0x43, + 0x20, 0xCC, 0x94, 0xC9, 0x43, 0x20, 0xCC, 0xA7, + 0xA5, 0x43, 0x20, 0xCC, 0xA8, 0xA5, 0x43, 0x20, + 0xCC, 0xB3, 0xB5, 0x43, 0x20, 0xCD, 0x82, 0xC9, + 0x43, 0x20, 0xCD, 0x85, 0xD9, 0x43, 0x20, 0xD9, + 0x8B, 0x59, 0x43, 0x20, 0xD9, 0x8C, 0x5D, 0x43, + 0x20, 0xD9, 0x8D, 0x61, 0x43, 0x20, 0xD9, 0x8E, + 0x65, 0x43, 0x20, 0xD9, 0x8F, 0x69, 0x43, 0x20, + // Bytes 4300 - 433f + 0xD9, 0x90, 0x6D, 0x43, 0x20, 0xD9, 0x91, 0x71, + 0x43, 0x20, 0xD9, 0x92, 0x75, 0x43, 0x41, 0xCC, + 0x8A, 0xC9, 0x43, 0x73, 0xCC, 0x87, 0xC9, 0x44, + 0x20, 0xE3, 0x82, 0x99, 0x0D, 0x44, 0x20, 0xE3, + 0x82, 0x9A, 0x0D, 0x44, 0xC2, 0xA8, 0xCC, 0x81, + 0xCA, 0x44, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x44, + 0xCE, 0x95, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x97, + 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x99, 0xCC, 0x81, + // Bytes 4340 - 437f + 0xC9, 0x44, 0xCE, 0x9F, 0xCC, 0x81, 0xC9, 0x44, + 0xCE, 0xA5, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xA5, + 0xCC, 0x88, 0xC9, 0x44, 0xCE, 0xA9, 0xCC, 0x81, + 0xC9, 0x44, 0xCE, 0xB1, 0xCC, 0x81, 0xC9, 0x44, + 0xCE, 0xB5, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB7, + 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB9, 0xCC, 0x81, + 0xC9, 0x44, 0xCE, 0xBF, 0xCC, 0x81, 0xC9, 0x44, + 0xCF, 0x85, 0xCC, 0x81, 0xC9, 0x44, 0xCF, 0x89, + // Bytes 4380 - 43bf + 0xCC, 0x81, 0xC9, 0x44, 0xD7, 0x90, 0xD6, 0xB7, + 0x31, 0x44, 0xD7, 0x90, 0xD6, 0xB8, 0x35, 0x44, + 0xD7, 0x90, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x91, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x91, 0xD6, 0xBF, + 0x49, 0x44, 0xD7, 0x92, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x93, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x94, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x95, 0xD6, 0xB9, + 0x39, 0x44, 0xD7, 0x95, 0xD6, 0xBC, 0x41, 0x44, + // Bytes 43c0 - 43ff + 0xD7, 0x96, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x98, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x99, 0xD6, 0xB4, + 0x25, 0x44, 0xD7, 0x99, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x9A, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9B, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0x9B, 0xD6, 0xBF, + 0x49, 0x44, 0xD7, 0x9C, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0x9E, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA0, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA1, 0xD6, 0xBC, + // Bytes 4400 - 443f + 0x41, 0x44, 0xD7, 0xA3, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0xA4, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA4, + 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0xA6, 0xD6, 0xBC, + 0x41, 0x44, 0xD7, 0xA7, 0xD6, 0xBC, 0x41, 0x44, + 0xD7, 0xA8, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA9, + 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA9, 0xD7, 0x81, + 0x4D, 0x44, 0xD7, 0xA9, 0xD7, 0x82, 0x51, 0x44, + 0xD7, 0xAA, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xB2, + // Bytes 4440 - 447f + 0xD6, 0xB7, 0x31, 0x44, 0xD8, 0xA7, 0xD9, 0x8B, + 0x59, 0x44, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x44, + 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x44, 0xD8, 0xA7, + 0xD9, 0x95, 0xB5, 0x44, 0xD8, 0xB0, 0xD9, 0xB0, + 0x79, 0x44, 0xD8, 0xB1, 0xD9, 0xB0, 0x79, 0x44, + 0xD9, 0x80, 0xD9, 0x8B, 0x59, 0x44, 0xD9, 0x80, + 0xD9, 0x8E, 0x65, 0x44, 0xD9, 0x80, 0xD9, 0x8F, + 0x69, 0x44, 0xD9, 0x80, 0xD9, 0x90, 0x6D, 0x44, + // Bytes 4480 - 44bf + 0xD9, 0x80, 0xD9, 0x91, 0x71, 0x44, 0xD9, 0x80, + 0xD9, 0x92, 0x75, 0x44, 0xD9, 0x87, 0xD9, 0xB0, + 0x79, 0x44, 0xD9, 0x88, 0xD9, 0x94, 0xC9, 0x44, + 0xD9, 0x89, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x8A, + 0xD9, 0x94, 0xC9, 0x44, 0xDB, 0x92, 0xD9, 0x94, + 0xC9, 0x44, 0xDB, 0x95, 0xD9, 0x94, 0xC9, 0x45, + 0x20, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x45, 0x20, + 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC, + // Bytes 44c0 - 44ff + 0x88, 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xCC, 0x93, + 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x93, 0xCC, + 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x93, 0xCD, 0x82, + 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCC, 0x80, 0xCA, + 0x45, 0x20, 0xCC, 0x94, 0xCC, 0x81, 0xCA, 0x45, + 0x20, 0xCC, 0x94, 0xCD, 0x82, 0xCA, 0x45, 0x20, + 0xD9, 0x8C, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, + 0x8D, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, 0x8E, + // Bytes 4500 - 453f + 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, 0x8F, 0xD9, + 0x91, 0x72, 0x45, 0x20, 0xD9, 0x90, 0xD9, 0x91, + 0x72, 0x45, 0x20, 0xD9, 0x91, 0xD9, 0xB0, 0x7A, + 0x45, 0xE2, 0xAB, 0x9D, 0xCC, 0xB8, 0x05, 0x46, + 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x46, + 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x46, + 0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0x4E, 0x46, + 0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x82, 0x52, 0x46, + // Bytes 4540 - 457f + 0xD9, 0x80, 0xD9, 0x8E, 0xD9, 0x91, 0x72, 0x46, + 0xD9, 0x80, 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x46, + 0xD9, 0x80, 0xD9, 0x90, 0xD9, 0x91, 0x72, 0x46, + 0xE0, 0xA4, 0x95, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA4, 0x96, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA4, 0x97, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA4, 0x9C, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA4, 0xA1, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + // Bytes 4580 - 45bf + 0xE0, 0xA4, 0xA2, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0x09, 0x46, + 0xE0, 0xA6, 0xA1, 0xE0, 0xA6, 0xBC, 0x09, 0x46, + 0xE0, 0xA6, 0xA2, 0xE0, 0xA6, 0xBC, 0x09, 0x46, + 0xE0, 0xA6, 0xAF, 0xE0, 0xA6, 0xBC, 0x09, 0x46, + 0xE0, 0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0x09, 0x46, + 0xE0, 0xA8, 0x97, 0xE0, 0xA8, 0xBC, 0x09, 0x46, + // Bytes 45c0 - 45ff + 0xE0, 0xA8, 0x9C, 0xE0, 0xA8, 0xBC, 0x09, 0x46, + 0xE0, 0xA8, 0xAB, 0xE0, 0xA8, 0xBC, 0x09, 0x46, + 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC, 0x09, 0x46, + 0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0x09, 0x46, + 0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC, 0x09, 0x46, + 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0x09, 0x46, + 0xE0, 0xBE, 0xB2, 0xE0, 0xBE, 0x80, 0x9D, 0x46, + 0xE0, 0xBE, 0xB3, 0xE0, 0xBE, 0x80, 0x9D, 0x46, + // Bytes 4600 - 463f + 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D, 0x48, + 0xF0, 0x9D, 0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, + 0xAD, 0x48, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, + 0x85, 0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x86, 0xB9, + 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, 0x9D, + 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x49, + 0xE0, 0xBE, 0xB2, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, + 0x80, 0x9E, 0x49, 0xE0, 0xBE, 0xB3, 0xE0, 0xBD, + // Bytes 4640 - 467f + 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x4C, 0xF0, 0x9D, + 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, + 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, + 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, + 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0xAE, 0x4C, + 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, + 0xF0, 0x9D, 0x85, 0xB1, 0xAE, 0x4C, 0xF0, 0x9D, + // Bytes 4680 - 46bf + 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + 0x85, 0xB2, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xB9, + 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, + 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, + 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x4C, + 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, + 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, + 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + // Bytes 46c0 - 46ff + 0x85, 0xAF, 0xAE, 0x83, 0x41, 0xCC, 0x82, 0xC9, + 0x83, 0x41, 0xCC, 0x86, 0xC9, 0x83, 0x41, 0xCC, + 0x87, 0xC9, 0x83, 0x41, 0xCC, 0x88, 0xC9, 0x83, + 0x41, 0xCC, 0x8A, 0xC9, 0x83, 0x41, 0xCC, 0xA3, + 0xB5, 0x83, 0x43, 0xCC, 0xA7, 0xA5, 0x83, 0x45, + 0xCC, 0x82, 0xC9, 0x83, 0x45, 0xCC, 0x84, 0xC9, + 0x83, 0x45, 0xCC, 0xA3, 0xB5, 0x83, 0x45, 0xCC, + 0xA7, 0xA5, 0x83, 0x49, 0xCC, 0x88, 0xC9, 0x83, + // Bytes 4700 - 473f + 0x4C, 0xCC, 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0x82, + 0xC9, 0x83, 0x4F, 0xCC, 0x83, 0xC9, 0x83, 0x4F, + 0xCC, 0x84, 0xC9, 0x83, 0x4F, 0xCC, 0x87, 0xC9, + 0x83, 0x4F, 0xCC, 0x88, 0xC9, 0x83, 0x4F, 0xCC, + 0x9B, 0xAD, 0x83, 0x4F, 0xCC, 0xA3, 0xB5, 0x83, + 0x4F, 0xCC, 0xA8, 0xA5, 0x83, 0x52, 0xCC, 0xA3, + 0xB5, 0x83, 0x53, 0xCC, 0x81, 0xC9, 0x83, 0x53, + 0xCC, 0x8C, 0xC9, 0x83, 0x53, 0xCC, 0xA3, 0xB5, + // Bytes 4740 - 477f + 0x83, 0x55, 0xCC, 0x83, 0xC9, 0x83, 0x55, 0xCC, + 0x84, 0xC9, 0x83, 0x55, 0xCC, 0x88, 0xC9, 0x83, + 0x55, 0xCC, 0x9B, 0xAD, 0x83, 0x61, 0xCC, 0x82, + 0xC9, 0x83, 0x61, 0xCC, 0x86, 0xC9, 0x83, 0x61, + 0xCC, 0x87, 0xC9, 0x83, 0x61, 0xCC, 0x88, 0xC9, + 0x83, 0x61, 0xCC, 0x8A, 0xC9, 0x83, 0x61, 0xCC, + 0xA3, 0xB5, 0x83, 0x63, 0xCC, 0xA7, 0xA5, 0x83, + 0x65, 0xCC, 0x82, 0xC9, 0x83, 0x65, 0xCC, 0x84, + // Bytes 4780 - 47bf + 0xC9, 0x83, 0x65, 0xCC, 0xA3, 0xB5, 0x83, 0x65, + 0xCC, 0xA7, 0xA5, 0x83, 0x69, 0xCC, 0x88, 0xC9, + 0x83, 0x6C, 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, + 0x82, 0xC9, 0x83, 0x6F, 0xCC, 0x83, 0xC9, 0x83, + 0x6F, 0xCC, 0x84, 0xC9, 0x83, 0x6F, 0xCC, 0x87, + 0xC9, 0x83, 0x6F, 0xCC, 0x88, 0xC9, 0x83, 0x6F, + 0xCC, 0x9B, 0xAD, 0x83, 0x6F, 0xCC, 0xA3, 0xB5, + 0x83, 0x6F, 0xCC, 0xA8, 0xA5, 0x83, 0x72, 0xCC, + // Bytes 47c0 - 47ff + 0xA3, 0xB5, 0x83, 0x73, 0xCC, 0x81, 0xC9, 0x83, + 0x73, 0xCC, 0x8C, 0xC9, 0x83, 0x73, 0xCC, 0xA3, + 0xB5, 0x83, 0x75, 0xCC, 0x83, 0xC9, 0x83, 0x75, + 0xCC, 0x84, 0xC9, 0x83, 0x75, 0xCC, 0x88, 0xC9, + 0x83, 0x75, 0xCC, 0x9B, 0xAD, 0x84, 0xCE, 0x91, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x91, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0x95, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0x95, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x97, + // Bytes 4800 - 483f + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x97, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0x99, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0x99, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x9F, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0x9F, 0xCC, 0x94, + 0xC9, 0x84, 0xCE, 0xA5, 0xCC, 0x94, 0xC9, 0x84, + 0xCE, 0xA9, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xA9, + 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x80, + 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x81, 0xC9, 0x84, + // Bytes 4840 - 487f + 0xCE, 0xB1, 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xB1, + 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xB1, 0xCD, 0x82, + 0xC9, 0x84, 0xCE, 0xB5, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0xB5, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xB7, + 0xCC, 0x80, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x81, + 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0xB7, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xB7, + 0xCD, 0x82, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, 0x88, + // Bytes 4880 - 48bf + 0xC9, 0x84, 0xCE, 0xB9, 0xCC, 0x93, 0xC9, 0x84, + 0xCE, 0xB9, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xBF, + 0xCC, 0x93, 0xC9, 0x84, 0xCE, 0xBF, 0xCC, 0x94, + 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x88, 0xC9, 0x84, + 0xCF, 0x85, 0xCC, 0x93, 0xC9, 0x84, 0xCF, 0x85, + 0xCC, 0x94, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x80, + 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x81, 0xC9, 0x84, + 0xCF, 0x89, 0xCC, 0x93, 0xC9, 0x84, 0xCF, 0x89, + // Bytes 48c0 - 48ff + 0xCC, 0x94, 0xC9, 0x84, 0xCF, 0x89, 0xCD, 0x82, + 0xC9, 0x86, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, + // Bytes 4900 - 493f + 0xCA, 0x86, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, + // Bytes 4940 - 497f + 0xCA, 0x86, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, + // Bytes 4980 - 49bf + 0xCA, 0x86, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, + 0xCA, 0x86, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, + 0xCA, 0x86, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, + 0xCA, 0x86, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, + 0xCA, 0x86, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80, + // Bytes 49c0 - 49ff + 0xCA, 0x86, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, + 0xCA, 0x86, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, + 0xCA, 0x86, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x80, + 0xCA, 0x86, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, + 0xCA, 0x86, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, + 0xCA, 0x42, 0xCC, 0x80, 0xC9, 0x32, 0x42, 0xCC, + 0x81, 0xC9, 0x32, 0x42, 0xCC, 0x93, 0xC9, 0x32, + 0x44, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x32, 0x43, + // Bytes 4a00 - 4a3f + 0xE3, 0x82, 0x99, 0x0D, 0x03, 0x43, 0xE3, 0x82, + 0x9A, 0x0D, 0x03, 0x46, 0xE0, 0xBD, 0xB1, 0xE0, + 0xBD, 0xB2, 0x9E, 0x26, 0x46, 0xE0, 0xBD, 0xB1, + 0xE0, 0xBD, 0xB4, 0xA2, 0x26, 0x46, 0xE0, 0xBD, + 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x26, 0x00, 0x01, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfcTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfcValues[c0], 1 + case c0 < 0xC0: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfcTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfcValues[c0] + } + i := nfcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfcTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfcValues[c0], 1 + case c0 < 0xC0: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfcTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfcValues[c0] + } + i := nfcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// nfcTrie. Total size: 10176 bytes (9.94 KiB). Checksum: d7c74933ce923a3f. +type nfcTrie struct{} + +func newNfcTrie(i int) *nfcTrie { + return &nfcTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 44: + return uint16(nfcValues[n<<6+uint32(b)]) + default: + n -= 44 + return uint16(nfcSparse.lookup(n, b)) + } +} + +// nfcValues: 46 blocks, 2944 entries, 5888 bytes +// The third block is the zero block. +var nfcValues = [2944]uint16{ + // Block 0x0, offset 0x0 + 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, + // Block 0x1, offset 0x40 + 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000, + 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000, + 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000, + 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000, + 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000, + 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000, + 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000, + 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000, + 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000, + 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x2faa, 0xc1: 0x2faf, 0xc2: 0x46c3, 0xc3: 0x2fb4, 0xc4: 0x46d2, 0xc5: 0x46d7, + 0xc6: 0xa000, 0xc7: 0x46e1, 0xc8: 0x301d, 0xc9: 0x3022, 0xca: 0x46e6, 0xcb: 0x3036, + 0xcc: 0x30a9, 0xcd: 0x30ae, 0xce: 0x30b3, 0xcf: 0x46fa, 0xd1: 0x313f, + 0xd2: 0x3162, 0xd3: 0x3167, 0xd4: 0x4704, 0xd5: 0x4709, 0xd6: 0x4718, + 0xd8: 0xa000, 0xd9: 0x31ee, 0xda: 0x31f3, 0xdb: 0x31f8, 0xdc: 0x474a, 0xdd: 0x3270, + 0xe0: 0x32b6, 0xe1: 0x32bb, 0xe2: 0x4754, 0xe3: 0x32c0, + 0xe4: 0x4763, 0xe5: 0x4768, 0xe6: 0xa000, 0xe7: 0x4772, 0xe8: 0x3329, 0xe9: 0x332e, + 0xea: 0x4777, 0xeb: 0x3342, 0xec: 0x33ba, 0xed: 0x33bf, 0xee: 0x33c4, 0xef: 0x478b, + 0xf1: 0x3450, 0xf2: 0x3473, 0xf3: 0x3478, 0xf4: 0x4795, 0xf5: 0x479a, + 0xf6: 0x47a9, 0xf8: 0xa000, 0xf9: 0x3504, 0xfa: 0x3509, 0xfb: 0x350e, + 0xfc: 0x47db, 0xfd: 0x358b, 0xff: 0x35a4, + // Block 0x4, offset 0x100 + 0x100: 0x2fb9, 0x101: 0x32c5, 0x102: 0x46c8, 0x103: 0x4759, 0x104: 0x2fd7, 0x105: 0x32e3, + 0x106: 0x2feb, 0x107: 0x32f7, 0x108: 0x2ff0, 0x109: 0x32fc, 0x10a: 0x2ff5, 0x10b: 0x3301, + 0x10c: 0x2ffa, 0x10d: 0x3306, 0x10e: 0x3004, 0x10f: 0x3310, + 0x112: 0x46eb, 0x113: 0x477c, 0x114: 0x302c, 0x115: 0x3338, 0x116: 0x3031, 0x117: 0x333d, + 0x118: 0x304f, 0x119: 0x335b, 0x11a: 0x3040, 0x11b: 0x334c, 0x11c: 0x3068, 0x11d: 0x3374, + 0x11e: 0x3072, 0x11f: 0x337e, 0x120: 0x3077, 0x121: 0x3383, 0x122: 0x3081, 0x123: 0x338d, + 0x124: 0x3086, 0x125: 0x3392, 0x128: 0x30b8, 0x129: 0x33c9, + 0x12a: 0x30bd, 0x12b: 0x33ce, 0x12c: 0x30c2, 0x12d: 0x33d3, 0x12e: 0x30e5, 0x12f: 0x33f1, + 0x130: 0x30c7, 0x134: 0x30ef, 0x135: 0x33fb, + 0x136: 0x3103, 0x137: 0x3414, 0x139: 0x310d, 0x13a: 0x341e, 0x13b: 0x3117, + 0x13c: 0x3428, 0x13d: 0x3112, 0x13e: 0x3423, + // Block 0x5, offset 0x140 + 0x143: 0x313a, 0x144: 0x344b, 0x145: 0x3153, + 0x146: 0x3464, 0x147: 0x3149, 0x148: 0x345a, + 0x14c: 0x470e, 0x14d: 0x479f, 0x14e: 0x316c, 0x14f: 0x347d, 0x150: 0x3176, 0x151: 0x3487, + 0x154: 0x3194, 0x155: 0x34a5, 0x156: 0x31ad, 0x157: 0x34be, + 0x158: 0x319e, 0x159: 0x34af, 0x15a: 0x4731, 0x15b: 0x47c2, 0x15c: 0x31b7, 0x15d: 0x34c8, + 0x15e: 0x31c6, 0x15f: 0x34d7, 0x160: 0x4736, 0x161: 0x47c7, 0x162: 0x31df, 0x163: 0x34f5, + 0x164: 0x31d0, 0x165: 0x34e6, 0x168: 0x4740, 0x169: 0x47d1, + 0x16a: 0x4745, 0x16b: 0x47d6, 0x16c: 0x31fd, 0x16d: 0x3513, 0x16e: 0x3207, 0x16f: 0x351d, + 0x170: 0x320c, 0x171: 0x3522, 0x172: 0x322a, 0x173: 0x3540, 0x174: 0x324d, 0x175: 0x3563, + 0x176: 0x3275, 0x177: 0x3590, 0x178: 0x3289, 0x179: 0x3298, 0x17a: 0x35b8, 0x17b: 0x32a2, + 0x17c: 0x35c2, 0x17d: 0x32a7, 0x17e: 0x35c7, 0x17f: 0xa000, + // Block 0x6, offset 0x180 + 0x184: 0x8100, 0x185: 0x8100, + 0x186: 0x8100, + 0x18d: 0x2fc3, 0x18e: 0x32cf, 0x18f: 0x30d1, 0x190: 0x33dd, 0x191: 0x317b, + 0x192: 0x348c, 0x193: 0x3211, 0x194: 0x3527, 0x195: 0x3a0a, 0x196: 0x3b99, 0x197: 0x3a03, + 0x198: 0x3b92, 0x199: 0x3a11, 0x19a: 0x3ba0, 0x19b: 0x39fc, 0x19c: 0x3b8b, + 0x19e: 0x38eb, 0x19f: 0x3a7a, 0x1a0: 0x38e4, 0x1a1: 0x3a73, 0x1a2: 0x35ee, 0x1a3: 0x3600, + 0x1a6: 0x307c, 0x1a7: 0x3388, 0x1a8: 0x30f9, 0x1a9: 0x340a, + 0x1aa: 0x4727, 0x1ab: 0x47b8, 0x1ac: 0x39cb, 0x1ad: 0x3b5a, 0x1ae: 0x3612, 0x1af: 0x3618, + 0x1b0: 0x3400, 0x1b4: 0x3063, 0x1b5: 0x336f, + 0x1b8: 0x3135, 0x1b9: 0x3446, 0x1ba: 0x38f2, 0x1bb: 0x3a81, + 0x1bc: 0x35e8, 0x1bd: 0x35fa, 0x1be: 0x35f4, 0x1bf: 0x3606, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x2fc8, 0x1c1: 0x32d4, 0x1c2: 0x2fcd, 0x1c3: 0x32d9, 0x1c4: 0x3045, 0x1c5: 0x3351, + 0x1c6: 0x304a, 0x1c7: 0x3356, 0x1c8: 0x30d6, 0x1c9: 0x33e2, 0x1ca: 0x30db, 0x1cb: 0x33e7, + 0x1cc: 0x3180, 0x1cd: 0x3491, 0x1ce: 0x3185, 0x1cf: 0x3496, 0x1d0: 0x31a3, 0x1d1: 0x34b4, + 0x1d2: 0x31a8, 0x1d3: 0x34b9, 0x1d4: 0x3216, 0x1d5: 0x352c, 0x1d6: 0x321b, 0x1d7: 0x3531, + 0x1d8: 0x31c1, 0x1d9: 0x34d2, 0x1da: 0x31da, 0x1db: 0x34f0, + 0x1de: 0x3095, 0x1df: 0x33a1, + 0x1e6: 0x46cd, 0x1e7: 0x475e, 0x1e8: 0x46f5, 0x1e9: 0x4786, + 0x1ea: 0x399a, 0x1eb: 0x3b29, 0x1ec: 0x3977, 0x1ed: 0x3b06, 0x1ee: 0x4713, 0x1ef: 0x47a4, + 0x1f0: 0x3993, 0x1f1: 0x3b22, 0x1f2: 0x327f, 0x1f3: 0x359a, + // Block 0x8, offset 0x200 + 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132, + 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932, + 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932, + 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d, + 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d, + 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d, + 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d, + 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d, + 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101, + 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d, + 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132, + // Block 0x9, offset 0x240 + 0x240: 0x49e9, 0x241: 0x49ee, 0x242: 0x9932, 0x243: 0x49f3, 0x244: 0x49f8, 0x245: 0x9936, + 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132, + 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132, + 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132, + 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135, + 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132, + 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132, + 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132, + 0x274: 0x0170, + 0x27a: 0x8100, + 0x27e: 0x0037, + // Block 0xa, offset 0x280 + 0x284: 0x8100, 0x285: 0x35dc, + 0x286: 0x3624, 0x287: 0x00ce, 0x288: 0x3642, 0x289: 0x364e, 0x28a: 0x3660, + 0x28c: 0x367e, 0x28e: 0x3690, 0x28f: 0x36ae, 0x290: 0x3e43, 0x291: 0xa000, + 0x295: 0xa000, 0x297: 0xa000, + 0x299: 0xa000, + 0x29f: 0xa000, 0x2a1: 0xa000, + 0x2a5: 0xa000, 0x2a9: 0xa000, + 0x2aa: 0x3672, 0x2ab: 0x36a2, 0x2ac: 0x4839, 0x2ad: 0x36d2, 0x2ae: 0x4863, 0x2af: 0x36e4, + 0x2b0: 0x3eab, 0x2b1: 0xa000, 0x2b5: 0xa000, + 0x2b7: 0xa000, 0x2b9: 0xa000, + 0x2bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x375c, 0x2c1: 0x3768, 0x2c3: 0x3756, + 0x2c6: 0xa000, 0x2c7: 0x3744, + 0x2cc: 0x3798, 0x2cd: 0x3780, 0x2ce: 0x37aa, 0x2d0: 0xa000, + 0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000, + 0x2d8: 0xa000, 0x2d9: 0x378c, 0x2da: 0xa000, + 0x2de: 0xa000, 0x2e3: 0xa000, + 0x2e7: 0xa000, + 0x2eb: 0xa000, 0x2ed: 0xa000, + 0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000, + 0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x3810, 0x2fa: 0xa000, + 0x2fe: 0xa000, + // Block 0xc, offset 0x300 + 0x301: 0x376e, 0x302: 0x37f2, + 0x310: 0x374a, 0x311: 0x37ce, + 0x312: 0x3750, 0x313: 0x37d4, 0x316: 0x3762, 0x317: 0x37e6, + 0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3864, 0x31b: 0x386a, 0x31c: 0x3774, 0x31d: 0x37f8, + 0x31e: 0x377a, 0x31f: 0x37fe, 0x322: 0x3786, 0x323: 0x380a, + 0x324: 0x3792, 0x325: 0x3816, 0x326: 0x379e, 0x327: 0x3822, 0x328: 0xa000, 0x329: 0xa000, + 0x32a: 0x3870, 0x32b: 0x3876, 0x32c: 0x37c8, 0x32d: 0x384c, 0x32e: 0x37a4, 0x32f: 0x3828, + 0x330: 0x37b0, 0x331: 0x3834, 0x332: 0x37b6, 0x333: 0x383a, 0x334: 0x37bc, 0x335: 0x3840, + 0x338: 0x37c2, 0x339: 0x3846, + // Block 0xd, offset 0x340 + 0x351: 0x812d, + 0x352: 0x8132, 0x353: 0x8132, 0x354: 0x8132, 0x355: 0x8132, 0x356: 0x812d, 0x357: 0x8132, + 0x358: 0x8132, 0x359: 0x8132, 0x35a: 0x812e, 0x35b: 0x812d, 0x35c: 0x8132, 0x35d: 0x8132, + 0x35e: 0x8132, 0x35f: 0x8132, 0x360: 0x8132, 0x361: 0x8132, 0x362: 0x812d, 0x363: 0x812d, + 0x364: 0x812d, 0x365: 0x812d, 0x366: 0x812d, 0x367: 0x812d, 0x368: 0x8132, 0x369: 0x8132, + 0x36a: 0x812d, 0x36b: 0x8132, 0x36c: 0x8132, 0x36d: 0x812e, 0x36e: 0x8131, 0x36f: 0x8132, + 0x370: 0x8105, 0x371: 0x8106, 0x372: 0x8107, 0x373: 0x8108, 0x374: 0x8109, 0x375: 0x810a, + 0x376: 0x810b, 0x377: 0x810c, 0x378: 0x810d, 0x379: 0x810e, 0x37a: 0x810e, 0x37b: 0x810f, + 0x37c: 0x8110, 0x37d: 0x8111, 0x37f: 0x8112, + // Block 0xe, offset 0x380 + 0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8116, + 0x38c: 0x8117, 0x38d: 0x8118, 0x38e: 0x8119, 0x38f: 0x811a, 0x390: 0x811b, 0x391: 0x811c, + 0x392: 0x811d, 0x393: 0x9932, 0x394: 0x9932, 0x395: 0x992d, 0x396: 0x812d, 0x397: 0x8132, + 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x8132, 0x39b: 0x8132, 0x39c: 0x812d, 0x39d: 0x8132, + 0x39e: 0x8132, 0x39f: 0x812d, + 0x3b0: 0x811e, + // Block 0xf, offset 0x3c0 + 0x3c5: 0xa000, + 0x3c6: 0x1958, 0x3c7: 0xa000, 0x3c8: 0x195f, 0x3c9: 0xa000, 0x3ca: 0x1966, 0x3cb: 0xa000, + 0x3cc: 0x196d, 0x3cd: 0xa000, 0x3ce: 0x1974, 0x3d1: 0xa000, + 0x3d2: 0x197b, + 0x3f4: 0x8102, 0x3f5: 0x9900, + 0x3fa: 0xa000, 0x3fb: 0x1982, + 0x3fc: 0xa000, 0x3fd: 0x1989, 0x3fe: 0xa000, 0x3ff: 0xa000, + // Block 0x10, offset 0x400 + 0x400: 0x2fd2, 0x401: 0x32de, 0x402: 0x2fdc, 0x403: 0x32e8, 0x404: 0x2fe1, 0x405: 0x32ed, + 0x406: 0x2fe6, 0x407: 0x32f2, 0x408: 0x3907, 0x409: 0x3a96, 0x40a: 0x2fff, 0x40b: 0x330b, + 0x40c: 0x3009, 0x40d: 0x3315, 0x40e: 0x3018, 0x40f: 0x3324, 0x410: 0x300e, 0x411: 0x331a, + 0x412: 0x3013, 0x413: 0x331f, 0x414: 0x392a, 0x415: 0x3ab9, 0x416: 0x3931, 0x417: 0x3ac0, + 0x418: 0x3054, 0x419: 0x3360, 0x41a: 0x3059, 0x41b: 0x3365, 0x41c: 0x393f, 0x41d: 0x3ace, + 0x41e: 0x305e, 0x41f: 0x336a, 0x420: 0x306d, 0x421: 0x3379, 0x422: 0x308b, 0x423: 0x3397, + 0x424: 0x309a, 0x425: 0x33a6, 0x426: 0x3090, 0x427: 0x339c, 0x428: 0x309f, 0x429: 0x33ab, + 0x42a: 0x30a4, 0x42b: 0x33b0, 0x42c: 0x30ea, 0x42d: 0x33f6, 0x42e: 0x3946, 0x42f: 0x3ad5, + 0x430: 0x30f4, 0x431: 0x3405, 0x432: 0x30fe, 0x433: 0x340f, 0x434: 0x3108, 0x435: 0x3419, + 0x436: 0x46ff, 0x437: 0x4790, 0x438: 0x394d, 0x439: 0x3adc, 0x43a: 0x3121, 0x43b: 0x3432, + 0x43c: 0x311c, 0x43d: 0x342d, 0x43e: 0x3126, 0x43f: 0x3437, + // Block 0x11, offset 0x440 + 0x440: 0x312b, 0x441: 0x343c, 0x442: 0x3130, 0x443: 0x3441, 0x444: 0x3144, 0x445: 0x3455, + 0x446: 0x314e, 0x447: 0x345f, 0x448: 0x315d, 0x449: 0x346e, 0x44a: 0x3158, 0x44b: 0x3469, + 0x44c: 0x3970, 0x44d: 0x3aff, 0x44e: 0x397e, 0x44f: 0x3b0d, 0x450: 0x3985, 0x451: 0x3b14, + 0x452: 0x398c, 0x453: 0x3b1b, 0x454: 0x318a, 0x455: 0x349b, 0x456: 0x318f, 0x457: 0x34a0, + 0x458: 0x3199, 0x459: 0x34aa, 0x45a: 0x472c, 0x45b: 0x47bd, 0x45c: 0x39d2, 0x45d: 0x3b61, + 0x45e: 0x31b2, 0x45f: 0x34c3, 0x460: 0x31bc, 0x461: 0x34cd, 0x462: 0x473b, 0x463: 0x47cc, + 0x464: 0x39d9, 0x465: 0x3b68, 0x466: 0x39e0, 0x467: 0x3b6f, 0x468: 0x39e7, 0x469: 0x3b76, + 0x46a: 0x31cb, 0x46b: 0x34dc, 0x46c: 0x31d5, 0x46d: 0x34eb, 0x46e: 0x31e9, 0x46f: 0x34ff, + 0x470: 0x31e4, 0x471: 0x34fa, 0x472: 0x3225, 0x473: 0x353b, 0x474: 0x3234, 0x475: 0x354a, + 0x476: 0x322f, 0x477: 0x3545, 0x478: 0x39ee, 0x479: 0x3b7d, 0x47a: 0x39f5, 0x47b: 0x3b84, + 0x47c: 0x3239, 0x47d: 0x354f, 0x47e: 0x323e, 0x47f: 0x3554, + // Block 0x12, offset 0x480 + 0x480: 0x3243, 0x481: 0x3559, 0x482: 0x3248, 0x483: 0x355e, 0x484: 0x3257, 0x485: 0x356d, + 0x486: 0x3252, 0x487: 0x3568, 0x488: 0x325c, 0x489: 0x3577, 0x48a: 0x3261, 0x48b: 0x357c, + 0x48c: 0x3266, 0x48d: 0x3581, 0x48e: 0x3284, 0x48f: 0x359f, 0x490: 0x329d, 0x491: 0x35bd, + 0x492: 0x32ac, 0x493: 0x35cc, 0x494: 0x32b1, 0x495: 0x35d1, 0x496: 0x33b5, 0x497: 0x34e1, + 0x498: 0x3572, 0x499: 0x35ae, 0x49b: 0x360c, + 0x4a0: 0x46dc, 0x4a1: 0x476d, 0x4a2: 0x2fbe, 0x4a3: 0x32ca, + 0x4a4: 0x38b3, 0x4a5: 0x3a42, 0x4a6: 0x38ac, 0x4a7: 0x3a3b, 0x4a8: 0x38c1, 0x4a9: 0x3a50, + 0x4aa: 0x38ba, 0x4ab: 0x3a49, 0x4ac: 0x38f9, 0x4ad: 0x3a88, 0x4ae: 0x38cf, 0x4af: 0x3a5e, + 0x4b0: 0x38c8, 0x4b1: 0x3a57, 0x4b2: 0x38dd, 0x4b3: 0x3a6c, 0x4b4: 0x38d6, 0x4b5: 0x3a65, + 0x4b6: 0x3900, 0x4b7: 0x3a8f, 0x4b8: 0x46f0, 0x4b9: 0x4781, 0x4ba: 0x303b, 0x4bb: 0x3347, + 0x4bc: 0x3027, 0x4bd: 0x3333, 0x4be: 0x3915, 0x4bf: 0x3aa4, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x390e, 0x4c1: 0x3a9d, 0x4c2: 0x3923, 0x4c3: 0x3ab2, 0x4c4: 0x391c, 0x4c5: 0x3aab, + 0x4c6: 0x3938, 0x4c7: 0x3ac7, 0x4c8: 0x30cc, 0x4c9: 0x33d8, 0x4ca: 0x30e0, 0x4cb: 0x33ec, + 0x4cc: 0x4722, 0x4cd: 0x47b3, 0x4ce: 0x3171, 0x4cf: 0x3482, 0x4d0: 0x395b, 0x4d1: 0x3aea, + 0x4d2: 0x3954, 0x4d3: 0x3ae3, 0x4d4: 0x3969, 0x4d5: 0x3af8, 0x4d6: 0x3962, 0x4d7: 0x3af1, + 0x4d8: 0x39c4, 0x4d9: 0x3b53, 0x4da: 0x39a8, 0x4db: 0x3b37, 0x4dc: 0x39a1, 0x4dd: 0x3b30, + 0x4de: 0x39b6, 0x4df: 0x3b45, 0x4e0: 0x39af, 0x4e1: 0x3b3e, 0x4e2: 0x39bd, 0x4e3: 0x3b4c, + 0x4e4: 0x3220, 0x4e5: 0x3536, 0x4e6: 0x3202, 0x4e7: 0x3518, 0x4e8: 0x3a1f, 0x4e9: 0x3bae, + 0x4ea: 0x3a18, 0x4eb: 0x3ba7, 0x4ec: 0x3a2d, 0x4ed: 0x3bbc, 0x4ee: 0x3a26, 0x4ef: 0x3bb5, + 0x4f0: 0x3a34, 0x4f1: 0x3bc3, 0x4f2: 0x326b, 0x4f3: 0x3586, 0x4f4: 0x3293, 0x4f5: 0x35b3, + 0x4f6: 0x328e, 0x4f7: 0x35a9, 0x4f8: 0x327a, 0x4f9: 0x3595, + // Block 0x14, offset 0x500 + 0x500: 0x483f, 0x501: 0x4845, 0x502: 0x4959, 0x503: 0x4971, 0x504: 0x4961, 0x505: 0x4979, + 0x506: 0x4969, 0x507: 0x4981, 0x508: 0x47e5, 0x509: 0x47eb, 0x50a: 0x48c9, 0x50b: 0x48e1, + 0x50c: 0x48d1, 0x50d: 0x48e9, 0x50e: 0x48d9, 0x50f: 0x48f1, 0x510: 0x4851, 0x511: 0x4857, + 0x512: 0x3df3, 0x513: 0x3e03, 0x514: 0x3dfb, 0x515: 0x3e0b, + 0x518: 0x47f1, 0x519: 0x47f7, 0x51a: 0x3d23, 0x51b: 0x3d33, 0x51c: 0x3d2b, 0x51d: 0x3d3b, + 0x520: 0x4869, 0x521: 0x486f, 0x522: 0x4989, 0x523: 0x49a1, + 0x524: 0x4991, 0x525: 0x49a9, 0x526: 0x4999, 0x527: 0x49b1, 0x528: 0x47fd, 0x529: 0x4803, + 0x52a: 0x48f9, 0x52b: 0x4911, 0x52c: 0x4901, 0x52d: 0x4919, 0x52e: 0x4909, 0x52f: 0x4921, + 0x530: 0x4881, 0x531: 0x4887, 0x532: 0x3e53, 0x533: 0x3e6b, 0x534: 0x3e5b, 0x535: 0x3e73, + 0x536: 0x3e63, 0x537: 0x3e7b, 0x538: 0x4809, 0x539: 0x480f, 0x53a: 0x3d53, 0x53b: 0x3d6b, + 0x53c: 0x3d5b, 0x53d: 0x3d73, 0x53e: 0x3d63, 0x53f: 0x3d7b, + // Block 0x15, offset 0x540 + 0x540: 0x488d, 0x541: 0x4893, 0x542: 0x3e83, 0x543: 0x3e93, 0x544: 0x3e8b, 0x545: 0x3e9b, + 0x548: 0x4815, 0x549: 0x481b, 0x54a: 0x3d83, 0x54b: 0x3d93, + 0x54c: 0x3d8b, 0x54d: 0x3d9b, 0x550: 0x489f, 0x551: 0x48a5, + 0x552: 0x3ebb, 0x553: 0x3ed3, 0x554: 0x3ec3, 0x555: 0x3edb, 0x556: 0x3ecb, 0x557: 0x3ee3, + 0x559: 0x4821, 0x55b: 0x3da3, 0x55d: 0x3dab, + 0x55f: 0x3db3, 0x560: 0x48b7, 0x561: 0x48bd, 0x562: 0x49b9, 0x563: 0x49d1, + 0x564: 0x49c1, 0x565: 0x49d9, 0x566: 0x49c9, 0x567: 0x49e1, 0x568: 0x4827, 0x569: 0x482d, + 0x56a: 0x4929, 0x56b: 0x4941, 0x56c: 0x4931, 0x56d: 0x4949, 0x56e: 0x4939, 0x56f: 0x4951, + 0x570: 0x4833, 0x571: 0x4359, 0x572: 0x36cc, 0x573: 0x435f, 0x574: 0x485d, 0x575: 0x4365, + 0x576: 0x36de, 0x577: 0x436b, 0x578: 0x36fc, 0x579: 0x4371, 0x57a: 0x3714, 0x57b: 0x4377, + 0x57c: 0x48ab, 0x57d: 0x437d, + // Block 0x16, offset 0x580 + 0x580: 0x3ddb, 0x581: 0x3de3, 0x582: 0x41bf, 0x583: 0x41dd, 0x584: 0x41c9, 0x585: 0x41e7, + 0x586: 0x41d3, 0x587: 0x41f1, 0x588: 0x3d13, 0x589: 0x3d1b, 0x58a: 0x410b, 0x58b: 0x4129, + 0x58c: 0x4115, 0x58d: 0x4133, 0x58e: 0x411f, 0x58f: 0x413d, 0x590: 0x3e23, 0x591: 0x3e2b, + 0x592: 0x41fb, 0x593: 0x4219, 0x594: 0x4205, 0x595: 0x4223, 0x596: 0x420f, 0x597: 0x422d, + 0x598: 0x3d43, 0x599: 0x3d4b, 0x59a: 0x4147, 0x59b: 0x4165, 0x59c: 0x4151, 0x59d: 0x416f, + 0x59e: 0x415b, 0x59f: 0x4179, 0x5a0: 0x3efb, 0x5a1: 0x3f03, 0x5a2: 0x4237, 0x5a3: 0x4255, + 0x5a4: 0x4241, 0x5a5: 0x425f, 0x5a6: 0x424b, 0x5a7: 0x4269, 0x5a8: 0x3dbb, 0x5a9: 0x3dc3, + 0x5aa: 0x4183, 0x5ab: 0x41a1, 0x5ac: 0x418d, 0x5ad: 0x41ab, 0x5ae: 0x4197, 0x5af: 0x41b5, + 0x5b0: 0x36c0, 0x5b1: 0x36ba, 0x5b2: 0x3dcb, 0x5b3: 0x36c6, 0x5b4: 0x3dd3, + 0x5b6: 0x484b, 0x5b7: 0x3deb, 0x5b8: 0x3630, 0x5b9: 0x362a, 0x5ba: 0x361e, 0x5bb: 0x4329, + 0x5bc: 0x3636, 0x5bd: 0x8100, 0x5be: 0x01d3, 0x5bf: 0xa100, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x8100, 0x5c1: 0x35e2, 0x5c2: 0x3e13, 0x5c3: 0x36d8, 0x5c4: 0x3e1b, + 0x5c6: 0x4875, 0x5c7: 0x3e33, 0x5c8: 0x363c, 0x5c9: 0x432f, 0x5ca: 0x3648, 0x5cb: 0x4335, + 0x5cc: 0x3654, 0x5cd: 0x3bca, 0x5ce: 0x3bd1, 0x5cf: 0x3bd8, 0x5d0: 0x36f0, 0x5d1: 0x36ea, + 0x5d2: 0x3e3b, 0x5d3: 0x451f, 0x5d6: 0x36f6, 0x5d7: 0x3e4b, + 0x5d8: 0x366c, 0x5d9: 0x3666, 0x5da: 0x365a, 0x5db: 0x433b, 0x5dd: 0x3bdf, + 0x5de: 0x3be6, 0x5df: 0x3bed, 0x5e0: 0x3726, 0x5e1: 0x3720, 0x5e2: 0x3ea3, 0x5e3: 0x4527, + 0x5e4: 0x3708, 0x5e5: 0x370e, 0x5e6: 0x372c, 0x5e7: 0x3eb3, 0x5e8: 0x369c, 0x5e9: 0x3696, + 0x5ea: 0x368a, 0x5eb: 0x4347, 0x5ec: 0x3684, 0x5ed: 0x35d6, 0x5ee: 0x4323, 0x5ef: 0x0081, + 0x5f2: 0x3eeb, 0x5f3: 0x3732, 0x5f4: 0x3ef3, + 0x5f6: 0x48c3, 0x5f7: 0x3f0b, 0x5f8: 0x3678, 0x5f9: 0x4341, 0x5fa: 0x36a8, 0x5fb: 0x4353, + 0x5fc: 0x36b4, 0x5fd: 0x4291, 0x5fe: 0xa100, + // Block 0x18, offset 0x600 + 0x601: 0x3c41, 0x603: 0xa000, 0x604: 0x3c48, 0x605: 0xa000, + 0x607: 0x3c4f, 0x608: 0xa000, 0x609: 0x3c56, + 0x60d: 0xa000, + 0x620: 0x2fa0, 0x621: 0xa000, 0x622: 0x3c64, + 0x624: 0xa000, 0x625: 0xa000, + 0x62d: 0x3c5d, 0x62e: 0x2f9b, 0x62f: 0x2fa5, + 0x630: 0x3c6b, 0x631: 0x3c72, 0x632: 0xa000, 0x633: 0xa000, 0x634: 0x3c79, 0x635: 0x3c80, + 0x636: 0xa000, 0x637: 0xa000, 0x638: 0x3c87, 0x639: 0x3c8e, 0x63a: 0xa000, 0x63b: 0xa000, + 0x63c: 0xa000, 0x63d: 0xa000, + // Block 0x19, offset 0x640 + 0x640: 0x3c95, 0x641: 0x3c9c, 0x642: 0xa000, 0x643: 0xa000, 0x644: 0x3cb1, 0x645: 0x3cb8, + 0x646: 0xa000, 0x647: 0xa000, 0x648: 0x3cbf, 0x649: 0x3cc6, + 0x651: 0xa000, + 0x652: 0xa000, + 0x662: 0xa000, + 0x668: 0xa000, 0x669: 0xa000, + 0x66b: 0xa000, 0x66c: 0x3cdb, 0x66d: 0x3ce2, 0x66e: 0x3ce9, 0x66f: 0x3cf0, + 0x672: 0xa000, 0x673: 0xa000, 0x674: 0xa000, 0x675: 0xa000, + // Block 0x1a, offset 0x680 + 0x686: 0xa000, 0x68b: 0xa000, + 0x68c: 0x3f43, 0x68d: 0xa000, 0x68e: 0x3f4b, 0x68f: 0xa000, 0x690: 0x3f53, 0x691: 0xa000, + 0x692: 0x3f5b, 0x693: 0xa000, 0x694: 0x3f63, 0x695: 0xa000, 0x696: 0x3f6b, 0x697: 0xa000, + 0x698: 0x3f73, 0x699: 0xa000, 0x69a: 0x3f7b, 0x69b: 0xa000, 0x69c: 0x3f83, 0x69d: 0xa000, + 0x69e: 0x3f8b, 0x69f: 0xa000, 0x6a0: 0x3f93, 0x6a1: 0xa000, 0x6a2: 0x3f9b, + 0x6a4: 0xa000, 0x6a5: 0x3fa3, 0x6a6: 0xa000, 0x6a7: 0x3fab, 0x6a8: 0xa000, 0x6a9: 0x3fb3, + 0x6af: 0xa000, + 0x6b0: 0x3fbb, 0x6b1: 0x3fc3, 0x6b2: 0xa000, 0x6b3: 0x3fcb, 0x6b4: 0x3fd3, 0x6b5: 0xa000, + 0x6b6: 0x3fdb, 0x6b7: 0x3fe3, 0x6b8: 0xa000, 0x6b9: 0x3feb, 0x6ba: 0x3ff3, 0x6bb: 0xa000, + 0x6bc: 0x3ffb, 0x6bd: 0x4003, + // Block 0x1b, offset 0x6c0 + 0x6d4: 0x3f3b, + 0x6d9: 0x9903, 0x6da: 0x9903, 0x6db: 0x8100, 0x6dc: 0x8100, 0x6dd: 0xa000, + 0x6de: 0x400b, + 0x6e6: 0xa000, + 0x6eb: 0xa000, 0x6ec: 0x401b, 0x6ed: 0xa000, 0x6ee: 0x4023, 0x6ef: 0xa000, + 0x6f0: 0x402b, 0x6f1: 0xa000, 0x6f2: 0x4033, 0x6f3: 0xa000, 0x6f4: 0x403b, 0x6f5: 0xa000, + 0x6f6: 0x4043, 0x6f7: 0xa000, 0x6f8: 0x404b, 0x6f9: 0xa000, 0x6fa: 0x4053, 0x6fb: 0xa000, + 0x6fc: 0x405b, 0x6fd: 0xa000, 0x6fe: 0x4063, 0x6ff: 0xa000, + // Block 0x1c, offset 0x700 + 0x700: 0x406b, 0x701: 0xa000, 0x702: 0x4073, 0x704: 0xa000, 0x705: 0x407b, + 0x706: 0xa000, 0x707: 0x4083, 0x708: 0xa000, 0x709: 0x408b, + 0x70f: 0xa000, 0x710: 0x4093, 0x711: 0x409b, + 0x712: 0xa000, 0x713: 0x40a3, 0x714: 0x40ab, 0x715: 0xa000, 0x716: 0x40b3, 0x717: 0x40bb, + 0x718: 0xa000, 0x719: 0x40c3, 0x71a: 0x40cb, 0x71b: 0xa000, 0x71c: 0x40d3, 0x71d: 0x40db, + 0x72f: 0xa000, + 0x730: 0xa000, 0x731: 0xa000, 0x732: 0xa000, 0x734: 0x4013, + 0x737: 0x40e3, 0x738: 0x40eb, 0x739: 0x40f3, 0x73a: 0x40fb, + 0x73d: 0xa000, 0x73e: 0x4103, + // Block 0x1d, offset 0x740 + 0x740: 0x13ef, 0x741: 0x0d73, 0x742: 0x144b, 0x743: 0x1417, 0x744: 0x0ecf, 0x745: 0x0763, + 0x746: 0x0957, 0x747: 0x169f, 0x748: 0x169f, 0x749: 0x0a83, 0x74a: 0x14d3, 0x74b: 0x09bb, + 0x74c: 0x0a7f, 0x74d: 0x0c67, 0x74e: 0x1047, 0x74f: 0x11d7, 0x750: 0x130f, 0x751: 0x134b, + 0x752: 0x137f, 0x753: 0x1493, 0x754: 0x0deb, 0x755: 0x0e77, 0x756: 0x0f23, 0x757: 0x0fbb, + 0x758: 0x12d7, 0x759: 0x14bb, 0x75a: 0x15e7, 0x75b: 0x0787, 0x75c: 0x092b, 0x75d: 0x0dff, + 0x75e: 0x0f47, 0x75f: 0x130b, 0x760: 0x1637, 0x761: 0x0b2b, 0x762: 0x0eef, 0x763: 0x12fb, + 0x764: 0x138f, 0x765: 0x0c9b, 0x766: 0x1233, 0x767: 0x1357, 0x768: 0x0b97, 0x769: 0x0d87, + 0x76a: 0x0e8f, 0x76b: 0x0f93, 0x76c: 0x149f, 0x76d: 0x07c7, 0x76e: 0x085f, 0x76f: 0x08cb, + 0x770: 0x0d03, 0x771: 0x0df7, 0x772: 0x0f43, 0x773: 0x1067, 0x774: 0x11ef, 0x775: 0x1303, + 0x776: 0x131b, 0x777: 0x143f, 0x778: 0x1563, 0x779: 0x1617, 0x77a: 0x1633, 0x77b: 0x10a3, + 0x77c: 0x10e3, 0x77d: 0x119b, 0x77e: 0x12bb, 0x77f: 0x14ef, + // Block 0x1e, offset 0x780 + 0x780: 0x163f, 0x781: 0x13c3, 0x782: 0x0a3f, 0x783: 0x0bb3, 0x784: 0x1153, 0x785: 0x1213, + 0x786: 0x0f77, 0x787: 0x10ab, 0x788: 0x140f, 0x789: 0x155b, 0x78a: 0x0a3b, 0x78b: 0x0b07, + 0x78c: 0x0def, 0x78d: 0x0ea3, 0x78e: 0x0ed7, 0x78f: 0x118b, 0x790: 0x11b3, 0x791: 0x151b, + 0x792: 0x08c7, 0x793: 0x121f, 0x794: 0x086b, 0x795: 0x0867, 0x796: 0x110f, 0x797: 0x119f, + 0x798: 0x12d3, 0x799: 0x1523, 0x79a: 0x13df, 0x79b: 0x0c9f, 0x79c: 0x0deb, 0x79d: 0x13cf, + 0x79e: 0x076f, 0x79f: 0x0adb, 0x7a0: 0x0c0b, 0x7a1: 0x0fa7, 0x7a2: 0x1027, 0x7a3: 0x08eb, + 0x7a4: 0x10b3, 0x7a5: 0x07d7, 0x7a6: 0x0bef, 0x7a7: 0x074f, 0x7a8: 0x0e63, 0x7a9: 0x0d1b, + 0x7aa: 0x1187, 0x7ab: 0x093f, 0x7ac: 0x0a2b, 0x7ad: 0x1073, 0x7ae: 0x12db, 0x7af: 0x13b3, + 0x7b0: 0x0e2f, 0x7b1: 0x146f, 0x7b2: 0x0e5b, 0x7b3: 0x0caf, 0x7b4: 0x1293, 0x7b5: 0x0ccf, + 0x7b6: 0x1023, 0x7b7: 0x07a3, 0x7b8: 0x081f, 0x7b9: 0x0863, 0x7ba: 0x0dcb, 0x7bb: 0x1173, + 0x7bc: 0x126b, 0x7bd: 0x13bf, 0x7be: 0x14cf, 0x7bf: 0x08d3, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x0987, 0x7c1: 0x0a8f, 0x7c2: 0x0ba7, 0x7c3: 0x0d37, 0x7c4: 0x0ef3, 0x7c5: 0x10b7, + 0x7c6: 0x150b, 0x7c7: 0x15ef, 0x7c8: 0x1643, 0x7c9: 0x165b, 0x7ca: 0x08af, 0x7cb: 0x0d6b, + 0x7cc: 0x0e1b, 0x7cd: 0x1463, 0x7ce: 0x0b73, 0x7cf: 0x0c4f, 0x7d0: 0x0c6b, 0x7d1: 0x0cfb, + 0x7d2: 0x0ee3, 0x7d3: 0x0f2f, 0x7d4: 0x0fdf, 0x7d5: 0x1103, 0x7d6: 0x11a7, 0x7d7: 0x120b, + 0x7d8: 0x1453, 0x7d9: 0x12e3, 0x7da: 0x147b, 0x7db: 0x14f3, 0x7dc: 0x0887, 0x7dd: 0x08b3, + 0x7de: 0x099b, 0x7df: 0x0f1f, 0x7e0: 0x136b, 0x7e1: 0x13b3, 0x7e2: 0x0b93, 0x7e3: 0x0c03, + 0x7e4: 0x0cc7, 0x7e5: 0x0e27, 0x7e6: 0x114f, 0x7e7: 0x0f9b, 0x7e8: 0x07b3, 0x7e9: 0x09f7, + 0x7ea: 0x0adb, 0x7eb: 0x0b3f, 0x7ec: 0x0c0f, 0x7ed: 0x0fb7, 0x7ee: 0x0fd3, 0x7ef: 0x11e3, + 0x7f0: 0x1203, 0x7f1: 0x14d7, 0x7f2: 0x1557, 0x7f3: 0x1567, 0x7f4: 0x15a3, 0x7f5: 0x07cb, + 0x7f6: 0x10f7, 0x7f7: 0x14c3, 0x7f8: 0x153f, 0x7f9: 0x0c27, 0x7fa: 0x078f, 0x7fb: 0x07ef, + 0x7fc: 0x0adf, 0x7fd: 0x0aff, 0x7fe: 0x0d27, 0x7ff: 0x0deb, + // Block 0x20, offset 0x800 + 0x800: 0x0f3b, 0x801: 0x1043, 0x802: 0x12ef, 0x803: 0x148f, 0x804: 0x1697, 0x805: 0x0d5b, + 0x806: 0x1517, 0x807: 0x08ab, 0x808: 0x0da7, 0x809: 0x0db3, 0x80a: 0x0e87, 0x80b: 0x0ebf, + 0x80c: 0x0fc3, 0x80d: 0x101f, 0x80e: 0x109f, 0x80f: 0x1183, 0x810: 0x15af, 0x811: 0x0827, + 0x812: 0x0c7b, 0x813: 0x1527, 0x814: 0x07df, 0x815: 0x0b23, 0x816: 0x0ea7, 0x817: 0x1457, + 0x818: 0x0bdf, 0x819: 0x0c2f, 0x81a: 0x0dbb, 0x81b: 0x0fa7, 0x81c: 0x152f, 0x81d: 0x088f, + 0x81e: 0x0977, 0x81f: 0x0b0f, 0x820: 0x0d4b, 0x821: 0x0d97, 0x822: 0x0dd7, 0x823: 0x0e6b, + 0x824: 0x0fbf, 0x825: 0x1033, 0x826: 0x11cf, 0x827: 0x136f, 0x828: 0x137b, 0x829: 0x14cb, + 0x82a: 0x154b, 0x82b: 0x08fb, 0x82c: 0x0ec3, 0x82d: 0x097b, 0x82e: 0x0f3f, 0x82f: 0x0fe3, + 0x830: 0x12ff, 0x831: 0x1533, 0x832: 0x161f, 0x833: 0x1647, 0x834: 0x0daf, 0x835: 0x0e9f, + 0x836: 0x123b, 0x837: 0x112f, 0x838: 0x113b, 0x839: 0x115f, 0x83a: 0x0f8f, 0x83b: 0x0f17, + 0x83c: 0x13db, 0x83d: 0x07ab, 0x83e: 0x12a3, 0x83f: 0x0893, + // Block 0x21, offset 0x840 + 0x840: 0x0883, 0x841: 0x0b83, 0x842: 0x0ca3, 0x843: 0x116b, 0x844: 0x0acb, 0x845: 0x0e7b, + 0x846: 0x0d67, 0x847: 0x145f, 0x848: 0x135f, 0x849: 0x151f, 0x84a: 0x139b, 0x84b: 0x0b9f, + 0x84c: 0x07ff, 0x84d: 0x09d3, 0x850: 0x0a27, + 0x852: 0x0d57, 0x855: 0x086f, 0x856: 0x0f97, 0x857: 0x105b, + 0x858: 0x10bf, 0x859: 0x10db, 0x85a: 0x10df, 0x85b: 0x10f3, 0x85c: 0x156f, 0x85d: 0x1163, + 0x85e: 0x11e7, 0x860: 0x1307, 0x862: 0x13cb, + 0x865: 0x147f, 0x866: 0x14ab, + 0x86a: 0x15c3, 0x86b: 0x15c7, 0x86c: 0x15cb, 0x86d: 0x162f, 0x86e: 0x14a3, 0x86f: 0x153b, + 0x870: 0x07cf, 0x871: 0x07f3, 0x872: 0x0807, 0x873: 0x08c3, 0x874: 0x08cf, 0x875: 0x090f, + 0x876: 0x09c3, 0x877: 0x09df, 0x878: 0x09e7, 0x879: 0x0a23, 0x87a: 0x0a2f, 0x87b: 0x0b0b, + 0x87c: 0x0b13, 0x87d: 0x0c1b, 0x87e: 0x0c43, 0x87f: 0x0c4b, + // Block 0x22, offset 0x880 + 0x880: 0x0c63, 0x881: 0x0d0f, 0x882: 0x0d3f, 0x883: 0x0d5f, 0x884: 0x0dcf, 0x885: 0x0e93, + 0x886: 0x0eaf, 0x887: 0x0edf, 0x888: 0x0f33, 0x889: 0x0f53, 0x88a: 0x0fc7, 0x88b: 0x10a7, + 0x88c: 0x10c3, 0x88d: 0x10cb, 0x88e: 0x10c7, 0x88f: 0x10cf, 0x890: 0x10d3, 0x891: 0x10d7, + 0x892: 0x10eb, 0x893: 0x10ef, 0x894: 0x1113, 0x895: 0x1127, 0x896: 0x1143, 0x897: 0x11a7, + 0x898: 0x11af, 0x899: 0x11b7, 0x89a: 0x11cb, 0x89b: 0x11f3, 0x89c: 0x1243, 0x89d: 0x1277, + 0x89e: 0x1277, 0x89f: 0x12df, 0x8a0: 0x1387, 0x8a1: 0x139f, 0x8a2: 0x13d3, 0x8a3: 0x13d7, + 0x8a4: 0x141b, 0x8a5: 0x141f, 0x8a6: 0x1477, 0x8a7: 0x147f, 0x8a8: 0x154f, 0x8a9: 0x1593, + 0x8aa: 0x15ab, 0x8ab: 0x0c13, 0x8ac: 0x1792, 0x8ad: 0x125b, + 0x8b0: 0x0757, 0x8b1: 0x085b, 0x8b2: 0x081b, 0x8b3: 0x07c3, 0x8b4: 0x0803, 0x8b5: 0x082f, + 0x8b6: 0x08bf, 0x8b7: 0x08db, 0x8b8: 0x09c3, 0x8b9: 0x09af, 0x8ba: 0x09bf, 0x8bb: 0x09db, + 0x8bc: 0x0a27, 0x8bd: 0x0a37, 0x8be: 0x0a7b, 0x8bf: 0x0a87, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0aa3, 0x8c1: 0x0ab3, 0x8c2: 0x0b9b, 0x8c3: 0x0ba3, 0x8c4: 0x0bd3, 0x8c5: 0x0bf3, + 0x8c6: 0x0c23, 0x8c7: 0x0c3b, 0x8c8: 0x0c2b, 0x8c9: 0x0c4b, 0x8ca: 0x0c3f, 0x8cb: 0x0c63, + 0x8cc: 0x0c7f, 0x8cd: 0x0cd7, 0x8ce: 0x0ce3, 0x8cf: 0x0ceb, 0x8d0: 0x0d13, 0x8d1: 0x0d57, + 0x8d2: 0x0d87, 0x8d3: 0x0d8b, 0x8d4: 0x0d9f, 0x8d5: 0x0e1f, 0x8d6: 0x0e2f, 0x8d7: 0x0e87, + 0x8d8: 0x0ed3, 0x8d9: 0x0ecb, 0x8da: 0x0edf, 0x8db: 0x0efb, 0x8dc: 0x0f33, 0x8dd: 0x108b, + 0x8de: 0x0f57, 0x8df: 0x0f8b, 0x8e0: 0x0f97, 0x8e1: 0x0fd7, 0x8e2: 0x0ff3, 0x8e3: 0x1017, + 0x8e4: 0x103b, 0x8e5: 0x103f, 0x8e6: 0x105b, 0x8e7: 0x105f, 0x8e8: 0x106f, 0x8e9: 0x1083, + 0x8ea: 0x107f, 0x8eb: 0x10af, 0x8ec: 0x112b, 0x8ed: 0x1143, 0x8ee: 0x115b, 0x8ef: 0x1193, + 0x8f0: 0x11a7, 0x8f1: 0x11c3, 0x8f2: 0x11f3, 0x8f3: 0x12a7, 0x8f4: 0x12cf, 0x8f5: 0x1343, + 0x8f6: 0x138b, 0x8f7: 0x1397, 0x8f8: 0x139f, 0x8f9: 0x13b7, 0x8fa: 0x13cb, 0x8fb: 0x13bb, + 0x8fc: 0x13d3, 0x8fd: 0x13cf, 0x8fe: 0x13c7, 0x8ff: 0x13d7, + // Block 0x24, offset 0x900 + 0x900: 0x13e3, 0x901: 0x141f, 0x902: 0x145b, 0x903: 0x148b, 0x904: 0x14bf, 0x905: 0x14df, + 0x906: 0x152b, 0x907: 0x154f, 0x908: 0x156f, 0x909: 0x1583, 0x90a: 0x1593, 0x90b: 0x159f, + 0x90c: 0x15ab, 0x90d: 0x15ff, 0x90e: 0x169f, 0x90f: 0x1729, 0x910: 0x1724, 0x911: 0x1756, + 0x912: 0x067f, 0x913: 0x06a7, 0x914: 0x06ab, 0x915: 0x17d8, 0x916: 0x1805, 0x917: 0x187d, + 0x918: 0x168b, 0x919: 0x169b, + // Block 0x25, offset 0x940 + 0x940: 0x0773, 0x941: 0x076b, 0x942: 0x077b, 0x943: 0x16bb, 0x944: 0x07bf, 0x945: 0x07cf, + 0x946: 0x07d3, 0x947: 0x07db, 0x948: 0x07e3, 0x949: 0x07e7, 0x94a: 0x07f3, 0x94b: 0x07eb, + 0x94c: 0x062b, 0x94d: 0x16cf, 0x94e: 0x0807, 0x94f: 0x080b, 0x950: 0x080f, 0x951: 0x082b, + 0x952: 0x16c0, 0x953: 0x062f, 0x954: 0x0817, 0x955: 0x0837, 0x956: 0x16ca, 0x957: 0x0847, + 0x958: 0x084f, 0x959: 0x07af, 0x95a: 0x0857, 0x95b: 0x085b, 0x95c: 0x18a5, 0x95d: 0x0877, + 0x95e: 0x087f, 0x95f: 0x0637, 0x960: 0x0897, 0x961: 0x089b, 0x962: 0x08a3, 0x963: 0x08a7, + 0x964: 0x063b, 0x965: 0x08bf, 0x966: 0x08c3, 0x967: 0x08cf, 0x968: 0x08db, 0x969: 0x08df, + 0x96a: 0x08e3, 0x96b: 0x08eb, 0x96c: 0x090b, 0x96d: 0x090f, 0x96e: 0x0917, 0x96f: 0x0927, + 0x970: 0x092f, 0x971: 0x0933, 0x972: 0x0933, 0x973: 0x0933, 0x974: 0x16de, 0x975: 0x0f0b, + 0x976: 0x0947, 0x977: 0x094f, 0x978: 0x16e3, 0x979: 0x095b, 0x97a: 0x0963, 0x97b: 0x096b, + 0x97c: 0x0993, 0x97d: 0x097f, 0x97e: 0x098b, 0x97f: 0x098f, + // Block 0x26, offset 0x980 + 0x980: 0x0997, 0x981: 0x099f, 0x982: 0x09a3, 0x983: 0x09ab, 0x984: 0x09b3, 0x985: 0x09b7, + 0x986: 0x09b7, 0x987: 0x09bf, 0x988: 0x09c7, 0x989: 0x09cb, 0x98a: 0x09d7, 0x98b: 0x09fb, + 0x98c: 0x09df, 0x98d: 0x09ff, 0x98e: 0x09e3, 0x98f: 0x09eb, 0x990: 0x0883, 0x991: 0x0a47, + 0x992: 0x0a0f, 0x993: 0x0a13, 0x994: 0x0a17, 0x995: 0x0a0b, 0x996: 0x0a1f, 0x997: 0x0a1b, + 0x998: 0x0a33, 0x999: 0x16e8, 0x99a: 0x0a4f, 0x99b: 0x0a53, 0x99c: 0x0a5b, 0x99d: 0x0a67, + 0x99e: 0x0a6f, 0x99f: 0x0a8b, 0x9a0: 0x16ed, 0x9a1: 0x16f2, 0x9a2: 0x0a97, 0x9a3: 0x0a9b, + 0x9a4: 0x0a9f, 0x9a5: 0x0a93, 0x9a6: 0x0aa7, 0x9a7: 0x063f, 0x9a8: 0x0643, 0x9a9: 0x0aaf, + 0x9aa: 0x0ab7, 0x9ab: 0x0ab7, 0x9ac: 0x16f7, 0x9ad: 0x0ad3, 0x9ae: 0x0ad7, 0x9af: 0x0adb, + 0x9b0: 0x0ae3, 0x9b1: 0x16fc, 0x9b2: 0x0aeb, 0x9b3: 0x0aef, 0x9b4: 0x0bc7, 0x9b5: 0x0af7, + 0x9b6: 0x0647, 0x9b7: 0x0b03, 0x9b8: 0x0b13, 0x9b9: 0x0b1f, 0x9ba: 0x0b1b, 0x9bb: 0x1706, + 0x9bc: 0x0b27, 0x9bd: 0x170b, 0x9be: 0x0b33, 0x9bf: 0x0b2f, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x0b37, 0x9c1: 0x0b47, 0x9c2: 0x0b4b, 0x9c3: 0x064b, 0x9c4: 0x0b5b, 0x9c5: 0x0b63, + 0x9c6: 0x0b67, 0x9c7: 0x0b6b, 0x9c8: 0x064f, 0x9c9: 0x1710, 0x9ca: 0x0653, 0x9cb: 0x0b87, + 0x9cc: 0x0b8b, 0x9cd: 0x0b8f, 0x9ce: 0x0b97, 0x9cf: 0x18d7, 0x9d0: 0x0baf, 0x9d1: 0x171a, + 0x9d2: 0x171a, 0x9d3: 0x124f, 0x9d4: 0x0bbf, 0x9d5: 0x0bbf, 0x9d6: 0x0657, 0x9d7: 0x173d, + 0x9d8: 0x180f, 0x9d9: 0x0bcf, 0x9da: 0x0bd7, 0x9db: 0x065b, 0x9dc: 0x0beb, 0x9dd: 0x0bfb, + 0x9de: 0x0bff, 0x9df: 0x0c07, 0x9e0: 0x0c17, 0x9e1: 0x0663, 0x9e2: 0x065f, 0x9e3: 0x0c1b, + 0x9e4: 0x171f, 0x9e5: 0x0c1f, 0x9e6: 0x0c33, 0x9e7: 0x0c37, 0x9e8: 0x0c3b, 0x9e9: 0x0c37, + 0x9ea: 0x0c47, 0x9eb: 0x0c4b, 0x9ec: 0x0c5b, 0x9ed: 0x0c53, 0x9ee: 0x0c57, 0x9ef: 0x0c5f, + 0x9f0: 0x0c63, 0x9f1: 0x0c67, 0x9f2: 0x0c73, 0x9f3: 0x0c77, 0x9f4: 0x0c8f, 0x9f5: 0x0c97, + 0x9f6: 0x0ca7, 0x9f7: 0x0cbb, 0x9f8: 0x172e, 0x9f9: 0x0cb7, 0x9fa: 0x0cab, 0x9fb: 0x0cc3, + 0x9fc: 0x0ccb, 0x9fd: 0x0cdf, 0x9fe: 0x1733, 0x9ff: 0x0ce7, + // Block 0x28, offset 0xa00 + 0xa00: 0x0cdb, 0xa01: 0x0cd3, 0xa02: 0x0667, 0xa03: 0x0cef, 0xa04: 0x0cf7, 0xa05: 0x0cff, + 0xa06: 0x0cf3, 0xa07: 0x066b, 0xa08: 0x0d0f, 0xa09: 0x0d17, 0xa0a: 0x1738, 0xa0b: 0x0d43, + 0xa0c: 0x0d77, 0xa0d: 0x0d53, 0xa0e: 0x0677, 0xa0f: 0x0d5f, 0xa10: 0x0673, 0xa11: 0x066f, + 0xa12: 0x083b, 0xa13: 0x083f, 0xa14: 0x0d7b, 0xa15: 0x0d63, 0xa16: 0x1223, 0xa17: 0x06db, + 0xa18: 0x0d87, 0xa19: 0x0d8b, 0xa1a: 0x0d8f, 0xa1b: 0x0da3, 0xa1c: 0x0d9b, 0xa1d: 0x1751, + 0xa1e: 0x067b, 0xa1f: 0x0db7, 0xa20: 0x0dab, 0xa21: 0x0dc7, 0xa22: 0x0dcf, 0xa23: 0x175b, + 0xa24: 0x0dd3, 0xa25: 0x0dbf, 0xa26: 0x0ddb, 0xa27: 0x067f, 0xa28: 0x0ddf, 0xa29: 0x0de3, + 0xa2a: 0x0de7, 0xa2b: 0x0df3, 0xa2c: 0x1760, 0xa2d: 0x0dfb, 0xa2e: 0x0683, 0xa2f: 0x0e07, + 0xa30: 0x1765, 0xa31: 0x0e0b, 0xa32: 0x0687, 0xa33: 0x0e17, 0xa34: 0x0e23, 0xa35: 0x0e2f, + 0xa36: 0x0e33, 0xa37: 0x176a, 0xa38: 0x1701, 0xa39: 0x176f, 0xa3a: 0x0e53, 0xa3b: 0x1774, + 0xa3c: 0x0e5f, 0xa3d: 0x0e67, 0xa3e: 0x0e57, 0xa3f: 0x0e73, + // Block 0x29, offset 0xa40 + 0xa40: 0x0e83, 0xa41: 0x0e93, 0xa42: 0x0e87, 0xa43: 0x0e8b, 0xa44: 0x0e97, 0xa45: 0x0e9b, + 0xa46: 0x1779, 0xa47: 0x0e7f, 0xa48: 0x0eb3, 0xa49: 0x0eb7, 0xa4a: 0x068b, 0xa4b: 0x0ecb, + 0xa4c: 0x0ec7, 0xa4d: 0x177e, 0xa4e: 0x0eab, 0xa4f: 0x0ee7, 0xa50: 0x1783, 0xa51: 0x1788, + 0xa52: 0x0eeb, 0xa53: 0x0eff, 0xa54: 0x0efb, 0xa55: 0x0ef7, 0xa56: 0x068f, 0xa57: 0x0f03, + 0xa58: 0x0f13, 0xa59: 0x0f0f, 0xa5a: 0x0f1b, 0xa5b: 0x16c5, 0xa5c: 0x0f2b, 0xa5d: 0x178d, + 0xa5e: 0x0f37, 0xa5f: 0x1797, 0xa60: 0x0f4b, 0xa61: 0x0f57, 0xa62: 0x0f6b, 0xa63: 0x179c, + 0xa64: 0x0f7f, 0xa65: 0x0f83, 0xa66: 0x17a1, 0xa67: 0x17a6, 0xa68: 0x0f9f, 0xa69: 0x0faf, + 0xa6a: 0x0693, 0xa6b: 0x0fb3, 0xa6c: 0x0697, 0xa6d: 0x0697, 0xa6e: 0x0fcb, 0xa6f: 0x0fcf, + 0xa70: 0x0fd7, 0xa71: 0x0fdb, 0xa72: 0x0fe7, 0xa73: 0x069b, 0xa74: 0x0fff, 0xa75: 0x17ab, + 0xa76: 0x101b, 0xa77: 0x17b0, 0xa78: 0x1027, 0xa79: 0x1715, 0xa7a: 0x1037, 0xa7b: 0x17b5, + 0xa7c: 0x17ba, 0xa7d: 0x17bf, 0xa7e: 0x069f, 0xa7f: 0x06a3, + // Block 0x2a, offset 0xa80 + 0xa80: 0x106f, 0xa81: 0x17c9, 0xa82: 0x17c4, 0xa83: 0x17ce, 0xa84: 0x17d3, 0xa85: 0x1077, + 0xa86: 0x107b, 0xa87: 0x107b, 0xa88: 0x1083, 0xa89: 0x06ab, 0xa8a: 0x1087, 0xa8b: 0x06af, + 0xa8c: 0x06b3, 0xa8d: 0x17dd, 0xa8e: 0x109b, 0xa8f: 0x10a3, 0xa90: 0x10af, 0xa91: 0x06b7, + 0xa92: 0x17e2, 0xa93: 0x10d3, 0xa94: 0x17e7, 0xa95: 0x17ec, 0xa96: 0x10f3, 0xa97: 0x110b, + 0xa98: 0x06bb, 0xa99: 0x1113, 0xa9a: 0x1117, 0xa9b: 0x111b, 0xa9c: 0x17f1, 0xa9d: 0x17f6, + 0xa9e: 0x17f6, 0xa9f: 0x1133, 0xaa0: 0x06bf, 0xaa1: 0x17fb, 0xaa2: 0x1147, 0xaa3: 0x114b, + 0xaa4: 0x06c3, 0xaa5: 0x1800, 0xaa6: 0x1167, 0xaa7: 0x06c7, 0xaa8: 0x1177, 0xaa9: 0x116f, + 0xaaa: 0x117f, 0xaab: 0x180a, 0xaac: 0x1197, 0xaad: 0x06cb, 0xaae: 0x11a3, 0xaaf: 0x11ab, + 0xab0: 0x11bb, 0xab1: 0x06cf, 0xab2: 0x1814, 0xab3: 0x1819, 0xab4: 0x06d3, 0xab5: 0x181e, + 0xab6: 0x11d3, 0xab7: 0x1823, 0xab8: 0x11df, 0xab9: 0x11eb, 0xaba: 0x11f3, 0xabb: 0x1828, + 0xabc: 0x182d, 0xabd: 0x1207, 0xabe: 0x1832, 0xabf: 0x120f, + // Block 0x2b, offset 0xac0 + 0xac0: 0x1742, 0xac1: 0x06d7, 0xac2: 0x1227, 0xac3: 0x122b, 0xac4: 0x06df, 0xac5: 0x122f, + 0xac6: 0x0aab, 0xac7: 0x1837, 0xac8: 0x183c, 0xac9: 0x1747, 0xaca: 0x174c, 0xacb: 0x124f, + 0xacc: 0x1253, 0xacd: 0x146b, 0xace: 0x06e3, 0xacf: 0x127f, 0xad0: 0x127b, 0xad1: 0x1283, + 0xad2: 0x08b7, 0xad3: 0x1287, 0xad4: 0x128b, 0xad5: 0x128f, 0xad6: 0x1297, 0xad7: 0x1841, + 0xad8: 0x1293, 0xad9: 0x129b, 0xada: 0x12af, 0xadb: 0x12b3, 0xadc: 0x129f, 0xadd: 0x12b7, + 0xade: 0x12cb, 0xadf: 0x12df, 0xae0: 0x12ab, 0xae1: 0x12bf, 0xae2: 0x12c3, 0xae3: 0x12c7, + 0xae4: 0x1846, 0xae5: 0x1850, 0xae6: 0x184b, 0xae7: 0x06e7, 0xae8: 0x12e7, 0xae9: 0x12eb, + 0xaea: 0x12f3, 0xaeb: 0x1864, 0xaec: 0x12f7, 0xaed: 0x1855, 0xaee: 0x06eb, 0xaef: 0x06ef, + 0xaf0: 0x185a, 0xaf1: 0x185f, 0xaf2: 0x06f3, 0xaf3: 0x1317, 0xaf4: 0x131b, 0xaf5: 0x131f, + 0xaf6: 0x1323, 0xaf7: 0x132f, 0xaf8: 0x132b, 0xaf9: 0x1337, 0xafa: 0x1333, 0xafb: 0x1343, + 0xafc: 0x133b, 0xafd: 0x133f, 0xafe: 0x1347, 0xaff: 0x06f7, + // Block 0x2c, offset 0xb00 + 0xb00: 0x134f, 0xb01: 0x1353, 0xb02: 0x06fb, 0xb03: 0x1363, 0xb04: 0x1367, 0xb05: 0x1869, + 0xb06: 0x1373, 0xb07: 0x1377, 0xb08: 0x06ff, 0xb09: 0x1383, 0xb0a: 0x0633, 0xb0b: 0x186e, + 0xb0c: 0x1873, 0xb0d: 0x0703, 0xb0e: 0x0707, 0xb0f: 0x13af, 0xb10: 0x13c7, 0xb11: 0x13e3, + 0xb12: 0x13f3, 0xb13: 0x1878, 0xb14: 0x1407, 0xb15: 0x140b, 0xb16: 0x1423, 0xb17: 0x142f, + 0xb18: 0x1882, 0xb19: 0x16d4, 0xb1a: 0x143b, 0xb1b: 0x1437, 0xb1c: 0x1443, 0xb1d: 0x16d9, + 0xb1e: 0x144f, 0xb1f: 0x145b, 0xb20: 0x1887, 0xb21: 0x188c, 0xb22: 0x149b, 0xb23: 0x14a7, + 0xb24: 0x14af, 0xb25: 0x1891, 0xb26: 0x14b3, 0xb27: 0x14db, 0xb28: 0x14e7, 0xb29: 0x14eb, + 0xb2a: 0x14e3, 0xb2b: 0x14f7, 0xb2c: 0x14fb, 0xb2d: 0x1896, 0xb2e: 0x1507, 0xb2f: 0x070b, + 0xb30: 0x150f, 0xb31: 0x189b, 0xb32: 0x070f, 0xb33: 0x1547, 0xb34: 0x0b3b, 0xb35: 0x155f, + 0xb36: 0x18a0, 0xb37: 0x18aa, 0xb38: 0x0713, 0xb39: 0x0717, 0xb3a: 0x1587, 0xb3b: 0x18af, + 0xb3c: 0x071b, 0xb3d: 0x18b4, 0xb3e: 0x159f, 0xb3f: 0x159f, + // Block 0x2d, offset 0xb40 + 0xb40: 0x15a7, 0xb41: 0x18b9, 0xb42: 0x15bf, 0xb43: 0x071f, 0xb44: 0x15cf, 0xb45: 0x15db, + 0xb46: 0x15e3, 0xb47: 0x15eb, 0xb48: 0x0723, 0xb49: 0x18be, 0xb4a: 0x15ff, 0xb4b: 0x161b, + 0xb4c: 0x1627, 0xb4d: 0x0727, 0xb4e: 0x072b, 0xb4f: 0x162b, 0xb50: 0x18c3, 0xb51: 0x072f, + 0xb52: 0x18c8, 0xb53: 0x18cd, 0xb54: 0x18d2, 0xb55: 0x164f, 0xb56: 0x0733, 0xb57: 0x1663, + 0xb58: 0x166b, 0xb59: 0x166f, 0xb5a: 0x1677, 0xb5b: 0x167f, 0xb5c: 0x1687, 0xb5d: 0x18dc, +} + +// nfcIndex: 22 blocks, 1408 entries, 1408 bytes +// Block 0 is the zero block. +var nfcIndex = [1408]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x2c, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2d, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x2e, 0xcb: 0x2f, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x30, + 0xd0: 0x09, 0xd1: 0x31, 0xd2: 0x32, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x33, + 0xd8: 0x34, 0xd9: 0x0c, 0xdb: 0x35, 0xdc: 0x36, 0xdd: 0x37, 0xdf: 0x38, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x13, + // Block 0x4, offset 0x100 + 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f, + 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46, + 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c, + 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54, + // Block 0x5, offset 0x140 + 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a, + 0x14d: 0x5b, + 0x15c: 0x5c, 0x15f: 0x5d, + 0x162: 0x5e, 0x164: 0x5f, + 0x168: 0x60, 0x169: 0x61, 0x16a: 0x62, 0x16c: 0x0d, 0x16d: 0x63, 0x16e: 0x64, 0x16f: 0x65, + 0x170: 0x66, 0x173: 0x67, 0x177: 0x68, + 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15, + // Block 0x6, offset 0x180 + 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d, + 0x188: 0x6e, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6f, 0x18c: 0x70, + 0x1ab: 0x71, + 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x75, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, + 0x1cc: 0x76, 0x1cd: 0x77, + // Block 0x8, offset 0x200 + 0x219: 0x78, 0x21a: 0x79, 0x21b: 0x7a, + 0x220: 0x7b, 0x223: 0x7c, 0x224: 0x7d, 0x225: 0x7e, 0x226: 0x7f, 0x227: 0x80, + 0x22a: 0x81, 0x22b: 0x82, 0x22f: 0x83, + 0x230: 0x84, 0x231: 0x85, 0x232: 0x86, 0x233: 0x87, 0x234: 0x88, 0x235: 0x89, 0x236: 0x8a, 0x237: 0x84, + 0x238: 0x85, 0x239: 0x86, 0x23a: 0x87, 0x23b: 0x88, 0x23c: 0x89, 0x23d: 0x8a, 0x23e: 0x84, 0x23f: 0x85, + // Block 0x9, offset 0x240 + 0x240: 0x86, 0x241: 0x87, 0x242: 0x88, 0x243: 0x89, 0x244: 0x8a, 0x245: 0x84, 0x246: 0x85, 0x247: 0x86, + 0x248: 0x87, 0x249: 0x88, 0x24a: 0x89, 0x24b: 0x8a, 0x24c: 0x84, 0x24d: 0x85, 0x24e: 0x86, 0x24f: 0x87, + 0x250: 0x88, 0x251: 0x89, 0x252: 0x8a, 0x253: 0x84, 0x254: 0x85, 0x255: 0x86, 0x256: 0x87, 0x257: 0x88, + 0x258: 0x89, 0x259: 0x8a, 0x25a: 0x84, 0x25b: 0x85, 0x25c: 0x86, 0x25d: 0x87, 0x25e: 0x88, 0x25f: 0x89, + 0x260: 0x8a, 0x261: 0x84, 0x262: 0x85, 0x263: 0x86, 0x264: 0x87, 0x265: 0x88, 0x266: 0x89, 0x267: 0x8a, + 0x268: 0x84, 0x269: 0x85, 0x26a: 0x86, 0x26b: 0x87, 0x26c: 0x88, 0x26d: 0x89, 0x26e: 0x8a, 0x26f: 0x84, + 0x270: 0x85, 0x271: 0x86, 0x272: 0x87, 0x273: 0x88, 0x274: 0x89, 0x275: 0x8a, 0x276: 0x84, 0x277: 0x85, + 0x278: 0x86, 0x279: 0x87, 0x27a: 0x88, 0x27b: 0x89, 0x27c: 0x8a, 0x27d: 0x84, 0x27e: 0x85, 0x27f: 0x86, + // Block 0xa, offset 0x280 + 0x280: 0x87, 0x281: 0x88, 0x282: 0x89, 0x283: 0x8a, 0x284: 0x84, 0x285: 0x85, 0x286: 0x86, 0x287: 0x87, + 0x288: 0x88, 0x289: 0x89, 0x28a: 0x8a, 0x28b: 0x84, 0x28c: 0x85, 0x28d: 0x86, 0x28e: 0x87, 0x28f: 0x88, + 0x290: 0x89, 0x291: 0x8a, 0x292: 0x84, 0x293: 0x85, 0x294: 0x86, 0x295: 0x87, 0x296: 0x88, 0x297: 0x89, + 0x298: 0x8a, 0x299: 0x84, 0x29a: 0x85, 0x29b: 0x86, 0x29c: 0x87, 0x29d: 0x88, 0x29e: 0x89, 0x29f: 0x8a, + 0x2a0: 0x84, 0x2a1: 0x85, 0x2a2: 0x86, 0x2a3: 0x87, 0x2a4: 0x88, 0x2a5: 0x89, 0x2a6: 0x8a, 0x2a7: 0x84, + 0x2a8: 0x85, 0x2a9: 0x86, 0x2aa: 0x87, 0x2ab: 0x88, 0x2ac: 0x89, 0x2ad: 0x8a, 0x2ae: 0x84, 0x2af: 0x85, + 0x2b0: 0x86, 0x2b1: 0x87, 0x2b2: 0x88, 0x2b3: 0x89, 0x2b4: 0x8a, 0x2b5: 0x84, 0x2b6: 0x85, 0x2b7: 0x86, + 0x2b8: 0x87, 0x2b9: 0x88, 0x2ba: 0x89, 0x2bb: 0x8a, 0x2bc: 0x84, 0x2bd: 0x85, 0x2be: 0x86, 0x2bf: 0x87, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x88, 0x2c1: 0x89, 0x2c2: 0x8a, 0x2c3: 0x84, 0x2c4: 0x85, 0x2c5: 0x86, 0x2c6: 0x87, 0x2c7: 0x88, + 0x2c8: 0x89, 0x2c9: 0x8a, 0x2ca: 0x84, 0x2cb: 0x85, 0x2cc: 0x86, 0x2cd: 0x87, 0x2ce: 0x88, 0x2cf: 0x89, + 0x2d0: 0x8a, 0x2d1: 0x84, 0x2d2: 0x85, 0x2d3: 0x86, 0x2d4: 0x87, 0x2d5: 0x88, 0x2d6: 0x89, 0x2d7: 0x8a, + 0x2d8: 0x84, 0x2d9: 0x85, 0x2da: 0x86, 0x2db: 0x87, 0x2dc: 0x88, 0x2dd: 0x89, 0x2de: 0x8b, + // Block 0xc, offset 0x300 + 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e, + 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8c, 0x32d: 0x8d, 0x32e: 0x8e, + 0x331: 0x8f, 0x332: 0x90, 0x333: 0x91, 0x334: 0x92, + 0x338: 0x93, 0x339: 0x94, 0x33a: 0x95, 0x33b: 0x96, 0x33e: 0x97, 0x33f: 0x98, + // Block 0xd, offset 0x340 + 0x347: 0x99, + 0x34b: 0x9a, 0x34d: 0x9b, + 0x368: 0x9c, 0x36b: 0x9d, + // Block 0xe, offset 0x380 + 0x381: 0x9e, 0x382: 0x9f, 0x384: 0xa0, 0x385: 0x7f, 0x387: 0x80, + 0x388: 0xa1, 0x38b: 0xa2, 0x38c: 0x3e, 0x38d: 0xa3, + 0x392: 0xa4, 0x393: 0xa5, 0x396: 0xa6, 0x397: 0xa7, + 0x398: 0x73, 0x39a: 0xa8, + // Block 0xf, offset 0x3c0 + 0x3eb: 0xa9, 0x3ec: 0xaa, + // Block 0x10, offset 0x400 + 0x432: 0xab, + // Block 0x11, offset 0x440 + 0x445: 0xac, 0x446: 0xad, 0x447: 0xae, + 0x449: 0xaf, + // Block 0x12, offset 0x480 + 0x4a3: 0xb0, + // Block 0x13, offset 0x4c0 + 0x4c8: 0xb1, + // Block 0x14, offset 0x500 + 0x520: 0x23, 0x521: 0x24, 0x522: 0x25, 0x523: 0x26, 0x524: 0x27, 0x525: 0x28, 0x526: 0x29, 0x527: 0x2a, + 0x528: 0x2b, + // Block 0x15, offset 0x540 + 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, + 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, + 0x56f: 0x12, +} + +// nfcSparseOffset: 134 entries, 268 bytes +var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x78, 0x80, 0x87, 0x8a, 0x92, 0x96, 0x9a, 0x9c, 0x9e, 0xa7, 0xab, 0xb2, 0xb7, 0xba, 0xc4, 0xc6, 0xcd, 0xd5, 0xd8, 0xda, 0xdc, 0xde, 0xe3, 0xf4, 0x100, 0x102, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x117, 0x11a, 0x11c, 0x11f, 0x122, 0x126, 0x12b, 0x134, 0x136, 0x139, 0x13b, 0x146, 0x155, 0x159, 0x167, 0x16a, 0x170, 0x176, 0x181, 0x185, 0x187, 0x189, 0x18b, 0x18d, 0x18f, 0x195, 0x19d, 0x1a1, 0x1a4, 0x1a6, 0x1a8, 0x1aa, 0x1ad, 0x1af, 0x1b1, 0x1b3, 0x1b5, 0x1bb, 0x1be, 0x1c0, 0x1c7, 0x1cd, 0x1d3, 0x1db, 0x1e1, 0x1e7, 0x1ed, 0x1f1, 0x1ff, 0x208, 0x20b, 0x20e, 0x210, 0x213, 0x215, 0x218, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x227, 0x229, 0x22b, 0x231, 0x234, 0x237, 0x23f, 0x246, 0x249, 0x24b, 0x253, 0x25a, 0x25d, 0x263, 0x265, 0x268, 0x26a, 0x26c, 0x26e, 0x27b, 0x285, 0x287, 0x289, 0x28b} + +// nfcSparseValues: 653 entries, 2612 bytes +var nfcSparseValues = [653]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0000, lo: 0x04}, + {value: 0xa100, lo: 0xa8, hi: 0xa8}, + {value: 0x8100, lo: 0xaf, hi: 0xaf}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb8, hi: 0xb8}, + // Block 0x1, offset 0x5 + {value: 0x0091, lo: 0x03}, + {value: 0x471d, lo: 0xa0, hi: 0xa1}, + {value: 0x474f, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x9 + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + // Block 0x3, offset 0xb + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x98, hi: 0x9d}, + // Block 0x4, offset 0xd + {value: 0x0006, lo: 0x0a}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x85, hi: 0x85}, + {value: 0xa000, lo: 0x89, hi: 0x89}, + {value: 0x487b, lo: 0x8a, hi: 0x8a}, + {value: 0x4899, lo: 0x8b, hi: 0x8b}, + {value: 0x3702, lo: 0x8c, hi: 0x8c}, + {value: 0x371a, lo: 0x8d, hi: 0x8d}, + {value: 0x48b1, lo: 0x8e, hi: 0x8e}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x3738, lo: 0x93, hi: 0x94}, + // Block 0x5, offset 0x18 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x37e0, lo: 0x90, hi: 0x90}, + {value: 0x37ec, lo: 0x91, hi: 0x91}, + {value: 0x37da, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x3852, lo: 0x97, hi: 0x97}, + {value: 0x381c, lo: 0x9c, hi: 0x9c}, + {value: 0x3804, lo: 0x9d, hi: 0x9d}, + {value: 0x382e, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x3858, lo: 0xb6, hi: 0xb6}, + {value: 0x385e, lo: 0xb7, hi: 0xb7}, + // Block 0x6, offset 0x28 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x7, offset 0x2a + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x8, offset 0x2f + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x387c, lo: 0xa2, hi: 0xa2}, + {value: 0x3882, lo: 0xa3, hi: 0xa3}, + {value: 0x388e, lo: 0xa4, hi: 0xa4}, + {value: 0x3888, lo: 0xa5, hi: 0xa5}, + {value: 0x3894, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x9, offset 0x3a + {value: 0x0000, lo: 0x0e}, + {value: 0x38a6, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x389a, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x38a0, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0xa, offset 0x49 + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xb, offset 0x56 + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xc, offset 0x5e + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xd, offset 0x62 + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xe, offset 0x67 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xf, offset 0x69 + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbf}, + // Block 0x10, offset 0x78 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3f13, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3f1b, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3f23, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x11, offset 0x80 + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x4557, lo: 0x98, hi: 0x9f}, + // Block 0x12, offset 0x87 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x13, offset 0x8a + {value: 0x0007, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18e1, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x4597, lo: 0x9c, hi: 0x9c}, + {value: 0x459f, lo: 0x9d, hi: 0x9d}, + {value: 0x45a7, lo: 0x9f, hi: 0x9f}, + // Block 0x14, offset 0x92 + {value: 0x0000, lo: 0x03}, + {value: 0x45cf, lo: 0xb3, hi: 0xb3}, + {value: 0x45d7, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x15, offset 0x96 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x45af, lo: 0x99, hi: 0x9b}, + {value: 0x45c7, lo: 0x9e, hi: 0x9e}, + // Block 0x16, offset 0x9a + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x17, offset 0x9c + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x18, offset 0x9e + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18f6, lo: 0x88, hi: 0x88}, + {value: 0x18ef, lo: 0x8b, hi: 0x8b}, + {value: 0x18fd, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x45df, lo: 0x9c, hi: 0x9c}, + {value: 0x45e7, lo: 0x9d, hi: 0x9d}, + // Block 0x19, offset 0xa7 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x1904, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1a, offset 0xab + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x190b, lo: 0x8a, hi: 0x8a}, + {value: 0x1919, lo: 0x8b, hi: 0x8b}, + {value: 0x1912, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1b, offset 0xb2 + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3f2b, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1c, offset 0xb7 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1d, offset 0xba + {value: 0x0000, lo: 0x09}, + {value: 0x1920, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x1927, lo: 0x87, hi: 0x87}, + {value: 0x192e, lo: 0x88, hi: 0x88}, + {value: 0x2eb7, lo: 0x8a, hi: 0x8a}, + {value: 0x19f6, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1e, offset 0xc4 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1f, offset 0xc6 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x1935, lo: 0x8a, hi: 0x8a}, + {value: 0x1943, lo: 0x8b, hi: 0x8b}, + {value: 0x193c, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x20, offset 0xcd + {value: 0x0007, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3f33, lo: 0x9a, hi: 0x9a}, + {value: 0x2ebe, lo: 0x9c, hi: 0x9d}, + {value: 0x194a, lo: 0x9e, hi: 0x9e}, + {value: 0x9900, lo: 0x9f, hi: 0x9f}, + // Block 0x21, offset 0xd5 + {value: 0x0000, lo: 0x02}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x22, offset 0xd8 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x23, offset 0xda + {value: 0x0000, lo: 0x01}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x24, offset 0xdc + {value: 0x0000, lo: 0x01}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + // Block 0x25, offset 0xde + {value: 0x0000, lo: 0x04}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x26, offset 0xe3 + {value: 0x0000, lo: 0x10}, + {value: 0x27d7, lo: 0x83, hi: 0x83}, + {value: 0x27de, lo: 0x8d, hi: 0x8d}, + {value: 0x27e5, lo: 0x92, hi: 0x92}, + {value: 0x27ec, lo: 0x97, hi: 0x97}, + {value: 0x27f3, lo: 0x9c, hi: 0x9c}, + {value: 0x27d0, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x4a0b, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x4a14, lo: 0xb5, hi: 0xb5}, + {value: 0x45ef, lo: 0xb6, hi: 0xb6}, + {value: 0x8200, lo: 0xb7, hi: 0xb7}, + {value: 0x45f7, lo: 0xb8, hi: 0xb8}, + {value: 0x8200, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x27, offset 0xf4 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x4a1d, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x2801, lo: 0x93, hi: 0x93}, + {value: 0x2808, lo: 0x9d, hi: 0x9d}, + {value: 0x280f, lo: 0xa2, hi: 0xa2}, + {value: 0x2816, lo: 0xa7, hi: 0xa7}, + {value: 0x281d, lo: 0xac, hi: 0xac}, + {value: 0x27fa, lo: 0xb9, hi: 0xb9}, + // Block 0x28, offset 0x100 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x29, offset 0x102 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x1951, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x2a, offset 0x108 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2b, offset 0x10a + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x10c + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x10e + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x110 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x112 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x114 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x117 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x11a + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x11c + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x11f + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x122 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x126 + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + {value: 0x812d, lo: 0xb5, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x37, offset 0x12b + {value: 0x0000, lo: 0x08}, + {value: 0x1990, lo: 0x80, hi: 0x80}, + {value: 0x1997, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x199e, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x38, offset 0x134 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x39, offset 0x136 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x3a, offset 0x139 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3b, offset 0x13b + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb8, hi: 0xb9}, + // Block 0x3c, offset 0x146 + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0x80, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x82}, + {value: 0x8132, lo: 0x83, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8a}, + {value: 0x8132, lo: 0x8b, hi: 0x8c}, + {value: 0x8135, lo: 0x8d, hi: 0x8d}, + {value: 0x812a, lo: 0x8e, hi: 0x8e}, + {value: 0x812d, lo: 0x8f, hi: 0x8f}, + {value: 0x8129, lo: 0x90, hi: 0x90}, + {value: 0x8132, lo: 0x91, hi: 0xb5}, + {value: 0x8134, lo: 0xbc, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + {value: 0x8132, lo: 0xbe, hi: 0xbe}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x155 + {value: 0x0004, lo: 0x03}, + {value: 0x04ab, lo: 0x80, hi: 0x81}, + {value: 0x8100, lo: 0x97, hi: 0x97}, + {value: 0x8100, lo: 0xbe, hi: 0xbe}, + // Block 0x3e, offset 0x159 + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x3f, offset 0x167 + {value: 0x42b6, lo: 0x02}, + {value: 0x01b8, lo: 0xa6, hi: 0xa6}, + {value: 0x0057, lo: 0xaa, hi: 0xab}, + // Block 0x40, offset 0x16a + {value: 0x0007, lo: 0x05}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3bf4, lo: 0x9a, hi: 0x9b}, + {value: 0x3c02, lo: 0xae, hi: 0xae}, + // Block 0x41, offset 0x170 + {value: 0x000e, lo: 0x05}, + {value: 0x3c09, lo: 0x8d, hi: 0x8e}, + {value: 0x3c10, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x42, offset 0x176 + {value: 0x63cd, lo: 0x0a}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3c1e, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3c25, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3c2c, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3c33, lo: 0xa4, hi: 0xa5}, + {value: 0x3c3a, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x43, offset 0x181 + {value: 0x0007, lo: 0x03}, + {value: 0x3ca3, lo: 0xa0, hi: 0xa1}, + {value: 0x3ccd, lo: 0xa2, hi: 0xa3}, + {value: 0x3cf7, lo: 0xaa, hi: 0xad}, + // Block 0x44, offset 0x185 + {value: 0x0004, lo: 0x01}, + {value: 0x0503, lo: 0xa9, hi: 0xaa}, + // Block 0x45, offset 0x187 + {value: 0x0000, lo: 0x01}, + {value: 0x4518, lo: 0x9c, hi: 0x9c}, + // Block 0x46, offset 0x189 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x47, offset 0x18b + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x48, offset 0x18d + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x49, offset 0x18f + {value: 0x0000, lo: 0x05}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xaf}, + // Block 0x4a, offset 0x195 + {value: 0x0000, lo: 0x07}, + {value: 0x8100, lo: 0x84, hi: 0x84}, + {value: 0x8100, lo: 0x87, hi: 0x87}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + {value: 0x8100, lo: 0x9e, hi: 0x9e}, + {value: 0x8100, lo: 0xa1, hi: 0xa1}, + {value: 0x8100, lo: 0xb2, hi: 0xb2}, + {value: 0x8100, lo: 0xbb, hi: 0xbb}, + // Block 0x4b, offset 0x19d + {value: 0x0000, lo: 0x03}, + {value: 0x8100, lo: 0x80, hi: 0x80}, + {value: 0x8100, lo: 0x8b, hi: 0x8b}, + {value: 0x8100, lo: 0x8e, hi: 0x8e}, + // Block 0x4c, offset 0x1a1 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x4d, offset 0x1a4 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9f, hi: 0x9f}, + // Block 0x4e, offset 0x1a6 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x4f, offset 0x1a8 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x50, offset 0x1aa + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x51, offset 0x1ad + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x52, offset 0x1af + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x53, offset 0x1b1 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x54, offset 0x1b3 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x55, offset 0x1b5 + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x56, offset 0x1bb + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x57, offset 0x1be + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x58, offset 0x1c0 + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x59, offset 0x1c7 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x5a, offset 0x1cd + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x5b, offset 0x1d3 + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x5c, offset 0x1db + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x5d, offset 0x1e1 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x5e, offset 0x1e7 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x5f, offset 0x1ed + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x60, offset 0x1f1 + {value: 0x0006, lo: 0x0d}, + {value: 0x43cb, lo: 0x9d, hi: 0x9d}, + {value: 0x8115, lo: 0x9e, hi: 0x9e}, + {value: 0x443d, lo: 0x9f, hi: 0x9f}, + {value: 0x442b, lo: 0xaa, hi: 0xab}, + {value: 0x452f, lo: 0xac, hi: 0xac}, + {value: 0x4537, lo: 0xad, hi: 0xad}, + {value: 0x4383, lo: 0xae, hi: 0xb1}, + {value: 0x43a1, lo: 0xb2, hi: 0xb4}, + {value: 0x43b9, lo: 0xb5, hi: 0xb6}, + {value: 0x43c5, lo: 0xb8, hi: 0xb8}, + {value: 0x43d1, lo: 0xb9, hi: 0xbb}, + {value: 0x43e9, lo: 0xbc, hi: 0xbc}, + {value: 0x43ef, lo: 0xbe, hi: 0xbe}, + // Block 0x61, offset 0x1ff + {value: 0x0006, lo: 0x08}, + {value: 0x43f5, lo: 0x80, hi: 0x81}, + {value: 0x4401, lo: 0x83, hi: 0x84}, + {value: 0x4413, lo: 0x86, hi: 0x89}, + {value: 0x4437, lo: 0x8a, hi: 0x8a}, + {value: 0x43b3, lo: 0x8b, hi: 0x8b}, + {value: 0x439b, lo: 0x8c, hi: 0x8c}, + {value: 0x43e3, lo: 0x8d, hi: 0x8d}, + {value: 0x440d, lo: 0x8e, hi: 0x8e}, + // Block 0x62, offset 0x208 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0xa4, hi: 0xa5}, + {value: 0x8100, lo: 0xb0, hi: 0xb1}, + // Block 0x63, offset 0x20b + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x9b, hi: 0x9d}, + {value: 0x8200, lo: 0x9e, hi: 0xa3}, + // Block 0x64, offset 0x20e + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x90, hi: 0x90}, + // Block 0x65, offset 0x210 + {value: 0x0000, lo: 0x02}, + {value: 0x8100, lo: 0x99, hi: 0x99}, + {value: 0x8200, lo: 0xb2, hi: 0xb4}, + // Block 0x66, offset 0x213 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xbc, hi: 0xbd}, + // Block 0x67, offset 0x215 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa0, hi: 0xa6}, + {value: 0x812d, lo: 0xa7, hi: 0xad}, + // Block 0x68, offset 0x218 + {value: 0x0000, lo: 0x04}, + {value: 0x8100, lo: 0x89, hi: 0x8c}, + {value: 0x8100, lo: 0xb0, hi: 0xb2}, + {value: 0x8100, lo: 0xb4, hi: 0xb4}, + {value: 0x8100, lo: 0xb6, hi: 0xbf}, + // Block 0x69, offset 0x21d + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x81, hi: 0x8c}, + // Block 0x6a, offset 0x21f + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xb5, hi: 0xba}, + // Block 0x6b, offset 0x221 + {value: 0x0000, lo: 0x01}, + {value: 0x4a26, lo: 0x9e, hi: 0x9f}, + // Block 0x6c, offset 0x223 + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0xa3, hi: 0xa3}, + // Block 0x6d, offset 0x225 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x6e, offset 0x227 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xa0, hi: 0xa0}, + // Block 0x6f, offset 0x229 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb6, hi: 0xba}, + // Block 0x70, offset 0x22b + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x71, offset 0x231 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa5, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + // Block 0x72, offset 0x234 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x73, offset 0x237 + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x4273, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x427d, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x4287, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x74, offset 0x23f + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x19a5, lo: 0xae, hi: 0xae}, + {value: 0x19ae, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x75, offset 0x246 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb5, hi: 0xb5}, + {value: 0x8102, lo: 0xb6, hi: 0xb6}, + // Block 0x76, offset 0x249 + {value: 0x0002, lo: 0x01}, + {value: 0x8102, lo: 0xa9, hi: 0xaa}, + // Block 0x77, offset 0x24b + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x19b7, lo: 0x8b, hi: 0x8b}, + {value: 0x19c0, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x8132, lo: 0xa6, hi: 0xac}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + // Block 0x78, offset 0x253 + {value: 0x7f37, lo: 0x06}, + {value: 0x9900, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xb9, hi: 0xb9}, + {value: 0x9900, lo: 0xba, hi: 0xba}, + {value: 0x19d2, lo: 0xbb, hi: 0xbb}, + {value: 0x19c9, lo: 0xbc, hi: 0xbd}, + {value: 0x19db, lo: 0xbe, hi: 0xbe}, + // Block 0x79, offset 0x25a + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x83, hi: 0x83}, + // Block 0x7a, offset 0x25d + {value: 0x0000, lo: 0x05}, + {value: 0x9900, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb8, hi: 0xb9}, + {value: 0x19e4, lo: 0xba, hi: 0xba}, + {value: 0x19ed, lo: 0xbb, hi: 0xbb}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7b, offset 0x263 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0x80, hi: 0x80}, + // Block 0x7c, offset 0x265 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x7d, offset 0x268 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0xb0, hi: 0xb4}, + // Block 0x7e, offset 0x26a + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb6}, + // Block 0x7f, offset 0x26c + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0x9e, hi: 0x9e}, + // Block 0x80, offset 0x26e + {value: 0x0000, lo: 0x0c}, + {value: 0x4607, lo: 0x9e, hi: 0x9e}, + {value: 0x4611, lo: 0x9f, hi: 0x9f}, + {value: 0x4645, lo: 0xa0, hi: 0xa0}, + {value: 0x4653, lo: 0xa1, hi: 0xa1}, + {value: 0x4661, lo: 0xa2, hi: 0xa2}, + {value: 0x466f, lo: 0xa3, hi: 0xa3}, + {value: 0x467d, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x81, offset 0x27b + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x461b, lo: 0xbb, hi: 0xbb}, + {value: 0x4625, lo: 0xbc, hi: 0xbc}, + {value: 0x468b, lo: 0xbd, hi: 0xbd}, + {value: 0x46a7, lo: 0xbe, hi: 0xbe}, + {value: 0x4699, lo: 0xbf, hi: 0xbf}, + // Block 0x82, offset 0x285 + {value: 0x0000, lo: 0x01}, + {value: 0x46b5, lo: 0x80, hi: 0x80}, + // Block 0x83, offset 0x287 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x84, offset 0x289 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x90, hi: 0x96}, + // Block 0x85, offset 0x28b + {value: 0x0000, lo: 0x01}, + {value: 0x8100, lo: 0x93, hi: 0x93}, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfkcTrie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfkcValues[c0], 1 + case c0 < 0xC0: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfkcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfkcTrie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfkcValues[c0] + } + i := nfkcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *nfkcTrie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return nfkcValues[c0], 1 + case c0 < 0xC0: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := nfkcIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = nfkcIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = nfkcIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return nfkcValues[c0] + } + i := nfkcIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = nfkcIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// nfkcTrie. Total size: 16752 bytes (16.36 KiB). Checksum: 5cd2e697fcf78b3e. +type nfkcTrie struct{} + +func newNfkcTrie(i int) *nfkcTrie { + return &nfkcTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 { + switch { + case n < 88: + return uint16(nfkcValues[n<<6+uint32(b)]) + default: + n -= 88 + return uint16(nfkcSparse.lookup(n, b)) + } +} + +// nfkcValues: 90 blocks, 5760 entries, 11520 bytes +// The third block is the zero block. +var nfkcValues = [5760]uint16{ + // Block 0x0, offset 0x0 + 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, + // Block 0x1, offset 0x40 + 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000, + 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000, + 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000, + 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000, + 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000, + 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000, + 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000, + 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000, + 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000, + 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x2faa, 0xc1: 0x2faf, 0xc2: 0x46c3, 0xc3: 0x2fb4, 0xc4: 0x46d2, 0xc5: 0x46d7, + 0xc6: 0xa000, 0xc7: 0x46e1, 0xc8: 0x301d, 0xc9: 0x3022, 0xca: 0x46e6, 0xcb: 0x3036, + 0xcc: 0x30a9, 0xcd: 0x30ae, 0xce: 0x30b3, 0xcf: 0x46fa, 0xd1: 0x313f, + 0xd2: 0x3162, 0xd3: 0x3167, 0xd4: 0x4704, 0xd5: 0x4709, 0xd6: 0x4718, + 0xd8: 0xa000, 0xd9: 0x31ee, 0xda: 0x31f3, 0xdb: 0x31f8, 0xdc: 0x474a, 0xdd: 0x3270, + 0xe0: 0x32b6, 0xe1: 0x32bb, 0xe2: 0x4754, 0xe3: 0x32c0, + 0xe4: 0x4763, 0xe5: 0x4768, 0xe6: 0xa000, 0xe7: 0x4772, 0xe8: 0x3329, 0xe9: 0x332e, + 0xea: 0x4777, 0xeb: 0x3342, 0xec: 0x33ba, 0xed: 0x33bf, 0xee: 0x33c4, 0xef: 0x478b, + 0xf1: 0x3450, 0xf2: 0x3473, 0xf3: 0x3478, 0xf4: 0x4795, 0xf5: 0x479a, + 0xf6: 0x47a9, 0xf8: 0xa000, 0xf9: 0x3504, 0xfa: 0x3509, 0xfb: 0x350e, + 0xfc: 0x47db, 0xfd: 0x358b, 0xff: 0x35a4, + // Block 0x4, offset 0x100 + 0x100: 0x2fb9, 0x101: 0x32c5, 0x102: 0x46c8, 0x103: 0x4759, 0x104: 0x2fd7, 0x105: 0x32e3, + 0x106: 0x2feb, 0x107: 0x32f7, 0x108: 0x2ff0, 0x109: 0x32fc, 0x10a: 0x2ff5, 0x10b: 0x3301, + 0x10c: 0x2ffa, 0x10d: 0x3306, 0x10e: 0x3004, 0x10f: 0x3310, + 0x112: 0x46eb, 0x113: 0x477c, 0x114: 0x302c, 0x115: 0x3338, 0x116: 0x3031, 0x117: 0x333d, + 0x118: 0x304f, 0x119: 0x335b, 0x11a: 0x3040, 0x11b: 0x334c, 0x11c: 0x3068, 0x11d: 0x3374, + 0x11e: 0x3072, 0x11f: 0x337e, 0x120: 0x3077, 0x121: 0x3383, 0x122: 0x3081, 0x123: 0x338d, + 0x124: 0x3086, 0x125: 0x3392, 0x128: 0x30b8, 0x129: 0x33c9, + 0x12a: 0x30bd, 0x12b: 0x33ce, 0x12c: 0x30c2, 0x12d: 0x33d3, 0x12e: 0x30e5, 0x12f: 0x33f1, + 0x130: 0x30c7, 0x132: 0x1af0, 0x133: 0x1b7a, 0x134: 0x30ef, 0x135: 0x33fb, + 0x136: 0x3103, 0x137: 0x3414, 0x139: 0x310d, 0x13a: 0x341e, 0x13b: 0x3117, + 0x13c: 0x3428, 0x13d: 0x3112, 0x13e: 0x3423, 0x13f: 0x1d3f, + // Block 0x5, offset 0x140 + 0x140: 0x1dc7, 0x143: 0x313a, 0x144: 0x344b, 0x145: 0x3153, + 0x146: 0x3464, 0x147: 0x3149, 0x148: 0x345a, 0x149: 0x1def, + 0x14c: 0x470e, 0x14d: 0x479f, 0x14e: 0x316c, 0x14f: 0x347d, 0x150: 0x3176, 0x151: 0x3487, + 0x154: 0x3194, 0x155: 0x34a5, 0x156: 0x31ad, 0x157: 0x34be, + 0x158: 0x319e, 0x159: 0x34af, 0x15a: 0x4731, 0x15b: 0x47c2, 0x15c: 0x31b7, 0x15d: 0x34c8, + 0x15e: 0x31c6, 0x15f: 0x34d7, 0x160: 0x4736, 0x161: 0x47c7, 0x162: 0x31df, 0x163: 0x34f5, + 0x164: 0x31d0, 0x165: 0x34e6, 0x168: 0x4740, 0x169: 0x47d1, + 0x16a: 0x4745, 0x16b: 0x47d6, 0x16c: 0x31fd, 0x16d: 0x3513, 0x16e: 0x3207, 0x16f: 0x351d, + 0x170: 0x320c, 0x171: 0x3522, 0x172: 0x322a, 0x173: 0x3540, 0x174: 0x324d, 0x175: 0x3563, + 0x176: 0x3275, 0x177: 0x3590, 0x178: 0x3289, 0x179: 0x3298, 0x17a: 0x35b8, 0x17b: 0x32a2, + 0x17c: 0x35c2, 0x17d: 0x32a7, 0x17e: 0x35c7, 0x17f: 0x00a7, + // Block 0x6, offset 0x180 + 0x184: 0x2ed0, 0x185: 0x2ed6, + 0x186: 0x2edc, 0x187: 0x1b05, 0x188: 0x1b08, 0x189: 0x1b9b, 0x18a: 0x1b1a, 0x18b: 0x1b1d, + 0x18c: 0x1bd1, 0x18d: 0x2fc3, 0x18e: 0x32cf, 0x18f: 0x30d1, 0x190: 0x33dd, 0x191: 0x317b, + 0x192: 0x348c, 0x193: 0x3211, 0x194: 0x3527, 0x195: 0x3a0a, 0x196: 0x3b99, 0x197: 0x3a03, + 0x198: 0x3b92, 0x199: 0x3a11, 0x19a: 0x3ba0, 0x19b: 0x39fc, 0x19c: 0x3b8b, + 0x19e: 0x38eb, 0x19f: 0x3a7a, 0x1a0: 0x38e4, 0x1a1: 0x3a73, 0x1a2: 0x35ee, 0x1a3: 0x3600, + 0x1a6: 0x307c, 0x1a7: 0x3388, 0x1a8: 0x30f9, 0x1a9: 0x340a, + 0x1aa: 0x4727, 0x1ab: 0x47b8, 0x1ac: 0x39cb, 0x1ad: 0x3b5a, 0x1ae: 0x3612, 0x1af: 0x3618, + 0x1b0: 0x3400, 0x1b1: 0x1ad5, 0x1b2: 0x1ad8, 0x1b3: 0x1b62, 0x1b4: 0x3063, 0x1b5: 0x336f, + 0x1b8: 0x3135, 0x1b9: 0x3446, 0x1ba: 0x38f2, 0x1bb: 0x3a81, + 0x1bc: 0x35e8, 0x1bd: 0x35fa, 0x1be: 0x35f4, 0x1bf: 0x3606, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x2fc8, 0x1c1: 0x32d4, 0x1c2: 0x2fcd, 0x1c3: 0x32d9, 0x1c4: 0x3045, 0x1c5: 0x3351, + 0x1c6: 0x304a, 0x1c7: 0x3356, 0x1c8: 0x30d6, 0x1c9: 0x33e2, 0x1ca: 0x30db, 0x1cb: 0x33e7, + 0x1cc: 0x3180, 0x1cd: 0x3491, 0x1ce: 0x3185, 0x1cf: 0x3496, 0x1d0: 0x31a3, 0x1d1: 0x34b4, + 0x1d2: 0x31a8, 0x1d3: 0x34b9, 0x1d4: 0x3216, 0x1d5: 0x352c, 0x1d6: 0x321b, 0x1d7: 0x3531, + 0x1d8: 0x31c1, 0x1d9: 0x34d2, 0x1da: 0x31da, 0x1db: 0x34f0, + 0x1de: 0x3095, 0x1df: 0x33a1, + 0x1e6: 0x46cd, 0x1e7: 0x475e, 0x1e8: 0x46f5, 0x1e9: 0x4786, + 0x1ea: 0x399a, 0x1eb: 0x3b29, 0x1ec: 0x3977, 0x1ed: 0x3b06, 0x1ee: 0x4713, 0x1ef: 0x47a4, + 0x1f0: 0x3993, 0x1f1: 0x3b22, 0x1f2: 0x327f, 0x1f3: 0x359a, + // Block 0x8, offset 0x200 + 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132, + 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932, + 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932, + 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d, + 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d, + 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d, + 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d, + 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d, + 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101, + 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d, + 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132, + // Block 0x9, offset 0x240 + 0x240: 0x49e9, 0x241: 0x49ee, 0x242: 0x9932, 0x243: 0x49f3, 0x244: 0x49f8, 0x245: 0x9936, + 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132, + 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132, + 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132, + 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135, + 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132, + 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132, + 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132, + 0x274: 0x0170, + 0x27a: 0x42e0, + 0x27e: 0x0037, + // Block 0xa, offset 0x280 + 0x284: 0x4295, 0x285: 0x44b6, + 0x286: 0x3624, 0x287: 0x00ce, 0x288: 0x3642, 0x289: 0x364e, 0x28a: 0x3660, + 0x28c: 0x367e, 0x28e: 0x3690, 0x28f: 0x36ae, 0x290: 0x3e43, 0x291: 0xa000, + 0x295: 0xa000, 0x297: 0xa000, + 0x299: 0xa000, + 0x29f: 0xa000, 0x2a1: 0xa000, + 0x2a5: 0xa000, 0x2a9: 0xa000, + 0x2aa: 0x3672, 0x2ab: 0x36a2, 0x2ac: 0x4839, 0x2ad: 0x36d2, 0x2ae: 0x4863, 0x2af: 0x36e4, + 0x2b0: 0x3eab, 0x2b1: 0xa000, 0x2b5: 0xa000, + 0x2b7: 0xa000, 0x2b9: 0xa000, + 0x2bf: 0xa000, + // Block 0xb, offset 0x2c0 + 0x2c1: 0xa000, 0x2c5: 0xa000, + 0x2c9: 0xa000, 0x2ca: 0x487b, 0x2cb: 0x4899, + 0x2cc: 0x3702, 0x2cd: 0x371a, 0x2ce: 0x48b1, 0x2d0: 0x01be, 0x2d1: 0x01d0, + 0x2d2: 0x01ac, 0x2d3: 0x4347, 0x2d4: 0x434d, 0x2d5: 0x01fa, 0x2d6: 0x01e8, + 0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7, + 0x2f9: 0x01a6, + // Block 0xc, offset 0x300 + 0x300: 0x375c, 0x301: 0x3768, 0x303: 0x3756, + 0x306: 0xa000, 0x307: 0x3744, + 0x30c: 0x3798, 0x30d: 0x3780, 0x30e: 0x37aa, 0x310: 0xa000, + 0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000, + 0x318: 0xa000, 0x319: 0x378c, 0x31a: 0xa000, + 0x31e: 0xa000, 0x323: 0xa000, + 0x327: 0xa000, + 0x32b: 0xa000, 0x32d: 0xa000, + 0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000, + 0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x3810, 0x33a: 0xa000, + 0x33e: 0xa000, + // Block 0xd, offset 0x340 + 0x341: 0x376e, 0x342: 0x37f2, + 0x350: 0x374a, 0x351: 0x37ce, + 0x352: 0x3750, 0x353: 0x37d4, 0x356: 0x3762, 0x357: 0x37e6, + 0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3864, 0x35b: 0x386a, 0x35c: 0x3774, 0x35d: 0x37f8, + 0x35e: 0x377a, 0x35f: 0x37fe, 0x362: 0x3786, 0x363: 0x380a, + 0x364: 0x3792, 0x365: 0x3816, 0x366: 0x379e, 0x367: 0x3822, 0x368: 0xa000, 0x369: 0xa000, + 0x36a: 0x3870, 0x36b: 0x3876, 0x36c: 0x37c8, 0x36d: 0x384c, 0x36e: 0x37a4, 0x36f: 0x3828, + 0x370: 0x37b0, 0x371: 0x3834, 0x372: 0x37b6, 0x373: 0x383a, 0x374: 0x37bc, 0x375: 0x3840, + 0x378: 0x37c2, 0x379: 0x3846, + // Block 0xe, offset 0x380 + 0x387: 0x1ef4, + 0x391: 0x812d, + 0x392: 0x8132, 0x393: 0x8132, 0x394: 0x8132, 0x395: 0x8132, 0x396: 0x812d, 0x397: 0x8132, + 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x812e, 0x39b: 0x812d, 0x39c: 0x8132, 0x39d: 0x8132, + 0x39e: 0x8132, 0x39f: 0x8132, 0x3a0: 0x8132, 0x3a1: 0x8132, 0x3a2: 0x812d, 0x3a3: 0x812d, + 0x3a4: 0x812d, 0x3a5: 0x812d, 0x3a6: 0x812d, 0x3a7: 0x812d, 0x3a8: 0x8132, 0x3a9: 0x8132, + 0x3aa: 0x812d, 0x3ab: 0x8132, 0x3ac: 0x8132, 0x3ad: 0x812e, 0x3ae: 0x8131, 0x3af: 0x8132, + 0x3b0: 0x8105, 0x3b1: 0x8106, 0x3b2: 0x8107, 0x3b3: 0x8108, 0x3b4: 0x8109, 0x3b5: 0x810a, + 0x3b6: 0x810b, 0x3b7: 0x810c, 0x3b8: 0x810d, 0x3b9: 0x810e, 0x3ba: 0x810e, 0x3bb: 0x810f, + 0x3bc: 0x8110, 0x3bd: 0x8111, 0x3bf: 0x8112, + // Block 0xf, offset 0x3c0 + 0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8116, + 0x3cc: 0x8117, 0x3cd: 0x8118, 0x3ce: 0x8119, 0x3cf: 0x811a, 0x3d0: 0x811b, 0x3d1: 0x811c, + 0x3d2: 0x811d, 0x3d3: 0x9932, 0x3d4: 0x9932, 0x3d5: 0x992d, 0x3d6: 0x812d, 0x3d7: 0x8132, + 0x3d8: 0x8132, 0x3d9: 0x8132, 0x3da: 0x8132, 0x3db: 0x8132, 0x3dc: 0x812d, 0x3dd: 0x8132, + 0x3de: 0x8132, 0x3df: 0x812d, + 0x3f0: 0x811e, 0x3f5: 0x1f17, + 0x3f6: 0x21a6, 0x3f7: 0x21e2, 0x3f8: 0x21dd, + // Block 0x10, offset 0x400 + 0x405: 0xa000, + 0x406: 0x1958, 0x407: 0xa000, 0x408: 0x195f, 0x409: 0xa000, 0x40a: 0x1966, 0x40b: 0xa000, + 0x40c: 0x196d, 0x40d: 0xa000, 0x40e: 0x1974, 0x411: 0xa000, + 0x412: 0x197b, + 0x434: 0x8102, 0x435: 0x9900, + 0x43a: 0xa000, 0x43b: 0x1982, + 0x43c: 0xa000, 0x43d: 0x1989, 0x43e: 0xa000, 0x43f: 0xa000, + // Block 0x11, offset 0x440 + 0x440: 0x0069, 0x441: 0x006b, 0x442: 0x006f, 0x443: 0x0083, 0x444: 0x00f5, 0x445: 0x00f8, + 0x446: 0x048b, 0x447: 0x0085, 0x448: 0x0089, 0x449: 0x008b, 0x44a: 0x0104, 0x44b: 0x0107, + 0x44c: 0x010a, 0x44d: 0x008f, 0x44f: 0x0097, 0x450: 0x009b, 0x451: 0x00e0, + 0x452: 0x009f, 0x453: 0x00fe, 0x454: 0x048f, 0x455: 0x0493, 0x456: 0x00a1, 0x457: 0x00a9, + 0x458: 0x00ab, 0x459: 0x049b, 0x45a: 0x012b, 0x45b: 0x00ad, 0x45c: 0x049f, 0x45d: 0x01be, + 0x45e: 0x01c1, 0x45f: 0x01c4, 0x460: 0x01fa, 0x461: 0x01fd, 0x462: 0x0093, 0x463: 0x00a5, + 0x464: 0x00ab, 0x465: 0x00ad, 0x466: 0x01be, 0x467: 0x01c1, 0x468: 0x01eb, 0x469: 0x01fa, + 0x46a: 0x01fd, + 0x478: 0x020c, + // Block 0x12, offset 0x480 + 0x49b: 0x00fb, 0x49c: 0x0087, 0x49d: 0x0101, + 0x49e: 0x00d4, 0x49f: 0x010a, 0x4a0: 0x008d, 0x4a1: 0x010d, 0x4a2: 0x0110, 0x4a3: 0x0116, + 0x4a4: 0x011c, 0x4a5: 0x011f, 0x4a6: 0x0122, 0x4a7: 0x04a3, 0x4a8: 0x016a, 0x4a9: 0x0128, + 0x4aa: 0x04a7, 0x4ab: 0x016d, 0x4ac: 0x0131, 0x4ad: 0x012e, 0x4ae: 0x0134, 0x4af: 0x0137, + 0x4b0: 0x013a, 0x4b1: 0x013d, 0x4b2: 0x0140, 0x4b3: 0x014c, 0x4b4: 0x014f, 0x4b5: 0x00ec, + 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x0497, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5, + 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x2fd2, 0x4c1: 0x32de, 0x4c2: 0x2fdc, 0x4c3: 0x32e8, 0x4c4: 0x2fe1, 0x4c5: 0x32ed, + 0x4c6: 0x2fe6, 0x4c7: 0x32f2, 0x4c8: 0x3907, 0x4c9: 0x3a96, 0x4ca: 0x2fff, 0x4cb: 0x330b, + 0x4cc: 0x3009, 0x4cd: 0x3315, 0x4ce: 0x3018, 0x4cf: 0x3324, 0x4d0: 0x300e, 0x4d1: 0x331a, + 0x4d2: 0x3013, 0x4d3: 0x331f, 0x4d4: 0x392a, 0x4d5: 0x3ab9, 0x4d6: 0x3931, 0x4d7: 0x3ac0, + 0x4d8: 0x3054, 0x4d9: 0x3360, 0x4da: 0x3059, 0x4db: 0x3365, 0x4dc: 0x393f, 0x4dd: 0x3ace, + 0x4de: 0x305e, 0x4df: 0x336a, 0x4e0: 0x306d, 0x4e1: 0x3379, 0x4e2: 0x308b, 0x4e3: 0x3397, + 0x4e4: 0x309a, 0x4e5: 0x33a6, 0x4e6: 0x3090, 0x4e7: 0x339c, 0x4e8: 0x309f, 0x4e9: 0x33ab, + 0x4ea: 0x30a4, 0x4eb: 0x33b0, 0x4ec: 0x30ea, 0x4ed: 0x33f6, 0x4ee: 0x3946, 0x4ef: 0x3ad5, + 0x4f0: 0x30f4, 0x4f1: 0x3405, 0x4f2: 0x30fe, 0x4f3: 0x340f, 0x4f4: 0x3108, 0x4f5: 0x3419, + 0x4f6: 0x46ff, 0x4f7: 0x4790, 0x4f8: 0x394d, 0x4f9: 0x3adc, 0x4fa: 0x3121, 0x4fb: 0x3432, + 0x4fc: 0x311c, 0x4fd: 0x342d, 0x4fe: 0x3126, 0x4ff: 0x3437, + // Block 0x14, offset 0x500 + 0x500: 0x312b, 0x501: 0x343c, 0x502: 0x3130, 0x503: 0x3441, 0x504: 0x3144, 0x505: 0x3455, + 0x506: 0x314e, 0x507: 0x345f, 0x508: 0x315d, 0x509: 0x346e, 0x50a: 0x3158, 0x50b: 0x3469, + 0x50c: 0x3970, 0x50d: 0x3aff, 0x50e: 0x397e, 0x50f: 0x3b0d, 0x510: 0x3985, 0x511: 0x3b14, + 0x512: 0x398c, 0x513: 0x3b1b, 0x514: 0x318a, 0x515: 0x349b, 0x516: 0x318f, 0x517: 0x34a0, + 0x518: 0x3199, 0x519: 0x34aa, 0x51a: 0x472c, 0x51b: 0x47bd, 0x51c: 0x39d2, 0x51d: 0x3b61, + 0x51e: 0x31b2, 0x51f: 0x34c3, 0x520: 0x31bc, 0x521: 0x34cd, 0x522: 0x473b, 0x523: 0x47cc, + 0x524: 0x39d9, 0x525: 0x3b68, 0x526: 0x39e0, 0x527: 0x3b6f, 0x528: 0x39e7, 0x529: 0x3b76, + 0x52a: 0x31cb, 0x52b: 0x34dc, 0x52c: 0x31d5, 0x52d: 0x34eb, 0x52e: 0x31e9, 0x52f: 0x34ff, + 0x530: 0x31e4, 0x531: 0x34fa, 0x532: 0x3225, 0x533: 0x353b, 0x534: 0x3234, 0x535: 0x354a, + 0x536: 0x322f, 0x537: 0x3545, 0x538: 0x39ee, 0x539: 0x3b7d, 0x53a: 0x39f5, 0x53b: 0x3b84, + 0x53c: 0x3239, 0x53d: 0x354f, 0x53e: 0x323e, 0x53f: 0x3554, + // Block 0x15, offset 0x540 + 0x540: 0x3243, 0x541: 0x3559, 0x542: 0x3248, 0x543: 0x355e, 0x544: 0x3257, 0x545: 0x356d, + 0x546: 0x3252, 0x547: 0x3568, 0x548: 0x325c, 0x549: 0x3577, 0x54a: 0x3261, 0x54b: 0x357c, + 0x54c: 0x3266, 0x54d: 0x3581, 0x54e: 0x3284, 0x54f: 0x359f, 0x550: 0x329d, 0x551: 0x35bd, + 0x552: 0x32ac, 0x553: 0x35cc, 0x554: 0x32b1, 0x555: 0x35d1, 0x556: 0x33b5, 0x557: 0x34e1, + 0x558: 0x3572, 0x559: 0x35ae, 0x55a: 0x1d73, 0x55b: 0x4312, + 0x560: 0x46dc, 0x561: 0x476d, 0x562: 0x2fbe, 0x563: 0x32ca, + 0x564: 0x38b3, 0x565: 0x3a42, 0x566: 0x38ac, 0x567: 0x3a3b, 0x568: 0x38c1, 0x569: 0x3a50, + 0x56a: 0x38ba, 0x56b: 0x3a49, 0x56c: 0x38f9, 0x56d: 0x3a88, 0x56e: 0x38cf, 0x56f: 0x3a5e, + 0x570: 0x38c8, 0x571: 0x3a57, 0x572: 0x38dd, 0x573: 0x3a6c, 0x574: 0x38d6, 0x575: 0x3a65, + 0x576: 0x3900, 0x577: 0x3a8f, 0x578: 0x46f0, 0x579: 0x4781, 0x57a: 0x303b, 0x57b: 0x3347, + 0x57c: 0x3027, 0x57d: 0x3333, 0x57e: 0x3915, 0x57f: 0x3aa4, + // Block 0x16, offset 0x580 + 0x580: 0x390e, 0x581: 0x3a9d, 0x582: 0x3923, 0x583: 0x3ab2, 0x584: 0x391c, 0x585: 0x3aab, + 0x586: 0x3938, 0x587: 0x3ac7, 0x588: 0x30cc, 0x589: 0x33d8, 0x58a: 0x30e0, 0x58b: 0x33ec, + 0x58c: 0x4722, 0x58d: 0x47b3, 0x58e: 0x3171, 0x58f: 0x3482, 0x590: 0x395b, 0x591: 0x3aea, + 0x592: 0x3954, 0x593: 0x3ae3, 0x594: 0x3969, 0x595: 0x3af8, 0x596: 0x3962, 0x597: 0x3af1, + 0x598: 0x39c4, 0x599: 0x3b53, 0x59a: 0x39a8, 0x59b: 0x3b37, 0x59c: 0x39a1, 0x59d: 0x3b30, + 0x59e: 0x39b6, 0x59f: 0x3b45, 0x5a0: 0x39af, 0x5a1: 0x3b3e, 0x5a2: 0x39bd, 0x5a3: 0x3b4c, + 0x5a4: 0x3220, 0x5a5: 0x3536, 0x5a6: 0x3202, 0x5a7: 0x3518, 0x5a8: 0x3a1f, 0x5a9: 0x3bae, + 0x5aa: 0x3a18, 0x5ab: 0x3ba7, 0x5ac: 0x3a2d, 0x5ad: 0x3bbc, 0x5ae: 0x3a26, 0x5af: 0x3bb5, + 0x5b0: 0x3a34, 0x5b1: 0x3bc3, 0x5b2: 0x326b, 0x5b3: 0x3586, 0x5b4: 0x3293, 0x5b5: 0x35b3, + 0x5b6: 0x328e, 0x5b7: 0x35a9, 0x5b8: 0x327a, 0x5b9: 0x3595, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x483f, 0x5c1: 0x4845, 0x5c2: 0x4959, 0x5c3: 0x4971, 0x5c4: 0x4961, 0x5c5: 0x4979, + 0x5c6: 0x4969, 0x5c7: 0x4981, 0x5c8: 0x47e5, 0x5c9: 0x47eb, 0x5ca: 0x48c9, 0x5cb: 0x48e1, + 0x5cc: 0x48d1, 0x5cd: 0x48e9, 0x5ce: 0x48d9, 0x5cf: 0x48f1, 0x5d0: 0x4851, 0x5d1: 0x4857, + 0x5d2: 0x3df3, 0x5d3: 0x3e03, 0x5d4: 0x3dfb, 0x5d5: 0x3e0b, + 0x5d8: 0x47f1, 0x5d9: 0x47f7, 0x5da: 0x3d23, 0x5db: 0x3d33, 0x5dc: 0x3d2b, 0x5dd: 0x3d3b, + 0x5e0: 0x4869, 0x5e1: 0x486f, 0x5e2: 0x4989, 0x5e3: 0x49a1, + 0x5e4: 0x4991, 0x5e5: 0x49a9, 0x5e6: 0x4999, 0x5e7: 0x49b1, 0x5e8: 0x47fd, 0x5e9: 0x4803, + 0x5ea: 0x48f9, 0x5eb: 0x4911, 0x5ec: 0x4901, 0x5ed: 0x4919, 0x5ee: 0x4909, 0x5ef: 0x4921, + 0x5f0: 0x4881, 0x5f1: 0x4887, 0x5f2: 0x3e53, 0x5f3: 0x3e6b, 0x5f4: 0x3e5b, 0x5f5: 0x3e73, + 0x5f6: 0x3e63, 0x5f7: 0x3e7b, 0x5f8: 0x4809, 0x5f9: 0x480f, 0x5fa: 0x3d53, 0x5fb: 0x3d6b, + 0x5fc: 0x3d5b, 0x5fd: 0x3d73, 0x5fe: 0x3d63, 0x5ff: 0x3d7b, + // Block 0x18, offset 0x600 + 0x600: 0x488d, 0x601: 0x4893, 0x602: 0x3e83, 0x603: 0x3e93, 0x604: 0x3e8b, 0x605: 0x3e9b, + 0x608: 0x4815, 0x609: 0x481b, 0x60a: 0x3d83, 0x60b: 0x3d93, + 0x60c: 0x3d8b, 0x60d: 0x3d9b, 0x610: 0x489f, 0x611: 0x48a5, + 0x612: 0x3ebb, 0x613: 0x3ed3, 0x614: 0x3ec3, 0x615: 0x3edb, 0x616: 0x3ecb, 0x617: 0x3ee3, + 0x619: 0x4821, 0x61b: 0x3da3, 0x61d: 0x3dab, + 0x61f: 0x3db3, 0x620: 0x48b7, 0x621: 0x48bd, 0x622: 0x49b9, 0x623: 0x49d1, + 0x624: 0x49c1, 0x625: 0x49d9, 0x626: 0x49c9, 0x627: 0x49e1, 0x628: 0x4827, 0x629: 0x482d, + 0x62a: 0x4929, 0x62b: 0x4941, 0x62c: 0x4931, 0x62d: 0x4949, 0x62e: 0x4939, 0x62f: 0x4951, + 0x630: 0x4833, 0x631: 0x4359, 0x632: 0x36cc, 0x633: 0x435f, 0x634: 0x485d, 0x635: 0x4365, + 0x636: 0x36de, 0x637: 0x436b, 0x638: 0x36fc, 0x639: 0x4371, 0x63a: 0x3714, 0x63b: 0x4377, + 0x63c: 0x48ab, 0x63d: 0x437d, + // Block 0x19, offset 0x640 + 0x640: 0x3ddb, 0x641: 0x3de3, 0x642: 0x41bf, 0x643: 0x41dd, 0x644: 0x41c9, 0x645: 0x41e7, + 0x646: 0x41d3, 0x647: 0x41f1, 0x648: 0x3d13, 0x649: 0x3d1b, 0x64a: 0x410b, 0x64b: 0x4129, + 0x64c: 0x4115, 0x64d: 0x4133, 0x64e: 0x411f, 0x64f: 0x413d, 0x650: 0x3e23, 0x651: 0x3e2b, + 0x652: 0x41fb, 0x653: 0x4219, 0x654: 0x4205, 0x655: 0x4223, 0x656: 0x420f, 0x657: 0x422d, + 0x658: 0x3d43, 0x659: 0x3d4b, 0x65a: 0x4147, 0x65b: 0x4165, 0x65c: 0x4151, 0x65d: 0x416f, + 0x65e: 0x415b, 0x65f: 0x4179, 0x660: 0x3efb, 0x661: 0x3f03, 0x662: 0x4237, 0x663: 0x4255, + 0x664: 0x4241, 0x665: 0x425f, 0x666: 0x424b, 0x667: 0x4269, 0x668: 0x3dbb, 0x669: 0x3dc3, + 0x66a: 0x4183, 0x66b: 0x41a1, 0x66c: 0x418d, 0x66d: 0x41ab, 0x66e: 0x4197, 0x66f: 0x41b5, + 0x670: 0x36c0, 0x671: 0x36ba, 0x672: 0x3dcb, 0x673: 0x36c6, 0x674: 0x3dd3, + 0x676: 0x484b, 0x677: 0x3deb, 0x678: 0x3630, 0x679: 0x362a, 0x67a: 0x361e, 0x67b: 0x4329, + 0x67c: 0x3636, 0x67d: 0x42c2, 0x67e: 0x01d3, 0x67f: 0x42c2, + // Block 0x1a, offset 0x680 + 0x680: 0x42db, 0x681: 0x44bd, 0x682: 0x3e13, 0x683: 0x36d8, 0x684: 0x3e1b, + 0x686: 0x4875, 0x687: 0x3e33, 0x688: 0x363c, 0x689: 0x432f, 0x68a: 0x3648, 0x68b: 0x4335, + 0x68c: 0x3654, 0x68d: 0x44c4, 0x68e: 0x44cb, 0x68f: 0x44d2, 0x690: 0x36f0, 0x691: 0x36ea, + 0x692: 0x3e3b, 0x693: 0x451f, 0x696: 0x36f6, 0x697: 0x3e4b, + 0x698: 0x366c, 0x699: 0x3666, 0x69a: 0x365a, 0x69b: 0x433b, 0x69d: 0x44d9, + 0x69e: 0x44e0, 0x69f: 0x44e7, 0x6a0: 0x3726, 0x6a1: 0x3720, 0x6a2: 0x3ea3, 0x6a3: 0x4527, + 0x6a4: 0x3708, 0x6a5: 0x370e, 0x6a6: 0x372c, 0x6a7: 0x3eb3, 0x6a8: 0x369c, 0x6a9: 0x3696, + 0x6aa: 0x368a, 0x6ab: 0x4347, 0x6ac: 0x3684, 0x6ad: 0x44af, 0x6ae: 0x44b6, 0x6af: 0x0081, + 0x6b2: 0x3eeb, 0x6b3: 0x3732, 0x6b4: 0x3ef3, + 0x6b6: 0x48c3, 0x6b7: 0x3f0b, 0x6b8: 0x3678, 0x6b9: 0x4341, 0x6ba: 0x36a8, 0x6bb: 0x4353, + 0x6bc: 0x36b4, 0x6bd: 0x4295, 0x6be: 0x42c7, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x1d6b, 0x6c1: 0x1d6f, 0x6c2: 0x0047, 0x6c3: 0x1de7, 0x6c5: 0x1d7b, + 0x6c6: 0x1d7f, 0x6c7: 0x00e9, 0x6c9: 0x1deb, 0x6ca: 0x008f, 0x6cb: 0x0051, + 0x6cc: 0x0051, 0x6cd: 0x0051, 0x6ce: 0x0091, 0x6cf: 0x00da, 0x6d0: 0x0053, 0x6d1: 0x0053, + 0x6d2: 0x0059, 0x6d3: 0x0099, 0x6d5: 0x005d, 0x6d6: 0x1b20, + 0x6d9: 0x0061, 0x6da: 0x0063, 0x6db: 0x0065, 0x6dc: 0x0065, 0x6dd: 0x0065, + 0x6e0: 0x1b32, 0x6e1: 0x1d5b, 0x6e2: 0x1b3b, + 0x6e4: 0x0075, 0x6e6: 0x01b8, 0x6e8: 0x0075, + 0x6ea: 0x0057, 0x6eb: 0x430d, 0x6ec: 0x0045, 0x6ed: 0x0047, 0x6ef: 0x008b, + 0x6f0: 0x004b, 0x6f1: 0x004d, 0x6f3: 0x005b, 0x6f4: 0x009f, 0x6f5: 0x0215, + 0x6f6: 0x0218, 0x6f7: 0x021b, 0x6f8: 0x021e, 0x6f9: 0x0093, 0x6fb: 0x1d2b, + 0x6fc: 0x01e8, 0x6fd: 0x01c1, 0x6fe: 0x0179, 0x6ff: 0x01a0, + // Block 0x1c, offset 0x700 + 0x700: 0x04db, 0x705: 0x0049, + 0x706: 0x0089, 0x707: 0x008b, 0x708: 0x0093, 0x709: 0x0095, + 0x710: 0x23c1, 0x711: 0x23cd, + 0x712: 0x2481, 0x713: 0x23a9, 0x714: 0x242d, 0x715: 0x23b5, 0x716: 0x2433, 0x717: 0x244b, + 0x718: 0x2457, 0x719: 0x23bb, 0x71a: 0x245d, 0x71b: 0x23c7, 0x71c: 0x2451, 0x71d: 0x2463, + 0x71e: 0x2469, 0x71f: 0x1e4f, 0x720: 0x0053, 0x721: 0x1aed, 0x722: 0x1d37, 0x723: 0x1af6, + 0x724: 0x006d, 0x725: 0x1b3e, 0x726: 0x1d63, 0x727: 0x1edb, 0x728: 0x1af9, 0x729: 0x0071, + 0x72a: 0x1b4a, 0x72b: 0x1d67, 0x72c: 0x0059, 0x72d: 0x0047, 0x72e: 0x0049, 0x72f: 0x005b, + 0x730: 0x0093, 0x731: 0x1b77, 0x732: 0x1dab, 0x733: 0x1b80, 0x734: 0x00ad, 0x735: 0x1bf5, + 0x736: 0x1ddf, 0x737: 0x1eef, 0x738: 0x1b83, 0x739: 0x00b1, 0x73a: 0x1bf8, 0x73b: 0x1de3, + 0x73c: 0x0099, 0x73d: 0x0087, 0x73e: 0x0089, 0x73f: 0x009b, + // Block 0x1d, offset 0x740 + 0x741: 0x3c41, 0x743: 0xa000, 0x744: 0x3c48, 0x745: 0xa000, + 0x747: 0x3c4f, 0x748: 0xa000, 0x749: 0x3c56, + 0x74d: 0xa000, + 0x760: 0x2fa0, 0x761: 0xa000, 0x762: 0x3c64, + 0x764: 0xa000, 0x765: 0xa000, + 0x76d: 0x3c5d, 0x76e: 0x2f9b, 0x76f: 0x2fa5, + 0x770: 0x3c6b, 0x771: 0x3c72, 0x772: 0xa000, 0x773: 0xa000, 0x774: 0x3c79, 0x775: 0x3c80, + 0x776: 0xa000, 0x777: 0xa000, 0x778: 0x3c87, 0x779: 0x3c8e, 0x77a: 0xa000, 0x77b: 0xa000, + 0x77c: 0xa000, 0x77d: 0xa000, + // Block 0x1e, offset 0x780 + 0x780: 0x3c95, 0x781: 0x3c9c, 0x782: 0xa000, 0x783: 0xa000, 0x784: 0x3cb1, 0x785: 0x3cb8, + 0x786: 0xa000, 0x787: 0xa000, 0x788: 0x3cbf, 0x789: 0x3cc6, + 0x791: 0xa000, + 0x792: 0xa000, + 0x7a2: 0xa000, + 0x7a8: 0xa000, 0x7a9: 0xa000, + 0x7ab: 0xa000, 0x7ac: 0x3cdb, 0x7ad: 0x3ce2, 0x7ae: 0x3ce9, 0x7af: 0x3cf0, + 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0xa000, 0x7b5: 0xa000, + // Block 0x1f, offset 0x7c0 + 0x7e0: 0x0023, 0x7e1: 0x0025, 0x7e2: 0x0027, 0x7e3: 0x0029, + 0x7e4: 0x002b, 0x7e5: 0x002d, 0x7e6: 0x002f, 0x7e7: 0x0031, 0x7e8: 0x0033, 0x7e9: 0x1a15, + 0x7ea: 0x1a18, 0x7eb: 0x1a1b, 0x7ec: 0x1a1e, 0x7ed: 0x1a21, 0x7ee: 0x1a24, 0x7ef: 0x1a27, + 0x7f0: 0x1a2a, 0x7f1: 0x1a2d, 0x7f2: 0x1a30, 0x7f3: 0x1a39, 0x7f4: 0x1bfb, 0x7f5: 0x1bff, + 0x7f6: 0x1c03, 0x7f7: 0x1c07, 0x7f8: 0x1c0b, 0x7f9: 0x1c0f, 0x7fa: 0x1c13, 0x7fb: 0x1c17, + 0x7fc: 0x1c1b, 0x7fd: 0x1e13, 0x7fe: 0x1e18, 0x7ff: 0x1e1d, + // Block 0x20, offset 0x800 + 0x800: 0x1e22, 0x801: 0x1e27, 0x802: 0x1e2c, 0x803: 0x1e31, 0x804: 0x1e36, 0x805: 0x1e3b, + 0x806: 0x1e40, 0x807: 0x1e45, 0x808: 0x1a12, 0x809: 0x1a36, 0x80a: 0x1a5a, 0x80b: 0x1a7e, + 0x80c: 0x1aa2, 0x80d: 0x1aab, 0x80e: 0x1ab1, 0x80f: 0x1ab7, 0x810: 0x1abd, 0x811: 0x1cf3, + 0x812: 0x1cf7, 0x813: 0x1cfb, 0x814: 0x1cff, 0x815: 0x1d03, 0x816: 0x1d07, 0x817: 0x1d0b, + 0x818: 0x1d0f, 0x819: 0x1d13, 0x81a: 0x1d17, 0x81b: 0x1d1b, 0x81c: 0x1c87, 0x81d: 0x1c8b, + 0x81e: 0x1c8f, 0x81f: 0x1c93, 0x820: 0x1c97, 0x821: 0x1c9b, 0x822: 0x1c9f, 0x823: 0x1ca3, + 0x824: 0x1ca7, 0x825: 0x1cab, 0x826: 0x1caf, 0x827: 0x1cb3, 0x828: 0x1cb7, 0x829: 0x1cbb, + 0x82a: 0x1cbf, 0x82b: 0x1cc3, 0x82c: 0x1cc7, 0x82d: 0x1ccb, 0x82e: 0x1ccf, 0x82f: 0x1cd3, + 0x830: 0x1cd7, 0x831: 0x1cdb, 0x832: 0x1cdf, 0x833: 0x1ce3, 0x834: 0x1ce7, 0x835: 0x1ceb, + 0x836: 0x0043, 0x837: 0x0045, 0x838: 0x0047, 0x839: 0x0049, 0x83a: 0x004b, 0x83b: 0x004d, + 0x83c: 0x004f, 0x83d: 0x0051, 0x83e: 0x0053, 0x83f: 0x0055, + // Block 0x21, offset 0x840 + 0x840: 0x0737, 0x841: 0x075b, 0x842: 0x0767, 0x843: 0x0777, 0x844: 0x077f, 0x845: 0x078b, + 0x846: 0x0793, 0x847: 0x079b, 0x848: 0x07a7, 0x849: 0x07fb, 0x84a: 0x0813, 0x84b: 0x0823, + 0x84c: 0x0833, 0x84d: 0x0843, 0x84e: 0x0853, 0x84f: 0x0873, 0x850: 0x0877, 0x851: 0x087b, + 0x852: 0x08af, 0x853: 0x08d7, 0x854: 0x08e7, 0x855: 0x08ef, 0x856: 0x08f3, 0x857: 0x08ff, + 0x858: 0x091b, 0x859: 0x091f, 0x85a: 0x0937, 0x85b: 0x093b, 0x85c: 0x0943, 0x85d: 0x0953, + 0x85e: 0x09ef, 0x85f: 0x0a03, 0x860: 0x0a43, 0x861: 0x0a57, 0x862: 0x0a5f, 0x863: 0x0a63, + 0x864: 0x0a73, 0x865: 0x0a8f, 0x866: 0x0abb, 0x867: 0x0ac7, 0x868: 0x0ae7, 0x869: 0x0af3, + 0x86a: 0x0af7, 0x86b: 0x0afb, 0x86c: 0x0b13, 0x86d: 0x0b17, 0x86e: 0x0b43, 0x86f: 0x0b4f, + 0x870: 0x0b57, 0x871: 0x0b5f, 0x872: 0x0b6f, 0x873: 0x0b77, 0x874: 0x0b7f, 0x875: 0x0bab, + 0x876: 0x0baf, 0x877: 0x0bb7, 0x878: 0x0bbb, 0x879: 0x0bc3, 0x87a: 0x0bcb, 0x87b: 0x0bdb, + 0x87c: 0x0bf7, 0x87d: 0x0c6f, 0x87e: 0x0c83, 0x87f: 0x0c87, + // Block 0x22, offset 0x880 + 0x880: 0x0d07, 0x881: 0x0d0b, 0x882: 0x0d1f, 0x883: 0x0d23, 0x884: 0x0d2b, 0x885: 0x0d33, + 0x886: 0x0d3b, 0x887: 0x0d47, 0x888: 0x0d6f, 0x889: 0x0d7f, 0x88a: 0x0d93, 0x88b: 0x0e03, + 0x88c: 0x0e0f, 0x88d: 0x0e1f, 0x88e: 0x0e2b, 0x88f: 0x0e37, 0x890: 0x0e3f, 0x891: 0x0e43, + 0x892: 0x0e47, 0x893: 0x0e4b, 0x894: 0x0e4f, 0x895: 0x0f07, 0x896: 0x0f4f, 0x897: 0x0f5b, + 0x898: 0x0f5f, 0x899: 0x0f63, 0x89a: 0x0f67, 0x89b: 0x0f6f, 0x89c: 0x0f73, 0x89d: 0x0f87, + 0x89e: 0x0fa3, 0x89f: 0x0fab, 0x8a0: 0x0feb, 0x8a1: 0x0fef, 0x8a2: 0x0ff7, 0x8a3: 0x0ffb, + 0x8a4: 0x1003, 0x8a5: 0x1007, 0x8a6: 0x102b, 0x8a7: 0x102f, 0x8a8: 0x104b, 0x8a9: 0x104f, + 0x8aa: 0x1053, 0x8ab: 0x1057, 0x8ac: 0x106b, 0x8ad: 0x108f, 0x8ae: 0x1093, 0x8af: 0x1097, + 0x8b0: 0x10bb, 0x8b1: 0x10fb, 0x8b2: 0x10ff, 0x8b3: 0x111f, 0x8b4: 0x112f, 0x8b5: 0x1137, + 0x8b6: 0x1157, 0x8b7: 0x117b, 0x8b8: 0x11bf, 0x8b9: 0x11c7, 0x8ba: 0x11db, 0x8bb: 0x11e7, + 0x8bc: 0x11ef, 0x8bd: 0x11f7, 0x8be: 0x11fb, 0x8bf: 0x11ff, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x1217, 0x8c1: 0x121b, 0x8c2: 0x1237, 0x8c3: 0x123f, 0x8c4: 0x1247, 0x8c5: 0x124b, + 0x8c6: 0x1257, 0x8c7: 0x125f, 0x8c8: 0x1263, 0x8c9: 0x1267, 0x8ca: 0x126f, 0x8cb: 0x1273, + 0x8cc: 0x1313, 0x8cd: 0x1327, 0x8ce: 0x135b, 0x8cf: 0x135f, 0x8d0: 0x1367, 0x8d1: 0x1393, + 0x8d2: 0x139b, 0x8d3: 0x13a3, 0x8d4: 0x13ab, 0x8d5: 0x13e7, 0x8d6: 0x13eb, 0x8d7: 0x13f3, + 0x8d8: 0x13f7, 0x8d9: 0x13fb, 0x8da: 0x1427, 0x8db: 0x142b, 0x8dc: 0x1433, 0x8dd: 0x1447, + 0x8de: 0x144b, 0x8df: 0x1467, 0x8e0: 0x146f, 0x8e1: 0x1473, 0x8e2: 0x1497, 0x8e3: 0x14b7, + 0x8e4: 0x14c7, 0x8e5: 0x14cb, 0x8e6: 0x14d3, 0x8e7: 0x14ff, 0x8e8: 0x1503, 0x8e9: 0x1513, + 0x8ea: 0x1537, 0x8eb: 0x1543, 0x8ec: 0x1553, 0x8ed: 0x156b, 0x8ee: 0x1573, 0x8ef: 0x1577, + 0x8f0: 0x157b, 0x8f1: 0x157f, 0x8f2: 0x158b, 0x8f3: 0x158f, 0x8f4: 0x1597, 0x8f5: 0x15b3, + 0x8f6: 0x15b7, 0x8f7: 0x15bb, 0x8f8: 0x15d3, 0x8f9: 0x15d7, 0x8fa: 0x15df, 0x8fb: 0x15f3, + 0x8fc: 0x15f7, 0x8fd: 0x15fb, 0x8fe: 0x1603, 0x8ff: 0x1607, + // Block 0x24, offset 0x900 + 0x906: 0xa000, 0x90b: 0xa000, + 0x90c: 0x3f43, 0x90d: 0xa000, 0x90e: 0x3f4b, 0x90f: 0xa000, 0x910: 0x3f53, 0x911: 0xa000, + 0x912: 0x3f5b, 0x913: 0xa000, 0x914: 0x3f63, 0x915: 0xa000, 0x916: 0x3f6b, 0x917: 0xa000, + 0x918: 0x3f73, 0x919: 0xa000, 0x91a: 0x3f7b, 0x91b: 0xa000, 0x91c: 0x3f83, 0x91d: 0xa000, + 0x91e: 0x3f8b, 0x91f: 0xa000, 0x920: 0x3f93, 0x921: 0xa000, 0x922: 0x3f9b, + 0x924: 0xa000, 0x925: 0x3fa3, 0x926: 0xa000, 0x927: 0x3fab, 0x928: 0xa000, 0x929: 0x3fb3, + 0x92f: 0xa000, + 0x930: 0x3fbb, 0x931: 0x3fc3, 0x932: 0xa000, 0x933: 0x3fcb, 0x934: 0x3fd3, 0x935: 0xa000, + 0x936: 0x3fdb, 0x937: 0x3fe3, 0x938: 0xa000, 0x939: 0x3feb, 0x93a: 0x3ff3, 0x93b: 0xa000, + 0x93c: 0x3ffb, 0x93d: 0x4003, + // Block 0x25, offset 0x940 + 0x954: 0x3f3b, + 0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x4317, 0x95c: 0x431d, 0x95d: 0xa000, + 0x95e: 0x400b, 0x95f: 0x28b0, + 0x966: 0xa000, + 0x96b: 0xa000, 0x96c: 0x401b, 0x96d: 0xa000, 0x96e: 0x4023, 0x96f: 0xa000, + 0x970: 0x402b, 0x971: 0xa000, 0x972: 0x4033, 0x973: 0xa000, 0x974: 0x403b, 0x975: 0xa000, + 0x976: 0x4043, 0x977: 0xa000, 0x978: 0x404b, 0x979: 0xa000, 0x97a: 0x4053, 0x97b: 0xa000, + 0x97c: 0x405b, 0x97d: 0xa000, 0x97e: 0x4063, 0x97f: 0xa000, + // Block 0x26, offset 0x980 + 0x980: 0x406b, 0x981: 0xa000, 0x982: 0x4073, 0x984: 0xa000, 0x985: 0x407b, + 0x986: 0xa000, 0x987: 0x4083, 0x988: 0xa000, 0x989: 0x408b, + 0x98f: 0xa000, 0x990: 0x4093, 0x991: 0x409b, + 0x992: 0xa000, 0x993: 0x40a3, 0x994: 0x40ab, 0x995: 0xa000, 0x996: 0x40b3, 0x997: 0x40bb, + 0x998: 0xa000, 0x999: 0x40c3, 0x99a: 0x40cb, 0x99b: 0xa000, 0x99c: 0x40d3, 0x99d: 0x40db, + 0x9af: 0xa000, + 0x9b0: 0xa000, 0x9b1: 0xa000, 0x9b2: 0xa000, 0x9b4: 0x4013, + 0x9b7: 0x40e3, 0x9b8: 0x40eb, 0x9b9: 0x40f3, 0x9ba: 0x40fb, + 0x9bd: 0xa000, 0x9be: 0x4103, 0x9bf: 0x28c5, + // Block 0x27, offset 0x9c0 + 0x9c0: 0x03af, 0x9c1: 0x03b3, 0x9c2: 0x0483, 0x9c3: 0x0487, 0x9c4: 0x03b7, 0x9c5: 0x03bb, + 0x9c6: 0x03bf, 0x9c7: 0x041b, 0x9c8: 0x041f, 0x9c9: 0x0423, 0x9ca: 0x0427, 0x9cb: 0x042b, + 0x9cc: 0x042f, 0x9cd: 0x0433, 0x9ce: 0x0437, + 0x9d2: 0x0737, 0x9d3: 0x0793, 0x9d4: 0x0743, 0x9d5: 0x09f3, 0x9d6: 0x0747, 0x9d7: 0x075f, + 0x9d8: 0x074b, 0x9d9: 0x100b, 0x9da: 0x077f, 0x9db: 0x0753, 0x9dc: 0x073b, 0x9dd: 0x0a77, + 0x9de: 0x0a07, 0x9df: 0x07a7, + // Block 0x28, offset 0xa00 + 0xa00: 0x21e7, 0xa01: 0x21ed, 0xa02: 0x21f3, 0xa03: 0x21f9, 0xa04: 0x21ff, 0xa05: 0x2205, + 0xa06: 0x220b, 0xa07: 0x2211, 0xa08: 0x2217, 0xa09: 0x221d, 0xa0a: 0x2223, 0xa0b: 0x2229, + 0xa0c: 0x222f, 0xa0d: 0x2235, 0xa0e: 0x2922, 0xa0f: 0x292b, 0xa10: 0x2934, 0xa11: 0x293d, + 0xa12: 0x2946, 0xa13: 0x294f, 0xa14: 0x2958, 0xa15: 0x2961, 0xa16: 0x296a, 0xa17: 0x297c, + 0xa18: 0x2985, 0xa19: 0x298e, 0xa1a: 0x2997, 0xa1b: 0x29a0, 0xa1c: 0x2973, 0xa1d: 0x2dc5, + 0xa1e: 0x2cf6, 0xa20: 0x223b, 0xa21: 0x2253, 0xa22: 0x2247, 0xa23: 0x229b, + 0xa24: 0x2259, 0xa25: 0x2277, 0xa26: 0x2241, 0xa27: 0x2271, 0xa28: 0x224d, 0xa29: 0x2283, + 0xa2a: 0x22b3, 0xa2b: 0x22d1, 0xa2c: 0x22cb, 0xa2d: 0x22bf, 0xa2e: 0x230d, 0xa2f: 0x22a1, + 0xa30: 0x22ad, 0xa31: 0x22c5, 0xa32: 0x22b9, 0xa33: 0x22e3, 0xa34: 0x228f, 0xa35: 0x22d7, + 0xa36: 0x2301, 0xa37: 0x22e9, 0xa38: 0x227d, 0xa39: 0x225f, 0xa3a: 0x2295, 0xa3b: 0x22a7, + 0xa3c: 0x22dd, 0xa3d: 0x2265, 0xa3e: 0x2307, 0xa3f: 0x2289, + // Block 0x29, offset 0xa40 + 0xa40: 0x22ef, 0xa41: 0x226b, 0xa42: 0x22f5, 0xa43: 0x22fb, 0xa44: 0x09a7, 0xa45: 0x0b7b, + 0xa46: 0x0d1f, 0xa47: 0x113f, + 0xa50: 0x1d57, 0xa51: 0x1a3c, + 0xa52: 0x1a3f, 0xa53: 0x1a42, 0xa54: 0x1a45, 0xa55: 0x1a48, 0xa56: 0x1a4b, 0xa57: 0x1a4e, + 0xa58: 0x1a51, 0xa59: 0x1a54, 0xa5a: 0x1a5d, 0xa5b: 0x1a60, 0xa5c: 0x1a63, 0xa5d: 0x1a66, + 0xa5e: 0x1a69, 0xa5f: 0x1a6c, 0xa60: 0x0313, 0xa61: 0x031b, 0xa62: 0x031f, 0xa63: 0x0327, + 0xa64: 0x032b, 0xa65: 0x032f, 0xa66: 0x0337, 0xa67: 0x033f, 0xa68: 0x0343, 0xa69: 0x034b, + 0xa6a: 0x034f, 0xa6b: 0x0353, 0xa6c: 0x0357, 0xa6d: 0x035b, 0xa6e: 0x2824, 0xa6f: 0x282b, + 0xa70: 0x2832, 0xa71: 0x2839, 0xa72: 0x2840, 0xa73: 0x2847, 0xa74: 0x284e, 0xa75: 0x2855, + 0xa76: 0x2863, 0xa77: 0x286a, 0xa78: 0x2871, 0xa79: 0x2878, 0xa7a: 0x287f, 0xa7b: 0x2886, + 0xa7c: 0x2d15, 0xa7d: 0x2b8a, 0xa7e: 0x285c, + // Block 0x2a, offset 0xa80 + 0xa80: 0x0737, 0xa81: 0x0793, 0xa82: 0x0743, 0xa83: 0x09f3, 0xa84: 0x0797, 0xa85: 0x0827, + 0xa86: 0x073f, 0xa87: 0x0823, 0xa88: 0x0783, 0xa89: 0x08ff, 0xa8a: 0x0d7f, 0xa8b: 0x0f07, + 0xa8c: 0x0e4f, 0xa8d: 0x0d93, 0xa8e: 0x14d3, 0xa8f: 0x0a03, 0xa90: 0x0d47, 0xa91: 0x0dc3, + 0xa92: 0x0d83, 0xa93: 0x10c3, 0xa94: 0x0973, 0xa95: 0x0f7b, 0xa96: 0x13ff, 0xa97: 0x10d7, + 0xa98: 0x08bb, 0xa99: 0x1107, 0xa9a: 0x1013, 0xa9b: 0x0a8f, 0xa9c: 0x1487, 0xa9d: 0x07f7, + 0xa9e: 0x0923, 0xa9f: 0x0e6f, 0xaa0: 0x159b, 0xaa1: 0x07bb, 0xaa2: 0x084b, 0xaa3: 0x0e13, + 0xaa4: 0x0747, 0xaa5: 0x075f, 0xaa6: 0x074b, 0xaa7: 0x0b53, 0xaa8: 0x0967, 0xaa9: 0x08f7, + 0xaaa: 0x0acf, 0xaab: 0x0ac3, 0xaac: 0x1063, 0xaad: 0x07b7, 0xaae: 0x1413, 0xaaf: 0x0913, + 0xab0: 0x0a6b, 0xab1: 0x1a6f, 0xab2: 0x1a72, 0xab3: 0x1a75, 0xab4: 0x1a78, 0xab5: 0x1a81, + 0xab6: 0x1a84, 0xab7: 0x1a87, 0xab8: 0x1a8a, 0xab9: 0x1a8d, 0xaba: 0x1a90, 0xabb: 0x1a93, + 0xabc: 0x1a96, 0xabd: 0x1a99, 0xabe: 0x1a9c, 0xabf: 0x1aa5, + // Block 0x2b, offset 0xac0 + 0xac0: 0x1e59, 0xac1: 0x1e68, 0xac2: 0x1e77, 0xac3: 0x1e86, 0xac4: 0x1e95, 0xac5: 0x1ea4, + 0xac6: 0x1eb3, 0xac7: 0x1ec2, 0xac8: 0x1ed1, 0xac9: 0x231f, 0xaca: 0x2331, 0xacb: 0x2343, + 0xacc: 0x1ae7, 0xacd: 0x1d97, 0xace: 0x1b65, 0xacf: 0x1d3b, 0xad0: 0x0543, 0xad1: 0x054b, + 0xad2: 0x0553, 0xad3: 0x055b, 0xad4: 0x0563, 0xad5: 0x0567, 0xad6: 0x056b, 0xad7: 0x056f, + 0xad8: 0x0573, 0xad9: 0x0577, 0xada: 0x057b, 0xadb: 0x057f, 0xadc: 0x0583, 0xadd: 0x0587, + 0xade: 0x058b, 0xadf: 0x058f, 0xae0: 0x0593, 0xae1: 0x059b, 0xae2: 0x059f, 0xae3: 0x05a3, + 0xae4: 0x05a7, 0xae5: 0x05ab, 0xae6: 0x05af, 0xae7: 0x05b3, 0xae8: 0x05b7, 0xae9: 0x05bb, + 0xaea: 0x05bf, 0xaeb: 0x05c3, 0xaec: 0x05c7, 0xaed: 0x05cb, 0xaee: 0x05cf, 0xaef: 0x05d3, + 0xaf0: 0x05d7, 0xaf1: 0x05db, 0xaf2: 0x05df, 0xaf3: 0x05e7, 0xaf4: 0x05ef, 0xaf5: 0x05f7, + 0xaf6: 0x05fb, 0xaf7: 0x05ff, 0xaf8: 0x0603, 0xaf9: 0x0607, 0xafa: 0x060b, 0xafb: 0x060f, + 0xafc: 0x0613, 0xafd: 0x0617, 0xafe: 0x061b, + // Block 0x2c, offset 0xb00 + 0xb00: 0x2d25, 0xb01: 0x2bb1, 0xb02: 0x2d35, 0xb03: 0x2a7c, 0xb04: 0x2f2f, 0xb05: 0x2a86, + 0xb06: 0x2a90, 0xb07: 0x2f73, 0xb08: 0x2bbe, 0xb09: 0x2a9a, 0xb0a: 0x2aa4, 0xb0b: 0x2aae, + 0xb0c: 0x2be5, 0xb0d: 0x2bf2, 0xb0e: 0x2bcb, 0xb0f: 0x2bd8, 0xb10: 0x2f05, 0xb11: 0x2bff, + 0xb12: 0x2c0c, 0xb13: 0x2dd7, 0xb14: 0x28b7, 0xb15: 0x2dea, 0xb16: 0x2dfd, 0xb17: 0x2d45, + 0xb18: 0x2c19, 0xb19: 0x2e10, 0xb1a: 0x2e23, 0xb1b: 0x2c26, 0xb1c: 0x2ab8, 0xb1d: 0x2ac2, + 0xb1e: 0x2f13, 0xb1f: 0x2c33, 0xb20: 0x2d55, 0xb21: 0x2f40, 0xb22: 0x2acc, 0xb23: 0x2ad6, + 0xb24: 0x2c40, 0xb25: 0x2ae0, 0xb26: 0x2aea, 0xb27: 0x28cc, 0xb28: 0x28d3, 0xb29: 0x2af4, + 0xb2a: 0x2afe, 0xb2b: 0x2e36, 0xb2c: 0x2c4d, 0xb2d: 0x2d65, 0xb2e: 0x2e49, 0xb2f: 0x2c5a, + 0xb30: 0x2b12, 0xb31: 0x2b08, 0xb32: 0x2f87, 0xb33: 0x2c67, 0xb34: 0x2e5c, 0xb35: 0x2b1c, + 0xb36: 0x2d75, 0xb37: 0x2b26, 0xb38: 0x2c81, 0xb39: 0x2b30, 0xb3a: 0x2c8e, 0xb3b: 0x2f51, + 0xb3c: 0x2c74, 0xb3d: 0x2d85, 0xb3e: 0x2c9b, 0xb3f: 0x28da, + // Block 0x2d, offset 0xb40 + 0xb40: 0x2f62, 0xb41: 0x2b3a, 0xb42: 0x2b44, 0xb43: 0x2ca8, 0xb44: 0x2b4e, 0xb45: 0x2b58, + 0xb46: 0x2b62, 0xb47: 0x2d95, 0xb48: 0x2cb5, 0xb49: 0x28e1, 0xb4a: 0x2e6f, 0xb4b: 0x2efa, + 0xb4c: 0x2da5, 0xb4d: 0x2cc2, 0xb4e: 0x2f21, 0xb4f: 0x2b6c, 0xb50: 0x2b76, 0xb51: 0x2ccf, + 0xb52: 0x28e8, 0xb53: 0x2cdc, 0xb54: 0x2db5, 0xb55: 0x28ef, 0xb56: 0x2e82, 0xb57: 0x2b80, + 0xb58: 0x1e4a, 0xb59: 0x1e5e, 0xb5a: 0x1e6d, 0xb5b: 0x1e7c, 0xb5c: 0x1e8b, 0xb5d: 0x1e9a, + 0xb5e: 0x1ea9, 0xb5f: 0x1eb8, 0xb60: 0x1ec7, 0xb61: 0x1ed6, 0xb62: 0x2325, 0xb63: 0x2337, + 0xb64: 0x2349, 0xb65: 0x2355, 0xb66: 0x2361, 0xb67: 0x236d, 0xb68: 0x2379, 0xb69: 0x2385, + 0xb6a: 0x2391, 0xb6b: 0x239d, 0xb6c: 0x23d9, 0xb6d: 0x23e5, 0xb6e: 0x23f1, 0xb6f: 0x23fd, + 0xb70: 0x2409, 0xb71: 0x1da7, 0xb72: 0x1b59, 0xb73: 0x1ac9, 0xb74: 0x1d77, 0xb75: 0x1bda, + 0xb76: 0x1be9, 0xb77: 0x1b5f, 0xb78: 0x1d8f, 0xb79: 0x1d93, 0xb7a: 0x1af3, 0xb7b: 0x28fd, + 0xb7c: 0x290b, 0xb7d: 0x28f6, 0xb7e: 0x2904, 0xb7f: 0x2ce9, + // Block 0x2e, offset 0xb80 + 0xb80: 0x1bdd, 0xb81: 0x1bc5, 0xb82: 0x1df3, 0xb83: 0x1bad, 0xb84: 0x1b86, 0xb85: 0x1afc, + 0xb86: 0x1b0b, 0xb87: 0x1adb, 0xb88: 0x1d83, 0xb89: 0x1ee5, 0xb8a: 0x1be0, 0xb8b: 0x1bc8, + 0xb8c: 0x1df7, 0xb8d: 0x1e03, 0xb8e: 0x1bb9, 0xb8f: 0x1b8f, 0xb90: 0x1aea, 0xb91: 0x1daf, + 0xb92: 0x1d43, 0xb93: 0x1d2f, 0xb94: 0x1d5f, 0xb95: 0x1e07, 0xb96: 0x1bbc, 0xb97: 0x1b5c, + 0xb98: 0x1b92, 0xb99: 0x1b71, 0xb9a: 0x1bd4, 0xb9b: 0x1e0b, 0xb9c: 0x1bbf, 0xb9d: 0x1b53, + 0xb9e: 0x1b95, 0xb9f: 0x1dcf, 0xba0: 0x1d87, 0xba1: 0x1ba7, 0xba2: 0x1db7, 0xba3: 0x1dd3, + 0xba4: 0x1d8b, 0xba5: 0x1baa, 0xba6: 0x1dbb, 0xba7: 0x247b, 0xba8: 0x248f, 0xba9: 0x1b29, + 0xbaa: 0x1db3, 0xbab: 0x1d47, 0xbac: 0x1d33, 0xbad: 0x1ddb, 0xbae: 0x2912, 0xbaf: 0x29a9, + 0xbb0: 0x1bec, 0xbb1: 0x1bd7, 0xbb2: 0x1e0f, 0xbb3: 0x1bc2, 0xbb4: 0x1be3, 0xbb5: 0x1bcb, + 0xbb6: 0x1dfb, 0xbb7: 0x1bb0, 0xbb8: 0x1b89, 0xbb9: 0x1b14, 0xbba: 0x1be6, 0xbbb: 0x1bce, + 0xbbc: 0x1dff, 0xbbd: 0x1bb3, 0xbbe: 0x1b8c, 0xbbf: 0x1b17, + // Block 0x2f, offset 0xbc0 + 0xbc0: 0x1dbf, 0xbc1: 0x1d4b, 0xbc2: 0x1ee0, 0xbc3: 0x1acc, 0xbc4: 0x1b4d, 0xbc5: 0x1b50, + 0xbc6: 0x2488, 0xbc7: 0x1d27, 0xbc8: 0x1b56, 0xbc9: 0x1ade, 0xbca: 0x1b74, 0xbcb: 0x1ae1, + 0xbcc: 0x1b7d, 0xbcd: 0x1aff, 0xbce: 0x1b02, 0xbcf: 0x1b98, 0xbd0: 0x1b9e, 0xbd1: 0x1ba1, + 0xbd2: 0x1dc3, 0xbd3: 0x1ba4, 0xbd4: 0x1bb6, 0xbd5: 0x1dcb, 0xbd6: 0x1dd7, 0xbd7: 0x1b23, + 0xbd8: 0x1eea, 0xbd9: 0x1d4f, 0xbda: 0x1b26, 0xbdb: 0x1bef, 0xbdc: 0x1b38, 0xbdd: 0x1b47, + 0xbde: 0x2475, 0xbdf: 0x246f, 0xbe0: 0x1e54, 0xbe1: 0x1e63, 0xbe2: 0x1e72, 0xbe3: 0x1e81, + 0xbe4: 0x1e90, 0xbe5: 0x1e9f, 0xbe6: 0x1eae, 0xbe7: 0x1ebd, 0xbe8: 0x1ecc, 0xbe9: 0x2319, + 0xbea: 0x232b, 0xbeb: 0x233d, 0xbec: 0x234f, 0xbed: 0x235b, 0xbee: 0x2367, 0xbef: 0x2373, + 0xbf0: 0x237f, 0xbf1: 0x238b, 0xbf2: 0x2397, 0xbf3: 0x23d3, 0xbf4: 0x23df, 0xbf5: 0x23eb, + 0xbf6: 0x23f7, 0xbf7: 0x2403, 0xbf8: 0x240f, 0xbf9: 0x2415, 0xbfa: 0x241b, 0xbfb: 0x2421, + 0xbfc: 0x2427, 0xbfd: 0x2439, 0xbfe: 0x243f, 0xbff: 0x1da3, + // Block 0x30, offset 0xc00 + 0xc00: 0x13ef, 0xc01: 0x0d73, 0xc02: 0x144b, 0xc03: 0x1417, 0xc04: 0x0ecf, 0xc05: 0x0763, + 0xc06: 0x0957, 0xc07: 0x169f, 0xc08: 0x169f, 0xc09: 0x0a83, 0xc0a: 0x14d3, 0xc0b: 0x09bb, + 0xc0c: 0x0a7f, 0xc0d: 0x0c67, 0xc0e: 0x1047, 0xc0f: 0x11d7, 0xc10: 0x130f, 0xc11: 0x134b, + 0xc12: 0x137f, 0xc13: 0x1493, 0xc14: 0x0deb, 0xc15: 0x0e77, 0xc16: 0x0f23, 0xc17: 0x0fbb, + 0xc18: 0x12d7, 0xc19: 0x14bb, 0xc1a: 0x15e7, 0xc1b: 0x0787, 0xc1c: 0x092b, 0xc1d: 0x0dff, + 0xc1e: 0x0f47, 0xc1f: 0x130b, 0xc20: 0x1637, 0xc21: 0x0b2b, 0xc22: 0x0eef, 0xc23: 0x12fb, + 0xc24: 0x138f, 0xc25: 0x0c9b, 0xc26: 0x1233, 0xc27: 0x1357, 0xc28: 0x0b97, 0xc29: 0x0d87, + 0xc2a: 0x0e8f, 0xc2b: 0x0f93, 0xc2c: 0x149f, 0xc2d: 0x07c7, 0xc2e: 0x085f, 0xc2f: 0x08cb, + 0xc30: 0x0d03, 0xc31: 0x0df7, 0xc32: 0x0f43, 0xc33: 0x1067, 0xc34: 0x11ef, 0xc35: 0x1303, + 0xc36: 0x131b, 0xc37: 0x143f, 0xc38: 0x1563, 0xc39: 0x1617, 0xc3a: 0x1633, 0xc3b: 0x10a3, + 0xc3c: 0x10e3, 0xc3d: 0x119b, 0xc3e: 0x12bb, 0xc3f: 0x14ef, + // Block 0x31, offset 0xc40 + 0xc40: 0x163f, 0xc41: 0x13c3, 0xc42: 0x0a3f, 0xc43: 0x0bb3, 0xc44: 0x1153, 0xc45: 0x1213, + 0xc46: 0x0f77, 0xc47: 0x10ab, 0xc48: 0x140f, 0xc49: 0x155b, 0xc4a: 0x0a3b, 0xc4b: 0x0b07, + 0xc4c: 0x0def, 0xc4d: 0x0ea3, 0xc4e: 0x0ed7, 0xc4f: 0x118b, 0xc50: 0x11b3, 0xc51: 0x151b, + 0xc52: 0x08c7, 0xc53: 0x121f, 0xc54: 0x086b, 0xc55: 0x0867, 0xc56: 0x110f, 0xc57: 0x119f, + 0xc58: 0x12d3, 0xc59: 0x1523, 0xc5a: 0x13df, 0xc5b: 0x0c9f, 0xc5c: 0x0deb, 0xc5d: 0x13cf, + 0xc5e: 0x076f, 0xc5f: 0x0adb, 0xc60: 0x0c0b, 0xc61: 0x0fa7, 0xc62: 0x1027, 0xc63: 0x08eb, + 0xc64: 0x10b3, 0xc65: 0x07d7, 0xc66: 0x0bef, 0xc67: 0x074f, 0xc68: 0x0e63, 0xc69: 0x0d1b, + 0xc6a: 0x1187, 0xc6b: 0x093f, 0xc6c: 0x0a2b, 0xc6d: 0x1073, 0xc6e: 0x12db, 0xc6f: 0x13b3, + 0xc70: 0x0e2f, 0xc71: 0x146f, 0xc72: 0x0e5b, 0xc73: 0x0caf, 0xc74: 0x1293, 0xc75: 0x0ccf, + 0xc76: 0x1023, 0xc77: 0x07a3, 0xc78: 0x081f, 0xc79: 0x0863, 0xc7a: 0x0dcb, 0xc7b: 0x1173, + 0xc7c: 0x126b, 0xc7d: 0x13bf, 0xc7e: 0x14cf, 0xc7f: 0x08d3, + // Block 0x32, offset 0xc80 + 0xc80: 0x0987, 0xc81: 0x0a8f, 0xc82: 0x0ba7, 0xc83: 0x0d37, 0xc84: 0x0ef3, 0xc85: 0x10b7, + 0xc86: 0x150b, 0xc87: 0x15ef, 0xc88: 0x1643, 0xc89: 0x165b, 0xc8a: 0x08af, 0xc8b: 0x0d6b, + 0xc8c: 0x0e1b, 0xc8d: 0x1463, 0xc8e: 0x0b73, 0xc8f: 0x0c4f, 0xc90: 0x0c6b, 0xc91: 0x0cfb, + 0xc92: 0x0ee3, 0xc93: 0x0f2f, 0xc94: 0x0fdf, 0xc95: 0x1103, 0xc96: 0x11a7, 0xc97: 0x120b, + 0xc98: 0x1453, 0xc99: 0x12e3, 0xc9a: 0x147b, 0xc9b: 0x14f3, 0xc9c: 0x0887, 0xc9d: 0x08b3, + 0xc9e: 0x099b, 0xc9f: 0x0f1f, 0xca0: 0x136b, 0xca1: 0x13b3, 0xca2: 0x0b93, 0xca3: 0x0c03, + 0xca4: 0x0cc7, 0xca5: 0x0e27, 0xca6: 0x114f, 0xca7: 0x0f9b, 0xca8: 0x07b3, 0xca9: 0x09f7, + 0xcaa: 0x0adb, 0xcab: 0x0b3f, 0xcac: 0x0c0f, 0xcad: 0x0fb7, 0xcae: 0x0fd3, 0xcaf: 0x11e3, + 0xcb0: 0x1203, 0xcb1: 0x14d7, 0xcb2: 0x1557, 0xcb3: 0x1567, 0xcb4: 0x15a3, 0xcb5: 0x07cb, + 0xcb6: 0x10f7, 0xcb7: 0x14c3, 0xcb8: 0x153f, 0xcb9: 0x0c27, 0xcba: 0x078f, 0xcbb: 0x07ef, + 0xcbc: 0x0adf, 0xcbd: 0x0aff, 0xcbe: 0x0d27, 0xcbf: 0x0deb, + // Block 0x33, offset 0xcc0 + 0xcc0: 0x0f3b, 0xcc1: 0x1043, 0xcc2: 0x12ef, 0xcc3: 0x148f, 0xcc4: 0x1697, 0xcc5: 0x0d5b, + 0xcc6: 0x1517, 0xcc7: 0x08ab, 0xcc8: 0x0da7, 0xcc9: 0x0db3, 0xcca: 0x0e87, 0xccb: 0x0ebf, + 0xccc: 0x0fc3, 0xccd: 0x101f, 0xcce: 0x109f, 0xccf: 0x1183, 0xcd0: 0x15af, 0xcd1: 0x0827, + 0xcd2: 0x0c7b, 0xcd3: 0x1527, 0xcd4: 0x07df, 0xcd5: 0x0b23, 0xcd6: 0x0ea7, 0xcd7: 0x1457, + 0xcd8: 0x0bdf, 0xcd9: 0x0c2f, 0xcda: 0x0dbb, 0xcdb: 0x0fa7, 0xcdc: 0x152f, 0xcdd: 0x088f, + 0xcde: 0x0977, 0xcdf: 0x0b0f, 0xce0: 0x0d4b, 0xce1: 0x0d97, 0xce2: 0x0dd7, 0xce3: 0x0e6b, + 0xce4: 0x0fbf, 0xce5: 0x1033, 0xce6: 0x11cf, 0xce7: 0x136f, 0xce8: 0x137b, 0xce9: 0x14cb, + 0xcea: 0x154b, 0xceb: 0x08fb, 0xcec: 0x0ec3, 0xced: 0x097b, 0xcee: 0x0f3f, 0xcef: 0x0fe3, + 0xcf0: 0x12ff, 0xcf1: 0x1533, 0xcf2: 0x161f, 0xcf3: 0x1647, 0xcf4: 0x0daf, 0xcf5: 0x0e9f, + 0xcf6: 0x123b, 0xcf7: 0x112f, 0xcf8: 0x113b, 0xcf9: 0x115f, 0xcfa: 0x0f8f, 0xcfb: 0x0f17, + 0xcfc: 0x13db, 0xcfd: 0x07ab, 0xcfe: 0x12a3, 0xcff: 0x0893, + // Block 0x34, offset 0xd00 + 0xd00: 0x0883, 0xd01: 0x0b83, 0xd02: 0x0ca3, 0xd03: 0x116b, 0xd04: 0x0acb, 0xd05: 0x0e7b, + 0xd06: 0x0d67, 0xd07: 0x145f, 0xd08: 0x135f, 0xd09: 0x151f, 0xd0a: 0x139b, 0xd0b: 0x0b9f, + 0xd0c: 0x07ff, 0xd0d: 0x09d3, 0xd10: 0x0a27, + 0xd12: 0x0d57, 0xd15: 0x086f, 0xd16: 0x0f97, 0xd17: 0x105b, + 0xd18: 0x10bf, 0xd19: 0x10db, 0xd1a: 0x10df, 0xd1b: 0x10f3, 0xd1c: 0x156f, 0xd1d: 0x1163, + 0xd1e: 0x11e7, 0xd20: 0x1307, 0xd22: 0x13cb, + 0xd25: 0x147f, 0xd26: 0x14ab, + 0xd2a: 0x15c3, 0xd2b: 0x15c7, 0xd2c: 0x15cb, 0xd2d: 0x162f, 0xd2e: 0x14a3, 0xd2f: 0x153b, + 0xd30: 0x07cf, 0xd31: 0x07f3, 0xd32: 0x0807, 0xd33: 0x08c3, 0xd34: 0x08cf, 0xd35: 0x090f, + 0xd36: 0x09c3, 0xd37: 0x09df, 0xd38: 0x09e7, 0xd39: 0x0a23, 0xd3a: 0x0a2f, 0xd3b: 0x0b0b, + 0xd3c: 0x0b13, 0xd3d: 0x0c1b, 0xd3e: 0x0c43, 0xd3f: 0x0c4b, + // Block 0x35, offset 0xd40 + 0xd40: 0x0c63, 0xd41: 0x0d0f, 0xd42: 0x0d3f, 0xd43: 0x0d5f, 0xd44: 0x0dcf, 0xd45: 0x0e93, + 0xd46: 0x0eaf, 0xd47: 0x0edf, 0xd48: 0x0f33, 0xd49: 0x0f53, 0xd4a: 0x0fc7, 0xd4b: 0x10a7, + 0xd4c: 0x10c3, 0xd4d: 0x10cb, 0xd4e: 0x10c7, 0xd4f: 0x10cf, 0xd50: 0x10d3, 0xd51: 0x10d7, + 0xd52: 0x10eb, 0xd53: 0x10ef, 0xd54: 0x1113, 0xd55: 0x1127, 0xd56: 0x1143, 0xd57: 0x11a7, + 0xd58: 0x11af, 0xd59: 0x11b7, 0xd5a: 0x11cb, 0xd5b: 0x11f3, 0xd5c: 0x1243, 0xd5d: 0x1277, + 0xd5e: 0x1277, 0xd5f: 0x12df, 0xd60: 0x1387, 0xd61: 0x139f, 0xd62: 0x13d3, 0xd63: 0x13d7, + 0xd64: 0x141b, 0xd65: 0x141f, 0xd66: 0x1477, 0xd67: 0x147f, 0xd68: 0x154f, 0xd69: 0x1593, + 0xd6a: 0x15ab, 0xd6b: 0x0c13, 0xd6c: 0x1792, 0xd6d: 0x125b, + 0xd70: 0x0757, 0xd71: 0x085b, 0xd72: 0x081b, 0xd73: 0x07c3, 0xd74: 0x0803, 0xd75: 0x082f, + 0xd76: 0x08bf, 0xd77: 0x08db, 0xd78: 0x09c3, 0xd79: 0x09af, 0xd7a: 0x09bf, 0xd7b: 0x09db, + 0xd7c: 0x0a27, 0xd7d: 0x0a37, 0xd7e: 0x0a7b, 0xd7f: 0x0a87, + // Block 0x36, offset 0xd80 + 0xd80: 0x0aa3, 0xd81: 0x0ab3, 0xd82: 0x0b9b, 0xd83: 0x0ba3, 0xd84: 0x0bd3, 0xd85: 0x0bf3, + 0xd86: 0x0c23, 0xd87: 0x0c3b, 0xd88: 0x0c2b, 0xd89: 0x0c4b, 0xd8a: 0x0c3f, 0xd8b: 0x0c63, + 0xd8c: 0x0c7f, 0xd8d: 0x0cd7, 0xd8e: 0x0ce3, 0xd8f: 0x0ceb, 0xd90: 0x0d13, 0xd91: 0x0d57, + 0xd92: 0x0d87, 0xd93: 0x0d8b, 0xd94: 0x0d9f, 0xd95: 0x0e1f, 0xd96: 0x0e2f, 0xd97: 0x0e87, + 0xd98: 0x0ed3, 0xd99: 0x0ecb, 0xd9a: 0x0edf, 0xd9b: 0x0efb, 0xd9c: 0x0f33, 0xd9d: 0x108b, + 0xd9e: 0x0f57, 0xd9f: 0x0f8b, 0xda0: 0x0f97, 0xda1: 0x0fd7, 0xda2: 0x0ff3, 0xda3: 0x1017, + 0xda4: 0x103b, 0xda5: 0x103f, 0xda6: 0x105b, 0xda7: 0x105f, 0xda8: 0x106f, 0xda9: 0x1083, + 0xdaa: 0x107f, 0xdab: 0x10af, 0xdac: 0x112b, 0xdad: 0x1143, 0xdae: 0x115b, 0xdaf: 0x1193, + 0xdb0: 0x11a7, 0xdb1: 0x11c3, 0xdb2: 0x11f3, 0xdb3: 0x12a7, 0xdb4: 0x12cf, 0xdb5: 0x1343, + 0xdb6: 0x138b, 0xdb7: 0x1397, 0xdb8: 0x139f, 0xdb9: 0x13b7, 0xdba: 0x13cb, 0xdbb: 0x13bb, + 0xdbc: 0x13d3, 0xdbd: 0x13cf, 0xdbe: 0x13c7, 0xdbf: 0x13d7, + // Block 0x37, offset 0xdc0 + 0xdc0: 0x13e3, 0xdc1: 0x141f, 0xdc2: 0x145b, 0xdc3: 0x148b, 0xdc4: 0x14bf, 0xdc5: 0x14df, + 0xdc6: 0x152b, 0xdc7: 0x154f, 0xdc8: 0x156f, 0xdc9: 0x1583, 0xdca: 0x1593, 0xdcb: 0x159f, + 0xdcc: 0x15ab, 0xdcd: 0x15ff, 0xdce: 0x169f, 0xdcf: 0x1729, 0xdd0: 0x1724, 0xdd1: 0x1756, + 0xdd2: 0x067f, 0xdd3: 0x06a7, 0xdd4: 0x06ab, 0xdd5: 0x17d8, 0xdd6: 0x1805, 0xdd7: 0x187d, + 0xdd8: 0x168b, 0xdd9: 0x169b, + // Block 0x38, offset 0xe00 + 0xe00: 0x1b68, 0xe01: 0x1b6b, 0xe02: 0x1b6e, 0xe03: 0x1d9b, 0xe04: 0x1d9f, 0xe05: 0x1bf2, + 0xe06: 0x1bf2, + 0xe13: 0x1f08, 0xe14: 0x1ef9, 0xe15: 0x1efe, 0xe16: 0x1f0d, 0xe17: 0x1f03, + 0xe1d: 0x43cb, + 0xe1e: 0x8115, 0xe1f: 0x443d, 0xe20: 0x022d, 0xe21: 0x0215, 0xe22: 0x021e, 0xe23: 0x0221, + 0xe24: 0x0224, 0xe25: 0x0227, 0xe26: 0x022a, 0xe27: 0x0230, 0xe28: 0x0233, 0xe29: 0x0017, + 0xe2a: 0x442b, 0xe2b: 0x4431, 0xe2c: 0x452f, 0xe2d: 0x4537, 0xe2e: 0x4383, 0xe2f: 0x4389, + 0xe30: 0x438f, 0xe31: 0x4395, 0xe32: 0x43a1, 0xe33: 0x43a7, 0xe34: 0x43ad, 0xe35: 0x43b9, + 0xe36: 0x43bf, 0xe38: 0x43c5, 0xe39: 0x43d1, 0xe3a: 0x43d7, 0xe3b: 0x43dd, + 0xe3c: 0x43e9, 0xe3e: 0x43ef, + // Block 0x39, offset 0xe40 + 0xe40: 0x43f5, 0xe41: 0x43fb, 0xe43: 0x4401, 0xe44: 0x4407, + 0xe46: 0x4413, 0xe47: 0x4419, 0xe48: 0x441f, 0xe49: 0x4425, 0xe4a: 0x4437, 0xe4b: 0x43b3, + 0xe4c: 0x439b, 0xe4d: 0x43e3, 0xe4e: 0x440d, 0xe4f: 0x1f12, 0xe50: 0x0299, 0xe51: 0x0299, + 0xe52: 0x02a2, 0xe53: 0x02a2, 0xe54: 0x02a2, 0xe55: 0x02a2, 0xe56: 0x02a5, 0xe57: 0x02a5, + 0xe58: 0x02a5, 0xe59: 0x02a5, 0xe5a: 0x02ab, 0xe5b: 0x02ab, 0xe5c: 0x02ab, 0xe5d: 0x02ab, + 0xe5e: 0x029f, 0xe5f: 0x029f, 0xe60: 0x029f, 0xe61: 0x029f, 0xe62: 0x02a8, 0xe63: 0x02a8, + 0xe64: 0x02a8, 0xe65: 0x02a8, 0xe66: 0x029c, 0xe67: 0x029c, 0xe68: 0x029c, 0xe69: 0x029c, + 0xe6a: 0x02cf, 0xe6b: 0x02cf, 0xe6c: 0x02cf, 0xe6d: 0x02cf, 0xe6e: 0x02d2, 0xe6f: 0x02d2, + 0xe70: 0x02d2, 0xe71: 0x02d2, 0xe72: 0x02b1, 0xe73: 0x02b1, 0xe74: 0x02b1, 0xe75: 0x02b1, + 0xe76: 0x02ae, 0xe77: 0x02ae, 0xe78: 0x02ae, 0xe79: 0x02ae, 0xe7a: 0x02b4, 0xe7b: 0x02b4, + 0xe7c: 0x02b4, 0xe7d: 0x02b4, 0xe7e: 0x02b7, 0xe7f: 0x02b7, + // Block 0x3a, offset 0xe80 + 0xe80: 0x02b7, 0xe81: 0x02b7, 0xe82: 0x02c0, 0xe83: 0x02c0, 0xe84: 0x02bd, 0xe85: 0x02bd, + 0xe86: 0x02c3, 0xe87: 0x02c3, 0xe88: 0x02ba, 0xe89: 0x02ba, 0xe8a: 0x02c9, 0xe8b: 0x02c9, + 0xe8c: 0x02c6, 0xe8d: 0x02c6, 0xe8e: 0x02d5, 0xe8f: 0x02d5, 0xe90: 0x02d5, 0xe91: 0x02d5, + 0xe92: 0x02db, 0xe93: 0x02db, 0xe94: 0x02db, 0xe95: 0x02db, 0xe96: 0x02e1, 0xe97: 0x02e1, + 0xe98: 0x02e1, 0xe99: 0x02e1, 0xe9a: 0x02de, 0xe9b: 0x02de, 0xe9c: 0x02de, 0xe9d: 0x02de, + 0xe9e: 0x02e4, 0xe9f: 0x02e4, 0xea0: 0x02e7, 0xea1: 0x02e7, 0xea2: 0x02e7, 0xea3: 0x02e7, + 0xea4: 0x44a9, 0xea5: 0x44a9, 0xea6: 0x02ed, 0xea7: 0x02ed, 0xea8: 0x02ed, 0xea9: 0x02ed, + 0xeaa: 0x02ea, 0xeab: 0x02ea, 0xeac: 0x02ea, 0xead: 0x02ea, 0xeae: 0x0308, 0xeaf: 0x0308, + 0xeb0: 0x44a3, 0xeb1: 0x44a3, + // Block 0x3b, offset 0xec0 + 0xed3: 0x02d8, 0xed4: 0x02d8, 0xed5: 0x02d8, 0xed6: 0x02d8, 0xed7: 0x02f6, + 0xed8: 0x02f6, 0xed9: 0x02f3, 0xeda: 0x02f3, 0xedb: 0x02f9, 0xedc: 0x02f9, 0xedd: 0x21e2, + 0xede: 0x02ff, 0xedf: 0x02ff, 0xee0: 0x02f0, 0xee1: 0x02f0, 0xee2: 0x02fc, 0xee3: 0x02fc, + 0xee4: 0x0305, 0xee5: 0x0305, 0xee6: 0x0305, 0xee7: 0x0305, 0xee8: 0x028d, 0xee9: 0x028d, + 0xeea: 0x273d, 0xeeb: 0x273d, 0xeec: 0x27ad, 0xeed: 0x27ad, 0xeee: 0x277c, 0xeef: 0x277c, + 0xef0: 0x2798, 0xef1: 0x2798, 0xef2: 0x2791, 0xef3: 0x2791, 0xef4: 0x279f, 0xef5: 0x279f, + 0xef6: 0x27a6, 0xef7: 0x27a6, 0xef8: 0x27a6, 0xef9: 0x2783, 0xefa: 0x2783, 0xefb: 0x2783, + 0xefc: 0x0302, 0xefd: 0x0302, 0xefe: 0x0302, 0xeff: 0x0302, + // Block 0x3c, offset 0xf00 + 0xf00: 0x2744, 0xf01: 0x274b, 0xf02: 0x2767, 0xf03: 0x2783, 0xf04: 0x278a, 0xf05: 0x1f1c, + 0xf06: 0x1f21, 0xf07: 0x1f26, 0xf08: 0x1f35, 0xf09: 0x1f44, 0xf0a: 0x1f49, 0xf0b: 0x1f4e, + 0xf0c: 0x1f53, 0xf0d: 0x1f58, 0xf0e: 0x1f67, 0xf0f: 0x1f76, 0xf10: 0x1f7b, 0xf11: 0x1f80, + 0xf12: 0x1f8f, 0xf13: 0x1f9e, 0xf14: 0x1fa3, 0xf15: 0x1fa8, 0xf16: 0x1fad, 0xf17: 0x1fbc, + 0xf18: 0x1fc1, 0xf19: 0x1fd0, 0xf1a: 0x1fd5, 0xf1b: 0x1fda, 0xf1c: 0x1fe9, 0xf1d: 0x1fee, + 0xf1e: 0x1ff3, 0xf1f: 0x1ffd, 0xf20: 0x2039, 0xf21: 0x2048, 0xf22: 0x2057, 0xf23: 0x205c, + 0xf24: 0x2061, 0xf25: 0x206b, 0xf26: 0x207a, 0xf27: 0x207f, 0xf28: 0x208e, 0xf29: 0x2093, + 0xf2a: 0x2098, 0xf2b: 0x20a7, 0xf2c: 0x20ac, 0xf2d: 0x20bb, 0xf2e: 0x20c0, 0xf2f: 0x20c5, + 0xf30: 0x20ca, 0xf31: 0x20cf, 0xf32: 0x20d4, 0xf33: 0x20d9, 0xf34: 0x20de, 0xf35: 0x20e3, + 0xf36: 0x20e8, 0xf37: 0x20ed, 0xf38: 0x20f2, 0xf39: 0x20f7, 0xf3a: 0x20fc, 0xf3b: 0x2101, + 0xf3c: 0x2106, 0xf3d: 0x210b, 0xf3e: 0x2110, 0xf3f: 0x211a, + // Block 0x3d, offset 0xf40 + 0xf40: 0x211f, 0xf41: 0x2124, 0xf42: 0x2129, 0xf43: 0x2133, 0xf44: 0x2138, 0xf45: 0x2142, + 0xf46: 0x2147, 0xf47: 0x214c, 0xf48: 0x2151, 0xf49: 0x2156, 0xf4a: 0x215b, 0xf4b: 0x2160, + 0xf4c: 0x2165, 0xf4d: 0x216a, 0xf4e: 0x2179, 0xf4f: 0x2188, 0xf50: 0x218d, 0xf51: 0x2192, + 0xf52: 0x2197, 0xf53: 0x219c, 0xf54: 0x21a1, 0xf55: 0x21ab, 0xf56: 0x21b0, 0xf57: 0x21b5, + 0xf58: 0x21c4, 0xf59: 0x21d3, 0xf5a: 0x21d8, 0xf5b: 0x445b, 0xf5c: 0x4461, 0xf5d: 0x4497, + 0xf5e: 0x44ee, 0xf5f: 0x44f5, 0xf60: 0x44fc, 0xf61: 0x4503, 0xf62: 0x450a, 0xf63: 0x4511, + 0xf64: 0x2759, 0xf65: 0x2760, 0xf66: 0x2767, 0xf67: 0x276e, 0xf68: 0x2783, 0xf69: 0x278a, + 0xf6a: 0x1f2b, 0xf6b: 0x1f30, 0xf6c: 0x1f35, 0xf6d: 0x1f3a, 0xf6e: 0x1f44, 0xf6f: 0x1f49, + 0xf70: 0x1f5d, 0xf71: 0x1f62, 0xf72: 0x1f67, 0xf73: 0x1f6c, 0xf74: 0x1f76, 0xf75: 0x1f7b, + 0xf76: 0x1f85, 0xf77: 0x1f8a, 0xf78: 0x1f8f, 0xf79: 0x1f94, 0xf7a: 0x1f9e, 0xf7b: 0x1fa3, + 0xf7c: 0x20cf, 0xf7d: 0x20d4, 0xf7e: 0x20e3, 0xf7f: 0x20e8, + // Block 0x3e, offset 0xf80 + 0xf80: 0x20ed, 0xf81: 0x2101, 0xf82: 0x2106, 0xf83: 0x210b, 0xf84: 0x2110, 0xf85: 0x2129, + 0xf86: 0x2133, 0xf87: 0x2138, 0xf88: 0x213d, 0xf89: 0x2151, 0xf8a: 0x216f, 0xf8b: 0x2174, + 0xf8c: 0x2179, 0xf8d: 0x217e, 0xf8e: 0x2188, 0xf8f: 0x218d, 0xf90: 0x4497, 0xf91: 0x21ba, + 0xf92: 0x21bf, 0xf93: 0x21c4, 0xf94: 0x21c9, 0xf95: 0x21d3, 0xf96: 0x21d8, 0xf97: 0x2744, + 0xf98: 0x274b, 0xf99: 0x2752, 0xf9a: 0x2767, 0xf9b: 0x2775, 0xf9c: 0x1f1c, 0xf9d: 0x1f21, + 0xf9e: 0x1f26, 0xf9f: 0x1f35, 0xfa0: 0x1f3f, 0xfa1: 0x1f4e, 0xfa2: 0x1f53, 0xfa3: 0x1f58, + 0xfa4: 0x1f67, 0xfa5: 0x1f71, 0xfa6: 0x1f8f, 0xfa7: 0x1fa8, 0xfa8: 0x1fad, 0xfa9: 0x1fbc, + 0xfaa: 0x1fc1, 0xfab: 0x1fd0, 0xfac: 0x1fda, 0xfad: 0x1fe9, 0xfae: 0x1fee, 0xfaf: 0x1ff3, + 0xfb0: 0x1ffd, 0xfb1: 0x2039, 0xfb2: 0x203e, 0xfb3: 0x2048, 0xfb4: 0x2057, 0xfb5: 0x205c, + 0xfb6: 0x2061, 0xfb7: 0x206b, 0xfb8: 0x207a, 0xfb9: 0x208e, 0xfba: 0x2093, 0xfbb: 0x2098, + 0xfbc: 0x20a7, 0xfbd: 0x20ac, 0xfbe: 0x20bb, 0xfbf: 0x20c0, + // Block 0x3f, offset 0xfc0 + 0xfc0: 0x20c5, 0xfc1: 0x20ca, 0xfc2: 0x20d9, 0xfc3: 0x20de, 0xfc4: 0x20f2, 0xfc5: 0x20f7, + 0xfc6: 0x20fc, 0xfc7: 0x2101, 0xfc8: 0x2106, 0xfc9: 0x211a, 0xfca: 0x211f, 0xfcb: 0x2124, + 0xfcc: 0x2129, 0xfcd: 0x212e, 0xfce: 0x2142, 0xfcf: 0x2147, 0xfd0: 0x214c, 0xfd1: 0x2151, + 0xfd2: 0x2160, 0xfd3: 0x2165, 0xfd4: 0x216a, 0xfd5: 0x2179, 0xfd6: 0x2183, 0xfd7: 0x2192, + 0xfd8: 0x2197, 0xfd9: 0x448b, 0xfda: 0x21ab, 0xfdb: 0x21b0, 0xfdc: 0x21b5, 0xfdd: 0x21c4, + 0xfde: 0x21ce, 0xfdf: 0x2767, 0xfe0: 0x2775, 0xfe1: 0x1f35, 0xfe2: 0x1f3f, 0xfe3: 0x1f67, + 0xfe4: 0x1f71, 0xfe5: 0x1f8f, 0xfe6: 0x1f99, 0xfe7: 0x1ffd, 0xfe8: 0x2002, 0xfe9: 0x2025, + 0xfea: 0x202a, 0xfeb: 0x2101, 0xfec: 0x2106, 0xfed: 0x2129, 0xfee: 0x2179, 0xfef: 0x2183, + 0xff0: 0x21c4, 0xff1: 0x21ce, 0xff2: 0x453f, 0xff3: 0x4547, 0xff4: 0x454f, 0xff5: 0x2084, + 0xff6: 0x2089, 0xff7: 0x209d, 0xff8: 0x20a2, 0xff9: 0x20b1, 0xffa: 0x20b6, 0xffb: 0x2007, + 0xffc: 0x200c, 0xffd: 0x202f, 0xffe: 0x2034, 0xfff: 0x1fc6, + // Block 0x40, offset 0x1000 + 0x1000: 0x1fcb, 0x1001: 0x1fb2, 0x1002: 0x1fb7, 0x1003: 0x1fdf, 0x1004: 0x1fe4, 0x1005: 0x204d, + 0x1006: 0x2052, 0x1007: 0x2070, 0x1008: 0x2075, 0x1009: 0x2011, 0x100a: 0x2016, 0x100b: 0x201b, + 0x100c: 0x2025, 0x100d: 0x2020, 0x100e: 0x1ff8, 0x100f: 0x2043, 0x1010: 0x2066, 0x1011: 0x2084, + 0x1012: 0x2089, 0x1013: 0x209d, 0x1014: 0x20a2, 0x1015: 0x20b1, 0x1016: 0x20b6, 0x1017: 0x2007, + 0x1018: 0x200c, 0x1019: 0x202f, 0x101a: 0x2034, 0x101b: 0x1fc6, 0x101c: 0x1fcb, 0x101d: 0x1fb2, + 0x101e: 0x1fb7, 0x101f: 0x1fdf, 0x1020: 0x1fe4, 0x1021: 0x204d, 0x1022: 0x2052, 0x1023: 0x2070, + 0x1024: 0x2075, 0x1025: 0x2011, 0x1026: 0x2016, 0x1027: 0x201b, 0x1028: 0x2025, 0x1029: 0x2020, + 0x102a: 0x1ff8, 0x102b: 0x2043, 0x102c: 0x2066, 0x102d: 0x2011, 0x102e: 0x2016, 0x102f: 0x201b, + 0x1030: 0x2025, 0x1031: 0x2002, 0x1032: 0x202a, 0x1033: 0x207f, 0x1034: 0x1fe9, 0x1035: 0x1fee, + 0x1036: 0x1ff3, 0x1037: 0x2011, 0x1038: 0x2016, 0x1039: 0x201b, 0x103a: 0x207f, 0x103b: 0x208e, + 0x103c: 0x4443, 0x103d: 0x4443, + // Block 0x41, offset 0x1040 + 0x1050: 0x24a4, 0x1051: 0x24b9, + 0x1052: 0x24b9, 0x1053: 0x24c0, 0x1054: 0x24c7, 0x1055: 0x24dc, 0x1056: 0x24e3, 0x1057: 0x24ea, + 0x1058: 0x250d, 0x1059: 0x250d, 0x105a: 0x2530, 0x105b: 0x2529, 0x105c: 0x2545, 0x105d: 0x2537, + 0x105e: 0x253e, 0x105f: 0x2561, 0x1060: 0x2561, 0x1061: 0x255a, 0x1062: 0x2568, 0x1063: 0x2568, + 0x1064: 0x2592, 0x1065: 0x2592, 0x1066: 0x25ae, 0x1067: 0x2576, 0x1068: 0x2576, 0x1069: 0x256f, + 0x106a: 0x2584, 0x106b: 0x2584, 0x106c: 0x258b, 0x106d: 0x258b, 0x106e: 0x25b5, 0x106f: 0x25c3, + 0x1070: 0x25c3, 0x1071: 0x25ca, 0x1072: 0x25ca, 0x1073: 0x25d1, 0x1074: 0x25d8, 0x1075: 0x25df, + 0x1076: 0x25e6, 0x1077: 0x25e6, 0x1078: 0x25ed, 0x1079: 0x25fb, 0x107a: 0x2609, 0x107b: 0x2602, + 0x107c: 0x2610, 0x107d: 0x2610, 0x107e: 0x2625, 0x107f: 0x262c, + // Block 0x42, offset 0x1080 + 0x1080: 0x265d, 0x1081: 0x266b, 0x1082: 0x2664, 0x1083: 0x2648, 0x1084: 0x2648, 0x1085: 0x2672, + 0x1086: 0x2672, 0x1087: 0x2679, 0x1088: 0x2679, 0x1089: 0x26a3, 0x108a: 0x26aa, 0x108b: 0x26b1, + 0x108c: 0x2687, 0x108d: 0x2695, 0x108e: 0x26b8, 0x108f: 0x26bf, + 0x1092: 0x268e, 0x1093: 0x2713, 0x1094: 0x271a, 0x1095: 0x26f0, 0x1096: 0x26f7, 0x1097: 0x26db, + 0x1098: 0x26db, 0x1099: 0x26e2, 0x109a: 0x270c, 0x109b: 0x2705, 0x109c: 0x272f, 0x109d: 0x272f, + 0x109e: 0x249d, 0x109f: 0x24b2, 0x10a0: 0x24ab, 0x10a1: 0x24d5, 0x10a2: 0x24ce, 0x10a3: 0x24f8, + 0x10a4: 0x24f1, 0x10a5: 0x251b, 0x10a6: 0x24ff, 0x10a7: 0x2514, 0x10a8: 0x254c, 0x10a9: 0x2599, + 0x10aa: 0x257d, 0x10ab: 0x25bc, 0x10ac: 0x2656, 0x10ad: 0x2680, 0x10ae: 0x2728, 0x10af: 0x2721, + 0x10b0: 0x2736, 0x10b1: 0x26cd, 0x10b2: 0x2633, 0x10b3: 0x26fe, 0x10b4: 0x2625, 0x10b5: 0x265d, + 0x10b6: 0x25f4, 0x10b7: 0x2641, 0x10b8: 0x26d4, 0x10b9: 0x26c6, 0x10ba: 0x264f, 0x10bb: 0x263a, + 0x10bc: 0x264f, 0x10bd: 0x26d4, 0x10be: 0x2506, 0x10bf: 0x2522, + // Block 0x43, offset 0x10c0 + 0x10c0: 0x269c, 0x10c1: 0x2617, 0x10c2: 0x2496, 0x10c3: 0x263a, 0x10c4: 0x25df, 0x10c5: 0x25ae, + 0x10c6: 0x2553, 0x10c7: 0x26e9, + 0x10f0: 0x25a7, 0x10f1: 0x261e, 0x10f2: 0x29bb, 0x10f3: 0x29b2, 0x10f4: 0x29e8, 0x10f5: 0x29d6, + 0x10f6: 0x29c4, 0x10f7: 0x29df, 0x10f8: 0x29f1, 0x10f9: 0x25a0, 0x10fa: 0x2e95, 0x10fb: 0x2d05, + 0x10fc: 0x29cd, + // Block 0x44, offset 0x1100 + 0x1110: 0x0019, 0x1111: 0x04fb, + 0x1112: 0x04ff, 0x1113: 0x0035, 0x1114: 0x0037, 0x1115: 0x0003, 0x1116: 0x003f, 0x1117: 0x0537, + 0x1118: 0x053b, 0x1119: 0x1cef, + 0x1120: 0x8132, 0x1121: 0x8132, 0x1122: 0x8132, 0x1123: 0x8132, + 0x1124: 0x8132, 0x1125: 0x8132, 0x1126: 0x8132, 0x1127: 0x812d, 0x1128: 0x812d, 0x1129: 0x812d, + 0x112a: 0x812d, 0x112b: 0x812d, 0x112c: 0x812d, 0x112d: 0x812d, + 0x1130: 0x1a06, 0x1131: 0x04bb, 0x1132: 0x04b7, 0x1133: 0x007f, 0x1134: 0x007f, 0x1135: 0x0011, + 0x1136: 0x0013, 0x1137: 0x00b7, 0x1138: 0x00bb, 0x1139: 0x052f, 0x113a: 0x0533, 0x113b: 0x0523, + 0x113c: 0x0527, 0x113d: 0x050b, 0x113e: 0x050f, 0x113f: 0x0503, + // Block 0x45, offset 0x1140 + 0x1140: 0x0507, 0x1141: 0x0513, 0x1142: 0x0517, 0x1143: 0x051b, 0x1144: 0x051f, + 0x1147: 0x0077, 0x1148: 0x007b, 0x1149: 0x42a4, 0x114a: 0x42a4, 0x114b: 0x42a4, + 0x114c: 0x42a4, 0x114d: 0x007f, 0x114e: 0x007f, 0x114f: 0x007f, 0x1150: 0x0019, 0x1151: 0x04fb, + 0x1152: 0x001d, 0x1154: 0x0037, 0x1155: 0x0035, 0x1156: 0x003f, 0x1157: 0x0003, + 0x1158: 0x04bb, 0x1159: 0x0011, 0x115a: 0x0013, 0x115b: 0x00b7, 0x115c: 0x00bb, 0x115d: 0x052f, + 0x115e: 0x0533, 0x115f: 0x0007, 0x1160: 0x000d, 0x1161: 0x0015, 0x1162: 0x0017, 0x1163: 0x001b, + 0x1164: 0x0039, 0x1165: 0x003d, 0x1166: 0x003b, 0x1168: 0x0079, 0x1169: 0x0009, + 0x116a: 0x000b, 0x116b: 0x0041, + 0x1170: 0x42e5, 0x1171: 0x4467, 0x1172: 0x42ea, 0x1174: 0x42ef, + 0x1176: 0x42f4, 0x1177: 0x446d, 0x1178: 0x42f9, 0x1179: 0x4473, 0x117a: 0x42fe, 0x117b: 0x4479, + 0x117c: 0x4303, 0x117d: 0x447f, 0x117e: 0x4308, 0x117f: 0x4485, + // Block 0x46, offset 0x1180 + 0x1180: 0x0236, 0x1181: 0x4449, 0x1182: 0x4449, 0x1183: 0x444f, 0x1184: 0x444f, 0x1185: 0x4491, + 0x1186: 0x4491, 0x1187: 0x4455, 0x1188: 0x4455, 0x1189: 0x449d, 0x118a: 0x449d, 0x118b: 0x449d, + 0x118c: 0x449d, 0x118d: 0x0239, 0x118e: 0x0239, 0x118f: 0x023c, 0x1190: 0x023c, 0x1191: 0x023c, + 0x1192: 0x023c, 0x1193: 0x023f, 0x1194: 0x023f, 0x1195: 0x0242, 0x1196: 0x0242, 0x1197: 0x0242, + 0x1198: 0x0242, 0x1199: 0x0245, 0x119a: 0x0245, 0x119b: 0x0245, 0x119c: 0x0245, 0x119d: 0x0248, + 0x119e: 0x0248, 0x119f: 0x0248, 0x11a0: 0x0248, 0x11a1: 0x024b, 0x11a2: 0x024b, 0x11a3: 0x024b, + 0x11a4: 0x024b, 0x11a5: 0x024e, 0x11a6: 0x024e, 0x11a7: 0x024e, 0x11a8: 0x024e, 0x11a9: 0x0251, + 0x11aa: 0x0251, 0x11ab: 0x0254, 0x11ac: 0x0254, 0x11ad: 0x0257, 0x11ae: 0x0257, 0x11af: 0x025a, + 0x11b0: 0x025a, 0x11b1: 0x025d, 0x11b2: 0x025d, 0x11b3: 0x025d, 0x11b4: 0x025d, 0x11b5: 0x0260, + 0x11b6: 0x0260, 0x11b7: 0x0260, 0x11b8: 0x0260, 0x11b9: 0x0263, 0x11ba: 0x0263, 0x11bb: 0x0263, + 0x11bc: 0x0263, 0x11bd: 0x0266, 0x11be: 0x0266, 0x11bf: 0x0266, + // Block 0x47, offset 0x11c0 + 0x11c0: 0x0266, 0x11c1: 0x0269, 0x11c2: 0x0269, 0x11c3: 0x0269, 0x11c4: 0x0269, 0x11c5: 0x026c, + 0x11c6: 0x026c, 0x11c7: 0x026c, 0x11c8: 0x026c, 0x11c9: 0x026f, 0x11ca: 0x026f, 0x11cb: 0x026f, + 0x11cc: 0x026f, 0x11cd: 0x0272, 0x11ce: 0x0272, 0x11cf: 0x0272, 0x11d0: 0x0272, 0x11d1: 0x0275, + 0x11d2: 0x0275, 0x11d3: 0x0275, 0x11d4: 0x0275, 0x11d5: 0x0278, 0x11d6: 0x0278, 0x11d7: 0x0278, + 0x11d8: 0x0278, 0x11d9: 0x027b, 0x11da: 0x027b, 0x11db: 0x027b, 0x11dc: 0x027b, 0x11dd: 0x027e, + 0x11de: 0x027e, 0x11df: 0x027e, 0x11e0: 0x027e, 0x11e1: 0x0281, 0x11e2: 0x0281, 0x11e3: 0x0281, + 0x11e4: 0x0281, 0x11e5: 0x0284, 0x11e6: 0x0284, 0x11e7: 0x0284, 0x11e8: 0x0284, 0x11e9: 0x0287, + 0x11ea: 0x0287, 0x11eb: 0x0287, 0x11ec: 0x0287, 0x11ed: 0x028a, 0x11ee: 0x028a, 0x11ef: 0x028d, + 0x11f0: 0x028d, 0x11f1: 0x0290, 0x11f2: 0x0290, 0x11f3: 0x0290, 0x11f4: 0x0290, 0x11f5: 0x2ee2, + 0x11f6: 0x2ee2, 0x11f7: 0x2eea, 0x11f8: 0x2eea, 0x11f9: 0x2ef2, 0x11fa: 0x2ef2, 0x11fb: 0x2115, + 0x11fc: 0x2115, + // Block 0x48, offset 0x1200 + 0x1200: 0x0081, 0x1201: 0x0083, 0x1202: 0x0085, 0x1203: 0x0087, 0x1204: 0x0089, 0x1205: 0x008b, + 0x1206: 0x008d, 0x1207: 0x008f, 0x1208: 0x0091, 0x1209: 0x0093, 0x120a: 0x0095, 0x120b: 0x0097, + 0x120c: 0x0099, 0x120d: 0x009b, 0x120e: 0x009d, 0x120f: 0x009f, 0x1210: 0x00a1, 0x1211: 0x00a3, + 0x1212: 0x00a5, 0x1213: 0x00a7, 0x1214: 0x00a9, 0x1215: 0x00ab, 0x1216: 0x00ad, 0x1217: 0x00af, + 0x1218: 0x00b1, 0x1219: 0x00b3, 0x121a: 0x00b5, 0x121b: 0x00b7, 0x121c: 0x00b9, 0x121d: 0x00bb, + 0x121e: 0x00bd, 0x121f: 0x04ef, 0x1220: 0x04f3, 0x1221: 0x04ff, 0x1222: 0x0513, 0x1223: 0x0517, + 0x1224: 0x04fb, 0x1225: 0x0623, 0x1226: 0x061b, 0x1227: 0x053f, 0x1228: 0x0547, 0x1229: 0x054f, + 0x122a: 0x0557, 0x122b: 0x055f, 0x122c: 0x05e3, 0x122d: 0x05eb, 0x122e: 0x05f3, 0x122f: 0x0597, + 0x1230: 0x0627, 0x1231: 0x0543, 0x1232: 0x054b, 0x1233: 0x0553, 0x1234: 0x055b, 0x1235: 0x0563, + 0x1236: 0x0567, 0x1237: 0x056b, 0x1238: 0x056f, 0x1239: 0x0573, 0x123a: 0x0577, 0x123b: 0x057b, + 0x123c: 0x057f, 0x123d: 0x0583, 0x123e: 0x0587, 0x123f: 0x058b, + // Block 0x49, offset 0x1240 + 0x1240: 0x058f, 0x1241: 0x0593, 0x1242: 0x059b, 0x1243: 0x059f, 0x1244: 0x05a3, 0x1245: 0x05a7, + 0x1246: 0x05ab, 0x1247: 0x05af, 0x1248: 0x05b3, 0x1249: 0x05b7, 0x124a: 0x05bb, 0x124b: 0x05bf, + 0x124c: 0x05c3, 0x124d: 0x05c7, 0x124e: 0x05cb, 0x124f: 0x05cf, 0x1250: 0x05d3, 0x1251: 0x05d7, + 0x1252: 0x05db, 0x1253: 0x05df, 0x1254: 0x05e7, 0x1255: 0x05ef, 0x1256: 0x05f7, 0x1257: 0x05fb, + 0x1258: 0x05ff, 0x1259: 0x0603, 0x125a: 0x0607, 0x125b: 0x060b, 0x125c: 0x060f, 0x125d: 0x061f, + 0x125e: 0x49ff, 0x125f: 0x4a05, 0x1260: 0x03c3, 0x1261: 0x0313, 0x1262: 0x0317, 0x1263: 0x043b, + 0x1264: 0x031b, 0x1265: 0x043f, 0x1266: 0x0443, 0x1267: 0x031f, 0x1268: 0x0323, 0x1269: 0x0327, + 0x126a: 0x0447, 0x126b: 0x044b, 0x126c: 0x044f, 0x126d: 0x0453, 0x126e: 0x0457, 0x126f: 0x045b, + 0x1270: 0x0367, 0x1271: 0x032b, 0x1272: 0x032f, 0x1273: 0x0333, 0x1274: 0x037b, 0x1275: 0x0337, + 0x1276: 0x033b, 0x1277: 0x033f, 0x1278: 0x0343, 0x1279: 0x0347, 0x127a: 0x034b, 0x127b: 0x034f, + 0x127c: 0x0353, 0x127d: 0x0357, 0x127e: 0x035b, + // Block 0x4a, offset 0x1280 + 0x1280: 0x0063, 0x1281: 0x0065, 0x1282: 0x0067, 0x1283: 0x0069, 0x1284: 0x006b, 0x1285: 0x006d, + 0x1286: 0x006f, 0x1287: 0x0071, 0x1288: 0x0073, 0x1289: 0x0075, 0x128a: 0x0083, 0x128b: 0x0085, + 0x128c: 0x0087, 0x128d: 0x0089, 0x128e: 0x008b, 0x128f: 0x008d, 0x1290: 0x008f, 0x1291: 0x0091, + 0x1292: 0x0093, 0x1293: 0x0095, 0x1294: 0x0097, 0x1295: 0x0099, 0x1296: 0x009b, 0x1297: 0x009d, + 0x1298: 0x009f, 0x1299: 0x00a1, 0x129a: 0x00a3, 0x129b: 0x00a5, 0x129c: 0x00a7, 0x129d: 0x00a9, + 0x129e: 0x00ab, 0x129f: 0x00ad, 0x12a0: 0x00af, 0x12a1: 0x00b1, 0x12a2: 0x00b3, 0x12a3: 0x00b5, + 0x12a4: 0x00dd, 0x12a5: 0x00f2, 0x12a8: 0x0173, 0x12a9: 0x0176, + 0x12aa: 0x0179, 0x12ab: 0x017c, 0x12ac: 0x017f, 0x12ad: 0x0182, 0x12ae: 0x0185, 0x12af: 0x0188, + 0x12b0: 0x018b, 0x12b1: 0x018e, 0x12b2: 0x0191, 0x12b3: 0x0194, 0x12b4: 0x0197, 0x12b5: 0x019a, + 0x12b6: 0x019d, 0x12b7: 0x01a0, 0x12b8: 0x01a3, 0x12b9: 0x0188, 0x12ba: 0x01a6, 0x12bb: 0x01a9, + 0x12bc: 0x01ac, 0x12bd: 0x01af, 0x12be: 0x01b2, 0x12bf: 0x01b5, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x01fd, 0x12c1: 0x0200, 0x12c2: 0x0203, 0x12c3: 0x04d3, 0x12c4: 0x01c7, 0x12c5: 0x01d0, + 0x12c6: 0x01d6, 0x12c7: 0x01fa, 0x12c8: 0x01eb, 0x12c9: 0x01e8, 0x12ca: 0x0206, 0x12cb: 0x0209, + 0x12ce: 0x0021, 0x12cf: 0x0023, 0x12d0: 0x0025, 0x12d1: 0x0027, + 0x12d2: 0x0029, 0x12d3: 0x002b, 0x12d4: 0x002d, 0x12d5: 0x002f, 0x12d6: 0x0031, 0x12d7: 0x0033, + 0x12d8: 0x0021, 0x12d9: 0x0023, 0x12da: 0x0025, 0x12db: 0x0027, 0x12dc: 0x0029, 0x12dd: 0x002b, + 0x12de: 0x002d, 0x12df: 0x002f, 0x12e0: 0x0031, 0x12e1: 0x0033, 0x12e2: 0x0021, 0x12e3: 0x0023, + 0x12e4: 0x0025, 0x12e5: 0x0027, 0x12e6: 0x0029, 0x12e7: 0x002b, 0x12e8: 0x002d, 0x12e9: 0x002f, + 0x12ea: 0x0031, 0x12eb: 0x0033, 0x12ec: 0x0021, 0x12ed: 0x0023, 0x12ee: 0x0025, 0x12ef: 0x0027, + 0x12f0: 0x0029, 0x12f1: 0x002b, 0x12f2: 0x002d, 0x12f3: 0x002f, 0x12f4: 0x0031, 0x12f5: 0x0033, + 0x12f6: 0x0021, 0x12f7: 0x0023, 0x12f8: 0x0025, 0x12f9: 0x0027, 0x12fa: 0x0029, 0x12fb: 0x002b, + 0x12fc: 0x002d, 0x12fd: 0x002f, 0x12fe: 0x0031, 0x12ff: 0x0033, + // Block 0x4c, offset 0x1300 + 0x1300: 0x0239, 0x1301: 0x023c, 0x1302: 0x0248, 0x1303: 0x0251, 0x1305: 0x028a, + 0x1306: 0x025a, 0x1307: 0x024b, 0x1308: 0x0269, 0x1309: 0x0290, 0x130a: 0x027b, 0x130b: 0x027e, + 0x130c: 0x0281, 0x130d: 0x0284, 0x130e: 0x025d, 0x130f: 0x026f, 0x1310: 0x0275, 0x1311: 0x0263, + 0x1312: 0x0278, 0x1313: 0x0257, 0x1314: 0x0260, 0x1315: 0x0242, 0x1316: 0x0245, 0x1317: 0x024e, + 0x1318: 0x0254, 0x1319: 0x0266, 0x131a: 0x026c, 0x131b: 0x0272, 0x131c: 0x0293, 0x131d: 0x02e4, + 0x131e: 0x02cc, 0x131f: 0x0296, 0x1321: 0x023c, 0x1322: 0x0248, + 0x1324: 0x0287, 0x1327: 0x024b, 0x1329: 0x0290, + 0x132a: 0x027b, 0x132b: 0x027e, 0x132c: 0x0281, 0x132d: 0x0284, 0x132e: 0x025d, 0x132f: 0x026f, + 0x1330: 0x0275, 0x1331: 0x0263, 0x1332: 0x0278, 0x1334: 0x0260, 0x1335: 0x0242, + 0x1336: 0x0245, 0x1337: 0x024e, 0x1339: 0x0266, 0x133b: 0x0272, + // Block 0x4d, offset 0x1340 + 0x1342: 0x0248, + 0x1347: 0x024b, 0x1349: 0x0290, 0x134b: 0x027e, + 0x134d: 0x0284, 0x134e: 0x025d, 0x134f: 0x026f, 0x1351: 0x0263, + 0x1352: 0x0278, 0x1354: 0x0260, 0x1357: 0x024e, + 0x1359: 0x0266, 0x135b: 0x0272, 0x135d: 0x02e4, + 0x135f: 0x0296, 0x1361: 0x023c, 0x1362: 0x0248, + 0x1364: 0x0287, 0x1367: 0x024b, 0x1368: 0x0269, 0x1369: 0x0290, + 0x136a: 0x027b, 0x136c: 0x0281, 0x136d: 0x0284, 0x136e: 0x025d, 0x136f: 0x026f, + 0x1370: 0x0275, 0x1371: 0x0263, 0x1372: 0x0278, 0x1374: 0x0260, 0x1375: 0x0242, + 0x1376: 0x0245, 0x1377: 0x024e, 0x1379: 0x0266, 0x137a: 0x026c, 0x137b: 0x0272, + 0x137c: 0x0293, 0x137e: 0x02cc, + // Block 0x4e, offset 0x1380 + 0x1380: 0x0239, 0x1381: 0x023c, 0x1382: 0x0248, 0x1383: 0x0251, 0x1384: 0x0287, 0x1385: 0x028a, + 0x1386: 0x025a, 0x1387: 0x024b, 0x1388: 0x0269, 0x1389: 0x0290, 0x138b: 0x027e, + 0x138c: 0x0281, 0x138d: 0x0284, 0x138e: 0x025d, 0x138f: 0x026f, 0x1390: 0x0275, 0x1391: 0x0263, + 0x1392: 0x0278, 0x1393: 0x0257, 0x1394: 0x0260, 0x1395: 0x0242, 0x1396: 0x0245, 0x1397: 0x024e, + 0x1398: 0x0254, 0x1399: 0x0266, 0x139a: 0x026c, 0x139b: 0x0272, + 0x13a1: 0x023c, 0x13a2: 0x0248, 0x13a3: 0x0251, + 0x13a5: 0x028a, 0x13a6: 0x025a, 0x13a7: 0x024b, 0x13a8: 0x0269, 0x13a9: 0x0290, + 0x13ab: 0x027e, 0x13ac: 0x0281, 0x13ad: 0x0284, 0x13ae: 0x025d, 0x13af: 0x026f, + 0x13b0: 0x0275, 0x13b1: 0x0263, 0x13b2: 0x0278, 0x13b3: 0x0257, 0x13b4: 0x0260, 0x13b5: 0x0242, + 0x13b6: 0x0245, 0x13b7: 0x024e, 0x13b8: 0x0254, 0x13b9: 0x0266, 0x13ba: 0x026c, 0x13bb: 0x0272, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x1a0c, 0x13c1: 0x1a09, 0x13c2: 0x1a0f, 0x13c3: 0x1a33, 0x13c4: 0x1a57, 0x13c5: 0x1a7b, + 0x13c6: 0x1a9f, 0x13c7: 0x1aa8, 0x13c8: 0x1aae, 0x13c9: 0x1ab4, 0x13ca: 0x1aba, + 0x13d0: 0x1c1f, 0x13d1: 0x1c23, + 0x13d2: 0x1c27, 0x13d3: 0x1c2b, 0x13d4: 0x1c2f, 0x13d5: 0x1c33, 0x13d6: 0x1c37, 0x13d7: 0x1c3b, + 0x13d8: 0x1c3f, 0x13d9: 0x1c43, 0x13da: 0x1c47, 0x13db: 0x1c4b, 0x13dc: 0x1c4f, 0x13dd: 0x1c53, + 0x13de: 0x1c57, 0x13df: 0x1c5b, 0x13e0: 0x1c5f, 0x13e1: 0x1c63, 0x13e2: 0x1c67, 0x13e3: 0x1c6b, + 0x13e4: 0x1c6f, 0x13e5: 0x1c73, 0x13e6: 0x1c77, 0x13e7: 0x1c7b, 0x13e8: 0x1c7f, 0x13e9: 0x1c83, + 0x13ea: 0x291a, 0x13eb: 0x0047, 0x13ec: 0x0065, 0x13ed: 0x1acf, 0x13ee: 0x1b44, + 0x13f0: 0x0043, 0x13f1: 0x0045, 0x13f2: 0x0047, 0x13f3: 0x0049, 0x13f4: 0x004b, 0x13f5: 0x004d, + 0x13f6: 0x004f, 0x13f7: 0x0051, 0x13f8: 0x0053, 0x13f9: 0x0055, 0x13fa: 0x0057, 0x13fb: 0x0059, + 0x13fc: 0x005b, 0x13fd: 0x005d, 0x13fe: 0x005f, 0x13ff: 0x0061, + // Block 0x50, offset 0x1400 + 0x1400: 0x28a9, 0x1401: 0x28be, 0x1402: 0x057b, + 0x1410: 0x0c87, 0x1411: 0x0abf, + 0x1412: 0x094b, 0x1413: 0x45ff, 0x1414: 0x0793, 0x1415: 0x0a67, 0x1416: 0x13a7, 0x1417: 0x0a77, + 0x1418: 0x079f, 0x1419: 0x0d4f, 0x141a: 0x0f27, 0x141b: 0x0d27, 0x141c: 0x089f, 0x141d: 0x0be3, + 0x141e: 0x0837, 0x141f: 0x0d2f, 0x1420: 0x088b, 0x1421: 0x118f, 0x1422: 0x0ffb, 0x1423: 0x1403, + 0x1424: 0x0a4b, 0x1425: 0x0983, 0x1426: 0x0edb, 0x1427: 0x0c93, 0x1428: 0x0cbf, 0x1429: 0x0737, + 0x142a: 0x0743, 0x142b: 0x1483, 0x142c: 0x0b53, 0x142d: 0x075f, 0x142e: 0x0967, 0x142f: 0x0cb3, + 0x1430: 0x142b, 0x1431: 0x0c8b, 0x1432: 0x10e7, 0x1433: 0x1123, 0x1434: 0x096f, 0x1435: 0x0ebb, + 0x1436: 0x0d83, 0x1437: 0x0d7f, 0x1438: 0x100f, 0x1439: 0x08a3, 0x143a: 0x09cf, + // Block 0x51, offset 0x1440 + 0x1440: 0x0773, 0x1441: 0x076b, 0x1442: 0x077b, 0x1443: 0x16bb, 0x1444: 0x07bf, 0x1445: 0x07cf, + 0x1446: 0x07d3, 0x1447: 0x07db, 0x1448: 0x07e3, 0x1449: 0x07e7, 0x144a: 0x07f3, 0x144b: 0x07eb, + 0x144c: 0x062b, 0x144d: 0x16cf, 0x144e: 0x0807, 0x144f: 0x080b, 0x1450: 0x080f, 0x1451: 0x082b, + 0x1452: 0x16c0, 0x1453: 0x062f, 0x1454: 0x0817, 0x1455: 0x0837, 0x1456: 0x16ca, 0x1457: 0x0847, + 0x1458: 0x084f, 0x1459: 0x07af, 0x145a: 0x0857, 0x145b: 0x085b, 0x145c: 0x18a5, 0x145d: 0x0877, + 0x145e: 0x087f, 0x145f: 0x0637, 0x1460: 0x0897, 0x1461: 0x089b, 0x1462: 0x08a3, 0x1463: 0x08a7, + 0x1464: 0x063b, 0x1465: 0x08bf, 0x1466: 0x08c3, 0x1467: 0x08cf, 0x1468: 0x08db, 0x1469: 0x08df, + 0x146a: 0x08e3, 0x146b: 0x08eb, 0x146c: 0x090b, 0x146d: 0x090f, 0x146e: 0x0917, 0x146f: 0x0927, + 0x1470: 0x092f, 0x1471: 0x0933, 0x1472: 0x0933, 0x1473: 0x0933, 0x1474: 0x16de, 0x1475: 0x0f0b, + 0x1476: 0x0947, 0x1477: 0x094f, 0x1478: 0x16e3, 0x1479: 0x095b, 0x147a: 0x0963, 0x147b: 0x096b, + 0x147c: 0x0993, 0x147d: 0x097f, 0x147e: 0x098b, 0x147f: 0x098f, + // Block 0x52, offset 0x1480 + 0x1480: 0x0997, 0x1481: 0x099f, 0x1482: 0x09a3, 0x1483: 0x09ab, 0x1484: 0x09b3, 0x1485: 0x09b7, + 0x1486: 0x09b7, 0x1487: 0x09bf, 0x1488: 0x09c7, 0x1489: 0x09cb, 0x148a: 0x09d7, 0x148b: 0x09fb, + 0x148c: 0x09df, 0x148d: 0x09ff, 0x148e: 0x09e3, 0x148f: 0x09eb, 0x1490: 0x0883, 0x1491: 0x0a47, + 0x1492: 0x0a0f, 0x1493: 0x0a13, 0x1494: 0x0a17, 0x1495: 0x0a0b, 0x1496: 0x0a1f, 0x1497: 0x0a1b, + 0x1498: 0x0a33, 0x1499: 0x16e8, 0x149a: 0x0a4f, 0x149b: 0x0a53, 0x149c: 0x0a5b, 0x149d: 0x0a67, + 0x149e: 0x0a6f, 0x149f: 0x0a8b, 0x14a0: 0x16ed, 0x14a1: 0x16f2, 0x14a2: 0x0a97, 0x14a3: 0x0a9b, + 0x14a4: 0x0a9f, 0x14a5: 0x0a93, 0x14a6: 0x0aa7, 0x14a7: 0x063f, 0x14a8: 0x0643, 0x14a9: 0x0aaf, + 0x14aa: 0x0ab7, 0x14ab: 0x0ab7, 0x14ac: 0x16f7, 0x14ad: 0x0ad3, 0x14ae: 0x0ad7, 0x14af: 0x0adb, + 0x14b0: 0x0ae3, 0x14b1: 0x16fc, 0x14b2: 0x0aeb, 0x14b3: 0x0aef, 0x14b4: 0x0bc7, 0x14b5: 0x0af7, + 0x14b6: 0x0647, 0x14b7: 0x0b03, 0x14b8: 0x0b13, 0x14b9: 0x0b1f, 0x14ba: 0x0b1b, 0x14bb: 0x1706, + 0x14bc: 0x0b27, 0x14bd: 0x170b, 0x14be: 0x0b33, 0x14bf: 0x0b2f, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x0b37, 0x14c1: 0x0b47, 0x14c2: 0x0b4b, 0x14c3: 0x064b, 0x14c4: 0x0b5b, 0x14c5: 0x0b63, + 0x14c6: 0x0b67, 0x14c7: 0x0b6b, 0x14c8: 0x064f, 0x14c9: 0x1710, 0x14ca: 0x0653, 0x14cb: 0x0b87, + 0x14cc: 0x0b8b, 0x14cd: 0x0b8f, 0x14ce: 0x0b97, 0x14cf: 0x18d7, 0x14d0: 0x0baf, 0x14d1: 0x171a, + 0x14d2: 0x171a, 0x14d3: 0x124f, 0x14d4: 0x0bbf, 0x14d5: 0x0bbf, 0x14d6: 0x0657, 0x14d7: 0x173d, + 0x14d8: 0x180f, 0x14d9: 0x0bcf, 0x14da: 0x0bd7, 0x14db: 0x065b, 0x14dc: 0x0beb, 0x14dd: 0x0bfb, + 0x14de: 0x0bff, 0x14df: 0x0c07, 0x14e0: 0x0c17, 0x14e1: 0x0663, 0x14e2: 0x065f, 0x14e3: 0x0c1b, + 0x14e4: 0x171f, 0x14e5: 0x0c1f, 0x14e6: 0x0c33, 0x14e7: 0x0c37, 0x14e8: 0x0c3b, 0x14e9: 0x0c37, + 0x14ea: 0x0c47, 0x14eb: 0x0c4b, 0x14ec: 0x0c5b, 0x14ed: 0x0c53, 0x14ee: 0x0c57, 0x14ef: 0x0c5f, + 0x14f0: 0x0c63, 0x14f1: 0x0c67, 0x14f2: 0x0c73, 0x14f3: 0x0c77, 0x14f4: 0x0c8f, 0x14f5: 0x0c97, + 0x14f6: 0x0ca7, 0x14f7: 0x0cbb, 0x14f8: 0x172e, 0x14f9: 0x0cb7, 0x14fa: 0x0cab, 0x14fb: 0x0cc3, + 0x14fc: 0x0ccb, 0x14fd: 0x0cdf, 0x14fe: 0x1733, 0x14ff: 0x0ce7, + // Block 0x54, offset 0x1500 + 0x1500: 0x0cdb, 0x1501: 0x0cd3, 0x1502: 0x0667, 0x1503: 0x0cef, 0x1504: 0x0cf7, 0x1505: 0x0cff, + 0x1506: 0x0cf3, 0x1507: 0x066b, 0x1508: 0x0d0f, 0x1509: 0x0d17, 0x150a: 0x1738, 0x150b: 0x0d43, + 0x150c: 0x0d77, 0x150d: 0x0d53, 0x150e: 0x0677, 0x150f: 0x0d5f, 0x1510: 0x0673, 0x1511: 0x066f, + 0x1512: 0x083b, 0x1513: 0x083f, 0x1514: 0x0d7b, 0x1515: 0x0d63, 0x1516: 0x1223, 0x1517: 0x06db, + 0x1518: 0x0d87, 0x1519: 0x0d8b, 0x151a: 0x0d8f, 0x151b: 0x0da3, 0x151c: 0x0d9b, 0x151d: 0x1751, + 0x151e: 0x067b, 0x151f: 0x0db7, 0x1520: 0x0dab, 0x1521: 0x0dc7, 0x1522: 0x0dcf, 0x1523: 0x175b, + 0x1524: 0x0dd3, 0x1525: 0x0dbf, 0x1526: 0x0ddb, 0x1527: 0x067f, 0x1528: 0x0ddf, 0x1529: 0x0de3, + 0x152a: 0x0de7, 0x152b: 0x0df3, 0x152c: 0x1760, 0x152d: 0x0dfb, 0x152e: 0x0683, 0x152f: 0x0e07, + 0x1530: 0x1765, 0x1531: 0x0e0b, 0x1532: 0x0687, 0x1533: 0x0e17, 0x1534: 0x0e23, 0x1535: 0x0e2f, + 0x1536: 0x0e33, 0x1537: 0x176a, 0x1538: 0x1701, 0x1539: 0x176f, 0x153a: 0x0e53, 0x153b: 0x1774, + 0x153c: 0x0e5f, 0x153d: 0x0e67, 0x153e: 0x0e57, 0x153f: 0x0e73, + // Block 0x55, offset 0x1540 + 0x1540: 0x0e83, 0x1541: 0x0e93, 0x1542: 0x0e87, 0x1543: 0x0e8b, 0x1544: 0x0e97, 0x1545: 0x0e9b, + 0x1546: 0x1779, 0x1547: 0x0e7f, 0x1548: 0x0eb3, 0x1549: 0x0eb7, 0x154a: 0x068b, 0x154b: 0x0ecb, + 0x154c: 0x0ec7, 0x154d: 0x177e, 0x154e: 0x0eab, 0x154f: 0x0ee7, 0x1550: 0x1783, 0x1551: 0x1788, + 0x1552: 0x0eeb, 0x1553: 0x0eff, 0x1554: 0x0efb, 0x1555: 0x0ef7, 0x1556: 0x068f, 0x1557: 0x0f03, + 0x1558: 0x0f13, 0x1559: 0x0f0f, 0x155a: 0x0f1b, 0x155b: 0x16c5, 0x155c: 0x0f2b, 0x155d: 0x178d, + 0x155e: 0x0f37, 0x155f: 0x1797, 0x1560: 0x0f4b, 0x1561: 0x0f57, 0x1562: 0x0f6b, 0x1563: 0x179c, + 0x1564: 0x0f7f, 0x1565: 0x0f83, 0x1566: 0x17a1, 0x1567: 0x17a6, 0x1568: 0x0f9f, 0x1569: 0x0faf, + 0x156a: 0x0693, 0x156b: 0x0fb3, 0x156c: 0x0697, 0x156d: 0x0697, 0x156e: 0x0fcb, 0x156f: 0x0fcf, + 0x1570: 0x0fd7, 0x1571: 0x0fdb, 0x1572: 0x0fe7, 0x1573: 0x069b, 0x1574: 0x0fff, 0x1575: 0x17ab, + 0x1576: 0x101b, 0x1577: 0x17b0, 0x1578: 0x1027, 0x1579: 0x1715, 0x157a: 0x1037, 0x157b: 0x17b5, + 0x157c: 0x17ba, 0x157d: 0x17bf, 0x157e: 0x069f, 0x157f: 0x06a3, + // Block 0x56, offset 0x1580 + 0x1580: 0x106f, 0x1581: 0x17c9, 0x1582: 0x17c4, 0x1583: 0x17ce, 0x1584: 0x17d3, 0x1585: 0x1077, + 0x1586: 0x107b, 0x1587: 0x107b, 0x1588: 0x1083, 0x1589: 0x06ab, 0x158a: 0x1087, 0x158b: 0x06af, + 0x158c: 0x06b3, 0x158d: 0x17dd, 0x158e: 0x109b, 0x158f: 0x10a3, 0x1590: 0x10af, 0x1591: 0x06b7, + 0x1592: 0x17e2, 0x1593: 0x10d3, 0x1594: 0x17e7, 0x1595: 0x17ec, 0x1596: 0x10f3, 0x1597: 0x110b, + 0x1598: 0x06bb, 0x1599: 0x1113, 0x159a: 0x1117, 0x159b: 0x111b, 0x159c: 0x17f1, 0x159d: 0x17f6, + 0x159e: 0x17f6, 0x159f: 0x1133, 0x15a0: 0x06bf, 0x15a1: 0x17fb, 0x15a2: 0x1147, 0x15a3: 0x114b, + 0x15a4: 0x06c3, 0x15a5: 0x1800, 0x15a6: 0x1167, 0x15a7: 0x06c7, 0x15a8: 0x1177, 0x15a9: 0x116f, + 0x15aa: 0x117f, 0x15ab: 0x180a, 0x15ac: 0x1197, 0x15ad: 0x06cb, 0x15ae: 0x11a3, 0x15af: 0x11ab, + 0x15b0: 0x11bb, 0x15b1: 0x06cf, 0x15b2: 0x1814, 0x15b3: 0x1819, 0x15b4: 0x06d3, 0x15b5: 0x181e, + 0x15b6: 0x11d3, 0x15b7: 0x1823, 0x15b8: 0x11df, 0x15b9: 0x11eb, 0x15ba: 0x11f3, 0x15bb: 0x1828, + 0x15bc: 0x182d, 0x15bd: 0x1207, 0x15be: 0x1832, 0x15bf: 0x120f, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x1742, 0x15c1: 0x06d7, 0x15c2: 0x1227, 0x15c3: 0x122b, 0x15c4: 0x06df, 0x15c5: 0x122f, + 0x15c6: 0x0aab, 0x15c7: 0x1837, 0x15c8: 0x183c, 0x15c9: 0x1747, 0x15ca: 0x174c, 0x15cb: 0x124f, + 0x15cc: 0x1253, 0x15cd: 0x146b, 0x15ce: 0x06e3, 0x15cf: 0x127f, 0x15d0: 0x127b, 0x15d1: 0x1283, + 0x15d2: 0x08b7, 0x15d3: 0x1287, 0x15d4: 0x128b, 0x15d5: 0x128f, 0x15d6: 0x1297, 0x15d7: 0x1841, + 0x15d8: 0x1293, 0x15d9: 0x129b, 0x15da: 0x12af, 0x15db: 0x12b3, 0x15dc: 0x129f, 0x15dd: 0x12b7, + 0x15de: 0x12cb, 0x15df: 0x12df, 0x15e0: 0x12ab, 0x15e1: 0x12bf, 0x15e2: 0x12c3, 0x15e3: 0x12c7, + 0x15e4: 0x1846, 0x15e5: 0x1850, 0x15e6: 0x184b, 0x15e7: 0x06e7, 0x15e8: 0x12e7, 0x15e9: 0x12eb, + 0x15ea: 0x12f3, 0x15eb: 0x1864, 0x15ec: 0x12f7, 0x15ed: 0x1855, 0x15ee: 0x06eb, 0x15ef: 0x06ef, + 0x15f0: 0x185a, 0x15f1: 0x185f, 0x15f2: 0x06f3, 0x15f3: 0x1317, 0x15f4: 0x131b, 0x15f5: 0x131f, + 0x15f6: 0x1323, 0x15f7: 0x132f, 0x15f8: 0x132b, 0x15f9: 0x1337, 0x15fa: 0x1333, 0x15fb: 0x1343, + 0x15fc: 0x133b, 0x15fd: 0x133f, 0x15fe: 0x1347, 0x15ff: 0x06f7, + // Block 0x58, offset 0x1600 + 0x1600: 0x134f, 0x1601: 0x1353, 0x1602: 0x06fb, 0x1603: 0x1363, 0x1604: 0x1367, 0x1605: 0x1869, + 0x1606: 0x1373, 0x1607: 0x1377, 0x1608: 0x06ff, 0x1609: 0x1383, 0x160a: 0x0633, 0x160b: 0x186e, + 0x160c: 0x1873, 0x160d: 0x0703, 0x160e: 0x0707, 0x160f: 0x13af, 0x1610: 0x13c7, 0x1611: 0x13e3, + 0x1612: 0x13f3, 0x1613: 0x1878, 0x1614: 0x1407, 0x1615: 0x140b, 0x1616: 0x1423, 0x1617: 0x142f, + 0x1618: 0x1882, 0x1619: 0x16d4, 0x161a: 0x143b, 0x161b: 0x1437, 0x161c: 0x1443, 0x161d: 0x16d9, + 0x161e: 0x144f, 0x161f: 0x145b, 0x1620: 0x1887, 0x1621: 0x188c, 0x1622: 0x149b, 0x1623: 0x14a7, + 0x1624: 0x14af, 0x1625: 0x1891, 0x1626: 0x14b3, 0x1627: 0x14db, 0x1628: 0x14e7, 0x1629: 0x14eb, + 0x162a: 0x14e3, 0x162b: 0x14f7, 0x162c: 0x14fb, 0x162d: 0x1896, 0x162e: 0x1507, 0x162f: 0x070b, + 0x1630: 0x150f, 0x1631: 0x189b, 0x1632: 0x070f, 0x1633: 0x1547, 0x1634: 0x0b3b, 0x1635: 0x155f, + 0x1636: 0x18a0, 0x1637: 0x18aa, 0x1638: 0x0713, 0x1639: 0x0717, 0x163a: 0x1587, 0x163b: 0x18af, + 0x163c: 0x071b, 0x163d: 0x18b4, 0x163e: 0x159f, 0x163f: 0x159f, + // Block 0x59, offset 0x1640 + 0x1640: 0x15a7, 0x1641: 0x18b9, 0x1642: 0x15bf, 0x1643: 0x071f, 0x1644: 0x15cf, 0x1645: 0x15db, + 0x1646: 0x15e3, 0x1647: 0x15eb, 0x1648: 0x0723, 0x1649: 0x18be, 0x164a: 0x15ff, 0x164b: 0x161b, + 0x164c: 0x1627, 0x164d: 0x0727, 0x164e: 0x072b, 0x164f: 0x162b, 0x1650: 0x18c3, 0x1651: 0x072f, + 0x1652: 0x18c8, 0x1653: 0x18cd, 0x1654: 0x18d2, 0x1655: 0x164f, 0x1656: 0x0733, 0x1657: 0x1663, + 0x1658: 0x166b, 0x1659: 0x166f, 0x165a: 0x1677, 0x165b: 0x167f, 0x165c: 0x1687, 0x165d: 0x18dc, +} + +// nfkcIndex: 22 blocks, 1408 entries, 1408 bytes +// Block 0 is the zero block. +var nfkcIndex = [1408]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x58, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x59, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x5a, 0xcb: 0x5b, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09, + 0xd0: 0x0a, 0xd1: 0x5c, 0xd2: 0x5d, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x5e, + 0xd8: 0x5f, 0xd9: 0x0d, 0xdb: 0x60, 0xdc: 0x61, 0xdd: 0x62, 0xdf: 0x63, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x13, + // Block 0x4, offset 0x100 + 0x120: 0x64, 0x121: 0x65, 0x123: 0x66, 0x124: 0x67, 0x125: 0x68, 0x126: 0x69, 0x127: 0x6a, + 0x128: 0x6b, 0x129: 0x6c, 0x12a: 0x6d, 0x12b: 0x6e, 0x12c: 0x69, 0x12d: 0x6f, 0x12e: 0x70, 0x12f: 0x71, + 0x131: 0x72, 0x132: 0x73, 0x133: 0x74, 0x134: 0x75, 0x135: 0x76, 0x137: 0x77, + 0x138: 0x78, 0x139: 0x79, 0x13a: 0x7a, 0x13b: 0x7b, 0x13c: 0x7c, 0x13d: 0x7d, 0x13e: 0x7e, 0x13f: 0x7f, + // Block 0x5, offset 0x140 + 0x140: 0x80, 0x142: 0x81, 0x143: 0x82, 0x144: 0x83, 0x145: 0x84, 0x146: 0x85, 0x147: 0x86, + 0x14d: 0x87, + 0x15c: 0x88, 0x15f: 0x89, + 0x162: 0x8a, 0x164: 0x8b, + 0x168: 0x8c, 0x169: 0x8d, 0x16a: 0x8e, 0x16c: 0x0e, 0x16d: 0x8f, 0x16e: 0x90, 0x16f: 0x91, + 0x170: 0x92, 0x173: 0x93, 0x174: 0x94, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x95, + 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18, + // Block 0x6, offset 0x180 + 0x180: 0x96, 0x181: 0x97, 0x182: 0x98, 0x183: 0x99, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x9a, 0x187: 0x9b, + 0x188: 0x9c, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9d, 0x18c: 0x9e, + 0x191: 0x1d, 0x192: 0x1e, 0x193: 0x9f, + 0x1a8: 0xa0, 0x1a9: 0xa1, 0x1ab: 0xa2, + 0x1b1: 0xa3, 0x1b3: 0xa4, 0x1b5: 0xa5, 0x1b7: 0xa6, + 0x1ba: 0xa7, 0x1bb: 0xa8, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xa9, + // Block 0x7, offset 0x1c0 + 0x1c0: 0xaa, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xab, 0x1c5: 0xac, 0x1c6: 0x25, + 0x1c8: 0x26, 0x1c9: 0x27, 0x1ca: 0x28, 0x1cb: 0x29, 0x1cc: 0x2a, 0x1cd: 0x2b, 0x1ce: 0x2c, 0x1cf: 0x2d, + // Block 0x8, offset 0x200 + 0x219: 0xad, 0x21a: 0xae, 0x21b: 0xaf, 0x21d: 0xb0, 0x21f: 0xb1, + 0x220: 0xb2, 0x223: 0xb3, 0x224: 0xb4, 0x225: 0xb5, 0x226: 0xb6, 0x227: 0xb7, + 0x22a: 0xb8, 0x22b: 0xb9, 0x22d: 0xba, 0x22f: 0xbb, + 0x230: 0xbc, 0x231: 0xbd, 0x232: 0xbe, 0x233: 0xbf, 0x234: 0xc0, 0x235: 0xc1, 0x236: 0xc2, 0x237: 0xbc, + 0x238: 0xbd, 0x239: 0xbe, 0x23a: 0xbf, 0x23b: 0xc0, 0x23c: 0xc1, 0x23d: 0xc2, 0x23e: 0xbc, 0x23f: 0xbd, + // Block 0x9, offset 0x240 + 0x240: 0xbe, 0x241: 0xbf, 0x242: 0xc0, 0x243: 0xc1, 0x244: 0xc2, 0x245: 0xbc, 0x246: 0xbd, 0x247: 0xbe, + 0x248: 0xbf, 0x249: 0xc0, 0x24a: 0xc1, 0x24b: 0xc2, 0x24c: 0xbc, 0x24d: 0xbd, 0x24e: 0xbe, 0x24f: 0xbf, + 0x250: 0xc0, 0x251: 0xc1, 0x252: 0xc2, 0x253: 0xbc, 0x254: 0xbd, 0x255: 0xbe, 0x256: 0xbf, 0x257: 0xc0, + 0x258: 0xc1, 0x259: 0xc2, 0x25a: 0xbc, 0x25b: 0xbd, 0x25c: 0xbe, 0x25d: 0xbf, 0x25e: 0xc0, 0x25f: 0xc1, + 0x260: 0xc2, 0x261: 0xbc, 0x262: 0xbd, 0x263: 0xbe, 0x264: 0xbf, 0x265: 0xc0, 0x266: 0xc1, 0x267: 0xc2, + 0x268: 0xbc, 0x269: 0xbd, 0x26a: 0xbe, 0x26b: 0xbf, 0x26c: 0xc0, 0x26d: 0xc1, 0x26e: 0xc2, 0x26f: 0xbc, + 0x270: 0xbd, 0x271: 0xbe, 0x272: 0xbf, 0x273: 0xc0, 0x274: 0xc1, 0x275: 0xc2, 0x276: 0xbc, 0x277: 0xbd, + 0x278: 0xbe, 0x279: 0xbf, 0x27a: 0xc0, 0x27b: 0xc1, 0x27c: 0xc2, 0x27d: 0xbc, 0x27e: 0xbd, 0x27f: 0xbe, + // Block 0xa, offset 0x280 + 0x280: 0xbf, 0x281: 0xc0, 0x282: 0xc1, 0x283: 0xc2, 0x284: 0xbc, 0x285: 0xbd, 0x286: 0xbe, 0x287: 0xbf, + 0x288: 0xc0, 0x289: 0xc1, 0x28a: 0xc2, 0x28b: 0xbc, 0x28c: 0xbd, 0x28d: 0xbe, 0x28e: 0xbf, 0x28f: 0xc0, + 0x290: 0xc1, 0x291: 0xc2, 0x292: 0xbc, 0x293: 0xbd, 0x294: 0xbe, 0x295: 0xbf, 0x296: 0xc0, 0x297: 0xc1, + 0x298: 0xc2, 0x299: 0xbc, 0x29a: 0xbd, 0x29b: 0xbe, 0x29c: 0xbf, 0x29d: 0xc0, 0x29e: 0xc1, 0x29f: 0xc2, + 0x2a0: 0xbc, 0x2a1: 0xbd, 0x2a2: 0xbe, 0x2a3: 0xbf, 0x2a4: 0xc0, 0x2a5: 0xc1, 0x2a6: 0xc2, 0x2a7: 0xbc, + 0x2a8: 0xbd, 0x2a9: 0xbe, 0x2aa: 0xbf, 0x2ab: 0xc0, 0x2ac: 0xc1, 0x2ad: 0xc2, 0x2ae: 0xbc, 0x2af: 0xbd, + 0x2b0: 0xbe, 0x2b1: 0xbf, 0x2b2: 0xc0, 0x2b3: 0xc1, 0x2b4: 0xc2, 0x2b5: 0xbc, 0x2b6: 0xbd, 0x2b7: 0xbe, + 0x2b8: 0xbf, 0x2b9: 0xc0, 0x2ba: 0xc1, 0x2bb: 0xc2, 0x2bc: 0xbc, 0x2bd: 0xbd, 0x2be: 0xbe, 0x2bf: 0xbf, + // Block 0xb, offset 0x2c0 + 0x2c0: 0xc0, 0x2c1: 0xc1, 0x2c2: 0xc2, 0x2c3: 0xbc, 0x2c4: 0xbd, 0x2c5: 0xbe, 0x2c6: 0xbf, 0x2c7: 0xc0, + 0x2c8: 0xc1, 0x2c9: 0xc2, 0x2ca: 0xbc, 0x2cb: 0xbd, 0x2cc: 0xbe, 0x2cd: 0xbf, 0x2ce: 0xc0, 0x2cf: 0xc1, + 0x2d0: 0xc2, 0x2d1: 0xbc, 0x2d2: 0xbd, 0x2d3: 0xbe, 0x2d4: 0xbf, 0x2d5: 0xc0, 0x2d6: 0xc1, 0x2d7: 0xc2, + 0x2d8: 0xbc, 0x2d9: 0xbd, 0x2da: 0xbe, 0x2db: 0xbf, 0x2dc: 0xc0, 0x2dd: 0xc1, 0x2de: 0xc3, + // Block 0xc, offset 0x300 + 0x324: 0x2e, 0x325: 0x2f, 0x326: 0x30, 0x327: 0x31, + 0x328: 0x32, 0x329: 0x33, 0x32a: 0x34, 0x32b: 0x35, 0x32c: 0x36, 0x32d: 0x37, 0x32e: 0x38, 0x32f: 0x39, + 0x330: 0x3a, 0x331: 0x3b, 0x332: 0x3c, 0x333: 0x3d, 0x334: 0x3e, 0x335: 0x3f, 0x336: 0x40, 0x337: 0x41, + 0x338: 0x42, 0x339: 0x43, 0x33a: 0x44, 0x33b: 0x45, 0x33c: 0xc4, 0x33d: 0x46, 0x33e: 0x47, 0x33f: 0xc5, + // Block 0xd, offset 0x340 + 0x347: 0xc6, + 0x34b: 0xc7, 0x34d: 0xc8, + 0x368: 0xc9, 0x36b: 0xca, + // Block 0xe, offset 0x380 + 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb6, 0x387: 0xb7, + 0x388: 0xce, 0x38b: 0xcf, 0x38c: 0x69, 0x38d: 0xd0, + 0x392: 0xd1, 0x393: 0xd2, 0x396: 0xd3, 0x397: 0xd4, + 0x398: 0xd5, 0x39a: 0xd6, + // Block 0xf, offset 0x3c0 + 0x3eb: 0xd7, 0x3ec: 0xd8, + // Block 0x10, offset 0x400 + 0x432: 0xd9, + // Block 0x11, offset 0x440 + 0x445: 0xda, 0x446: 0xdb, 0x447: 0xdc, + 0x449: 0xdd, + 0x450: 0xde, 0x451: 0xdf, 0x452: 0xe0, 0x453: 0xe1, 0x454: 0xe2, 0x455: 0xe3, 0x456: 0xe4, 0x457: 0xe5, + 0x458: 0xe6, 0x459: 0xe7, 0x45a: 0x48, 0x45b: 0xe8, 0x45c: 0xe9, 0x45d: 0xea, 0x45e: 0xeb, 0x45f: 0x49, + // Block 0x12, offset 0x480 + 0x4a3: 0xec, + 0x4b8: 0x4a, 0x4b9: 0x4b, 0x4ba: 0x4c, + // Block 0x13, offset 0x4c0 + 0x4c4: 0x4d, 0x4c5: 0xed, 0x4c6: 0xee, + 0x4c8: 0x4e, 0x4c9: 0xef, + // Block 0x14, offset 0x500 + 0x520: 0x4f, 0x521: 0x50, 0x522: 0x51, 0x523: 0x52, 0x524: 0x53, 0x525: 0x54, 0x526: 0x55, 0x527: 0x56, + 0x528: 0x57, + // Block 0x15, offset 0x540 + 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, + 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, + 0x56f: 0x12, +} + +// nfkcSparseOffset: 152 entries, 304 bytes +var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x85, 0x8d, 0x94, 0x97, 0x9f, 0xa3, 0xa7, 0xa9, 0xab, 0xb4, 0xb8, 0xbf, 0xc4, 0xc7, 0xd1, 0xd3, 0xda, 0xe2, 0xe6, 0xe8, 0xeb, 0xef, 0xf5, 0x106, 0x112, 0x114, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12b, 0x12e, 0x130, 0x133, 0x136, 0x13a, 0x13f, 0x148, 0x14a, 0x14d, 0x14f, 0x15a, 0x165, 0x174, 0x182, 0x190, 0x1a0, 0x1ae, 0x1b5, 0x1bb, 0x1ca, 0x1ce, 0x1d0, 0x1d4, 0x1d6, 0x1d9, 0x1db, 0x1de, 0x1e0, 0x1e3, 0x1e5, 0x1e7, 0x1e9, 0x1f5, 0x1ff, 0x206, 0x213, 0x216, 0x219, 0x21b, 0x21d, 0x21f, 0x221, 0x224, 0x226, 0x228, 0x22a, 0x22c, 0x232, 0x235, 0x239, 0x23b, 0x242, 0x248, 0x24e, 0x256, 0x25c, 0x262, 0x268, 0x26c, 0x26e, 0x27d, 0x27f, 0x281, 0x283, 0x289, 0x28c, 0x28f, 0x297, 0x29e, 0x2a1, 0x2a3, 0x2ab, 0x2b2, 0x2b5, 0x2bb, 0x2bd, 0x2bf, 0x2c2, 0x2c4, 0x2c6, 0x2c8, 0x2d5, 0x2df, 0x2e1, 0x2e3, 0x2e7, 0x2ec, 0x2f8, 0x2fd, 0x306, 0x30c, 0x311, 0x315, 0x31a, 0x31e, 0x32e, 0x33c, 0x34a, 0x358, 0x35a, 0x364, 0x366} + +// nfkcSparseValues: 880 entries, 3520 bytes +var nfkcSparseValues = [880]valueRange{ + // Block 0x0, offset 0x0 + {value: 0x0002, lo: 0x0d}, + {value: 0x0001, lo: 0xa0, hi: 0xa0}, + {value: 0x42b3, lo: 0xa8, hi: 0xa8}, + {value: 0x0083, lo: 0xaa, hi: 0xaa}, + {value: 0x429f, lo: 0xaf, hi: 0xaf}, + {value: 0x0025, lo: 0xb2, hi: 0xb3}, + {value: 0x4295, lo: 0xb4, hi: 0xb4}, + {value: 0x01dc, lo: 0xb5, hi: 0xb5}, + {value: 0x42cc, lo: 0xb8, hi: 0xb8}, + {value: 0x0023, lo: 0xb9, hi: 0xb9}, + {value: 0x009f, lo: 0xba, hi: 0xba}, + {value: 0x23af, lo: 0xbc, hi: 0xbc}, + {value: 0x23a3, lo: 0xbd, hi: 0xbd}, + {value: 0x2445, lo: 0xbe, hi: 0xbe}, + // Block 0x1, offset 0xe + {value: 0x0091, lo: 0x03}, + {value: 0x471d, lo: 0xa0, hi: 0xa1}, + {value: 0x474f, lo: 0xaf, hi: 0xb0}, + {value: 0xa000, lo: 0xb7, hi: 0xb7}, + // Block 0x2, offset 0x12 + {value: 0x0003, lo: 0x08}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x0091, lo: 0xb0, hi: 0xb0}, + {value: 0x0119, lo: 0xb1, hi: 0xb1}, + {value: 0x0095, lo: 0xb2, hi: 0xb2}, + {value: 0x00a5, lo: 0xb3, hi: 0xb3}, + {value: 0x0143, lo: 0xb4, hi: 0xb6}, + {value: 0x00af, lo: 0xb7, hi: 0xb7}, + {value: 0x00b3, lo: 0xb8, hi: 0xb8}, + // Block 0x3, offset 0x1b + {value: 0x000a, lo: 0x09}, + {value: 0x42a9, lo: 0x98, hi: 0x98}, + {value: 0x42ae, lo: 0x99, hi: 0x9a}, + {value: 0x42d1, lo: 0x9b, hi: 0x9b}, + {value: 0x429a, lo: 0x9c, hi: 0x9c}, + {value: 0x42bd, lo: 0x9d, hi: 0x9d}, + {value: 0x0113, lo: 0xa0, hi: 0xa0}, + {value: 0x0099, lo: 0xa1, hi: 0xa1}, + {value: 0x00a7, lo: 0xa2, hi: 0xa3}, + {value: 0x0167, lo: 0xa4, hi: 0xa4}, + // Block 0x4, offset 0x25 + {value: 0x0000, lo: 0x0f}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0xa000, lo: 0x8d, hi: 0x8d}, + {value: 0x37e0, lo: 0x90, hi: 0x90}, + {value: 0x37ec, lo: 0x91, hi: 0x91}, + {value: 0x37da, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x96, hi: 0x96}, + {value: 0x3852, lo: 0x97, hi: 0x97}, + {value: 0x381c, lo: 0x9c, hi: 0x9c}, + {value: 0x3804, lo: 0x9d, hi: 0x9d}, + {value: 0x382e, lo: 0x9e, hi: 0x9e}, + {value: 0xa000, lo: 0xb4, hi: 0xb5}, + {value: 0x3858, lo: 0xb6, hi: 0xb6}, + {value: 0x385e, lo: 0xb7, hi: 0xb7}, + // Block 0x5, offset 0x35 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x83, hi: 0x87}, + // Block 0x6, offset 0x37 + {value: 0x0001, lo: 0x04}, + {value: 0x8113, lo: 0x81, hi: 0x82}, + {value: 0x8132, lo: 0x84, hi: 0x84}, + {value: 0x812d, lo: 0x85, hi: 0x85}, + {value: 0x810d, lo: 0x87, hi: 0x87}, + // Block 0x7, offset 0x3c + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x97}, + {value: 0x8119, lo: 0x98, hi: 0x98}, + {value: 0x811a, lo: 0x99, hi: 0x99}, + {value: 0x811b, lo: 0x9a, hi: 0x9a}, + {value: 0x387c, lo: 0xa2, hi: 0xa2}, + {value: 0x3882, lo: 0xa3, hi: 0xa3}, + {value: 0x388e, lo: 0xa4, hi: 0xa4}, + {value: 0x3888, lo: 0xa5, hi: 0xa5}, + {value: 0x3894, lo: 0xa6, hi: 0xa6}, + {value: 0xa000, lo: 0xa7, hi: 0xa7}, + // Block 0x8, offset 0x47 + {value: 0x0000, lo: 0x0e}, + {value: 0x38a6, lo: 0x80, hi: 0x80}, + {value: 0xa000, lo: 0x81, hi: 0x81}, + {value: 0x389a, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x38a0, lo: 0x93, hi: 0x93}, + {value: 0xa000, lo: 0x95, hi: 0x95}, + {value: 0x8132, lo: 0x96, hi: 0x9c}, + {value: 0x8132, lo: 0x9f, hi: 0xa2}, + {value: 0x812d, lo: 0xa3, hi: 0xa3}, + {value: 0x8132, lo: 0xa4, hi: 0xa4}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xaa, hi: 0xaa}, + {value: 0x8132, lo: 0xab, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + // Block 0x9, offset 0x56 + {value: 0x0000, lo: 0x0c}, + {value: 0x811f, lo: 0x91, hi: 0x91}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x812d, lo: 0xb1, hi: 0xb1}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb5, hi: 0xb6}, + {value: 0x812d, lo: 0xb7, hi: 0xb9}, + {value: 0x8132, lo: 0xba, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbc}, + {value: 0x8132, lo: 0xbd, hi: 0xbd}, + {value: 0x812d, lo: 0xbe, hi: 0xbe}, + {value: 0x8132, lo: 0xbf, hi: 0xbf}, + // Block 0xa, offset 0x63 + {value: 0x0005, lo: 0x07}, + {value: 0x8132, lo: 0x80, hi: 0x80}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x83}, + {value: 0x812d, lo: 0x84, hi: 0x85}, + {value: 0x812d, lo: 0x86, hi: 0x87}, + {value: 0x812d, lo: 0x88, hi: 0x89}, + {value: 0x8132, lo: 0x8a, hi: 0x8a}, + // Block 0xb, offset 0x6b + {value: 0x0000, lo: 0x03}, + {value: 0x8132, lo: 0xab, hi: 0xb1}, + {value: 0x812d, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb3}, + // Block 0xc, offset 0x6f + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0x96, hi: 0x99}, + {value: 0x8132, lo: 0x9b, hi: 0xa3}, + {value: 0x8132, lo: 0xa5, hi: 0xa7}, + {value: 0x8132, lo: 0xa9, hi: 0xad}, + // Block 0xd, offset 0x74 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x99, hi: 0x9b}, + // Block 0xe, offset 0x76 + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0xa4, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa8}, + {value: 0x812d, lo: 0xa9, hi: 0xa9}, + {value: 0x8132, lo: 0xaa, hi: 0xac}, + {value: 0x812d, lo: 0xad, hi: 0xaf}, + {value: 0x8116, lo: 0xb0, hi: 0xb0}, + {value: 0x8117, lo: 0xb1, hi: 0xb1}, + {value: 0x8118, lo: 0xb2, hi: 0xb2}, + {value: 0x8132, lo: 0xb3, hi: 0xb5}, + {value: 0x812d, lo: 0xb6, hi: 0xb6}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x812d, lo: 0xb9, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbf}, + // Block 0xf, offset 0x85 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0xa8, hi: 0xa8}, + {value: 0x3f13, lo: 0xa9, hi: 0xa9}, + {value: 0xa000, lo: 0xb0, hi: 0xb0}, + {value: 0x3f1b, lo: 0xb1, hi: 0xb1}, + {value: 0xa000, lo: 0xb3, hi: 0xb3}, + {value: 0x3f23, lo: 0xb4, hi: 0xb4}, + {value: 0x9902, lo: 0xbc, hi: 0xbc}, + // Block 0x10, offset 0x8d + {value: 0x0008, lo: 0x06}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x91, hi: 0x91}, + {value: 0x812d, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x93, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x94}, + {value: 0x4557, lo: 0x98, hi: 0x9f}, + // Block 0x11, offset 0x94 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x12, offset 0x97 + {value: 0x0007, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18e1, lo: 0x8b, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x4597, lo: 0x9c, hi: 0x9c}, + {value: 0x459f, lo: 0x9d, hi: 0x9d}, + {value: 0x45a7, lo: 0x9f, hi: 0x9f}, + // Block 0x13, offset 0x9f + {value: 0x0000, lo: 0x03}, + {value: 0x45cf, lo: 0xb3, hi: 0xb3}, + {value: 0x45d7, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x14, offset 0xa3 + {value: 0x0008, lo: 0x03}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x45af, lo: 0x99, hi: 0x9b}, + {value: 0x45c7, lo: 0x9e, hi: 0x9e}, + // Block 0x15, offset 0xa7 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + // Block 0x16, offset 0xa9 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + // Block 0x17, offset 0xab + {value: 0x0000, lo: 0x08}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x18f6, lo: 0x88, hi: 0x88}, + {value: 0x18ef, lo: 0x8b, hi: 0x8b}, + {value: 0x18fd, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x96, hi: 0x97}, + {value: 0x45df, lo: 0x9c, hi: 0x9c}, + {value: 0x45e7, lo: 0x9d, hi: 0x9d}, + // Block 0x18, offset 0xb4 + {value: 0x0000, lo: 0x03}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0x1904, lo: 0x94, hi: 0x94}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x19, offset 0xb8 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x190b, lo: 0x8a, hi: 0x8a}, + {value: 0x1919, lo: 0x8b, hi: 0x8b}, + {value: 0x1912, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1a, offset 0xbf + {value: 0x1801, lo: 0x04}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x3f2b, lo: 0x88, hi: 0x88}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x8120, lo: 0x95, hi: 0x96}, + // Block 0x1b, offset 0xc4 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xbc, hi: 0xbc}, + {value: 0xa000, lo: 0xbf, hi: 0xbf}, + // Block 0x1c, offset 0xc7 + {value: 0x0000, lo: 0x09}, + {value: 0x1920, lo: 0x80, hi: 0x80}, + {value: 0x9900, lo: 0x82, hi: 0x82}, + {value: 0xa000, lo: 0x86, hi: 0x86}, + {value: 0x1927, lo: 0x87, hi: 0x87}, + {value: 0x192e, lo: 0x88, hi: 0x88}, + {value: 0x2eb7, lo: 0x8a, hi: 0x8a}, + {value: 0x19f6, lo: 0x8b, hi: 0x8b}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x95, hi: 0x96}, + // Block 0x1d, offset 0xd1 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xbe, hi: 0xbe}, + // Block 0x1e, offset 0xd3 + {value: 0x0000, lo: 0x06}, + {value: 0xa000, lo: 0x86, hi: 0x87}, + {value: 0x1935, lo: 0x8a, hi: 0x8a}, + {value: 0x1943, lo: 0x8b, hi: 0x8b}, + {value: 0x193c, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + // Block 0x1f, offset 0xda + {value: 0x0007, lo: 0x07}, + {value: 0x9904, lo: 0x8a, hi: 0x8a}, + {value: 0x9900, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x3f33, lo: 0x9a, hi: 0x9a}, + {value: 0x2ebe, lo: 0x9c, hi: 0x9d}, + {value: 0x194a, lo: 0x9e, hi: 0x9e}, + {value: 0x9900, lo: 0x9f, hi: 0x9f}, + // Block 0x20, offset 0xe2 + {value: 0x0000, lo: 0x03}, + {value: 0x27b4, lo: 0xb3, hi: 0xb3}, + {value: 0x8122, lo: 0xb8, hi: 0xb9}, + {value: 0x8104, lo: 0xba, hi: 0xba}, + // Block 0x21, offset 0xe6 + {value: 0x0000, lo: 0x01}, + {value: 0x8123, lo: 0x88, hi: 0x8b}, + // Block 0x22, offset 0xe8 + {value: 0x0000, lo: 0x02}, + {value: 0x27c9, lo: 0xb3, hi: 0xb3}, + {value: 0x8124, lo: 0xb8, hi: 0xb9}, + // Block 0x23, offset 0xeb + {value: 0x0000, lo: 0x03}, + {value: 0x8125, lo: 0x88, hi: 0x8b}, + {value: 0x27bb, lo: 0x9c, hi: 0x9c}, + {value: 0x27c2, lo: 0x9d, hi: 0x9d}, + // Block 0x24, offset 0xef + {value: 0x0000, lo: 0x05}, + {value: 0x030b, lo: 0x8c, hi: 0x8c}, + {value: 0x812d, lo: 0x98, hi: 0x99}, + {value: 0x812d, lo: 0xb5, hi: 0xb5}, + {value: 0x812d, lo: 0xb7, hi: 0xb7}, + {value: 0x812b, lo: 0xb9, hi: 0xb9}, + // Block 0x25, offset 0xf5 + {value: 0x0000, lo: 0x10}, + {value: 0x27d7, lo: 0x83, hi: 0x83}, + {value: 0x27de, lo: 0x8d, hi: 0x8d}, + {value: 0x27e5, lo: 0x92, hi: 0x92}, + {value: 0x27ec, lo: 0x97, hi: 0x97}, + {value: 0x27f3, lo: 0x9c, hi: 0x9c}, + {value: 0x27d0, lo: 0xa9, hi: 0xa9}, + {value: 0x8126, lo: 0xb1, hi: 0xb1}, + {value: 0x8127, lo: 0xb2, hi: 0xb2}, + {value: 0x4a0b, lo: 0xb3, hi: 0xb3}, + {value: 0x8128, lo: 0xb4, hi: 0xb4}, + {value: 0x4a14, lo: 0xb5, hi: 0xb5}, + {value: 0x45ef, lo: 0xb6, hi: 0xb6}, + {value: 0x462f, lo: 0xb7, hi: 0xb7}, + {value: 0x45f7, lo: 0xb8, hi: 0xb8}, + {value: 0x463a, lo: 0xb9, hi: 0xb9}, + {value: 0x8127, lo: 0xba, hi: 0xbd}, + // Block 0x26, offset 0x106 + {value: 0x0000, lo: 0x0b}, + {value: 0x8127, lo: 0x80, hi: 0x80}, + {value: 0x4a1d, lo: 0x81, hi: 0x81}, + {value: 0x8132, lo: 0x82, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0x86, hi: 0x87}, + {value: 0x2801, lo: 0x93, hi: 0x93}, + {value: 0x2808, lo: 0x9d, hi: 0x9d}, + {value: 0x280f, lo: 0xa2, hi: 0xa2}, + {value: 0x2816, lo: 0xa7, hi: 0xa7}, + {value: 0x281d, lo: 0xac, hi: 0xac}, + {value: 0x27fa, lo: 0xb9, hi: 0xb9}, + // Block 0x27, offset 0x112 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x86, hi: 0x86}, + // Block 0x28, offset 0x114 + {value: 0x0000, lo: 0x05}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x1951, lo: 0xa6, hi: 0xa6}, + {value: 0x9900, lo: 0xae, hi: 0xae}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x29, offset 0x11a + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + // Block 0x2a, offset 0x11c + {value: 0x0000, lo: 0x01}, + {value: 0x030f, lo: 0xbc, hi: 0xbc}, + // Block 0x2b, offset 0x11e + {value: 0x0000, lo: 0x01}, + {value: 0xa000, lo: 0x80, hi: 0x92}, + // Block 0x2c, offset 0x120 + {value: 0x0000, lo: 0x01}, + {value: 0xb900, lo: 0xa1, hi: 0xb5}, + // Block 0x2d, offset 0x122 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0xa8, hi: 0xbf}, + // Block 0x2e, offset 0x124 + {value: 0x0000, lo: 0x01}, + {value: 0x9900, lo: 0x80, hi: 0x82}, + // Block 0x2f, offset 0x126 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x9d, hi: 0x9f}, + // Block 0x30, offset 0x128 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x94, hi: 0x94}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x31, offset 0x12b + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x92, hi: 0x92}, + {value: 0x8132, lo: 0x9d, hi: 0x9d}, + // Block 0x32, offset 0x12e + {value: 0x0000, lo: 0x01}, + {value: 0x8131, lo: 0xa9, hi: 0xa9}, + // Block 0x33, offset 0x130 + {value: 0x0004, lo: 0x02}, + {value: 0x812e, lo: 0xb9, hi: 0xba}, + {value: 0x812d, lo: 0xbb, hi: 0xbb}, + // Block 0x34, offset 0x133 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x97, hi: 0x97}, + {value: 0x812d, lo: 0x98, hi: 0x98}, + // Block 0x35, offset 0x136 + {value: 0x0000, lo: 0x03}, + {value: 0x8104, lo: 0xa0, hi: 0xa0}, + {value: 0x8132, lo: 0xb5, hi: 0xbc}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x36, offset 0x13a + {value: 0x0000, lo: 0x04}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + {value: 0x812d, lo: 0xb5, hi: 0xba}, + {value: 0x8132, lo: 0xbb, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x37, offset 0x13f + {value: 0x0000, lo: 0x08}, + {value: 0x1990, lo: 0x80, hi: 0x80}, + {value: 0x1997, lo: 0x81, hi: 0x81}, + {value: 0xa000, lo: 0x82, hi: 0x82}, + {value: 0x199e, lo: 0x83, hi: 0x83}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xab, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xac}, + {value: 0x8132, lo: 0xad, hi: 0xb3}, + // Block 0x38, offset 0x148 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xaa, hi: 0xab}, + // Block 0x39, offset 0x14a + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0xa6, hi: 0xa6}, + {value: 0x8104, lo: 0xb2, hi: 0xb3}, + // Block 0x3a, offset 0x14d + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x3b, offset 0x14f + {value: 0x0000, lo: 0x0a}, + {value: 0x8132, lo: 0x90, hi: 0x92}, + {value: 0x8101, lo: 0x94, hi: 0x94}, + {value: 0x812d, lo: 0x95, hi: 0x99}, + {value: 0x8132, lo: 0x9a, hi: 0x9b}, + {value: 0x812d, lo: 0x9c, hi: 0x9f}, + {value: 0x8132, lo: 0xa0, hi: 0xa0}, + {value: 0x8101, lo: 0xa2, hi: 0xa8}, + {value: 0x812d, lo: 0xad, hi: 0xad}, + {value: 0x8132, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb8, hi: 0xb9}, + // Block 0x3c, offset 0x15a + {value: 0x0002, lo: 0x0a}, + {value: 0x0043, lo: 0xac, hi: 0xac}, + {value: 0x00d1, lo: 0xad, hi: 0xad}, + {value: 0x0045, lo: 0xae, hi: 0xae}, + {value: 0x0049, lo: 0xb0, hi: 0xb1}, + {value: 0x00e6, lo: 0xb2, hi: 0xb2}, + {value: 0x004f, lo: 0xb3, hi: 0xba}, + {value: 0x005f, lo: 0xbc, hi: 0xbc}, + {value: 0x00ef, lo: 0xbd, hi: 0xbd}, + {value: 0x0061, lo: 0xbe, hi: 0xbe}, + {value: 0x0065, lo: 0xbf, hi: 0xbf}, + // Block 0x3d, offset 0x165 + {value: 0x0000, lo: 0x0e}, + {value: 0x8132, lo: 0x80, hi: 0x81}, + {value: 0x812d, lo: 0x82, hi: 0x82}, + {value: 0x8132, lo: 0x83, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8a}, + {value: 0x8132, lo: 0x8b, hi: 0x8c}, + {value: 0x8135, lo: 0x8d, hi: 0x8d}, + {value: 0x812a, lo: 0x8e, hi: 0x8e}, + {value: 0x812d, lo: 0x8f, hi: 0x8f}, + {value: 0x8129, lo: 0x90, hi: 0x90}, + {value: 0x8132, lo: 0x91, hi: 0xb5}, + {value: 0x8134, lo: 0xbc, hi: 0xbc}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + {value: 0x8132, lo: 0xbe, hi: 0xbe}, + {value: 0x812d, lo: 0xbf, hi: 0xbf}, + // Block 0x3e, offset 0x174 + {value: 0x0000, lo: 0x0d}, + {value: 0x0001, lo: 0x80, hi: 0x8a}, + {value: 0x04b3, lo: 0x91, hi: 0x91}, + {value: 0x42d6, lo: 0x97, hi: 0x97}, + {value: 0x001d, lo: 0xa4, hi: 0xa4}, + {value: 0x1a06, lo: 0xa5, hi: 0xa5}, + {value: 0x1cef, lo: 0xa6, hi: 0xa6}, + {value: 0x0001, lo: 0xaf, hi: 0xaf}, + {value: 0x288d, lo: 0xb3, hi: 0xb3}, + {value: 0x29fa, lo: 0xb4, hi: 0xb4}, + {value: 0x2894, lo: 0xb6, hi: 0xb6}, + {value: 0x2a04, lo: 0xb7, hi: 0xb7}, + {value: 0x1a00, lo: 0xbc, hi: 0xbc}, + {value: 0x42a4, lo: 0xbe, hi: 0xbe}, + // Block 0x3f, offset 0x182 + {value: 0x0002, lo: 0x0d}, + {value: 0x1ac6, lo: 0x87, hi: 0x87}, + {value: 0x1ac3, lo: 0x88, hi: 0x88}, + {value: 0x1a03, lo: 0x89, hi: 0x89}, + {value: 0x2b97, lo: 0x97, hi: 0x97}, + {value: 0x0001, lo: 0x9f, hi: 0x9f}, + {value: 0x0021, lo: 0xb0, hi: 0xb0}, + {value: 0x0093, lo: 0xb1, hi: 0xb1}, + {value: 0x0029, lo: 0xb4, hi: 0xb9}, + {value: 0x0017, lo: 0xba, hi: 0xba}, + {value: 0x04df, lo: 0xbb, hi: 0xbb}, + {value: 0x003b, lo: 0xbc, hi: 0xbc}, + {value: 0x0011, lo: 0xbd, hi: 0xbe}, + {value: 0x009d, lo: 0xbf, hi: 0xbf}, + // Block 0x40, offset 0x190 + {value: 0x0002, lo: 0x0f}, + {value: 0x0021, lo: 0x80, hi: 0x89}, + {value: 0x0017, lo: 0x8a, hi: 0x8a}, + {value: 0x04df, lo: 0x8b, hi: 0x8b}, + {value: 0x003b, lo: 0x8c, hi: 0x8c}, + {value: 0x0011, lo: 0x8d, hi: 0x8e}, + {value: 0x0083, lo: 0x90, hi: 0x90}, + {value: 0x008b, lo: 0x91, hi: 0x91}, + {value: 0x009f, lo: 0x92, hi: 0x92}, + {value: 0x00b1, lo: 0x93, hi: 0x93}, + {value: 0x0104, lo: 0x94, hi: 0x94}, + {value: 0x0091, lo: 0x95, hi: 0x95}, + {value: 0x0097, lo: 0x96, hi: 0x99}, + {value: 0x00a1, lo: 0x9a, hi: 0x9a}, + {value: 0x00a7, lo: 0x9b, hi: 0x9c}, + {value: 0x1b2c, lo: 0xa8, hi: 0xa8}, + // Block 0x41, offset 0x1a0 + {value: 0x0000, lo: 0x0d}, + {value: 0x8132, lo: 0x90, hi: 0x91}, + {value: 0x8101, lo: 0x92, hi: 0x93}, + {value: 0x8132, lo: 0x94, hi: 0x97}, + {value: 0x8101, lo: 0x98, hi: 0x9a}, + {value: 0x8132, lo: 0x9b, hi: 0x9c}, + {value: 0x8132, lo: 0xa1, hi: 0xa1}, + {value: 0x8101, lo: 0xa5, hi: 0xa6}, + {value: 0x8132, lo: 0xa7, hi: 0xa7}, + {value: 0x812d, lo: 0xa8, hi: 0xa8}, + {value: 0x8132, lo: 0xa9, hi: 0xa9}, + {value: 0x8101, lo: 0xaa, hi: 0xab}, + {value: 0x812d, lo: 0xac, hi: 0xaf}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + // Block 0x42, offset 0x1ae + {value: 0x0007, lo: 0x06}, + {value: 0x2313, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + {value: 0x3bf4, lo: 0x9a, hi: 0x9b}, + {value: 0x3c02, lo: 0xae, hi: 0xae}, + // Block 0x43, offset 0x1b5 + {value: 0x000e, lo: 0x05}, + {value: 0x3c09, lo: 0x8d, hi: 0x8e}, + {value: 0x3c10, lo: 0x8f, hi: 0x8f}, + {value: 0xa000, lo: 0x90, hi: 0x90}, + {value: 0xa000, lo: 0x92, hi: 0x92}, + {value: 0xa000, lo: 0x94, hi: 0x94}, + // Block 0x44, offset 0x1bb + {value: 0x0173, lo: 0x0e}, + {value: 0xa000, lo: 0x83, hi: 0x83}, + {value: 0x3c1e, lo: 0x84, hi: 0x84}, + {value: 0xa000, lo: 0x88, hi: 0x88}, + {value: 0x3c25, lo: 0x89, hi: 0x89}, + {value: 0xa000, lo: 0x8b, hi: 0x8b}, + {value: 0x3c2c, lo: 0x8c, hi: 0x8c}, + {value: 0xa000, lo: 0xa3, hi: 0xa3}, + {value: 0x3c33, lo: 0xa4, hi: 0xa4}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x3c3a, lo: 0xa6, hi: 0xa6}, + {value: 0x289b, lo: 0xac, hi: 0xad}, + {value: 0x28a2, lo: 0xaf, hi: 0xaf}, + {value: 0x2a18, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xbc, hi: 0xbc}, + // Block 0x45, offset 0x1ca + {value: 0x0007, lo: 0x03}, + {value: 0x3ca3, lo: 0xa0, hi: 0xa1}, + {value: 0x3ccd, lo: 0xa2, hi: 0xa3}, + {value: 0x3cf7, lo: 0xaa, hi: 0xad}, + // Block 0x46, offset 0x1ce + {value: 0x0004, lo: 0x01}, + {value: 0x0503, lo: 0xa9, hi: 0xaa}, + // Block 0x47, offset 0x1d0 + {value: 0x0002, lo: 0x03}, + {value: 0x0057, lo: 0x80, hi: 0x8f}, + {value: 0x0083, lo: 0x90, hi: 0xa9}, + {value: 0x0021, lo: 0xaa, hi: 0xaa}, + // Block 0x48, offset 0x1d4 + {value: 0x0000, lo: 0x01}, + {value: 0x2ba4, lo: 0x8c, hi: 0x8c}, + // Block 0x49, offset 0x1d6 + {value: 0x0263, lo: 0x02}, + {value: 0x1d1f, lo: 0xb4, hi: 0xb4}, + {value: 0x1ac0, lo: 0xb5, hi: 0xb6}, + // Block 0x4a, offset 0x1d9 + {value: 0x0000, lo: 0x01}, + {value: 0x4518, lo: 0x9c, hi: 0x9c}, + // Block 0x4b, offset 0x1db + {value: 0x0000, lo: 0x02}, + {value: 0x0095, lo: 0xbc, hi: 0xbc}, + {value: 0x006d, lo: 0xbd, hi: 0xbd}, + // Block 0x4c, offset 0x1de + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xaf, hi: 0xb1}, + // Block 0x4d, offset 0x1e0 + {value: 0x0000, lo: 0x02}, + {value: 0x04f7, lo: 0xaf, hi: 0xaf}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x4e, offset 0x1e3 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xa0, hi: 0xbf}, + // Block 0x4f, offset 0x1e5 + {value: 0x0000, lo: 0x01}, + {value: 0x0e3b, lo: 0x9f, hi: 0x9f}, + // Block 0x50, offset 0x1e7 + {value: 0x0000, lo: 0x01}, + {value: 0x16a3, lo: 0xb3, hi: 0xb3}, + // Block 0x51, offset 0x1e9 + {value: 0x0004, lo: 0x0b}, + {value: 0x160b, lo: 0x80, hi: 0x82}, + {value: 0x1623, lo: 0x83, hi: 0x83}, + {value: 0x163b, lo: 0x84, hi: 0x85}, + {value: 0x164b, lo: 0x86, hi: 0x89}, + {value: 0x165f, lo: 0x8a, hi: 0x8c}, + {value: 0x1673, lo: 0x8d, hi: 0x8d}, + {value: 0x167b, lo: 0x8e, hi: 0x8e}, + {value: 0x1683, lo: 0x8f, hi: 0x90}, + {value: 0x168f, lo: 0x91, hi: 0x93}, + {value: 0x169f, lo: 0x94, hi: 0x94}, + {value: 0x16a7, lo: 0x95, hi: 0x95}, + // Block 0x52, offset 0x1f5 + {value: 0x0004, lo: 0x09}, + {value: 0x0001, lo: 0x80, hi: 0x80}, + {value: 0x812c, lo: 0xaa, hi: 0xaa}, + {value: 0x8131, lo: 0xab, hi: 0xab}, + {value: 0x8133, lo: 0xac, hi: 0xac}, + {value: 0x812e, lo: 0xad, hi: 0xad}, + {value: 0x812f, lo: 0xae, hi: 0xae}, + {value: 0x812f, lo: 0xaf, hi: 0xaf}, + {value: 0x052b, lo: 0xb6, hi: 0xb6}, + {value: 0x08ff, lo: 0xb8, hi: 0xba}, + // Block 0x53, offset 0x1ff + {value: 0x0004, lo: 0x06}, + {value: 0x0313, lo: 0xb1, hi: 0xb2}, + {value: 0x043b, lo: 0xb3, hi: 0xb3}, + {value: 0x031b, lo: 0xb4, hi: 0xb4}, + {value: 0x043f, lo: 0xb5, hi: 0xb6}, + {value: 0x031f, lo: 0xb7, hi: 0xb9}, + {value: 0x0447, lo: 0xba, hi: 0xbf}, + // Block 0x54, offset 0x206 + {value: 0x0004, lo: 0x0c}, + {value: 0x0367, lo: 0x80, hi: 0x80}, + {value: 0x032b, lo: 0x81, hi: 0x83}, + {value: 0x037b, lo: 0x84, hi: 0x84}, + {value: 0x0337, lo: 0x85, hi: 0x8e}, + {value: 0x03c7, lo: 0x8f, hi: 0xa3}, + {value: 0x03c3, lo: 0xa4, hi: 0xa4}, + {value: 0x035f, lo: 0xa5, hi: 0xa6}, + {value: 0x045f, lo: 0xa7, hi: 0xad}, + {value: 0x036b, lo: 0xae, hi: 0xae}, + {value: 0x047b, lo: 0xaf, hi: 0xb0}, + {value: 0x036f, lo: 0xb1, hi: 0xb3}, + {value: 0x037f, lo: 0xb4, hi: 0xbf}, + // Block 0x55, offset 0x213 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xaf, hi: 0xaf}, + {value: 0x8132, lo: 0xb4, hi: 0xbd}, + // Block 0x56, offset 0x216 + {value: 0x0003, lo: 0x02}, + {value: 0x020f, lo: 0x9c, hi: 0x9d}, + {value: 0x8132, lo: 0x9f, hi: 0x9f}, + // Block 0x57, offset 0x219 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb1}, + // Block 0x58, offset 0x21b + {value: 0x0000, lo: 0x01}, + {value: 0x16af, lo: 0xb0, hi: 0xb0}, + // Block 0x59, offset 0x21d + {value: 0x000c, lo: 0x01}, + {value: 0x00d7, lo: 0xb8, hi: 0xb9}, + // Block 0x5a, offset 0x21f + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + // Block 0x5b, offset 0x221 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x84, hi: 0x84}, + {value: 0x8132, lo: 0xa0, hi: 0xb1}, + // Block 0x5c, offset 0x224 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xab, hi: 0xad}, + // Block 0x5d, offset 0x226 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x93, hi: 0x93}, + // Block 0x5e, offset 0x228 + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0xb3, hi: 0xb3}, + // Block 0x5f, offset 0x22a + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x80, hi: 0x80}, + // Block 0x60, offset 0x22c + {value: 0x0000, lo: 0x05}, + {value: 0x8132, lo: 0xb0, hi: 0xb0}, + {value: 0x8132, lo: 0xb2, hi: 0xb3}, + {value: 0x812d, lo: 0xb4, hi: 0xb4}, + {value: 0x8132, lo: 0xb7, hi: 0xb8}, + {value: 0x8132, lo: 0xbe, hi: 0xbf}, + // Block 0x61, offset 0x232 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0x81, hi: 0x81}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + // Block 0x62, offset 0x235 + {value: 0x0008, lo: 0x03}, + {value: 0x16ab, lo: 0x9c, hi: 0x9d}, + {value: 0x0125, lo: 0x9e, hi: 0x9e}, + {value: 0x16b7, lo: 0x9f, hi: 0x9f}, + // Block 0x63, offset 0x239 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xad, hi: 0xad}, + // Block 0x64, offset 0x23b + {value: 0x0000, lo: 0x06}, + {value: 0xe500, lo: 0x80, hi: 0x80}, + {value: 0xc600, lo: 0x81, hi: 0x9b}, + {value: 0xe500, lo: 0x9c, hi: 0x9c}, + {value: 0xc600, lo: 0x9d, hi: 0xb7}, + {value: 0xe500, lo: 0xb8, hi: 0xb8}, + {value: 0xc600, lo: 0xb9, hi: 0xbf}, + // Block 0x65, offset 0x242 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x93}, + {value: 0xe500, lo: 0x94, hi: 0x94}, + {value: 0xc600, lo: 0x95, hi: 0xaf}, + {value: 0xe500, lo: 0xb0, hi: 0xb0}, + {value: 0xc600, lo: 0xb1, hi: 0xbf}, + // Block 0x66, offset 0x248 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8b}, + {value: 0xe500, lo: 0x8c, hi: 0x8c}, + {value: 0xc600, lo: 0x8d, hi: 0xa7}, + {value: 0xe500, lo: 0xa8, hi: 0xa8}, + {value: 0xc600, lo: 0xa9, hi: 0xbf}, + // Block 0x67, offset 0x24e + {value: 0x0000, lo: 0x07}, + {value: 0xc600, lo: 0x80, hi: 0x83}, + {value: 0xe500, lo: 0x84, hi: 0x84}, + {value: 0xc600, lo: 0x85, hi: 0x9f}, + {value: 0xe500, lo: 0xa0, hi: 0xa0}, + {value: 0xc600, lo: 0xa1, hi: 0xbb}, + {value: 0xe500, lo: 0xbc, hi: 0xbc}, + {value: 0xc600, lo: 0xbd, hi: 0xbf}, + // Block 0x68, offset 0x256 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x97}, + {value: 0xe500, lo: 0x98, hi: 0x98}, + {value: 0xc600, lo: 0x99, hi: 0xb3}, + {value: 0xe500, lo: 0xb4, hi: 0xb4}, + {value: 0xc600, lo: 0xb5, hi: 0xbf}, + // Block 0x69, offset 0x25c + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x8f}, + {value: 0xe500, lo: 0x90, hi: 0x90}, + {value: 0xc600, lo: 0x91, hi: 0xab}, + {value: 0xe500, lo: 0xac, hi: 0xac}, + {value: 0xc600, lo: 0xad, hi: 0xbf}, + // Block 0x6a, offset 0x262 + {value: 0x0000, lo: 0x05}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + {value: 0xe500, lo: 0xa4, hi: 0xa4}, + {value: 0xc600, lo: 0xa5, hi: 0xbf}, + // Block 0x6b, offset 0x268 + {value: 0x0000, lo: 0x03}, + {value: 0xc600, lo: 0x80, hi: 0x87}, + {value: 0xe500, lo: 0x88, hi: 0x88}, + {value: 0xc600, lo: 0x89, hi: 0xa3}, + // Block 0x6c, offset 0x26c + {value: 0x0002, lo: 0x01}, + {value: 0x0003, lo: 0x81, hi: 0xbf}, + // Block 0x6d, offset 0x26e + {value: 0x0004, lo: 0x0e}, + {value: 0x03c7, lo: 0x82, hi: 0x87}, + {value: 0x03df, lo: 0x8a, hi: 0x8f}, + {value: 0x03f7, lo: 0x92, hi: 0x97}, + {value: 0x040f, lo: 0x9a, hi: 0x9c}, + {value: 0x00bf, lo: 0xa0, hi: 0xa0}, + {value: 0x00c2, lo: 0xa1, hi: 0xa1}, + {value: 0x00cb, lo: 0xa2, hi: 0xa2}, + {value: 0x429f, lo: 0xa3, hi: 0xa3}, + {value: 0x00c8, lo: 0xa4, hi: 0xa4}, + {value: 0x00c5, lo: 0xa5, hi: 0xa5}, + {value: 0x04bf, lo: 0xa6, hi: 0xa6}, + {value: 0x04e3, lo: 0xa8, hi: 0xa8}, + {value: 0x04c3, lo: 0xa9, hi: 0xac}, + {value: 0x04e7, lo: 0xad, hi: 0xae}, + // Block 0x6e, offset 0x27d + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xbd, hi: 0xbd}, + // Block 0x6f, offset 0x27f + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0xa0, hi: 0xa0}, + // Block 0x70, offset 0x281 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb6, hi: 0xba}, + // Block 0x71, offset 0x283 + {value: 0x002c, lo: 0x05}, + {value: 0x812d, lo: 0x8d, hi: 0x8d}, + {value: 0x8132, lo: 0x8f, hi: 0x8f}, + {value: 0x8132, lo: 0xb8, hi: 0xb8}, + {value: 0x8101, lo: 0xb9, hi: 0xba}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x72, offset 0x289 + {value: 0x0000, lo: 0x02}, + {value: 0x8132, lo: 0xa5, hi: 0xa5}, + {value: 0x812d, lo: 0xa6, hi: 0xa6}, + // Block 0x73, offset 0x28c + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x86, hi: 0x86}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x74, offset 0x28f + {value: 0x17fe, lo: 0x07}, + {value: 0xa000, lo: 0x99, hi: 0x99}, + {value: 0x4273, lo: 0x9a, hi: 0x9a}, + {value: 0xa000, lo: 0x9b, hi: 0x9b}, + {value: 0x427d, lo: 0x9c, hi: 0x9c}, + {value: 0xa000, lo: 0xa5, hi: 0xa5}, + {value: 0x4287, lo: 0xab, hi: 0xab}, + {value: 0x8104, lo: 0xb9, hi: 0xba}, + // Block 0x75, offset 0x297 + {value: 0x0000, lo: 0x06}, + {value: 0x8132, lo: 0x80, hi: 0x82}, + {value: 0x9900, lo: 0xa7, hi: 0xa7}, + {value: 0x19a5, lo: 0xae, hi: 0xae}, + {value: 0x19ae, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb1, hi: 0xb2}, + {value: 0x8104, lo: 0xb3, hi: 0xb4}, + // Block 0x76, offset 0x29e + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb5, hi: 0xb5}, + {value: 0x8102, lo: 0xb6, hi: 0xb6}, + // Block 0x77, offset 0x2a1 + {value: 0x0002, lo: 0x01}, + {value: 0x8102, lo: 0xa9, hi: 0xaa}, + // Block 0x78, offset 0x2a3 + {value: 0x0000, lo: 0x07}, + {value: 0xa000, lo: 0x87, hi: 0x87}, + {value: 0x19b7, lo: 0x8b, hi: 0x8b}, + {value: 0x19c0, lo: 0x8c, hi: 0x8c}, + {value: 0x8104, lo: 0x8d, hi: 0x8d}, + {value: 0x9900, lo: 0x97, hi: 0x97}, + {value: 0x8132, lo: 0xa6, hi: 0xac}, + {value: 0x8132, lo: 0xb0, hi: 0xb4}, + // Block 0x79, offset 0x2ab + {value: 0x7f37, lo: 0x06}, + {value: 0x9900, lo: 0xb0, hi: 0xb0}, + {value: 0xa000, lo: 0xb9, hi: 0xb9}, + {value: 0x9900, lo: 0xba, hi: 0xba}, + {value: 0x19d2, lo: 0xbb, hi: 0xbb}, + {value: 0x19c9, lo: 0xbc, hi: 0xbd}, + {value: 0x19db, lo: 0xbe, hi: 0xbe}, + // Block 0x7a, offset 0x2b2 + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0x82, hi: 0x82}, + {value: 0x8102, lo: 0x83, hi: 0x83}, + // Block 0x7b, offset 0x2b5 + {value: 0x0000, lo: 0x05}, + {value: 0x9900, lo: 0xaf, hi: 0xaf}, + {value: 0xa000, lo: 0xb8, hi: 0xb9}, + {value: 0x19e4, lo: 0xba, hi: 0xba}, + {value: 0x19ed, lo: 0xbb, hi: 0xbb}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7c, offset 0x2bb + {value: 0x0000, lo: 0x01}, + {value: 0x8102, lo: 0x80, hi: 0x80}, + // Block 0x7d, offset 0x2bd + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xbf, hi: 0xbf}, + // Block 0x7e, offset 0x2bf + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xb6, hi: 0xb6}, + {value: 0x8102, lo: 0xb7, hi: 0xb7}, + // Block 0x7f, offset 0x2c2 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0xb0, hi: 0xb4}, + // Block 0x80, offset 0x2c4 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0xb0, hi: 0xb6}, + // Block 0x81, offset 0x2c6 + {value: 0x0000, lo: 0x01}, + {value: 0x8101, lo: 0x9e, hi: 0x9e}, + // Block 0x82, offset 0x2c8 + {value: 0x0000, lo: 0x0c}, + {value: 0x4607, lo: 0x9e, hi: 0x9e}, + {value: 0x4611, lo: 0x9f, hi: 0x9f}, + {value: 0x4645, lo: 0xa0, hi: 0xa0}, + {value: 0x4653, lo: 0xa1, hi: 0xa1}, + {value: 0x4661, lo: 0xa2, hi: 0xa2}, + {value: 0x466f, lo: 0xa3, hi: 0xa3}, + {value: 0x467d, lo: 0xa4, hi: 0xa4}, + {value: 0x812b, lo: 0xa5, hi: 0xa6}, + {value: 0x8101, lo: 0xa7, hi: 0xa9}, + {value: 0x8130, lo: 0xad, hi: 0xad}, + {value: 0x812b, lo: 0xae, hi: 0xb2}, + {value: 0x812d, lo: 0xbb, hi: 0xbf}, + // Block 0x83, offset 0x2d5 + {value: 0x0000, lo: 0x09}, + {value: 0x812d, lo: 0x80, hi: 0x82}, + {value: 0x8132, lo: 0x85, hi: 0x89}, + {value: 0x812d, lo: 0x8a, hi: 0x8b}, + {value: 0x8132, lo: 0xaa, hi: 0xad}, + {value: 0x461b, lo: 0xbb, hi: 0xbb}, + {value: 0x4625, lo: 0xbc, hi: 0xbc}, + {value: 0x468b, lo: 0xbd, hi: 0xbd}, + {value: 0x46a7, lo: 0xbe, hi: 0xbe}, + {value: 0x4699, lo: 0xbf, hi: 0xbf}, + // Block 0x84, offset 0x2df + {value: 0x0000, lo: 0x01}, + {value: 0x46b5, lo: 0x80, hi: 0x80}, + // Block 0x85, offset 0x2e1 + {value: 0x0000, lo: 0x01}, + {value: 0x8132, lo: 0x82, hi: 0x84}, + // Block 0x86, offset 0x2e3 + {value: 0x0002, lo: 0x03}, + {value: 0x0043, lo: 0x80, hi: 0x99}, + {value: 0x0083, lo: 0x9a, hi: 0xb3}, + {value: 0x0043, lo: 0xb4, hi: 0xbf}, + // Block 0x87, offset 0x2e7 + {value: 0x0002, lo: 0x04}, + {value: 0x005b, lo: 0x80, hi: 0x8d}, + {value: 0x0083, lo: 0x8e, hi: 0x94}, + {value: 0x0093, lo: 0x96, hi: 0xa7}, + {value: 0x0043, lo: 0xa8, hi: 0xbf}, + // Block 0x88, offset 0x2ec + {value: 0x0002, lo: 0x0b}, + {value: 0x0073, lo: 0x80, hi: 0x81}, + {value: 0x0083, lo: 0x82, hi: 0x9b}, + {value: 0x0043, lo: 0x9c, hi: 0x9c}, + {value: 0x0047, lo: 0x9e, hi: 0x9f}, + {value: 0x004f, lo: 0xa2, hi: 0xa2}, + {value: 0x0055, lo: 0xa5, hi: 0xa6}, + {value: 0x005d, lo: 0xa9, hi: 0xac}, + {value: 0x0067, lo: 0xae, hi: 0xb5}, + {value: 0x0083, lo: 0xb6, hi: 0xb9}, + {value: 0x008d, lo: 0xbb, hi: 0xbb}, + {value: 0x0091, lo: 0xbd, hi: 0xbf}, + // Block 0x89, offset 0x2f8 + {value: 0x0002, lo: 0x04}, + {value: 0x0097, lo: 0x80, hi: 0x83}, + {value: 0x00a1, lo: 0x85, hi: 0x8f}, + {value: 0x0043, lo: 0x90, hi: 0xa9}, + {value: 0x0083, lo: 0xaa, hi: 0xbf}, + // Block 0x8a, offset 0x2fd + {value: 0x0002, lo: 0x08}, + {value: 0x00af, lo: 0x80, hi: 0x83}, + {value: 0x0043, lo: 0x84, hi: 0x85}, + {value: 0x0049, lo: 0x87, hi: 0x8a}, + {value: 0x0055, lo: 0x8d, hi: 0x94}, + {value: 0x0067, lo: 0x96, hi: 0x9c}, + {value: 0x0083, lo: 0x9e, hi: 0xb7}, + {value: 0x0043, lo: 0xb8, hi: 0xb9}, + {value: 0x0049, lo: 0xbb, hi: 0xbe}, + // Block 0x8b, offset 0x306 + {value: 0x0002, lo: 0x05}, + {value: 0x0053, lo: 0x80, hi: 0x84}, + {value: 0x005f, lo: 0x86, hi: 0x86}, + {value: 0x0067, lo: 0x8a, hi: 0x90}, + {value: 0x0083, lo: 0x92, hi: 0xab}, + {value: 0x0043, lo: 0xac, hi: 0xbf}, + // Block 0x8c, offset 0x30c + {value: 0x0002, lo: 0x04}, + {value: 0x006b, lo: 0x80, hi: 0x85}, + {value: 0x0083, lo: 0x86, hi: 0x9f}, + {value: 0x0043, lo: 0xa0, hi: 0xb9}, + {value: 0x0083, lo: 0xba, hi: 0xbf}, + // Block 0x8d, offset 0x311 + {value: 0x0002, lo: 0x03}, + {value: 0x008f, lo: 0x80, hi: 0x93}, + {value: 0x0043, lo: 0x94, hi: 0xad}, + {value: 0x0083, lo: 0xae, hi: 0xbf}, + // Block 0x8e, offset 0x315 + {value: 0x0002, lo: 0x04}, + {value: 0x00a7, lo: 0x80, hi: 0x87}, + {value: 0x0043, lo: 0x88, hi: 0xa1}, + {value: 0x0083, lo: 0xa2, hi: 0xbb}, + {value: 0x0043, lo: 0xbc, hi: 0xbf}, + // Block 0x8f, offset 0x31a + {value: 0x0002, lo: 0x03}, + {value: 0x004b, lo: 0x80, hi: 0x95}, + {value: 0x0083, lo: 0x96, hi: 0xaf}, + {value: 0x0043, lo: 0xb0, hi: 0xbf}, + // Block 0x90, offset 0x31e + {value: 0x0003, lo: 0x0f}, + {value: 0x01b8, lo: 0x80, hi: 0x80}, + {value: 0x04d7, lo: 0x81, hi: 0x81}, + {value: 0x01bb, lo: 0x82, hi: 0x9a}, + {value: 0x04d3, lo: 0x9b, hi: 0x9b}, + {value: 0x01c7, lo: 0x9c, hi: 0x9c}, + {value: 0x01d0, lo: 0x9d, hi: 0x9d}, + {value: 0x01d6, lo: 0x9e, hi: 0x9e}, + {value: 0x01fa, lo: 0x9f, hi: 0x9f}, + {value: 0x01eb, lo: 0xa0, hi: 0xa0}, + {value: 0x01e8, lo: 0xa1, hi: 0xa1}, + {value: 0x0173, lo: 0xa2, hi: 0xb2}, + {value: 0x0188, lo: 0xb3, hi: 0xb3}, + {value: 0x01a6, lo: 0xb4, hi: 0xba}, + {value: 0x04d7, lo: 0xbb, hi: 0xbb}, + {value: 0x01bb, lo: 0xbc, hi: 0xbf}, + // Block 0x91, offset 0x32e + {value: 0x0003, lo: 0x0d}, + {value: 0x01c7, lo: 0x80, hi: 0x94}, + {value: 0x04d3, lo: 0x95, hi: 0x95}, + {value: 0x01c7, lo: 0x96, hi: 0x96}, + {value: 0x01d0, lo: 0x97, hi: 0x97}, + {value: 0x01d6, lo: 0x98, hi: 0x98}, + {value: 0x01fa, lo: 0x99, hi: 0x99}, + {value: 0x01eb, lo: 0x9a, hi: 0x9a}, + {value: 0x01e8, lo: 0x9b, hi: 0x9b}, + {value: 0x0173, lo: 0x9c, hi: 0xac}, + {value: 0x0188, lo: 0xad, hi: 0xad}, + {value: 0x01a6, lo: 0xae, hi: 0xb4}, + {value: 0x04d7, lo: 0xb5, hi: 0xb5}, + {value: 0x01bb, lo: 0xb6, hi: 0xbf}, + // Block 0x92, offset 0x33c + {value: 0x0003, lo: 0x0d}, + {value: 0x01d9, lo: 0x80, hi: 0x8e}, + {value: 0x04d3, lo: 0x8f, hi: 0x8f}, + {value: 0x01c7, lo: 0x90, hi: 0x90}, + {value: 0x01d0, lo: 0x91, hi: 0x91}, + {value: 0x01d6, lo: 0x92, hi: 0x92}, + {value: 0x01fa, lo: 0x93, hi: 0x93}, + {value: 0x01eb, lo: 0x94, hi: 0x94}, + {value: 0x01e8, lo: 0x95, hi: 0x95}, + {value: 0x0173, lo: 0x96, hi: 0xa6}, + {value: 0x0188, lo: 0xa7, hi: 0xa7}, + {value: 0x01a6, lo: 0xa8, hi: 0xae}, + {value: 0x04d7, lo: 0xaf, hi: 0xaf}, + {value: 0x01bb, lo: 0xb0, hi: 0xbf}, + // Block 0x93, offset 0x34a + {value: 0x0003, lo: 0x0d}, + {value: 0x01eb, lo: 0x80, hi: 0x88}, + {value: 0x04d3, lo: 0x89, hi: 0x89}, + {value: 0x01c7, lo: 0x8a, hi: 0x8a}, + {value: 0x01d0, lo: 0x8b, hi: 0x8b}, + {value: 0x01d6, lo: 0x8c, hi: 0x8c}, + {value: 0x01fa, lo: 0x8d, hi: 0x8d}, + {value: 0x01eb, lo: 0x8e, hi: 0x8e}, + {value: 0x01e8, lo: 0x8f, hi: 0x8f}, + {value: 0x0173, lo: 0x90, hi: 0xa0}, + {value: 0x0188, lo: 0xa1, hi: 0xa1}, + {value: 0x01a6, lo: 0xa2, hi: 0xa8}, + {value: 0x04d7, lo: 0xa9, hi: 0xa9}, + {value: 0x01bb, lo: 0xaa, hi: 0xbf}, + // Block 0x94, offset 0x358 + {value: 0x0000, lo: 0x01}, + {value: 0x812d, lo: 0x90, hi: 0x96}, + // Block 0x95, offset 0x35a + {value: 0x0002, lo: 0x09}, + {value: 0x0063, lo: 0x80, hi: 0x89}, + {value: 0x1ae4, lo: 0x8a, hi: 0x8a}, + {value: 0x1b14, lo: 0x8b, hi: 0x8b}, + {value: 0x1b2f, lo: 0x8c, hi: 0x8c}, + {value: 0x1b35, lo: 0x8d, hi: 0x8d}, + {value: 0x1d53, lo: 0x8e, hi: 0x8e}, + {value: 0x1b41, lo: 0x8f, hi: 0x8f}, + {value: 0x1b0e, lo: 0xaa, hi: 0xaa}, + {value: 0x1b11, lo: 0xab, hi: 0xab}, + // Block 0x96, offset 0x364 + {value: 0x0000, lo: 0x01}, + {value: 0x1ad2, lo: 0x90, hi: 0x90}, + // Block 0x97, offset 0x366 + {value: 0x0028, lo: 0x09}, + {value: 0x2a5e, lo: 0x80, hi: 0x80}, + {value: 0x2a22, lo: 0x81, hi: 0x81}, + {value: 0x2a2c, lo: 0x82, hi: 0x82}, + {value: 0x2a40, lo: 0x83, hi: 0x84}, + {value: 0x2a4a, lo: 0x85, hi: 0x86}, + {value: 0x2a36, lo: 0x87, hi: 0x87}, + {value: 0x2a54, lo: 0x88, hi: 0x88}, + {value: 0x0be7, lo: 0x90, hi: 0x90}, + {value: 0x095f, lo: 0x91, hi: 0x91}, +} + +// recompMap: 7520 bytes (entries only) +var recompMap = map[uint32]rune{ + 0x00410300: 0x00C0, + 0x00410301: 0x00C1, + 0x00410302: 0x00C2, + 0x00410303: 0x00C3, + 0x00410308: 0x00C4, + 0x0041030A: 0x00C5, + 0x00430327: 0x00C7, + 0x00450300: 0x00C8, + 0x00450301: 0x00C9, + 0x00450302: 0x00CA, + 0x00450308: 0x00CB, + 0x00490300: 0x00CC, + 0x00490301: 0x00CD, + 0x00490302: 0x00CE, + 0x00490308: 0x00CF, + 0x004E0303: 0x00D1, + 0x004F0300: 0x00D2, + 0x004F0301: 0x00D3, + 0x004F0302: 0x00D4, + 0x004F0303: 0x00D5, + 0x004F0308: 0x00D6, + 0x00550300: 0x00D9, + 0x00550301: 0x00DA, + 0x00550302: 0x00DB, + 0x00550308: 0x00DC, + 0x00590301: 0x00DD, + 0x00610300: 0x00E0, + 0x00610301: 0x00E1, + 0x00610302: 0x00E2, + 0x00610303: 0x00E3, + 0x00610308: 0x00E4, + 0x0061030A: 0x00E5, + 0x00630327: 0x00E7, + 0x00650300: 0x00E8, + 0x00650301: 0x00E9, + 0x00650302: 0x00EA, + 0x00650308: 0x00EB, + 0x00690300: 0x00EC, + 0x00690301: 0x00ED, + 0x00690302: 0x00EE, + 0x00690308: 0x00EF, + 0x006E0303: 0x00F1, + 0x006F0300: 0x00F2, + 0x006F0301: 0x00F3, + 0x006F0302: 0x00F4, + 0x006F0303: 0x00F5, + 0x006F0308: 0x00F6, + 0x00750300: 0x00F9, + 0x00750301: 0x00FA, + 0x00750302: 0x00FB, + 0x00750308: 0x00FC, + 0x00790301: 0x00FD, + 0x00790308: 0x00FF, + 0x00410304: 0x0100, + 0x00610304: 0x0101, + 0x00410306: 0x0102, + 0x00610306: 0x0103, + 0x00410328: 0x0104, + 0x00610328: 0x0105, + 0x00430301: 0x0106, + 0x00630301: 0x0107, + 0x00430302: 0x0108, + 0x00630302: 0x0109, + 0x00430307: 0x010A, + 0x00630307: 0x010B, + 0x0043030C: 0x010C, + 0x0063030C: 0x010D, + 0x0044030C: 0x010E, + 0x0064030C: 0x010F, + 0x00450304: 0x0112, + 0x00650304: 0x0113, + 0x00450306: 0x0114, + 0x00650306: 0x0115, + 0x00450307: 0x0116, + 0x00650307: 0x0117, + 0x00450328: 0x0118, + 0x00650328: 0x0119, + 0x0045030C: 0x011A, + 0x0065030C: 0x011B, + 0x00470302: 0x011C, + 0x00670302: 0x011D, + 0x00470306: 0x011E, + 0x00670306: 0x011F, + 0x00470307: 0x0120, + 0x00670307: 0x0121, + 0x00470327: 0x0122, + 0x00670327: 0x0123, + 0x00480302: 0x0124, + 0x00680302: 0x0125, + 0x00490303: 0x0128, + 0x00690303: 0x0129, + 0x00490304: 0x012A, + 0x00690304: 0x012B, + 0x00490306: 0x012C, + 0x00690306: 0x012D, + 0x00490328: 0x012E, + 0x00690328: 0x012F, + 0x00490307: 0x0130, + 0x004A0302: 0x0134, + 0x006A0302: 0x0135, + 0x004B0327: 0x0136, + 0x006B0327: 0x0137, + 0x004C0301: 0x0139, + 0x006C0301: 0x013A, + 0x004C0327: 0x013B, + 0x006C0327: 0x013C, + 0x004C030C: 0x013D, + 0x006C030C: 0x013E, + 0x004E0301: 0x0143, + 0x006E0301: 0x0144, + 0x004E0327: 0x0145, + 0x006E0327: 0x0146, + 0x004E030C: 0x0147, + 0x006E030C: 0x0148, + 0x004F0304: 0x014C, + 0x006F0304: 0x014D, + 0x004F0306: 0x014E, + 0x006F0306: 0x014F, + 0x004F030B: 0x0150, + 0x006F030B: 0x0151, + 0x00520301: 0x0154, + 0x00720301: 0x0155, + 0x00520327: 0x0156, + 0x00720327: 0x0157, + 0x0052030C: 0x0158, + 0x0072030C: 0x0159, + 0x00530301: 0x015A, + 0x00730301: 0x015B, + 0x00530302: 0x015C, + 0x00730302: 0x015D, + 0x00530327: 0x015E, + 0x00730327: 0x015F, + 0x0053030C: 0x0160, + 0x0073030C: 0x0161, + 0x00540327: 0x0162, + 0x00740327: 0x0163, + 0x0054030C: 0x0164, + 0x0074030C: 0x0165, + 0x00550303: 0x0168, + 0x00750303: 0x0169, + 0x00550304: 0x016A, + 0x00750304: 0x016B, + 0x00550306: 0x016C, + 0x00750306: 0x016D, + 0x0055030A: 0x016E, + 0x0075030A: 0x016F, + 0x0055030B: 0x0170, + 0x0075030B: 0x0171, + 0x00550328: 0x0172, + 0x00750328: 0x0173, + 0x00570302: 0x0174, + 0x00770302: 0x0175, + 0x00590302: 0x0176, + 0x00790302: 0x0177, + 0x00590308: 0x0178, + 0x005A0301: 0x0179, + 0x007A0301: 0x017A, + 0x005A0307: 0x017B, + 0x007A0307: 0x017C, + 0x005A030C: 0x017D, + 0x007A030C: 0x017E, + 0x004F031B: 0x01A0, + 0x006F031B: 0x01A1, + 0x0055031B: 0x01AF, + 0x0075031B: 0x01B0, + 0x0041030C: 0x01CD, + 0x0061030C: 0x01CE, + 0x0049030C: 0x01CF, + 0x0069030C: 0x01D0, + 0x004F030C: 0x01D1, + 0x006F030C: 0x01D2, + 0x0055030C: 0x01D3, + 0x0075030C: 0x01D4, + 0x00DC0304: 0x01D5, + 0x00FC0304: 0x01D6, + 0x00DC0301: 0x01D7, + 0x00FC0301: 0x01D8, + 0x00DC030C: 0x01D9, + 0x00FC030C: 0x01DA, + 0x00DC0300: 0x01DB, + 0x00FC0300: 0x01DC, + 0x00C40304: 0x01DE, + 0x00E40304: 0x01DF, + 0x02260304: 0x01E0, + 0x02270304: 0x01E1, + 0x00C60304: 0x01E2, + 0x00E60304: 0x01E3, + 0x0047030C: 0x01E6, + 0x0067030C: 0x01E7, + 0x004B030C: 0x01E8, + 0x006B030C: 0x01E9, + 0x004F0328: 0x01EA, + 0x006F0328: 0x01EB, + 0x01EA0304: 0x01EC, + 0x01EB0304: 0x01ED, + 0x01B7030C: 0x01EE, + 0x0292030C: 0x01EF, + 0x006A030C: 0x01F0, + 0x00470301: 0x01F4, + 0x00670301: 0x01F5, + 0x004E0300: 0x01F8, + 0x006E0300: 0x01F9, + 0x00C50301: 0x01FA, + 0x00E50301: 0x01FB, + 0x00C60301: 0x01FC, + 0x00E60301: 0x01FD, + 0x00D80301: 0x01FE, + 0x00F80301: 0x01FF, + 0x0041030F: 0x0200, + 0x0061030F: 0x0201, + 0x00410311: 0x0202, + 0x00610311: 0x0203, + 0x0045030F: 0x0204, + 0x0065030F: 0x0205, + 0x00450311: 0x0206, + 0x00650311: 0x0207, + 0x0049030F: 0x0208, + 0x0069030F: 0x0209, + 0x00490311: 0x020A, + 0x00690311: 0x020B, + 0x004F030F: 0x020C, + 0x006F030F: 0x020D, + 0x004F0311: 0x020E, + 0x006F0311: 0x020F, + 0x0052030F: 0x0210, + 0x0072030F: 0x0211, + 0x00520311: 0x0212, + 0x00720311: 0x0213, + 0x0055030F: 0x0214, + 0x0075030F: 0x0215, + 0x00550311: 0x0216, + 0x00750311: 0x0217, + 0x00530326: 0x0218, + 0x00730326: 0x0219, + 0x00540326: 0x021A, + 0x00740326: 0x021B, + 0x0048030C: 0x021E, + 0x0068030C: 0x021F, + 0x00410307: 0x0226, + 0x00610307: 0x0227, + 0x00450327: 0x0228, + 0x00650327: 0x0229, + 0x00D60304: 0x022A, + 0x00F60304: 0x022B, + 0x00D50304: 0x022C, + 0x00F50304: 0x022D, + 0x004F0307: 0x022E, + 0x006F0307: 0x022F, + 0x022E0304: 0x0230, + 0x022F0304: 0x0231, + 0x00590304: 0x0232, + 0x00790304: 0x0233, + 0x00A80301: 0x0385, + 0x03910301: 0x0386, + 0x03950301: 0x0388, + 0x03970301: 0x0389, + 0x03990301: 0x038A, + 0x039F0301: 0x038C, + 0x03A50301: 0x038E, + 0x03A90301: 0x038F, + 0x03CA0301: 0x0390, + 0x03990308: 0x03AA, + 0x03A50308: 0x03AB, + 0x03B10301: 0x03AC, + 0x03B50301: 0x03AD, + 0x03B70301: 0x03AE, + 0x03B90301: 0x03AF, + 0x03CB0301: 0x03B0, + 0x03B90308: 0x03CA, + 0x03C50308: 0x03CB, + 0x03BF0301: 0x03CC, + 0x03C50301: 0x03CD, + 0x03C90301: 0x03CE, + 0x03D20301: 0x03D3, + 0x03D20308: 0x03D4, + 0x04150300: 0x0400, + 0x04150308: 0x0401, + 0x04130301: 0x0403, + 0x04060308: 0x0407, + 0x041A0301: 0x040C, + 0x04180300: 0x040D, + 0x04230306: 0x040E, + 0x04180306: 0x0419, + 0x04380306: 0x0439, + 0x04350300: 0x0450, + 0x04350308: 0x0451, + 0x04330301: 0x0453, + 0x04560308: 0x0457, + 0x043A0301: 0x045C, + 0x04380300: 0x045D, + 0x04430306: 0x045E, + 0x0474030F: 0x0476, + 0x0475030F: 0x0477, + 0x04160306: 0x04C1, + 0x04360306: 0x04C2, + 0x04100306: 0x04D0, + 0x04300306: 0x04D1, + 0x04100308: 0x04D2, + 0x04300308: 0x04D3, + 0x04150306: 0x04D6, + 0x04350306: 0x04D7, + 0x04D80308: 0x04DA, + 0x04D90308: 0x04DB, + 0x04160308: 0x04DC, + 0x04360308: 0x04DD, + 0x04170308: 0x04DE, + 0x04370308: 0x04DF, + 0x04180304: 0x04E2, + 0x04380304: 0x04E3, + 0x04180308: 0x04E4, + 0x04380308: 0x04E5, + 0x041E0308: 0x04E6, + 0x043E0308: 0x04E7, + 0x04E80308: 0x04EA, + 0x04E90308: 0x04EB, + 0x042D0308: 0x04EC, + 0x044D0308: 0x04ED, + 0x04230304: 0x04EE, + 0x04430304: 0x04EF, + 0x04230308: 0x04F0, + 0x04430308: 0x04F1, + 0x0423030B: 0x04F2, + 0x0443030B: 0x04F3, + 0x04270308: 0x04F4, + 0x04470308: 0x04F5, + 0x042B0308: 0x04F8, + 0x044B0308: 0x04F9, + 0x06270653: 0x0622, + 0x06270654: 0x0623, + 0x06480654: 0x0624, + 0x06270655: 0x0625, + 0x064A0654: 0x0626, + 0x06D50654: 0x06C0, + 0x06C10654: 0x06C2, + 0x06D20654: 0x06D3, + 0x0928093C: 0x0929, + 0x0930093C: 0x0931, + 0x0933093C: 0x0934, + 0x09C709BE: 0x09CB, + 0x09C709D7: 0x09CC, + 0x0B470B56: 0x0B48, + 0x0B470B3E: 0x0B4B, + 0x0B470B57: 0x0B4C, + 0x0B920BD7: 0x0B94, + 0x0BC60BBE: 0x0BCA, + 0x0BC70BBE: 0x0BCB, + 0x0BC60BD7: 0x0BCC, + 0x0C460C56: 0x0C48, + 0x0CBF0CD5: 0x0CC0, + 0x0CC60CD5: 0x0CC7, + 0x0CC60CD6: 0x0CC8, + 0x0CC60CC2: 0x0CCA, + 0x0CCA0CD5: 0x0CCB, + 0x0D460D3E: 0x0D4A, + 0x0D470D3E: 0x0D4B, + 0x0D460D57: 0x0D4C, + 0x0DD90DCA: 0x0DDA, + 0x0DD90DCF: 0x0DDC, + 0x0DDC0DCA: 0x0DDD, + 0x0DD90DDF: 0x0DDE, + 0x1025102E: 0x1026, + 0x1B051B35: 0x1B06, + 0x1B071B35: 0x1B08, + 0x1B091B35: 0x1B0A, + 0x1B0B1B35: 0x1B0C, + 0x1B0D1B35: 0x1B0E, + 0x1B111B35: 0x1B12, + 0x1B3A1B35: 0x1B3B, + 0x1B3C1B35: 0x1B3D, + 0x1B3E1B35: 0x1B40, + 0x1B3F1B35: 0x1B41, + 0x1B421B35: 0x1B43, + 0x00410325: 0x1E00, + 0x00610325: 0x1E01, + 0x00420307: 0x1E02, + 0x00620307: 0x1E03, + 0x00420323: 0x1E04, + 0x00620323: 0x1E05, + 0x00420331: 0x1E06, + 0x00620331: 0x1E07, + 0x00C70301: 0x1E08, + 0x00E70301: 0x1E09, + 0x00440307: 0x1E0A, + 0x00640307: 0x1E0B, + 0x00440323: 0x1E0C, + 0x00640323: 0x1E0D, + 0x00440331: 0x1E0E, + 0x00640331: 0x1E0F, + 0x00440327: 0x1E10, + 0x00640327: 0x1E11, + 0x0044032D: 0x1E12, + 0x0064032D: 0x1E13, + 0x01120300: 0x1E14, + 0x01130300: 0x1E15, + 0x01120301: 0x1E16, + 0x01130301: 0x1E17, + 0x0045032D: 0x1E18, + 0x0065032D: 0x1E19, + 0x00450330: 0x1E1A, + 0x00650330: 0x1E1B, + 0x02280306: 0x1E1C, + 0x02290306: 0x1E1D, + 0x00460307: 0x1E1E, + 0x00660307: 0x1E1F, + 0x00470304: 0x1E20, + 0x00670304: 0x1E21, + 0x00480307: 0x1E22, + 0x00680307: 0x1E23, + 0x00480323: 0x1E24, + 0x00680323: 0x1E25, + 0x00480308: 0x1E26, + 0x00680308: 0x1E27, + 0x00480327: 0x1E28, + 0x00680327: 0x1E29, + 0x0048032E: 0x1E2A, + 0x0068032E: 0x1E2B, + 0x00490330: 0x1E2C, + 0x00690330: 0x1E2D, + 0x00CF0301: 0x1E2E, + 0x00EF0301: 0x1E2F, + 0x004B0301: 0x1E30, + 0x006B0301: 0x1E31, + 0x004B0323: 0x1E32, + 0x006B0323: 0x1E33, + 0x004B0331: 0x1E34, + 0x006B0331: 0x1E35, + 0x004C0323: 0x1E36, + 0x006C0323: 0x1E37, + 0x1E360304: 0x1E38, + 0x1E370304: 0x1E39, + 0x004C0331: 0x1E3A, + 0x006C0331: 0x1E3B, + 0x004C032D: 0x1E3C, + 0x006C032D: 0x1E3D, + 0x004D0301: 0x1E3E, + 0x006D0301: 0x1E3F, + 0x004D0307: 0x1E40, + 0x006D0307: 0x1E41, + 0x004D0323: 0x1E42, + 0x006D0323: 0x1E43, + 0x004E0307: 0x1E44, + 0x006E0307: 0x1E45, + 0x004E0323: 0x1E46, + 0x006E0323: 0x1E47, + 0x004E0331: 0x1E48, + 0x006E0331: 0x1E49, + 0x004E032D: 0x1E4A, + 0x006E032D: 0x1E4B, + 0x00D50301: 0x1E4C, + 0x00F50301: 0x1E4D, + 0x00D50308: 0x1E4E, + 0x00F50308: 0x1E4F, + 0x014C0300: 0x1E50, + 0x014D0300: 0x1E51, + 0x014C0301: 0x1E52, + 0x014D0301: 0x1E53, + 0x00500301: 0x1E54, + 0x00700301: 0x1E55, + 0x00500307: 0x1E56, + 0x00700307: 0x1E57, + 0x00520307: 0x1E58, + 0x00720307: 0x1E59, + 0x00520323: 0x1E5A, + 0x00720323: 0x1E5B, + 0x1E5A0304: 0x1E5C, + 0x1E5B0304: 0x1E5D, + 0x00520331: 0x1E5E, + 0x00720331: 0x1E5F, + 0x00530307: 0x1E60, + 0x00730307: 0x1E61, + 0x00530323: 0x1E62, + 0x00730323: 0x1E63, + 0x015A0307: 0x1E64, + 0x015B0307: 0x1E65, + 0x01600307: 0x1E66, + 0x01610307: 0x1E67, + 0x1E620307: 0x1E68, + 0x1E630307: 0x1E69, + 0x00540307: 0x1E6A, + 0x00740307: 0x1E6B, + 0x00540323: 0x1E6C, + 0x00740323: 0x1E6D, + 0x00540331: 0x1E6E, + 0x00740331: 0x1E6F, + 0x0054032D: 0x1E70, + 0x0074032D: 0x1E71, + 0x00550324: 0x1E72, + 0x00750324: 0x1E73, + 0x00550330: 0x1E74, + 0x00750330: 0x1E75, + 0x0055032D: 0x1E76, + 0x0075032D: 0x1E77, + 0x01680301: 0x1E78, + 0x01690301: 0x1E79, + 0x016A0308: 0x1E7A, + 0x016B0308: 0x1E7B, + 0x00560303: 0x1E7C, + 0x00760303: 0x1E7D, + 0x00560323: 0x1E7E, + 0x00760323: 0x1E7F, + 0x00570300: 0x1E80, + 0x00770300: 0x1E81, + 0x00570301: 0x1E82, + 0x00770301: 0x1E83, + 0x00570308: 0x1E84, + 0x00770308: 0x1E85, + 0x00570307: 0x1E86, + 0x00770307: 0x1E87, + 0x00570323: 0x1E88, + 0x00770323: 0x1E89, + 0x00580307: 0x1E8A, + 0x00780307: 0x1E8B, + 0x00580308: 0x1E8C, + 0x00780308: 0x1E8D, + 0x00590307: 0x1E8E, + 0x00790307: 0x1E8F, + 0x005A0302: 0x1E90, + 0x007A0302: 0x1E91, + 0x005A0323: 0x1E92, + 0x007A0323: 0x1E93, + 0x005A0331: 0x1E94, + 0x007A0331: 0x1E95, + 0x00680331: 0x1E96, + 0x00740308: 0x1E97, + 0x0077030A: 0x1E98, + 0x0079030A: 0x1E99, + 0x017F0307: 0x1E9B, + 0x00410323: 0x1EA0, + 0x00610323: 0x1EA1, + 0x00410309: 0x1EA2, + 0x00610309: 0x1EA3, + 0x00C20301: 0x1EA4, + 0x00E20301: 0x1EA5, + 0x00C20300: 0x1EA6, + 0x00E20300: 0x1EA7, + 0x00C20309: 0x1EA8, + 0x00E20309: 0x1EA9, + 0x00C20303: 0x1EAA, + 0x00E20303: 0x1EAB, + 0x1EA00302: 0x1EAC, + 0x1EA10302: 0x1EAD, + 0x01020301: 0x1EAE, + 0x01030301: 0x1EAF, + 0x01020300: 0x1EB0, + 0x01030300: 0x1EB1, + 0x01020309: 0x1EB2, + 0x01030309: 0x1EB3, + 0x01020303: 0x1EB4, + 0x01030303: 0x1EB5, + 0x1EA00306: 0x1EB6, + 0x1EA10306: 0x1EB7, + 0x00450323: 0x1EB8, + 0x00650323: 0x1EB9, + 0x00450309: 0x1EBA, + 0x00650309: 0x1EBB, + 0x00450303: 0x1EBC, + 0x00650303: 0x1EBD, + 0x00CA0301: 0x1EBE, + 0x00EA0301: 0x1EBF, + 0x00CA0300: 0x1EC0, + 0x00EA0300: 0x1EC1, + 0x00CA0309: 0x1EC2, + 0x00EA0309: 0x1EC3, + 0x00CA0303: 0x1EC4, + 0x00EA0303: 0x1EC5, + 0x1EB80302: 0x1EC6, + 0x1EB90302: 0x1EC7, + 0x00490309: 0x1EC8, + 0x00690309: 0x1EC9, + 0x00490323: 0x1ECA, + 0x00690323: 0x1ECB, + 0x004F0323: 0x1ECC, + 0x006F0323: 0x1ECD, + 0x004F0309: 0x1ECE, + 0x006F0309: 0x1ECF, + 0x00D40301: 0x1ED0, + 0x00F40301: 0x1ED1, + 0x00D40300: 0x1ED2, + 0x00F40300: 0x1ED3, + 0x00D40309: 0x1ED4, + 0x00F40309: 0x1ED5, + 0x00D40303: 0x1ED6, + 0x00F40303: 0x1ED7, + 0x1ECC0302: 0x1ED8, + 0x1ECD0302: 0x1ED9, + 0x01A00301: 0x1EDA, + 0x01A10301: 0x1EDB, + 0x01A00300: 0x1EDC, + 0x01A10300: 0x1EDD, + 0x01A00309: 0x1EDE, + 0x01A10309: 0x1EDF, + 0x01A00303: 0x1EE0, + 0x01A10303: 0x1EE1, + 0x01A00323: 0x1EE2, + 0x01A10323: 0x1EE3, + 0x00550323: 0x1EE4, + 0x00750323: 0x1EE5, + 0x00550309: 0x1EE6, + 0x00750309: 0x1EE7, + 0x01AF0301: 0x1EE8, + 0x01B00301: 0x1EE9, + 0x01AF0300: 0x1EEA, + 0x01B00300: 0x1EEB, + 0x01AF0309: 0x1EEC, + 0x01B00309: 0x1EED, + 0x01AF0303: 0x1EEE, + 0x01B00303: 0x1EEF, + 0x01AF0323: 0x1EF0, + 0x01B00323: 0x1EF1, + 0x00590300: 0x1EF2, + 0x00790300: 0x1EF3, + 0x00590323: 0x1EF4, + 0x00790323: 0x1EF5, + 0x00590309: 0x1EF6, + 0x00790309: 0x1EF7, + 0x00590303: 0x1EF8, + 0x00790303: 0x1EF9, + 0x03B10313: 0x1F00, + 0x03B10314: 0x1F01, + 0x1F000300: 0x1F02, + 0x1F010300: 0x1F03, + 0x1F000301: 0x1F04, + 0x1F010301: 0x1F05, + 0x1F000342: 0x1F06, + 0x1F010342: 0x1F07, + 0x03910313: 0x1F08, + 0x03910314: 0x1F09, + 0x1F080300: 0x1F0A, + 0x1F090300: 0x1F0B, + 0x1F080301: 0x1F0C, + 0x1F090301: 0x1F0D, + 0x1F080342: 0x1F0E, + 0x1F090342: 0x1F0F, + 0x03B50313: 0x1F10, + 0x03B50314: 0x1F11, + 0x1F100300: 0x1F12, + 0x1F110300: 0x1F13, + 0x1F100301: 0x1F14, + 0x1F110301: 0x1F15, + 0x03950313: 0x1F18, + 0x03950314: 0x1F19, + 0x1F180300: 0x1F1A, + 0x1F190300: 0x1F1B, + 0x1F180301: 0x1F1C, + 0x1F190301: 0x1F1D, + 0x03B70313: 0x1F20, + 0x03B70314: 0x1F21, + 0x1F200300: 0x1F22, + 0x1F210300: 0x1F23, + 0x1F200301: 0x1F24, + 0x1F210301: 0x1F25, + 0x1F200342: 0x1F26, + 0x1F210342: 0x1F27, + 0x03970313: 0x1F28, + 0x03970314: 0x1F29, + 0x1F280300: 0x1F2A, + 0x1F290300: 0x1F2B, + 0x1F280301: 0x1F2C, + 0x1F290301: 0x1F2D, + 0x1F280342: 0x1F2E, + 0x1F290342: 0x1F2F, + 0x03B90313: 0x1F30, + 0x03B90314: 0x1F31, + 0x1F300300: 0x1F32, + 0x1F310300: 0x1F33, + 0x1F300301: 0x1F34, + 0x1F310301: 0x1F35, + 0x1F300342: 0x1F36, + 0x1F310342: 0x1F37, + 0x03990313: 0x1F38, + 0x03990314: 0x1F39, + 0x1F380300: 0x1F3A, + 0x1F390300: 0x1F3B, + 0x1F380301: 0x1F3C, + 0x1F390301: 0x1F3D, + 0x1F380342: 0x1F3E, + 0x1F390342: 0x1F3F, + 0x03BF0313: 0x1F40, + 0x03BF0314: 0x1F41, + 0x1F400300: 0x1F42, + 0x1F410300: 0x1F43, + 0x1F400301: 0x1F44, + 0x1F410301: 0x1F45, + 0x039F0313: 0x1F48, + 0x039F0314: 0x1F49, + 0x1F480300: 0x1F4A, + 0x1F490300: 0x1F4B, + 0x1F480301: 0x1F4C, + 0x1F490301: 0x1F4D, + 0x03C50313: 0x1F50, + 0x03C50314: 0x1F51, + 0x1F500300: 0x1F52, + 0x1F510300: 0x1F53, + 0x1F500301: 0x1F54, + 0x1F510301: 0x1F55, + 0x1F500342: 0x1F56, + 0x1F510342: 0x1F57, + 0x03A50314: 0x1F59, + 0x1F590300: 0x1F5B, + 0x1F590301: 0x1F5D, + 0x1F590342: 0x1F5F, + 0x03C90313: 0x1F60, + 0x03C90314: 0x1F61, + 0x1F600300: 0x1F62, + 0x1F610300: 0x1F63, + 0x1F600301: 0x1F64, + 0x1F610301: 0x1F65, + 0x1F600342: 0x1F66, + 0x1F610342: 0x1F67, + 0x03A90313: 0x1F68, + 0x03A90314: 0x1F69, + 0x1F680300: 0x1F6A, + 0x1F690300: 0x1F6B, + 0x1F680301: 0x1F6C, + 0x1F690301: 0x1F6D, + 0x1F680342: 0x1F6E, + 0x1F690342: 0x1F6F, + 0x03B10300: 0x1F70, + 0x03B50300: 0x1F72, + 0x03B70300: 0x1F74, + 0x03B90300: 0x1F76, + 0x03BF0300: 0x1F78, + 0x03C50300: 0x1F7A, + 0x03C90300: 0x1F7C, + 0x1F000345: 0x1F80, + 0x1F010345: 0x1F81, + 0x1F020345: 0x1F82, + 0x1F030345: 0x1F83, + 0x1F040345: 0x1F84, + 0x1F050345: 0x1F85, + 0x1F060345: 0x1F86, + 0x1F070345: 0x1F87, + 0x1F080345: 0x1F88, + 0x1F090345: 0x1F89, + 0x1F0A0345: 0x1F8A, + 0x1F0B0345: 0x1F8B, + 0x1F0C0345: 0x1F8C, + 0x1F0D0345: 0x1F8D, + 0x1F0E0345: 0x1F8E, + 0x1F0F0345: 0x1F8F, + 0x1F200345: 0x1F90, + 0x1F210345: 0x1F91, + 0x1F220345: 0x1F92, + 0x1F230345: 0x1F93, + 0x1F240345: 0x1F94, + 0x1F250345: 0x1F95, + 0x1F260345: 0x1F96, + 0x1F270345: 0x1F97, + 0x1F280345: 0x1F98, + 0x1F290345: 0x1F99, + 0x1F2A0345: 0x1F9A, + 0x1F2B0345: 0x1F9B, + 0x1F2C0345: 0x1F9C, + 0x1F2D0345: 0x1F9D, + 0x1F2E0345: 0x1F9E, + 0x1F2F0345: 0x1F9F, + 0x1F600345: 0x1FA0, + 0x1F610345: 0x1FA1, + 0x1F620345: 0x1FA2, + 0x1F630345: 0x1FA3, + 0x1F640345: 0x1FA4, + 0x1F650345: 0x1FA5, + 0x1F660345: 0x1FA6, + 0x1F670345: 0x1FA7, + 0x1F680345: 0x1FA8, + 0x1F690345: 0x1FA9, + 0x1F6A0345: 0x1FAA, + 0x1F6B0345: 0x1FAB, + 0x1F6C0345: 0x1FAC, + 0x1F6D0345: 0x1FAD, + 0x1F6E0345: 0x1FAE, + 0x1F6F0345: 0x1FAF, + 0x03B10306: 0x1FB0, + 0x03B10304: 0x1FB1, + 0x1F700345: 0x1FB2, + 0x03B10345: 0x1FB3, + 0x03AC0345: 0x1FB4, + 0x03B10342: 0x1FB6, + 0x1FB60345: 0x1FB7, + 0x03910306: 0x1FB8, + 0x03910304: 0x1FB9, + 0x03910300: 0x1FBA, + 0x03910345: 0x1FBC, + 0x00A80342: 0x1FC1, + 0x1F740345: 0x1FC2, + 0x03B70345: 0x1FC3, + 0x03AE0345: 0x1FC4, + 0x03B70342: 0x1FC6, + 0x1FC60345: 0x1FC7, + 0x03950300: 0x1FC8, + 0x03970300: 0x1FCA, + 0x03970345: 0x1FCC, + 0x1FBF0300: 0x1FCD, + 0x1FBF0301: 0x1FCE, + 0x1FBF0342: 0x1FCF, + 0x03B90306: 0x1FD0, + 0x03B90304: 0x1FD1, + 0x03CA0300: 0x1FD2, + 0x03B90342: 0x1FD6, + 0x03CA0342: 0x1FD7, + 0x03990306: 0x1FD8, + 0x03990304: 0x1FD9, + 0x03990300: 0x1FDA, + 0x1FFE0300: 0x1FDD, + 0x1FFE0301: 0x1FDE, + 0x1FFE0342: 0x1FDF, + 0x03C50306: 0x1FE0, + 0x03C50304: 0x1FE1, + 0x03CB0300: 0x1FE2, + 0x03C10313: 0x1FE4, + 0x03C10314: 0x1FE5, + 0x03C50342: 0x1FE6, + 0x03CB0342: 0x1FE7, + 0x03A50306: 0x1FE8, + 0x03A50304: 0x1FE9, + 0x03A50300: 0x1FEA, + 0x03A10314: 0x1FEC, + 0x00A80300: 0x1FED, + 0x1F7C0345: 0x1FF2, + 0x03C90345: 0x1FF3, + 0x03CE0345: 0x1FF4, + 0x03C90342: 0x1FF6, + 0x1FF60345: 0x1FF7, + 0x039F0300: 0x1FF8, + 0x03A90300: 0x1FFA, + 0x03A90345: 0x1FFC, + 0x21900338: 0x219A, + 0x21920338: 0x219B, + 0x21940338: 0x21AE, + 0x21D00338: 0x21CD, + 0x21D40338: 0x21CE, + 0x21D20338: 0x21CF, + 0x22030338: 0x2204, + 0x22080338: 0x2209, + 0x220B0338: 0x220C, + 0x22230338: 0x2224, + 0x22250338: 0x2226, + 0x223C0338: 0x2241, + 0x22430338: 0x2244, + 0x22450338: 0x2247, + 0x22480338: 0x2249, + 0x003D0338: 0x2260, + 0x22610338: 0x2262, + 0x224D0338: 0x226D, + 0x003C0338: 0x226E, + 0x003E0338: 0x226F, + 0x22640338: 0x2270, + 0x22650338: 0x2271, + 0x22720338: 0x2274, + 0x22730338: 0x2275, + 0x22760338: 0x2278, + 0x22770338: 0x2279, + 0x227A0338: 0x2280, + 0x227B0338: 0x2281, + 0x22820338: 0x2284, + 0x22830338: 0x2285, + 0x22860338: 0x2288, + 0x22870338: 0x2289, + 0x22A20338: 0x22AC, + 0x22A80338: 0x22AD, + 0x22A90338: 0x22AE, + 0x22AB0338: 0x22AF, + 0x227C0338: 0x22E0, + 0x227D0338: 0x22E1, + 0x22910338: 0x22E2, + 0x22920338: 0x22E3, + 0x22B20338: 0x22EA, + 0x22B30338: 0x22EB, + 0x22B40338: 0x22EC, + 0x22B50338: 0x22ED, + 0x304B3099: 0x304C, + 0x304D3099: 0x304E, + 0x304F3099: 0x3050, + 0x30513099: 0x3052, + 0x30533099: 0x3054, + 0x30553099: 0x3056, + 0x30573099: 0x3058, + 0x30593099: 0x305A, + 0x305B3099: 0x305C, + 0x305D3099: 0x305E, + 0x305F3099: 0x3060, + 0x30613099: 0x3062, + 0x30643099: 0x3065, + 0x30663099: 0x3067, + 0x30683099: 0x3069, + 0x306F3099: 0x3070, + 0x306F309A: 0x3071, + 0x30723099: 0x3073, + 0x3072309A: 0x3074, + 0x30753099: 0x3076, + 0x3075309A: 0x3077, + 0x30783099: 0x3079, + 0x3078309A: 0x307A, + 0x307B3099: 0x307C, + 0x307B309A: 0x307D, + 0x30463099: 0x3094, + 0x309D3099: 0x309E, + 0x30AB3099: 0x30AC, + 0x30AD3099: 0x30AE, + 0x30AF3099: 0x30B0, + 0x30B13099: 0x30B2, + 0x30B33099: 0x30B4, + 0x30B53099: 0x30B6, + 0x30B73099: 0x30B8, + 0x30B93099: 0x30BA, + 0x30BB3099: 0x30BC, + 0x30BD3099: 0x30BE, + 0x30BF3099: 0x30C0, + 0x30C13099: 0x30C2, + 0x30C43099: 0x30C5, + 0x30C63099: 0x30C7, + 0x30C83099: 0x30C9, + 0x30CF3099: 0x30D0, + 0x30CF309A: 0x30D1, + 0x30D23099: 0x30D3, + 0x30D2309A: 0x30D4, + 0x30D53099: 0x30D6, + 0x30D5309A: 0x30D7, + 0x30D83099: 0x30D9, + 0x30D8309A: 0x30DA, + 0x30DB3099: 0x30DC, + 0x30DB309A: 0x30DD, + 0x30A63099: 0x30F4, + 0x30EF3099: 0x30F7, + 0x30F03099: 0x30F8, + 0x30F13099: 0x30F9, + 0x30F23099: 0x30FA, + 0x30FD3099: 0x30FE, + 0x109910BA: 0x1109A, + 0x109B10BA: 0x1109C, + 0x10A510BA: 0x110AB, + 0x11311127: 0x1112E, + 0x11321127: 0x1112F, + 0x1347133E: 0x1134B, + 0x13471357: 0x1134C, + 0x14B914BA: 0x114BB, + 0x14B914B0: 0x114BC, + 0x14B914BD: 0x114BE, + 0x15B815AF: 0x115BA, + 0x15B915AF: 0x115BB, +} + +// Total size of tables: 52KB (53487 bytes) diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform.go new file mode 100644 index 00000000..8eff9d91 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform.go @@ -0,0 +1,88 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "unicode/utf8" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/transform" +) + +// Reset implements the Reset method of the transform.Transformer interface. +func (Form) Reset() {} + +// Transform implements the Transform method of the transform.Transformer +// interface. It may need to write segments of up to MaxSegmentSize at once. +// Users should either catch ErrShortDst and allow dst to grow or have dst be at +// least of size MaxTransformChunkSize to be guaranteed of progress. +func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := 0 + // Cap the maximum number of src bytes to check. + b := src + eof := atEOF + if ns := len(dst); ns < len(b) { + err = transform.ErrShortDst + eof = false + b = b[:ns] + } + i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof) + n += copy(dst[n:], b[n:i]) + if !ok { + nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF) + return nDst + n, nSrc + n, err + } + if n < len(src) && !atEOF { + err = transform.ErrShortSrc + } + return n, n, err +} + +func flushTransform(rb *reorderBuffer) bool { + // Write out (must fully fit in dst, or else it is a ErrShortDst). + if len(rb.out) < rb.nrune*utf8.UTFMax { + return false + } + rb.out = rb.out[rb.flushCopy(rb.out):] + return true +} + +var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc} + +// transform implements the transform.Transformer interface. It is only called +// when quickSpan does not pass for a given string. +func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + // TODO: get rid of reorderBuffer. See CL 23460044. + rb := reorderBuffer{} + rb.init(f, src) + for { + // Load segment into reorder buffer. + rb.setFlusher(dst[nDst:], flushTransform) + end := decomposeSegment(&rb, nSrc, atEOF) + if end < 0 { + return nDst, nSrc, errs[-end] + } + nDst = len(dst) - len(rb.out) + nSrc = end + + // Next quickSpan. + end = rb.nsrc + eof := atEOF + if n := nSrc + len(dst) - nDst; n < end { + err = transform.ErrShortDst + end = n + eof = false + } + end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof) + n := copy(dst[nDst:], rb.src.bytes[nSrc:end]) + nSrc += n + nDst += n + if ok { + if n < rb.nsrc && !atEOF { + err = transform.ErrShortSrc + } + return nDst, nSrc, err + } + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform_test.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform_test.go new file mode 100644 index 00000000..df5b091a --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/transform_test.go @@ -0,0 +1,101 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "fmt" + "testing" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/text/transform" +) + +func TestTransform(t *testing.T) { + tests := []struct { + f Form + in, out string + eof bool + dstSize int + err error + }{ + {NFC, "ab", "ab", true, 2, nil}, + {NFC, "qx", "qx", true, 2, nil}, + {NFD, "qx", "qx", true, 2, nil}, + {NFC, "", "", true, 1, nil}, + {NFD, "", "", true, 1, nil}, + {NFC, "", "", false, 1, nil}, + {NFD, "", "", false, 1, nil}, + + // Normalized segment does not fit in destination. + {NFD, "ö", "", true, 1, transform.ErrShortDst}, + {NFD, "ö", "", true, 2, transform.ErrShortDst}, + + // As an artifact of the algorithm, only full segments are written. + // This is not strictly required, and some bytes could be written. + // In practice, for Transform to not block, the destination buffer + // should be at least MaxSegmentSize to work anyway and these edge + // conditions will be relatively rare. + {NFC, "ab", "", true, 1, transform.ErrShortDst}, + // This is even true for inert runes. + {NFC, "qx", "", true, 1, transform.ErrShortDst}, + {NFC, "a\u0300abc", "\u00e0a", true, 4, transform.ErrShortDst}, + + // We cannot write a segment if succesive runes could still change the result. + {NFD, "ö", "", false, 3, transform.ErrShortSrc}, + {NFC, "a\u0300", "", false, 4, transform.ErrShortSrc}, + {NFD, "a\u0300", "", false, 4, transform.ErrShortSrc}, + {NFC, "ö", "", false, 3, transform.ErrShortSrc}, + + {NFC, "a\u0300", "", true, 1, transform.ErrShortDst}, + // Theoretically could fit, but won't due to simplified checks. + {NFC, "a\u0300", "", true, 2, transform.ErrShortDst}, + {NFC, "a\u0300", "", true, 3, transform.ErrShortDst}, + {NFC, "a\u0300", "\u00e0", true, 4, nil}, + + {NFD, "öa\u0300", "o\u0308", false, 8, transform.ErrShortSrc}, + {NFD, "öa\u0300ö", "o\u0308a\u0300", true, 8, transform.ErrShortDst}, + {NFD, "öa\u0300ö", "o\u0308a\u0300", false, 12, transform.ErrShortSrc}, + + // Illegal input is copied verbatim. + {NFD, "\xbd\xb2=\xbc ", "\xbd\xb2=\xbc ", true, 8, nil}, + } + b := make([]byte, 100) + for i, tt := range tests { + nDst, _, err := tt.f.Transform(b[:tt.dstSize], []byte(tt.in), tt.eof) + out := string(b[:nDst]) + if out != tt.out || err != tt.err { + t.Errorf("%d: was %+q (%v); want %+q (%v)", i, out, err, tt.out, tt.err) + } + if want := tt.f.String(tt.in)[:nDst]; want != out { + t.Errorf("%d: incorect normalization: was %+q; want %+q", i, out, want) + } + } +} + +var transBufSizes = []int{ + MaxTransformChunkSize, + 3 * MaxTransformChunkSize / 2, + 2 * MaxTransformChunkSize, + 3 * MaxTransformChunkSize, + 100 * MaxTransformChunkSize, +} + +func doTransNorm(f Form, buf []byte, b []byte) []byte { + acc := []byte{} + for p := 0; p < len(b); { + nd, ns, _ := f.Transform(buf[:], b[p:], true) + p += ns + acc = append(acc, buf[:nd]...) + } + return acc +} + +func TestTransformNorm(t *testing.T) { + for _, sz := range transBufSizes { + buf := make([]byte, sz) + runNormTests(t, fmt.Sprintf("Transform:%d", sz), func(f Form, out []byte, s string) []byte { + return doTransNorm(f, buf, append(out, s...)) + }) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/trie.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/trie.go new file mode 100644 index 00000000..423386bf --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/trie.go @@ -0,0 +1,54 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +type valueRange struct { + value uint16 // header: value:stride + lo, hi byte // header: lo:n +} + +type sparseBlocks struct { + values []valueRange + offset []uint16 +} + +var nfcSparse = sparseBlocks{ + values: nfcSparseValues[:], + offset: nfcSparseOffset[:], +} + +var nfkcSparse = sparseBlocks{ + values: nfkcSparseValues[:], + offset: nfkcSparseOffset[:], +} + +var ( + nfcData = newNfcTrie(0) + nfkcData = newNfkcTrie(0) +) + +// lookupValue determines the type of block n and looks up the value for b. +// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block +// is a list of ranges with an accompanying value. Given a matching range r, +// the value for b is by r.value + (b - r.lo) * stride. +func (t *sparseBlocks) lookup(n uint32, b byte) uint16 { + offset := t.offset[n] + header := t.values[offset] + lo := offset + 1 + hi := lo + uint16(header.lo) + for lo < hi { + m := lo + (hi-lo)/2 + r := t.values[m] + if r.lo <= b && b <= r.hi { + return r.value + uint16(b-r.lo)*header.value + } + if b < r.lo { + hi = m + } else { + lo = m + 1 + } + } + return 0 +} diff --git a/Godeps/_workspace/src/golang.org/x/text/unicode/norm/triegen.go b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/triegen.go new file mode 100644 index 00000000..45d71190 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/text/unicode/norm/triegen.go @@ -0,0 +1,117 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Trie table generator. +// Used by make*tables tools to generate a go file with trie data structures +// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte +// sequence are used to lookup offsets in the index table to be used for the +// next byte. The last byte is used to index into a table with 16-bit values. + +package main + +import ( + "fmt" + "io" +) + +const maxSparseEntries = 16 + +type normCompacter struct { + sparseBlocks [][]uint64 + sparseOffset []uint16 + sparseCount int + name string +} + +func mostFrequentStride(a []uint64) int { + counts := make(map[int]int) + var v int + for _, x := range a { + if stride := int(x) - v; v != 0 && stride >= 0 { + counts[stride]++ + } + v = int(x) + } + var maxs, maxc int + for stride, cnt := range counts { + if cnt > maxc || (cnt == maxc && stride < maxs) { + maxs, maxc = stride, cnt + } + } + return maxs +} + +func countSparseEntries(a []uint64) int { + stride := mostFrequentStride(a) + var v, count int + for _, tv := range a { + if int(tv)-v != stride { + if tv != 0 { + count++ + } + } + v = int(tv) + } + return count +} + +func (c *normCompacter) Size(v []uint64) (sz int, ok bool) { + if n := countSparseEntries(v); n <= maxSparseEntries { + return (n+1)*4 + 2, true + } + return 0, false +} + +func (c *normCompacter) Store(v []uint64) uint32 { + h := uint32(len(c.sparseOffset)) + c.sparseBlocks = append(c.sparseBlocks, v) + c.sparseOffset = append(c.sparseOffset, uint16(c.sparseCount)) + c.sparseCount += countSparseEntries(v) + 1 + return h +} + +func (c *normCompacter) Handler() string { + return c.name + "Sparse.lookup" +} + +func (c *normCompacter) Print(w io.Writer) (retErr error) { + p := func(f string, x ...interface{}) { + if _, err := fmt.Fprintf(w, f, x...); retErr == nil && err != nil { + retErr = err + } + } + + ls := len(c.sparseBlocks) + p("// %sSparseOffset: %d entries, %d bytes\n", c.name, ls, ls*2) + p("var %sSparseOffset = %#v\n\n", c.name, c.sparseOffset) + + ns := c.sparseCount + p("// %sSparseValues: %d entries, %d bytes\n", c.name, ns, ns*4) + p("var %sSparseValues = [%d]valueRange {", c.name, ns) + for i, b := range c.sparseBlocks { + p("\n// Block %#x, offset %#x", i, c.sparseOffset[i]) + var v int + stride := mostFrequentStride(b) + n := countSparseEntries(b) + p("\n{value:%#04x,lo:%#02x},", stride, uint8(n)) + for i, nv := range b { + if int(nv)-v != stride { + if v != 0 { + p(",hi:%#02x},", 0x80+i-1) + } + if nv != 0 { + p("\n{value:%#04x,lo:%#02x", nv, 0x80+i) + } + } + v = int(nv) + } + if v != 0 { + p(",hi:%#02x},", 0x80+len(b)-1) + } + } + p("\n}\n\n") + return +} diff --git a/args/args.go b/args/args.go new file mode 100644 index 00000000..b680eabe --- /dev/null +++ b/args/args.go @@ -0,0 +1,14 @@ +package args + +import ( + "flag" +) + +var ( + Development bool +) + +func init() { + flag.BoolVar(&Development, "dev", false, "") + flag.Parse() +} diff --git a/bindata.go b/bindata.go index 4aacd2ca..ebff4318 100644 --- a/bindata.go +++ b/bindata.go @@ -71,7 +71,7 @@ func (fi bindata_file_info) Sys() interface{} { return nil } -var _dist_bundle_js = "\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\xfd\x79\x77\x1b\xc9\xb2\x20\x86\xff\xfd\x9b\xdf\x97\x20\xf0\x74\xa1\xaa\x46\x12\x24\xa5\xdb\xfd\xba\x0b\x4a\xe2\x69\xa3\xc4\x6e\x89\xd4\xbe\x91\xbc\x7c\x45\xa0\x00\x94\x58\xa8\x82\xaa\xb2\xb8\x88\x85\x39\x3d\xfb\x62\x7b\xbc\xfb\xd8\xe3\x65\xc6\xfb\xee\xf1\x7e\x6c\x8f\xed\x39\xc7\xf7\x93\x4c\xfb\x03\xf8\x2b\x38\x22\x72\xa9\xac\x42\x81\x52\xdf\x77\xe7\xf8\x1c\x89\xc8\xca\x7d\x89\x8c\x8c\x88\x8c\x88\x6c\x8d\xf3\x78\x28\xc2\x24\x5e\x0b\x1c\xc1\x62\x96\xba\x57\x26\x26\x71\x7c\x96\xb9\x57\xe1\xd8\x69\xc5\x07\xfe\x91\x0c\x09\x0a\x9d\xf9\xe9\x5a\xce\xdb\x3a\x6b\x9b\x73\x71\x39\x0f\x92\xf1\x5a\x1a\x7c\xca\xc3\x34\xe8\x74\x54\xa0\x8f\x65\xb2\x4e\x27\x77\xd3\x40\xe4\x69\xbc\x96\x43\xa5\xad\x4d\x17\xe3\x43\x1d\x17\xaa\x38\xac\x75\xc8\xe3\xe0\x7c\xed\x61\x9a\x26\xa9\xd3\xbe\xef\xc7\x71\x22\xd6\xc6\x61\x3c\x5a\x9b\x25\xa3\x3c\x0a\xd6\x6e\xb6\xbb\x7e\xb7\x7d\xb3\xed\xf6\xc5\x34\x4d\xce\xd7\x86\xbd\x61\x32\x0a\x78\xfb\xe9\xfe\x83\xd7\x4f\x1e\x1e\xef\xed\xbf\x3a\xde\xd9\x7f\xbd\xf7\xa0\xcd\x86\x0b\xac\x2f\xe2\xd8\x77\x7e\x15\x5c\xcc\x93\x54\x64\xde\xd5\x62\xd1\xc7\x31\x1c\x6c\x1e\xf5\x86\x7e\x14\x39\x51\x4f\x25\x31\x3d\x1a\x27\x90\x03\x8c\x39\x65\xdc\x3a\x3a\x08\x8e\xfa\xaa\xab\x89\x13\x0f\x62\x2f\x70\x17\x2c\x62\x65\xc9\x80\xc9\xb9\x5b\xa8\x5c\xd8\xa4\x4e\x5c\x8c\x61\x24\x58\x5d\xf8\x35\xf3\xc5\x7c\xbe\xd9\xf7\xef\xa4\xbd\x28\x88\x27\x62\xda\xf7\xbb\x5d\x37\x71\x52\x9c\x74\xd3\x85\x85\x73\xb5\xe5\x1d\xd8\xbd\x6d\xe7\x59\xb0\x96\x89\x34\x1c\x8a\x36\xcd\xa2\xe0\x81\xd3\x4e\x03\x1f\xbe\x5d\x16\x9b\x8f\xf5\x34\xc9\x45\x90\x42\x5c\xca\xe3\xde\x0b\xfc\x60\x09\x84\x1e\x04\x63\x3f\x8f\x04\x45\xf4\x21\x73\x6f\x23\x4c\x87\x90\x8b\x82\xc3\x64\x36\xf3\xe3\x51\x5b\xae\x4f\xc8\x29\x32\x4b\x86\xa7\x01\x56\xee\xcb\xef\x5c\x84\x11\x7c\x65\x5c\x17\x99\x27\x71\x10\x8b\x6c\xe3\xee\x7c\xde\xfb\x98\x5d\x40\x5a\xbe\x94\x76\x3f\x89\xe3\x60\x28\x54\xfa\x70\x39\x7d\xea\xeb\xc4\x68\x29\xf1\x65\x20\x44\x18\x4f\x32\x95\x61\x2e\x33\xf8\x34\x27\xd9\x06\x0d\x14\xa2\xc7\x3c\x4a\x60\x99\x5f\x8a\x24\xf5\x27\x41\x2f\xcf\xc3\x51\x7f\x5c\x14\xce\xbc\x17\xfb\x67\xe1\xc4\x17\x50\x6a\x28\xbb\x81\xad\xd4\xf3\xf2\x31\xf7\x7b\xaf\x5f\xef\x3e\x70\x5c\x97\x85\x3d\x98\x6d\x93\xbb\x04\x17\xf7\x4a\xc3\x71\x2f\x0b\xe2\x91\xd3\xc6\x92\x90\xee\x2e\x74\x99\x00\xc1\xb9\x5d\x01\x30\x55\x04\x6a\xcb\x92\x28\xe8\x45\xc9\xc4\x09\xa0\x78\x7a\x16\xa4\xdd\xb6\xb7\xd6\xee\x06\xbd\x59\x90\x65\xd0\x11\xa8\x86\x66\x7e\xca\x45\x6f\x08\xcb\x28\x82\x87\x51\x30\x83\x39\x70\x52\x76\x15\xfb\xb3\xc0\x6b\xfb\xf3\x79\x9b\xcd\x7d\x31\xf5\xda\x1b\x6d\x36\x85\xd5\x8a\x82\xd4\xcb\x16\x6c\x65\x09\x33\x0a\x9d\x39\x87\xce\xae\xcc\x9d\xa9\xb9\x2e\xb3\x47\xd7\x66\x17\xbe\xc8\x33\xd3\x23\x4f\x0e\xab\x2c\x3c\xbc\xae\xf0\x10\x16\xbd\x5e\x74\xc3\x83\x58\xe8\x70\x74\x7d\x1d\x09\xbb\xb2\xfa\xe7\xf6\xe3\x5e\x9a\xc7\xce\x94\xc5\xbd\xc7\x61\x06\xab\x7a\xf9\x04\xd6\x17\x17\xa0\xb2\x12\xa2\x97\xc2\xaa\x05\xa9\x53\xaf\x2e\x60\x71\x1e\x45\x2e\x1b\x25\xc3\x1c\x23\x7a\x27\xc9\xe8\x12\x56\x63\xc1\xae\x96\x20\xcd\xbb\xb5\xf5\x2d\xb3\x36\x0b\x7c\x7f\xcf\x9a\x77\x02\x24\xfd\xc0\x56\x00\xba\x77\xeb\xd6\x66\x3d\xcd\xda\x24\x90\x7c\x8b\x5d\xb3\x0d\x20\xfd\x3b\xa6\x76\xaf\x77\xeb\xf6\x16\x2b\x77\x2a\x7c\x52\x51\xda\xa8\xde\xad\xdf\x6e\x32\xc2\x08\xde\xd6\x0f\xd0\x60\x05\x39\x78\xb7\x37\x17\x47\xec\x96\x8d\x61\x10\xbd\xb9\x57\x2d\x2b\x02\xce\x89\x06\x6c\x36\x0a\x00\x55\x03\x32\x93\xbf\x3d\x7f\x36\x1a\xc8\xa0\x73\x70\xd4\xb0\x5f\x82\xde\xdd\x5c\x24\x51\x18\x9f\x06\x29\x4f\x1d\x98\x5a\xaf\x9d\x9c\x7c\x44\xb8\x34\x55\xc6\x03\xa1\x31\x29\x66\xf1\x96\xca\x38\x62\x1a\x66\x76\xe5\xb8\x57\x02\x6e\x22\x84\x7b\x15\xf4\x5e\xc3\xa8\x7b\x7e\x96\x85\x93\x58\xe6\x17\xee\xa2\x6f\x7a\x31\x4f\x13\x91\x60\x7b\xfc\x0a\xf7\xa3\x48\xf3\x21\x40\x8b\x17\xb0\x3c\x8d\x32\xaf\xb5\xc9\x82\x99\x1f\x46\x18\x10\xe7\xa1\x80\x39\xc2\x20\x1c\x53\x6f\xe1\x5c\x4a\xce\xf1\x03\x71\xef\xfc\x59\x0a\x63\xbd\xa0\x6c\x00\x77\x00\x69\x81\x77\x96\x84\xa3\xb5\x4d\x36\x8c\xa0\xed\x3d\x02\x6f\x80\x60\x31\x8b\x9e\xf9\x29\x40\xb6\x4e\x9e\xf9\x62\x38\xad\x46\x09\x7f\x72\x2f\x0f\xa3\x51\x19\x83\x43\xf6\x6c\xb8\xd5\xe7\x8a\xe0\x38\xa2\xde\x24\x10\x8f\x4d\xcd\x0e\x62\x7d\xd1\x9b\xe3\x07\xe4\x05\x74\xbf\x09\x88\x1e\x16\x21\x84\x80\x0f\x18\x5f\x1f\x2f\xdb\x61\x3f\x84\x23\x86\x26\x2d\x83\xa3\x32\x3c\x02\x3c\x4d\x95\xbd\x82\xf9\x70\x10\x2b\xcb\xaf\xe0\x42\x38\x74\x6a\xb7\x03\xb9\x3d\x60\x89\x78\xee\xb6\x7d\xfc\x95\x59\xfc\x09\x0e\xd1\x71\x3b\x1d\x27\xeb\x85\xd9\xfd\x28\xc9\x00\x32\x1d\x77\x90\xf2\xa7\xb0\x9d\x7b\x33\xff\xc2\x49\xd7\xb7\xd8\xa6\xeb\xa5\xd0\x26\x4b\x7a\xf3\x3c\x9b\x3a\x43\xb7\x1f\x44\x70\x7e\x51\xdd\xb1\x08\xc5\xa5\xac\x7a\x39\x79\x13\xe2\x53\xd9\xd7\x48\x0e\x1a\x27\x25\x1c\x5f\xbe\x14\x29\xe6\x53\x25\x22\x77\x41\x25\x4c\x05\xfa\x58\x4e\x7a\x1f\x93\x10\xd0\x71\x1b\x8f\x6f\x53\xd2\x6b\x40\xcb\x7a\x46\x9f\x96\x2b\xe3\xb8\x80\x27\xe6\x91\x3f\x0c\x70\x3f\x60\xba\xc4\x16\x94\xe5\x05\x15\x7b\xe3\x47\x94\x02\xd5\x37\xa5\x79\x36\x4c\x12\x81\x81\xf3\x49\x55\xa9\x9a\x77\x62\x98\xbb\x98\x57\xa3\x24\x99\x22\xa1\x56\x82\xae\xcb\xda\x08\x70\xf1\xc4\xda\x26\x9a\x96\xa2\x3a\x63\x98\xa8\xd6\x96\x8e\x12\x66\x24\xc1\xa8\x5c\x47\x38\xae\x00\xd4\xfd\x78\x88\xc5\x83\x1e\xc2\x0e\xac\xa0\xa9\xa6\x27\x92\x97\xd4\x86\x23\x4f\x9f\xd4\x40\xd9\x2b\x03\x9a\x00\x1e\x09\x4f\x7b\x27\xf8\x05\x63\x32\x04\x8a\x55\x76\xc1\x2a\x70\xe9\xd5\xf6\xa9\x82\xdd\x72\x4b\xe8\x3a\x04\x9c\xd1\x4b\x89\x44\x1a\x06\x56\x44\xaf\xac\x19\x4e\x03\x6a\xcb\x5a\xb1\x15\x8d\x59\xbb\xad\xa1\x35\x2b\x55\x35\x67\xc5\xf4\x6c\x78\xb8\x22\xec\x40\x85\x30\xa4\x90\x04\x7d\x53\xd0\x20\x0b\x8a\x52\x1f\x15\x4c\x41\x09\x56\x04\x9c\x59\x6a\x14\xe5\x1c\xaf\x18\x44\x89\x1f\x1a\xc6\x50\x26\xaa\x21\xdc\x8d\x87\xd3\x24\xb5\x16\xee\xaa\xc4\x5e\x54\xc2\x7c\x96\xa8\x4b\xd6\xa4\xbe\x2c\x0c\x26\x41\x5f\x7f\xca\x2e\x2f\x58\x40\x5b\xd1\xc2\xba\x78\x60\x48\xb8\xa1\x2e\x38\xb1\x01\x8f\x94\xb2\x02\xbc\x60\x29\x9a\x5c\x7e\x85\x41\x6b\x9d\xaf\x4c\x92\x1d\x81\x48\x9c\x5f\xf9\x27\x30\x63\x70\x5c\x3d\x0d\xc4\x34\x19\xd9\xd3\x43\x0c\x41\x5b\xa7\xb7\x17\x4c\x22\x7c\xcf\x3e\xc7\x4a\xb4\x89\xf0\xbf\x26\x5c\xd1\x9b\xfa\xd9\xfe\x79\xfc\x2c\x4d\xe6\x41\x2a\x2e\xa1\xa3\xb0\x07\x83\x83\xf8\x08\xa8\xff\xb8\xa4\xba\x03\xe8\xc1\x85\x00\x42\xc1\x6b\x1a\xa3\x28\xcf\x10\xd8\x12\x56\x9f\x16\x88\x94\xcc\xf1\x92\x4a\x12\xba\x1f\x02\x06\xae\x35\xdb\xb6\x4e\x9e\xb6\x3b\x80\x5d\x6f\x9d\x44\xf6\xd1\x69\x27\xf4\x80\xf0\x8b\x2e\x25\x6e\xf0\xd3\x09\x51\x29\x80\x7d\xa8\x15\x9f\x87\x56\xcb\xb8\x08\x89\x1e\x8b\x6f\xd7\xc1\x43\xe6\xf7\xb2\x1c\x7a\x41\x8b\xca\x53\x36\x02\x0c\x2f\x82\xb5\x4a\x17\x58\xf5\x0c\xf5\x61\xe8\x2c\x84\x29\x89\xa2\x70\x9e\x85\x99\x57\xa7\x15\xcc\xd9\x2a\x0f\x9a\x6d\x41\x88\x0d\xe9\x29\xce\xe3\x41\xbb\xd7\x6b\x7b\x31\x0b\x38\x90\xbc\xf9\x89\xc4\x65\x0e\x1c\x7a\xeb\xfa\x60\x72\xbb\x50\x3f\x4c\x39\xc0\x64\x70\xb1\x3f\xae\x2d\x21\x60\xaf\xbb\x69\xea\x5f\x96\xe3\xeb\xa9\x8c\xae\x69\x57\x45\x20\x5a\x32\x2b\x0e\x67\x5f\xca\x75\x97\xfa\xe9\x76\xdc\x8f\xe1\x1c\x82\xda\x68\xb9\x01\x97\x96\x48\x54\x06\xd6\xb7\x16\x2c\x9b\x47\xa1\xb8\x1b\x8f\xee\xfb\x73\x88\x0a\x96\xbb\xd2\x02\xfc\x1a\x25\x27\x7e\xe4\x4a\x8e\xd4\xe2\x5f\xff\x9c\x0a\xbf\x08\x26\xc1\xc5\x9f\xaf\xcd\xf2\x4c\xac\x4d\xfd\xb3\x00\x4e\x17\xe0\x63\x27\x37\xd7\xc6\x91\x3f\x59\xcb\x90\x8d\x2a\xfb\x08\x3d\x84\x63\x3a\x01\x2e\x10\x0f\xf0\xe0\x22\x18\xc2\xb1\xd4\x77\x53\x79\x96\xd9\xf3\x95\x00\x5d\x4b\xa3\x84\x2d\xa8\x92\x63\xe0\x6a\x5d\xe2\xe8\x28\xa1\x8b\xdf\x66\xb8\x7a\xf7\x2d\x57\x84\x15\xd0\x1e\x56\x87\x00\x57\x8b\x2d\x01\xde\xd9\x27\x92\x8c\x5d\x9d\x4f\x43\x11\x64\x73\x38\x94\x68\x44\xde\xc6\x61\xd6\xdd\x60\x8d\x70\xba\x8a\xe8\x92\x07\x67\x08\x14\x6d\x8a\x6d\xf1\xea\x67\x51\x58\xdf\xaf\x9e\x3e\x81\xc9\x37\x64\xc5\xca\x53\x5a\xc8\x74\x2e\x0f\x65\x8d\x3d\xab\x45\x1a\x4b\x14\x45\xbb\x4d\x2d\xdc\x15\x15\x22\x80\x09\xc3\xfe\xab\x13\x0f\x33\x64\x8e\x41\x05\xf1\x41\x00\xc8\xa1\x6c\xae\x56\x7e\x89\x88\x50\xc5\xa1\x94\x69\x2e\x5b\xa6\x05\x56\xb5\x56\x9d\xc7\x58\x4f\xa2\x69\x39\x5b\x35\x4c\x1f\x13\xf1\x50\x30\x1f\x80\x46\x5d\xea\xc2\x7d\xdc\xe9\x2b\xbb\xac\xfa\x08\x28\x09\xb3\xb5\x19\x4a\x3b\xfc\xd1\xa8\x56\xc8\x46\xa5\xac\xa4\x0e\x28\x17\x11\x06\x14\x53\x83\x19\xa0\x3f\xd5\x78\xd4\xfe\x04\x62\x34\x1d\xa4\x3d\xda\x27\x00\x88\x1e\xc0\x7e\x06\x70\xaf\xbf\x61\x13\x40\x7f\xa6\xe1\x18\x89\x16\x77\x7d\x0b\x36\x69\x48\xc8\xa7\xd3\xf1\x15\xc8\x9b\x89\xaa\x4f\xb7\xea\xfe\x11\x70\xf0\x92\xec\x5b\x6b\xeb\xa9\x4b\x83\x59\x72\x16\xfc\x7f\x32\x20\x5f\xed\x47\xc2\x87\x66\x6c\x30\x38\x25\x53\x93\xc3\xeb\xaf\x6f\xb5\x80\x06\xc6\x51\x62\x49\xa0\x39\x73\xb6\x65\xe8\xd8\x5f\x31\xd2\xc9\xd2\x62\xaf\x04\x4f\x5d\x8b\xdc\x17\x70\x3c\xad\x82\x12\xea\x1b\x36\xd2\xad\xcd\x51\x17\x1b\x36\x98\x17\x33\x04\x14\x45\x30\xb7\xab\x77\xf9\x4a\xb8\x2b\xd1\x82\xb5\x97\x1b\x8a\xad\x28\x25\xfb\xad\x49\xcf\x3a\xdd\x14\xd8\xf4\xab\xe4\x53\x98\x22\x97\x88\x7e\xa5\x59\x40\x3e\xa2\x84\x27\x2e\x06\x34\x48\x64\xda\x0e\xda\x77\xda\x24\xe6\x6b\x6f\xb7\x99\xae\xc9\xf4\x0d\xea\x6a\xdf\xd9\xc0\x0c\x90\x7c\x64\x71\x19\x95\xaa\xed\x2e\xd1\xb9\x61\x36\xa6\x3a\x77\xda\x52\x78\x17\xd4\x51\x01\x74\xf4\xe0\xa8\x5f\x21\x5c\x02\x37\x68\x22\x5c\x84\xda\x14\xdd\x9b\xbc\x7d\xb3\x8b\xc7\x5a\xf7\x66\xfb\x66\x39\xa4\x12\x3e\x16\x0b\x38\x60\x97\x08\xc3\x15\x98\xff\x57\xe1\x78\x35\xea\x06\x0c\x27\x89\x51\x75\xc8\x38\x57\x0a\x0f\x7b\xc0\x43\x32\x9a\x06\xcf\x62\xab\xe4\xd0\x85\xc5\x89\x52\x58\x76\xf8\x31\x90\xcb\x24\x91\x33\xc0\x41\x25\x81\x1c\x18\x06\x59\xa6\x06\x85\x9c\x8e\x55\x46\x72\x3e\x28\x4c\xd3\x68\x5c\x73\x69\x35\x2c\x6a\x1d\x00\x57\x53\x68\xc8\x03\x92\x5c\xa1\x03\x99\xff\x7e\x26\xb7\x06\x1e\xcc\xfa\x54\xc5\xed\x5c\xee\xc3\x54\x1d\x74\x86\xac\xc6\x64\x38\x77\x52\xe8\x0d\x6f\x1f\x9f\x44\x7e\x7c\x8a\x82\x59\xdd\x03\x5d\xa3\x57\x17\x41\x2b\x08\x35\xe4\xb6\x59\xc8\x81\xe8\x12\x6c\x76\xdb\xeb\xb0\xcb\x3c\x84\xfc\xa5\xd1\x37\x6d\x34\x05\x5b\xa3\xe4\x95\xa2\xec\x1d\xc4\xee\xe5\x67\x65\xd5\xaa\x27\x90\xa6\xf5\x1c\x79\xf4\x19\xde\xa0\x28\xf6\xf2\xd9\x09\x30\x47\xcf\xf6\x5f\xee\xbe\xda\x7d\xf3\xf0\x78\x77\x6f\x67\x77\x6f\xf7\xd5\x7b\x05\x64\x8d\xfc\xda\x0a\x48\xc3\xbc\x92\xba\x58\xda\xbf\x1b\x07\x9b\xeb\x3f\xf8\xeb\x9f\xef\xae\x7f\x38\x2a\x83\xde\xd1\x37\x1b\xb0\x3f\x36\x0e\x7e\x77\x98\x1d\x6e\xb6\x6f\x6e\x1f\x6e\xf0\xc3\x8b\xcd\xad\xf5\xc3\x8b\xad\x9d\xc3\x8b\x3f\xdd\x39\x02\x1a\x25\xe6\x1b\xce\xc0\x6b\x1f\xfc\xae\x7d\xf4\xcd\xa0\x5d\xdc\x3c\xf8\xdd\x4d\x08\xdc\x2c\xe0\xb7\xcd\xef\x6c\xff\xf9\x61\x76\xd4\x75\x37\x70\x95\x7b\x59\x92\xa7\x43\x40\x5b\x90\xff\xf0\x30\xfb\x86\xe3\x9f\x76\x37\x36\xf1\xee\xa0\x6d\x00\x08\xc0\x19\xfa\xfa\xf0\x62\xee\x1c\x60\xfe\x36\x20\x01\xa7\xf5\x60\xff\xfe\xab\xf7\xcf\x1e\xba\xf0\x25\xe3\xa0\x86\xae\xfe\x48\x59\xbb\x68\x33\xab\x36\x48\x70\xbf\x69\x13\x56\xa1\x8f\xc2\x14\xbb\xe3\x6c\x40\x5b\xf0\x85\xa2\x60\x3b\xbf\x5d\x6b\xaa\x8a\x63\x2f\x37\x06\xa6\x9e\x12\x05\xb1\xf6\x24\x84\xcd\x0e\xdb\x07\x67\xf6\xfe\xd4\x47\xd6\x28\x48\x1f\xa2\x9c\x25\x0c\x32\x45\xc8\x39\x9d\xf8\x24\x9b\xf7\x8b\xce\x9f\x6c\x7d\xb7\x09\x3f\x91\xc0\x30\x05\x27\x32\x78\x0b\xfe\x7e\xca\x13\xfa\xb8\xfd\x5b\xfa\xfb\x43\xdf\xdd\x98\x84\x8c\x64\x4c\xcd\x82\x29\x66\xce\x51\xb3\xac\x48\xd9\xc2\x99\x09\xe8\x0c\x79\x01\x3c\x47\x04\x4f\x35\x99\xab\x4f\x41\x1f\x58\xaf\x4d\x3a\x37\x0f\xb6\xe0\x38\x12\x07\xb7\x51\x2a\xd5\x6a\x89\x83\x5b\x47\x78\x4d\x50\x21\x82\x85\x22\x82\xfb\xc3\x52\x76\x42\x7d\xc2\x2d\x00\x74\x3b\x0d\xf5\x72\x2f\x19\x05\x99\x33\x44\x81\x3c\x62\x48\xc5\x38\x85\x70\xd4\xea\x28\xc7\xda\xe1\x4a\x02\x8c\x85\xf0\x0e\x8c\xe5\x2e\x9d\xff\x8a\xaa\xd6\x47\xf8\x02\x90\x78\x72\x47\xf3\x13\x5a\x2e\x55\xa5\xac\xfb\xd1\x97\x7b\x15\x35\xf5\x4a\x9f\xf5\xc0\x64\xad\x28\xd7\x4c\xb9\x20\xf7\x60\x36\x57\x8d\x77\xd1\x3b\x77\x35\x28\xb8\x6a\x7d\xcc\xfd\x53\xb8\x9d\xf4\x93\x2e\xbf\xa5\x17\x26\x3d\x48\x70\x61\xe0\xa7\xbb\x75\xd4\xf7\x3b\x9d\x78\x69\xf2\xb0\xa7\x72\xe6\x60\xd6\xb2\xa6\x1c\xe5\x20\x9c\xac\x1c\xa9\xc1\x86\xd6\xec\x57\x98\x6d\x14\x3a\x5b\x5b\xaf\x82\x58\xec\x15\xbb\x12\x88\xfc\x04\xd3\xe7\x0b\xca\xb2\x9e\x24\xe7\x41\x7a\xdf\xcf\x48\xa4\x29\x05\x93\x5e\xba\x30\x82\xba\xb2\x47\x4d\x08\x70\xb9\xb5\x72\x00\xaa\xb1\xb2\x2a\x3d\xfc\xaf\xaa\xc8\xcc\x55\x59\x4d\x13\xca\xc4\x2c\x2b\x10\x26\x95\x03\x02\xe5\x57\x1e\xd1\xea\x58\xf5\x74\x72\x45\xa8\xc2\x94\xc0\x77\x25\x03\x05\x69\x4b\xfd\xb4\x56\xa0\xd6\xd5\xc6\xe1\xb0\xf2\xf8\x6f\x9b\x15\x69\x6d\x99\x8e\x2d\x35\x6d\xe4\xce\xbf\x82\xc5\x5b\x30\x23\x86\x5e\x95\x53\x35\xbd\x3c\x1c\xb3\xc4\x5f\x37\x9a\x6b\xfa\x2d\x65\xda\x4b\x2d\xe8\xb5\xff\x8b\xd6\x8f\xab\xa1\x6a\x5f\x21\xaa\x5c\x01\x3a\xd7\xdd\x6e\xd4\x2e\x34\xa8\xe2\x20\x5d\x75\x32\x3b\xbf\x83\xa3\xf4\xf0\xfc\xc8\xfd\x33\xe7\xf0\xfc\x6a\x8b\x6d\x7d\xbb\x70\xe9\x54\x86\xb3\xea\xe0\x70\xbd\xef\x75\xf8\x61\xf7\xf0\x06\x3b\x3c\x3f\xec\x1d\x75\xff\xcc\xd5\x27\xf2\x01\x1c\xe0\x70\x8c\x1f\x1d\xac\xf7\xba\x32\x08\xe7\xfa\x51\xd7\x73\x06\xad\x55\x49\x87\x1b\x87\x1b\x2e\xa4\x1f\x8e\xba\x87\x1b\x03\x17\x8f\x69\x8c\x19\xd0\xf1\x8d\x75\x9e\x9f\x43\x23\xf0\x95\x00\x4d\x60\x0a\x1e\xf6\x0e\xd7\x8f\xbe\xb1\xbe\xd7\x8f\x36\x00\xcd\x6d\x1c\xf6\xa0\x44\x18\xc3\xa0\x63\xba\x18\xf4\xa3\xc2\x6c\x24\xf8\xc4\x0f\xda\x17\x09\x70\xd2\x01\x66\x9b\xa7\x61\x16\x64\xc5\x7c\x9a\x88\x64\x92\xfa\xf3\xe9\x65\x01\x74\xd7\x48\x66\xcf\x8a\x71\x92\xc7\x23\xaa\xa9\x08\x67\xb3\xe4\x24\x8c\xc2\x00\x82\xf1\x28\xc7\x09\x85\x82\x33\x3f\xf6\x27\x04\xc7\x58\x0e\x09\x77\x8c\x15\xc1\x70\x1a\x27\x51\x32\xb9\x2c\x86\x53\x68\x41\xcc\xfc\xac\xc0\xab\xc4\x3c\x06\xd0\x29\x46\x61\x1a\x60\x1f\x2e\x8b\x00\x5a\x92\xd5\xa3\xba\xc0\x9c\xea\x41\x31\x7e\x28\x72\x20\xc4\x66\x7e\x7a\x1a\xe0\x6d\x60\x91\x25\x51\x2e\x7b\x74\xe6\xcb\x02\x59\x71\x02\xe4\xa7\x1f\x62\x20\x81\xb4\x4f\x79\x50\x9c\x48\xa2\x1f\x9a\x02\xbc\x85\x07\x56\x31\x8c\x02\x3f\x96\x81\x04\xb6\x07\x06\x92\xd9\x1c\xaf\x05\x8b\x11\xf0\xcc\xc3\xd4\x17\xd0\x1b\x7f\x96\xc4\xa3\xac\xa0\xf1\x87\xc3\xac\x98\x26\xd1\x08\xef\x20\x8b\x28\x9c\x4c\xa9\x7d\x38\xb2\x44\x8c\x35\xcf\x23\xa0\x0d\xa9\x47\x39\x9c\x6d\x34\xd6\x14\x3a\x81\x31\x67\xd0\x79\x38\x94\xb2\x02\x7a\x08\x95\xc3\xd0\xfd\x34\xa0\xde\x40\x93\x7e\x0c\xdf\x69\x4e\x93\x3d\x4a\x66\xd4\x6f\xbc\x06\xcc\x82\x51\x31\xa6\x66\x60\xb2\xa3\x04\xe7\xaa\x98\xf8\x51\x14\xc0\xe4\x4c\xf2\x10\x48\x6c\xea\x4e\x38\xf2\x2f\x8b\xd3\x10\x81\x36\x2e\xe2\x00\x66\xdf\x4f\x8b\xe4\x34\x8c\xfd\x73\xbf\x80\xc9\x0c\xe7\x50\x6f\x0a\x1d\xf0\x23\xfc\x3d\x0b\x83\xf3\xac\x00\x5e\xfc\x34\x9b\xfa\x05\xe2\x83\x08\xd2\xb1\xcb\x49\x2a\x8a\xec\x32\x13\xc1\x0c\xfa\x39\x09\xe2\xe1\x65\x01\xa4\x6e\x14\x02\x68\x00\x7e\x49\xfd\x62\x48\x60\x01\x7d\x1e\x8f\x83\x00\xe1\x65\x94\x40\x8f\x7d\x9a\x85\x00\x2f\xc2\x83\x22\xc0\x91\x52\xf7\x61\xb9\x8b\x71\x2e\x4e\x92\xa8\x38\xf5\xf3\x31\xf4\x2d\xca\x2f\x72\xe8\x3a\x0c\x30\x83\x45\x85\x79\xf5\xb3\x69\x31\xcb\xb3\x20\x9f\x15\x00\x29\xc9\xa5\x2f\x61\x0d\x7b\x39\xf7\xc3\x14\x7f\xa8\x4f\xc9\x30\x04\x60\xa5\x59\xbd\x2c\xa0\x19\x91\x24\x05\xc0\x12\x40\x1f\xce\xf0\x59\x10\x15\x67\xa1\xff\x11\x46\x71\x16\x46\xc0\x3d\xc0\x4f\x86\x60\x73\x96\x50\xcf\xce\xa0\xe2\x49\x50\x10\x64\x4b\x30\xc0\xd9\x87\x35\x85\x09\xf3\xe7\x05\xaa\xd4\xe0\x28\xe2\x21\xf4\x1e\xb1\x43\x31\x41\x0e\x04\x66\x16\x7a\x86\x30\x3c\x49\x0a\x58\xc3\x8f\x3e\x2d\xb4\xda\x0e\x30\x7f\x09\xce\x5a\x12\xc1\x5c\x8b\x04\x57\x40\x24\xa7\x97\xd0\xad\x24\x81\x59\x3e\x47\x14\x52\x9c\x27\xe9\x29\xcc\x64\x90\x26\x85\x9f\xce\xfd\xc2\xcf\x42\x1f\x66\x14\x56\xf1\x24\x3c\x05\x88\x8c\x08\x2c\x3f\x7f\xc6\xe9\x85\x7e\x44\xf9\x09\x74\x26\xc1\x5d\x99\xcc\x8b\xb1\x9f\xce\x8a\x71\x08\x33\x34\x09\xc7\xb0\xee\x79\x9a\x03\xf4\x8f\x93\xe2\x63\x72\x92\xc1\x72\x9f\x87\xc5\x69\x0a\x00\x02\xec\x15\xfc\x09\x67\x49\x81\x37\x0d\x05\xec\x92\xbc\xc0\xcd\x08\x7f\x60\x7a\x50\xcd\xa0\x98\x23\xdc\xce\x31\x15\x60\x4a\x14\x9f\xe6\x30\x37\x69\x08\x1d\x4c\xf3\x69\x5a\x64\xc1\x05\x74\x1e\xb8\x1d\x9c\xaf\x00\xff\x24\xd0\x7f\x98\xb7\x73\xdc\xce\xe7\xe1\x69\x58\x7c\x4e\xe2\x00\xb7\x14\xf4\x7b\x04\xff\xb1\xc3\x27\xb8\x8f\x00\x20\x12\x84\x60\xdc\xaa\xc5\x24\x39\x83\x0e\x0a\xe8\xda\xac\x98\xc1\x2c\xc6\x81\x28\x92\x38\x2a\x92\x74\x82\xdb\xbf\x98\xc3\xf0\xb0\xc3\x02\x96\x2b\x8f\xa1\x0d\x08\x5f\x5c\x5c\x14\x17\x97\x9f\x61\x6d\x0a\x7f\x04\x33\x55\xf8\x63\x80\xbc\xc2\x0f\x0b\x58\x6f\x7f\x56\xf8\x71\xe1\xc3\xe4\x7d\x82\xf9\x83\xd9\x2b\xa0\x45\x3f\x2f\xfc\xf3\xc2\xbf\x28\xfc\xcf\xd0\xa3\xe2\xe4\xa4\x38\x81\x2e\x41\xef\xc6\xc5\xc9\xa4\x38\x99\x42\xf7\x8a\x93\x8f\xc5\xc9\xac\x38\x89\x61\xf3\x17\x27\xd0\x69\xc0\x02\x30\xe5\x67\xc5\xc9\x79\x71\x02\x20\x8d\xdd\x2f\x86\xc3\x62\x08\x70\x30\x2e\x86\xb0\xed\xa7\xc5\x30\x2c\x86\xa7\xb0\x04\xc5\x70\x56\x0c\x11\x15\xc2\x86\x2c\x86\x79\x31\x3c\x2b\x86\xe7\xc5\xf0\xa2\x80\xbd\x30\xfc\x0c\x78\xa1\x18\x7d\x2c\x46\xa7\xc5\x68\x06\x3b\xb5\x18\x7d\x2e\x82\x61\x01\x5b\x21\x00\xf8\x4f\x61\x0b\x14\x30\xe6\x20\x87\x65\x2b\xc6\x1f\x8b\xf1\x69\x31\x86\x25\x4c\x8a\x71\x0a\xdb\xb6\x98\x9c\x14\x93\x51\x01\x80\x38\x19\x17\x93\x49\x31\xc1\x85\x05\x50\x2b\x26\xb3\x62\x12\x17\x93\x79\x31\xf9\x04\x58\xa6\x00\xcc\x32\xc1\xe5\x2e\x26\xe7\x05\xa0\xc8\xe9\x69\x31\x9d\x15\xd3\xb8\x80\x95\x9a\x8a\x62\x0a\x40\x30\x2a\xc2\xa0\x80\x09\x86\x79\x86\xad\x19\x26\x45\xf8\xa9\x80\xcd\x12\x66\x45\x28\x8a\x8f\x41\xf1\x71\x06\x30\x52\x7c\x9c\x17\x00\x63\xa7\x93\xe2\x74\x0a\x4b\x52\x9c\xce\x8a\xd3\xb8\x38\x85\xc8\xb4\x38\x3d\x2f\x4e\x01\x63\x7c\x06\xd8\x29\xa2\x93\x22\x1a\x02\xe8\x14\xd1\x69\x11\xa5\x05\xc0\x6e\x24\x60\xa3\x16\xd1\x59\x11\xe1\x56\x2d\x66\xc3\x62\x36\x02\xb0\x2a\x66\x93\x62\x06\xdb\x15\x40\x2c\x2a\x66\xb0\xc4\xb8\x83\x0b\x80\xdb\xd9\xa7\x62\x96\x16\x80\x32\x66\x02\x36\x73\x31\x3b\x2b\x66\xe7\xc5\xec\xa2\x00\x24\x37\xfb\x0c\x00\x58\xc4\x43\x80\x85\x22\x1e\x17\x00\x53\x71\x58\x00\x48\xc0\xea\xc7\xf3\x22\x4e\x0b\x80\xd5\xf8\x73\x01\x00\x04\xbb\x63\x0e\x80\x3a\x2e\xe6\x00\x2c\xd3\x62\x0e\xa0\x1a\x15\x73\x88\x8f\x01\x76\x0a\x80\xcd\x39\x9c\x21\xe7\xc5\xfc\xb2\xf8\x84\x38\xad\x00\x78\x02\xe4\x07\x5b\x22\x3d\x2f\x32\xc0\x62\x27\x45\x36\x2c\xb2\x11\x00\x73\x91\x01\xfe\x9d\x02\x5e\x2b\xb2\x8f\x45\x76\x5a\x64\x80\x38\x66\x45\x16\xc3\x5e\x2d\x32\x80\x76\x40\x27\x79\x91\x9d\x15\xd9\x05\xe0\xba\x22\xfb\x5c\x88\x61\x21\x00\x2a\xc7\x85\x98\x14\x62\x5a\x88\x8f\x85\x38\x2d\x44\x54\x88\x59\x21\x62\xd8\xcf\x85\x98\x03\x96\x29\x84\x28\xc4\x59\x21\xce\x0b\xf1\xb9\xc8\xfd\x22\x9f\x14\xf9\x69\x91\x67\x45\x7e\x59\xe4\x9f\xe1\xe4\x29\xce\x86\x80\xe5\x8b\x33\xc0\x37\x61\x71\x06\xc8\x27\x2f\xce\xc7\x05\x60\xda\xcb\xa0\xb8\x14\xc5\x67\xbf\xf8\x3c\x2b\x3e\x9f\xbb\x87\x27\x1b\xcc\x87\xe3\xfa\x70\xdd\x1c\xd0\xdd\xce\x9f\xfd\xc9\xe1\xc6\x6f\xf8\x5f\x3e\x76\xdc\xe2\xe6\x8d\x6f\x0e\x0f\x0e\x8f\x06\x2d\x8f\xf5\xfa\x70\x8c\x7f\x21\xdf\xd1\x46\x33\x87\xde\x66\x9a\x91\xb6\x78\xed\x36\xd3\x3c\x3f\x4b\x74\x20\x6c\xca\xa6\xf8\x6e\xa7\x64\xdf\xcb\x02\x35\xd6\xdd\xe9\x0d\x36\x88\x79\x4f\xbf\x3a\xe7\x8a\xb6\x35\xbf\x0f\x3c\xa7\x25\x80\x58\xc5\xe2\x0f\x81\xa7\xbb\x17\x00\x2b\x18\x3c\xc3\x8b\xb1\x61\x02\x3c\x77\xa4\x74\x10\x88\xcf\xff\x9d\xd3\x73\x07\x48\x2f\xfd\x41\xd7\x36\x44\x04\xbe\xf1\xf1\x70\xc5\x7b\x43\xc9\xcc\x3c\xad\x44\xa2\x68\x9d\xd4\x16\x96\x2e\x04\x4b\x1d\x82\xf2\x62\x43\xeb\x53\x94\xb5\x2b\x12\xd3\xd2\xcf\x62\x09\x0b\x19\xf1\xe0\x6c\xc8\x22\x36\x97\x35\x8d\x81\x43\x55\xf2\xae\xfb\x80\xec\xb1\x71\xa9\x6c\xd1\x50\x00\x95\x1d\xc6\xb2\x18\xa9\xd0\xa1\x36\x45\xcc\xc6\xb2\x41\x23\xc1\x1b\x43\x7d\x48\xed\xbe\x14\x69\x77\xda\x1d\x03\x13\x3f\x96\x5f\x0b\x73\x01\xec\x1a\x19\x5b\xb5\xcd\x1a\x93\x6a\x77\x40\x09\x05\xd8\x9c\xe7\x45\x31\x64\x63\x8e\xfa\x3f\xf0\x87\x14\x30\x3a\x9d\x96\xad\x1a\x50\x14\xa1\x8e\x91\x67\x6e\xe1\xeb\x6f\xa4\xd4\x8b\xa2\xd5\xb0\x0a\xbd\x30\xa3\xb0\x1c\x3c\xb6\x3a\x77\xcd\x2d\x66\x1e\x45\x46\xc3\x84\x8a\x3d\xf6\xb3\xd7\xf1\x89\x1f\xe1\xc1\x3e\x52\x8c\x11\xb0\x08\x01\xae\x7c\xa7\x83\xea\x03\x4a\x78\x81\x97\xb1\x4a\x04\xb0\xbe\xe5\x62\x97\x5d\x00\xb4\xd0\x8d\x6c\x9d\x88\xde\x43\xec\xa6\x73\x35\x2b\x55\x4b\x80\xeb\x96\xdc\x44\xb8\x28\xd5\x76\x62\x17\xc5\xa3\xb0\x64\x8c\x1a\xa0\xeb\x8c\x2d\x17\x75\x3a\xed\xca\x5e\xc9\x59\xa8\x57\xa7\x26\xe7\x31\xe9\xf5\x79\x89\xaa\x16\xe5\xe7\x0a\x14\x46\x7c\x2e\x6b\x50\x12\x86\xeb\xf7\x80\x4b\x12\x25\x58\x80\x11\x75\x69\x54\xed\xd2\xa2\xda\xa5\xd7\xe9\xd2\xe8\x60\x25\xe0\xef\x5c\x55\x0d\x19\x24\x04\xb4\x5a\x99\x89\x84\xf6\x80\xfc\x3b\x0b\x74\xca\xfc\x0b\x3a\x1f\x0a\xc0\xae\x0c\xfc\x79\x63\x66\xa0\xcf\x9b\x4a\xde\xcb\x8b\x16\x0b\x76\xfd\x1a\x36\x08\x8f\x03\x9a\x8e\xbb\xc2\x09\xca\xc5\x24\x1d\x2e\xb7\x4d\xd7\xdd\x4a\xcc\xad\xc6\xeb\x6c\x1c\x3a\x1b\x13\x97\xc4\x47\x3a\xc2\xc5\x88\x84\xc7\x28\xc6\x91\x55\x14\x05\x09\x88\x3a\x9d\xb4\x8c\x20\x6d\xee\xed\x44\x01\x5e\x6b\x53\x0d\xa9\xb5\x25\xd9\xd2\x2a\x8e\x58\xc1\x8d\x86\xf1\x19\xe6\x58\x85\xb9\x0e\x80\xbd\x94\x98\x6b\xea\x67\x3b\x00\xd9\x65\x46\x95\xe1\x1a\x86\x71\x03\xd6\x2d\x7c\x09\xcb\x38\x0b\xbe\x94\x9d\xea\x7f\x9b\xa4\x23\x14\x90\xdd\x1d\x03\xe8\xd5\x1a\xf2\x50\xd2\x7c\xf4\xcd\x40\x57\x00\x7c\xa4\xb5\x05\x57\x29\x42\x08\xbd\x95\x55\xe6\xd7\xba\x3f\xb0\xf3\xd4\xb5\x77\xae\x80\xe9\x01\x50\xd1\x7b\x89\x78\x0c\x44\xbc\x6e\x7a\x3f\x7d\x90\x08\xba\x98\x58\x9d\xf7\xae\x78\x12\xf8\x99\xd8\x8f\x03\xdd\x7b\xbb\x40\x98\xed\x2e\xcd\x6f\x09\xa5\xb0\x45\x07\xad\x2d\x60\xf4\x17\xac\xde\xbf\x46\xa8\xb2\xf6\x5b\x75\x62\x5d\x54\x38\xa8\x48\xdb\x14\x7e\x6d\x7f\xf4\xcf\xfc\x6c\x08\x60\x2f\xbc\x76\x0b\x60\xaf\xd3\x69\x9f\x9d\xd8\x11\x0b\xf6\xa5\x09\xa8\x5d\xd1\x28\x18\x73\x5a\x01\x8c\xb1\xd3\x91\x92\xcd\x06\xd8\xe8\x09\x60\x2f\x68\x9a\xe9\xe2\xb2\x54\x0d\x69\xf7\xda\xb0\xe5\x9b\x9a\x5d\x9e\xcb\xc6\xb6\xd7\x02\x68\x76\xd0\xd2\x2d\xaf\x86\x1a\xd9\x85\xc0\xf5\x60\x47\xb0\xeb\x97\xa2\xe1\xd2\xa6\xd5\x0a\xd4\xf0\xae\xdb\x23\xba\x0d\x4b\x12\x24\x37\xde\x1f\xe7\x4e\xef\x8b\x02\x43\x4b\xc1\x70\x95\xac\xcd\x42\xa5\x52\x7d\xc1\x5c\xe6\xad\xae\xd6\xba\xce\x6a\xcc\x63\x8d\x96\x8e\xa3\x25\x69\x9a\x35\x13\xd7\x4a\xe9\xb0\xb0\x94\x2d\x52\x3d\xab\xc6\x40\xf9\xea\xbd\x5f\xae\x0e\x73\x89\xc4\x53\x57\xe4\xf5\x42\xd7\x4d\x92\xcc\x6b\x0d\x4b\x1d\x8c\x7f\xe8\xc0\xd4\x01\xaa\xc4\xa6\x95\xd3\x74\x95\xf0\xd4\xce\xf4\xe5\xa1\x4e\x85\x98\x67\xde\xc6\x86\x2a\xd6\x03\xe6\x77\x43\x8d\x7b\x55\x4d\xcd\xe3\x6f\xff\x59\x63\x31\x6b\x2a\xe0\xbc\xbd\x7e\x1a\x60\x2f\xcb\x63\xd5\x10\xbc\xd4\x3b\x2d\x24\x74\xa4\x70\x70\xb0\x11\x2e\x9d\xd6\xba\x80\x3c\x2e\x74\x2a\x54\x36\x47\xe3\x80\xd1\xf5\xa2\x69\x68\x56\xce\x2f\x74\x70\x85\xe2\x01\x64\xa9\x28\xaa\x34\x52\x0b\x0a\x59\xd7\xc9\x8b\x5a\xb4\xe9\x54\x51\x38\x65\xed\x9c\x16\x02\xd6\xa1\xdd\x55\xfa\xc9\x4b\xf9\x79\x6b\x93\xb4\xea\x56\xae\x68\x55\xfb\x00\xc9\x1f\x77\x99\x5a\xdf\xe8\xf8\xb3\x79\x7f\x63\xc2\xda\x9d\xb6\x7b\xcd\xa2\x5e\x53\xd9\xea\x19\x40\xdd\x4b\x6e\xd3\x48\xd5\x3c\x72\x71\xf1\xaa\x90\xd5\x09\xa9\x5a\xc9\xd7\x1a\x12\x28\x73\xa0\x75\xaa\x51\xef\xe7\x55\x0a\x3b\x0c\xa8\xa6\x97\x91\x8f\x9a\x70\xa8\x9e\x52\x29\xd1\x78\x6f\x5e\x65\x56\xaa\x70\xc6\x48\xd7\xe3\x9a\x0e\x7f\x45\x8d\x8d\xf0\x28\x2b\x6e\xe8\x75\x43\x85\xed\x0d\xa4\xe9\x9a\x28\x3e\x9a\x99\x40\x51\xb9\x9b\x6c\x1d\x69\x6f\xb9\xad\xc8\x96\x65\x71\xc4\x6e\x57\x8d\x3d\x2c\x1b\x40\xa9\x57\x0b\xfd\x3b\x96\x52\x4c\x6e\x7f\x14\xc5\xd5\x42\xae\xc3\xf1\xcc\xbf\x78\x12\x66\xb0\x25\x83\x54\xe7\xb1\xa3\x8a\x42\x5a\x31\x2c\x4c\xc5\xa9\xd5\xf3\x65\x43\x92\x60\x61\x59\x21\x96\x19\x63\x52\x34\x68\xcc\x16\x5a\xd9\xea\x36\x24\x70\x7c\xaa\xdb\x66\xab\x80\x6f\xad\x85\xec\x1c\x4e\xdf\xa2\xb4\x36\x89\x81\xd1\x7f\x88\xe3\x7c\x38\x93\x08\x18\x23\x4a\x8d\x53\x3d\x21\xca\x3c\xa3\x92\x54\x99\x0d\x93\x61\x24\xad\xec\x9e\xda\x89\x5b\xd5\x92\x59\x50\x4d\xb6\x97\x19\x55\x86\x70\x32\x80\xde\xde\x06\x92\x27\xcc\xf6\xfc\x3d\x04\x6e\xa9\x75\x8a\x98\x49\x69\x9d\xc6\x52\xd5\xf4\x24\x58\xf3\xd7\xe6\xc0\x1f\x20\x38\xad\xa9\xa9\xab\x6e\xc1\x6a\x47\xb5\xd6\x95\xdd\xa1\x00\xc6\xce\x97\x48\x40\x60\x73\x13\xc9\xe0\x1a\xfe\xd2\x80\x44\xe5\x13\x35\x0e\x99\x32\x7f\xc3\xe9\x05\x50\x6c\xd9\xe9\x3d\x4a\x82\xc1\x38\xcb\xb1\xae\x26\x99\x2b\xb1\xfa\xb6\x9d\xe6\x43\x70\xa3\xf5\x0c\x7c\x1d\x13\xb6\x49\x03\x4d\x86\x9a\x1c\xd1\xaf\x4f\xd2\xcd\xd7\xf1\xd0\xcf\x27\x53\xc1\xd6\xf2\x38\x9b\x07\xc3\x70\x1c\x06\xa3\x35\xd5\xd5\x35\x6a\xb1\x77\xd3\x5d\x90\x31\x85\xdd\x8b\x83\xe0\x88\xf9\x40\x2f\x6b\x5e\x67\x0b\x67\x20\xc5\x88\xec\x3c\x24\x1e\x5c\xf7\xc8\xe8\x05\x0c\x81\x10\x5e\xdb\xf2\x2c\x43\x0e\xb7\x7f\x92\x06\xfe\x69\x9f\x52\x6e\xd9\x29\xcc\x1e\x50\x25\xdb\xed\x95\xd9\xac\x8f\x5b\xa6\x8c\x02\x36\x0f\x15\x03\x12\x5e\xef\x14\xcb\x88\xd1\x25\x2d\x6a\x27\x41\x16\x3f\xe7\x5b\xfd\x64\x3b\xef\xe7\xdd\xae\x9b\x1d\xe4\xeb\x5b\x47\xd6\xdc\xe6\x47\xfd\xd8\xd6\x35\xcf\x94\x85\x0d\xb2\x7d\x38\xf4\xab\x3f\x56\x2b\x58\xcf\x90\xc7\x0a\x57\x21\xe7\x39\xd4\x75\xe5\x7c\xd3\x14\x1d\x42\xde\x5a\x7f\x0c\xeb\x59\x01\x5f\x7f\x34\xd2\xf0\xcd\x97\x15\xbc\x12\xb2\x4e\x4e\x81\xea\x5d\xde\x44\x91\x2a\x66\xed\x25\x83\xa6\xdc\xaf\x81\xfa\x0a\xe8\xc2\x34\xe8\x7e\x28\x52\x1e\x37\x16\x6c\xd5\x32\x1e\xb5\x07\xd1\x06\x51\x37\xec\x0e\xca\xb0\x27\xaa\xf5\x01\x10\x0e\xaa\x5b\x06\x62\xa0\x40\x35\x42\xe9\x5d\xb8\x5e\x2d\x9e\x1f\xd4\x01\x5a\x1c\x2d\xe5\x11\x6c\xb9\x81\xda\x86\xc4\x26\xce\xfd\x34\x0e\x46\x7a\x3a\x01\x04\x9c\x65\xc4\x82\xd6\x0c\x0d\xb8\xcf\x5b\xce\xc9\x92\x4e\x27\xd9\xde\x54\x53\x64\x35\xa3\xac\x08\x12\x14\x52\x35\xf6\x00\x48\x1b\xa6\x6d\x69\x03\xb9\x82\x4e\x9c\x8c\x02\x77\x0d\xd3\xf1\xfe\x1f\x51\x61\x16\x9e\x44\xc1\x9a\x8d\xd4\xd7\x66\x70\xb8\xa6\x97\x6b\x11\xec\x99\xb5\x51\x20\xe0\xdc\x08\x46\xbd\xb5\xdf\x8c\xd6\xf4\xdc\x67\x6b\x00\x44\x18\xf7\x1a\x00\x3e\x90\xa5\xea\x78\xda\x71\xd7\x44\x02\xc8\x07\x35\x40\x20\x57\x14\x42\xb6\x5e\xbb\xbe\x64\x1a\x21\xb0\x86\x03\x4f\xf7\x1d\x39\x1b\xc0\x92\x95\x4f\xc7\xad\x68\xfe\x56\x21\x3c\x89\xf9\x0a\x80\xaf\x65\x1b\x06\xfc\x4b\x67\xbc\x24\x34\x74\x79\xb4\x7f\x85\x1d\x08\xb0\x9d\xe0\xec\x8a\x66\x63\x13\x42\x91\x7f\xd0\x1e\x22\x90\xe1\x80\x40\x8d\xc9\x99\xce\xaf\x94\xeb\x7b\xd4\xd3\xd8\x6d\x38\x96\xaa\x3d\x6d\xd8\xda\x78\x40\xf9\x2c\xfb\x8b\x6c\xf0\x56\x75\x87\xd7\x41\xdf\xb5\x96\xa4\xdf\x7c\x4c\x18\x3b\x4b\xc0\x63\xeb\x5b\x0c\xad\xf2\x44\x51\xc0\x61\x51\x6e\x72\x92\xab\xe9\x61\xa0\x48\x4e\x19\xdf\x2c\xed\x50\x1b\x9b\x54\x47\x5f\x41\x28\xd5\x24\x52\x59\x2e\x05\xb1\x25\xae\xce\xb8\xdf\xcf\xd6\xd7\xb7\x37\xfb\x68\xfe\x12\x1f\x64\x47\xb2\x6f\x18\x32\xfd\x81\xbe\xd9\x9f\x52\x62\x98\xf0\x4c\x9e\x30\xb8\xee\x9b\x46\xe6\x27\xa7\x01\xf5\xf3\xf5\x98\x07\x8e\x0e\xf1\x4d\xd6\x3c\x2a\x17\x8e\x34\xa5\xde\x9e\xb0\x2d\xf7\x2f\x34\xc8\xd5\x3b\x44\xe6\xbe\x1b\x45\xcd\x64\x95\x22\x68\x96\x56\xbc\xbe\xbe\xad\x6b\x7a\xa7\xf3\x22\x09\x59\x3f\x04\x07\xb5\x93\xa1\x8e\x69\xd1\x5a\x7a\xe5\x92\xf7\x95\xd5\xeb\x32\x51\x81\xab\x28\xc8\x84\xcd\xee\x73\x7d\x6a\xa4\xa4\xcd\xda\xdc\xf6\x34\x58\x26\x9b\xab\x72\xd4\xeb\xab\xae\x11\x57\xe4\x7f\x33\x95\x44\x44\xd1\x2a\xbc\x22\x61\x12\x07\xd1\x37\xc6\xc8\xab\x32\x1f\xc4\x86\x97\x29\xed\xf1\xae\x99\xb4\xea\xf2\x47\xab\x57\xdd\xd2\xf4\xb7\xaa\x59\x3a\x7d\x06\xe9\xf2\x51\x5b\x3f\x42\x97\x0e\x50\x4d\xc2\x78\x07\x47\xd8\x1f\xdd\x8b\xfb\x49\x1e\x8b\x26\x7c\x65\xb0\x20\x0f\xca\x8e\x98\xe0\x81\xc0\x5e\xd8\x9f\xee\x60\xcb\xb3\xbf\xd5\x14\x79\x9b\x0b\xc9\xd2\xfd\xf6\x5a\x96\x6e\xa1\xcd\x16\x35\xb3\x73\xb5\xe8\xa7\x40\xa5\x5c\x88\x57\xe1\xf0\x94\x2f\x71\xf1\xed\x3c\x96\x86\xfc\x23\x00\x29\x75\x64\x9d\x2b\xcd\x76\xf9\x8b\x47\xe2\xee\x6c\x16\x8c\x42\x34\x17\x15\x5f\x53\xe2\x69\x2e\x48\x35\x69\xff\x44\x7a\x79\x00\x04\xf9\x15\xa5\x50\x5f\xe3\xa9\xf4\x8c\x61\xe2\xe0\xd4\xa3\x43\x5d\x43\x0d\x6e\x9b\x40\x6f\xca\x06\xde\xbb\xa1\xcb\x28\x07\x50\x86\xce\x07\x47\x44\xdf\x29\xa2\x86\x1b\xf7\x0f\x55\xef\x10\xed\x51\x78\x86\x77\x62\x44\xe2\xd6\x87\xe2\x2c\xcd\x60\xaa\x01\xa2\x9f\x96\x68\x31\xe8\xc1\x0e\x78\xe8\x03\xd7\x60\x77\x32\x40\x4f\x08\xa5\x9d\x42\xd8\x4b\x64\xad\xe8\xdf\x02\xed\x24\xc2\x93\x5c\x04\xa8\xb9\x07\x54\x66\x65\x70\xe6\x42\x26\xd1\x36\x5c\x94\xd5\x69\x5f\x06\x59\x9b\xb5\xe3\xa4\x6d\x2c\x05\x51\x4e\xac\x21\x6e\xe0\xac\x98\x46\xa7\xad\x5c\x90\xb4\x97\x7c\xe3\xe0\x2d\x80\xbc\x91\xc6\xb9\x02\x46\x8c\x73\x59\x09\x9c\x21\x64\xe4\xc9\xf1\x46\xb1\xad\xee\x4b\xd7\x05\x40\x95\x14\x4f\x8c\x7c\xe1\xa3\x40\xa2\x97\x89\x04\xa5\x25\x73\x7f\xe2\xcb\x89\x62\xba\xff\xdb\x9b\xae\xbe\x99\x4a\x8d\xf1\x17\x64\x00\xc8\x46\x01\x56\x75\xc8\x6a\x34\x6c\x19\x3a\x9c\x6a\xeb\xac\xfd\x4d\x1b\x3d\x4c\xd8\xc5\xd1\xbc\x30\x9c\x05\x49\x8e\x97\x2b\x9b\xd0\x00\xf5\x42\x84\x22\x02\x90\x3f\x01\x82\x21\xc3\xe3\x25\xed\xa9\x20\x92\x41\x69\x2f\x88\xcf\x10\xf1\xa5\x3d\x40\xca\x67\xa4\x6e\x4d\x44\x18\x46\x58\xdc\x46\x4c\xd1\x40\x74\x51\x60\x3c\xa6\xdf\x1a\xd9\x52\x46\x55\x4e\x27\x8c\x26\xbe\x1b\x03\x27\x30\x2e\x20\x5f\x79\xdd\xce\xd9\x36\x33\x55\xe3\xd4\x79\xd7\xc2\x6c\x0d\xdd\x26\x29\xfd\x35\xd8\x4b\x28\x44\xea\x0d\xcf\x47\x7c\x59\x74\xb9\xd1\xa6\xb4\xe9\x28\x4c\xbf\xaa\x0d\xca\xd9\xd4\x82\x44\x3b\xdf\x2e\xbb\x0d\xa9\xc0\xb6\xbd\x31\x6c\x59\x90\xb2\xa5\x0d\x5a\xf6\xb5\x24\x02\x0c\x5a\x10\x20\x34\xd1\x96\xde\x06\x12\xa5\x15\x17\x85\x85\x26\x6c\x21\x8f\x39\x87\x89\x29\x17\x28\x25\x69\xa5\xcd\xb9\xe1\x54\xd4\x2e\x13\xd6\xb7\xf4\x4e\xd8\xac\x48\x9d\x64\xef\xb1\xa2\x96\x65\x1a\x3c\x93\xc7\x97\xd6\xb7\x4f\xb9\x03\xfd\xd9\x74\x81\xbc\x4b\x4a\xd3\xe2\x6e\x37\xbd\x93\xf4\xa5\x65\x71\x5a\xb1\x2c\x4e\x4b\xcb\x62\x5b\x74\xc5\xac\xbb\x58\x55\x07\xb6\x80\x7b\x2c\xc5\xbb\xab\x7e\xbc\xbe\xde\x77\xc9\x4c\x19\xff\xf4\xce\xfc\x28\x0f\x4a\xd3\xf4\x26\xa1\xd6\x92\x8b\x88\x60\x10\x78\x72\x6f\x06\x83\x76\xdb\x0b\xba\xed\x76\x59\x30\xab\x48\x26\x51\x86\x78\x1f\xb8\xa7\xbb\xc2\x81\x5d\x61\x32\xe5\x35\x0b\x7a\x24\x6a\x53\x7b\xd4\xf1\x1d\x24\xd4\xcc\x05\x9b\x11\x46\x02\x21\xb0\xbd\xbe\xd5\xb7\x4c\xaf\x4c\x9d\xc3\x7a\x9d\xa6\x3a\x18\xf2\xaf\xad\x2c\xaa\xdc\xce\xe1\xfc\x0d\xd3\x10\x55\x5b\x7d\xf2\x15\x24\x83\x6e\x51\xa8\x3b\xc0\x75\x55\x7b\x59\xc1\xbc\x61\x84\xb8\xae\xa6\x9a\x90\x97\x15\x01\x81\x9f\xd8\x63\xf7\xfb\xda\x8f\x4a\xea\x24\xb0\x4a\x2c\x24\x07\x02\x00\x05\x86\x98\xcc\x16\x55\x03\xf5\xe5\x1e\x8c\xad\x85\x78\x2c\xd0\x66\xd8\x24\x4d\xad\xa4\x37\xd5\xa4\x91\xb5\xee\x87\x87\xed\xee\xa7\x6a\xf2\x4c\x43\x73\x09\xb6\x41\xc9\x9a\xc4\x03\xe4\x4a\x3c\x47\x48\x40\xee\xc7\x83\x64\x7d\xdd\xeb\x76\x93\x3b\xa9\x1a\x51\x08\x50\x97\xd0\xa9\x18\xc2\x5e\x30\x7e\xdb\x92\xc5\x32\x30\x9f\xd9\x80\x04\x27\xc0\x92\x2c\x16\xf6\xa4\x95\x7d\x62\x65\xdf\xfa\x6e\x73\x1b\x45\x84\xc1\x36\xff\xa1\xd3\xd9\xba\x0d\x1f\x45\x71\xfb\x16\xc7\x1f\x48\xa3\xdf\x6f\xff\x54\x05\xbe\xdb\xfa\xf6\x7b\x0a\x40\xee\xef\xb7\x7e\xb8\x05\x67\xca\xf7\xb7\x36\x6f\x51\x99\xef\x6f\xa9\x52\x10\xb8\xad\x03\x3f\xa8\xc0\xf7\x7f\x2a\x2b\xbc\x75\xeb\x7b\x59\xc1\x77\xdf\xde\xfa\x53\x4c\xb4\x00\xfd\xf2\x5a\x40\x97\xdc\x1c\x19\x31\x11\xc8\xab\x8d\x49\xa4\xb6\x74\x25\xf0\x16\x96\x1e\xe6\xef\x88\x97\xd6\xc9\x61\x59\xfb\xc3\x5a\xed\x50\x75\x05\x7d\x40\xd5\xf0\xed\xcb\xfa\x09\x91\x28\xb0\x42\x64\xc2\x72\x2e\x06\xc2\xc9\x58\xca\x02\xd7\xcb\xfa\xc8\xa5\xa1\xbb\x1c\x60\xd3\x63\x9e\x33\x1f\xda\x0d\x8f\xb8\x11\x88\xad\xf9\x65\xbb\xf7\xab\x5e\x83\x88\x23\xb5\x36\xaf\xb8\x13\x77\x3a\x13\xa7\xb2\xfb\x05\xda\x64\x19\x32\xb9\xac\xea\xa4\x5a\x95\xa9\x45\xe0\x9e\xfd\xca\x3a\x2e\xac\xa5\x7f\x5b\x85\xd7\x17\x54\xbd\xfe\x12\x4a\xfa\x8d\xa0\xd5\xe9\xb4\x6e\x64\xf2\xd7\x09\x6c\x71\xef\x44\x4a\x84\x2b\x71\xc6\x29\x0e\x11\x29\x41\x26\xe5\xa7\x01\x6b\x1f\x1f\x43\xff\xc2\xf8\xf8\xb8\x0d\x15\x55\xe2\xcf\x53\x7f\x3e\x0f\x46\x98\xa2\x0b\xdf\xc5\xab\x8a\x85\xa5\x51\x88\x07\xd9\xc2\x22\xa7\xd5\xde\x92\x0c\x40\x59\x83\x92\xa7\x43\x94\x72\x15\x06\x51\x70\x56\x1c\x68\x66\x5e\xf7\x01\x0d\xdb\x6a\x1b\xe2\xab\xaa\x02\x54\xae\x63\xe1\x48\x86\x98\x2d\xf3\x09\x64\x15\x31\x1a\x10\xb9\xa9\x23\xc7\x61\x04\x58\x8b\x6a\x6b\x99\x9c\x88\xc8\x80\xa6\x0d\xea\x15\x0a\xff\x34\xd0\x35\xbc\xcc\x74\x2c\xa9\xc9\xab\x9c\x65\x8f\x6f\x54\xef\xfa\xac\x3e\x6a\x03\xeb\x4a\x3b\x4c\x73\x8a\xba\x3a\x26\x55\x09\x27\x4e\x7d\xd4\x96\xc7\x18\x7b\xe0\xc1\xe0\x06\xe9\x52\x50\x7f\x53\x33\x7a\x7b\x2a\x64\xb4\x35\x0b\xcb\x13\x43\x59\xac\x39\x59\x9a\x25\xca\x60\xcf\x8f\xc0\x76\x85\xd5\xae\x3d\x49\xcb\xf3\x46\x59\xcc\x8c\x61\xd9\x58\x97\x2d\xe7\x2e\x10\xd2\x16\x7c\xa9\x75\x3d\xa5\xe5\xcc\x00\xcb\x6c\xc6\x0a\x5b\x37\xa8\x2d\xe9\xa6\x94\xc8\x07\xda\x60\x38\x89\x51\x7e\x6e\x8a\x7c\x03\x65\x1a\xe8\x85\x58\xd4\x17\xcf\xcc\xbe\xa4\x31\xa4\xaf\x28\xb9\xe7\xf4\x86\x78\x1e\x3b\xcb\xf0\xe8\xf6\x2d\x7b\x65\xbd\x0c\x31\xdf\xdc\x16\xb0\xbe\x97\xa8\x50\x68\xd0\x5b\x75\xf9\xa5\x0f\x29\x34\xd0\x10\x64\x78\x18\xc4\x23\xc0\x7d\xe1\x7a\xc2\xb2\xa6\x65\xcb\xf9\x71\xe6\xf8\x0d\x70\x8a\xae\xca\xe2\x41\xe8\x25\x30\x39\x51\x13\xdc\xcd\x79\x34\x88\x0c\x9b\xcc\xc6\xb0\x35\xa6\x88\x63\x03\xba\x23\xe9\xfb\x88\xba\xf2\xed\x31\x60\xdb\x61\x17\xe8\x4d\x8d\xdd\x46\x38\xdb\x33\xc0\xbd\x43\x44\xc7\xa3\x3b\x73\x85\x8e\xcf\x78\x74\x30\x3a\x62\x13\x7e\xd6\xd3\xad\xb0\x4b\x3e\x71\x66\x6c\x08\x98\x99\x3d\x84\x78\x3c\xf2\x70\xfa\x1e\x72\x7e\xcf\x9d\xf1\x4b\x23\x88\x6b\x5d\xd2\xaa\x43\xfc\x8e\x8b\x26\x46\x61\x9c\xc3\xd2\x49\xb9\x1a\x2c\xcf\x22\x1b\x64\x70\x02\x4f\x0f\xc6\xdd\xee\x11\x9f\x69\xdc\x33\x2d\xd7\xed\xb1\x30\xf7\xb2\xc7\xc8\x51\x01\x04\x5c\x2d\xca\xe4\x37\xa2\xee\x5b\x61\xea\x4b\xac\x59\x11\x9b\xa8\xa2\x15\xd4\xfb\xd6\x2a\x0a\xf8\x90\xe4\x28\x80\x0d\x91\x68\x3c\xf6\x56\x17\xfb\xdc\x5c\xac\x45\xe7\x79\x56\x5e\x5c\x99\xd2\xcc\xc6\xa1\x9f\x84\x4d\xb8\xd5\xcb\x3b\xf5\x66\xb9\xf6\x81\x62\x2a\x78\x2f\x2c\xc6\x74\x10\x98\x55\xa6\x55\xa4\xe2\x58\x98\x5f\x4d\xf1\xee\xfc\x7e\xe6\x48\xc7\x8e\xc0\xfe\x79\xb8\xc1\xa6\xd9\x02\x4f\x2e\x25\x80\x92\x1c\x25\x8a\x58\xca\xfa\x1f\x89\x2a\x8d\x8e\xb5\x01\x5c\x2f\xd1\xd8\x40\x42\xed\x87\x80\x24\x06\x31\x72\xe0\x34\xeb\x88\x31\x30\x30\x85\x1a\x0d\x42\x1b\x6c\x7a\x36\xd1\xf4\x5c\xd4\x0c\xfe\xb1\xfe\xfe\x32\x05\x4f\xb5\x07\x78\x33\x84\xb5\x03\xbb\x89\x78\x50\xc8\xda\x61\x5a\x5a\x16\x03\x73\xa3\xd2\xe3\x2a\xa1\x4e\x93\x42\xee\xc2\x76\x7c\x27\x85\xe3\x59\x91\x31\x42\xf3\x17\x0d\xa7\xf5\x07\xf1\x75\xc4\x3f\x11\x40\x2c\x86\xe5\x6d\xa1\x0f\xba\xbe\xdb\x80\x75\x7e\x5c\xaa\xab\x46\xf4\x7f\x4d\x25\x41\xdd\x9f\x57\x53\x87\x88\x07\x6b\x59\xf5\x95\xd7\xb6\xe6\xc2\xb0\xa4\x33\xae\xaf\x71\x99\xec\x53\x36\xd1\x34\x63\x02\xfd\xb6\x30\xdc\x62\x8e\xa2\xfd\x7c\xcb\x86\xbb\x44\xb8\x5f\x6c\x83\x96\x44\xb7\x90\x90\x1f\xb2\xb2\xfb\xa5\x0f\xe0\x92\x79\x8e\xaf\x21\xeb\xa0\xea\x67\x99\xa4\xed\xfa\x5a\x9e\x85\xa0\xdd\x4f\xb6\x51\x27\x3b\xe5\x89\xe9\xa4\x75\x2a\xd5\xfd\x4b\xd6\xab\x7c\xd9\x58\x65\x4a\xd7\x73\x2b\xaa\xf4\x15\x99\xc4\x52\x5d\x86\xe6\xb2\x02\x92\xd0\xa3\x90\xac\xe5\x03\x9a\x40\x9c\x84\xe4\x4e\xd8\x77\x81\x60\x70\x60\xf0\x68\x79\x9e\x58\x73\x60\xf1\x7d\xd9\x52\xed\xf5\x8a\x13\x55\xf1\xfa\x3a\x56\x9c\xe0\x66\xff\x72\xb5\xf9\x57\x83\x58\x03\x84\x6d\xf6\x8d\x12\x74\xc9\xec\x56\xd4\x47\x1b\xa5\x18\x03\xe1\x59\x40\x1e\x59\x03\x5b\x2a\xd4\xb2\x44\x1f\x1a\xc7\xa6\x40\x89\x02\x9f\x6f\x6d\xdc\x79\xcd\x04\x23\xc8\x51\x9e\x40\x4e\xbd\xf5\x81\x3e\x45\xcb\x05\xf4\xe9\x6a\x0e\x3d\xb5\x3c\x69\x39\x52\x5a\x89\xaa\x13\x80\xe0\xc0\x47\x76\x24\x06\x66\x04\x1d\x65\x33\x5f\xde\x36\x39\x39\xf2\x23\x03\xfc\x9b\x79\x19\x6c\xe0\x0c\x37\x45\x53\xbf\xb3\xa2\xf0\xa5\x33\x1b\xd4\x64\x43\x37\xdd\xb9\xbb\x58\xde\xe9\xe3\x2f\xee\x99\x73\x58\x63\x97\x78\x73\x15\xe5\xe3\x36\x0a\xe5\x36\x0a\x0d\xff\x84\xf8\xad\x9f\x0c\x9c\x8c\x93\x4b\x85\x9d\x28\xf1\x81\x93\x72\x81\x69\x82\x5d\xf6\x22\x45\xa6\x0a\x26\xef\x20\x3b\xf2\x8e\x5d\xcf\x97\xc8\x30\x3b\x6a\xe0\xa4\xa6\x66\x4e\x63\xe2\xbb\x04\x50\xba\x57\x0b\x5b\x2a\x44\x0c\x5d\x5c\x93\x07\x29\x5e\x3a\x06\x36\xae\x2f\x0e\x42\xac\x3e\x34\xd5\x5b\x4b\x36\x6a\x1e\xb0\xa8\xc1\x9d\x02\x75\x1a\x15\x82\x31\x9f\x03\xa7\x82\x4b\xf3\x94\x05\x4d\xf3\x38\xab\x1b\xe3\x28\xe8\xe9\x2f\xab\x61\xa5\x83\xa6\xf5\x02\xfe\xf6\x02\x99\xa1\xc1\x07\x5d\x93\x57\x8a\x94\xf6\x7d\xcb\x79\x6f\x3a\x78\x8d\x38\xc4\x6b\x14\xbd\x0d\x1e\x43\x5a\xb7\xdd\x76\xbd\x8f\x32\x80\xd7\x77\xa5\x00\xc1\x80\xbc\x34\xa4\x51\x8b\xa7\x2c\x66\x60\xed\x92\x01\x39\x20\x66\x09\x1c\xac\xa4\xdc\xd7\x08\x5a\x46\xe2\x42\xa0\x4e\xc7\x66\xc9\x0d\x4a\x57\x5b\x44\xd4\x62\x72\x4e\xd4\x58\xc6\x1f\xe2\xe0\x58\xcb\x08\xeb\xe8\x0c\x55\xba\x2e\x57\xca\x39\xbd\x66\x16\xd1\x7c\x65\xc8\xf9\x73\x2c\x3f\x6c\xf1\x0f\x9d\x0e\xfc\xfd\x8c\xfa\x4d\x51\x51\x24\xa6\xad\x1d\x01\x74\xe3\xe0\x04\x25\x9c\x43\x18\xa6\x97\xc0\xe6\xbc\x5a\x90\x4c\x88\xdf\x4f\x9d\x68\x70\xb5\xf0\x2a\x6d\x12\x68\x65\x0c\x76\x69\x80\x77\xeb\x00\x5e\x78\xe2\x00\x8c\x42\x08\x45\x02\x25\x90\xcd\x79\xa8\x01\x62\x8e\xf8\x0c\xa5\x33\x07\xf3\x23\x94\x64\x68\x88\x85\xcf\xf2\x16\x41\x4b\xca\x95\xe3\x34\x80\x7b\x27\x1f\x7c\x10\xde\xb3\xd8\x85\x26\x8d\x5c\x16\x27\xf6\x2a\x43\x70\x3a\xc3\x0f\xa9\xeb\x15\xd0\x4a\x2c\x80\x64\xb2\x38\x55\x0b\x37\xa1\x4d\x89\x01\x9f\x12\x2f\x59\x1e\x11\x1f\xf9\xce\x9b\xf2\xf2\x2e\xb3\xe5\xc0\x81\xd2\x2c\x38\x66\x9f\xd0\xc1\x5d\x8a\x4a\xf9\x36\x44\x5c\x56\x7c\x32\xd9\xe4\x1d\xd3\x97\x35\x25\x2e\x53\x2e\x36\xa5\x04\x65\x82\x2e\x6a\x33\xee\x73\x9e\xa0\x5b\x63\x14\x27\xaa\x2b\x06\x7e\x6b\x73\xb3\xd3\xb9\x87\xe4\x19\xf0\x0d\x66\x67\xe5\xb0\x80\x3e\x7f\x24\xa0\x10\x32\xc9\x80\x8f\x34\x7b\xd0\xed\x86\xe6\xc0\x8b\x68\xe3\xd2\x22\x76\x3a\x78\xd7\x11\x95\x7b\x75\xce\x87\x66\x39\x04\x2d\x07\xa4\x5a\x34\x7e\x5a\xf5\x51\xec\x03\xe6\x8d\xdc\x3b\x9b\x68\x4e\xa3\x13\x96\x4f\xcf\x87\x2b\x67\x80\x06\x7f\x9e\x96\x0a\x69\x6b\xcf\x64\xde\x3a\x2e\x3a\x45\xd8\x26\x44\x14\x23\x81\x95\xa0\x28\x09\x97\x7a\x35\x81\x75\xff\x57\x34\xfa\x72\xa9\x51\xd9\x9e\x22\xe7\x52\x79\x38\xa6\xd7\xb4\x76\x52\x69\xcd\x9c\x9e\x72\xe8\xd6\x95\x02\x81\xa7\xb9\x2b\x6d\x21\x6d\x47\x71\x0b\x74\xa7\x55\xca\x96\xae\x27\x08\x4a\x4f\xa4\x9b\x5e\x17\xe5\xf7\x6c\x73\x5b\xba\x5e\x5e\x8f\xb7\x13\x88\x4c\xd0\xff\x68\xca\x9b\xd0\x57\x5a\x14\x40\xe9\x0c\x12\xaf\x9b\xca\x82\x44\x48\x75\x81\xec\x41\x8c\xbf\x8d\xa4\x7d\xba\xbd\xbd\xbd\xc9\x62\xf8\x4b\x3a\x6b\x31\x09\x08\x91\x95\x13\x0d\x03\x7f\x51\x19\xf8\xc1\xd1\xb5\x03\xd7\xa3\x35\x5e\x75\x82\xda\xc0\x8f\xeb\x03\x37\x64\x4d\xb5\xb6\x98\x85\x25\x83\xa8\xbe\x07\x0e\x70\xe2\xf8\xba\x05\x6b\x6d\xb9\xca\xed\x38\xd4\x6e\xd1\x9a\xe7\x56\xed\x25\xa9\xe0\xa4\xea\x06\xa4\xa4\xe7\x60\xef\xc1\x77\x26\x69\xe5\x92\x74\xc8\x8d\x1c\xf9\x0c\x90\x6e\xa7\x03\x30\x94\x6b\x8d\x06\x98\x45\x40\xc8\x39\x90\x02\xf7\x43\xf8\x71\x61\xb0\x10\x95\x73\x68\x33\xa7\xb3\x46\xbf\x0f\x42\xfc\x7d\x6e\x2f\xa7\xd6\x8a\xe8\xf2\x08\x9a\x1b\xde\x89\xfa\x6e\x06\x24\x24\xd2\x13\x80\x7d\xe5\x46\xc3\x83\x5a\x47\x9a\x2d\x66\x61\xb3\xa7\xf1\xb2\x8c\xbc\xdc\x38\x78\xcd\x4b\xb8\xb3\xc4\xb9\xb8\x95\x4a\x89\x7f\x88\x67\x3a\x11\x82\x09\x90\x0c\x80\xc0\x13\x57\xfa\xe0\x96\xba\x32\xcb\xcb\xfe\xaa\xa1\x3d\xd9\x54\x22\x9b\x0a\xcb\xcb\x85\x10\xf1\x89\xa2\xbd\x12\x85\x79\x04\x3d\x0a\x02\x34\x57\xfa\x85\x86\xf6\xab\x26\x4b\x6a\x9c\xef\x42\x0b\xc1\x3e\x6b\xcc\x12\xe4\x56\x96\x97\xd5\x2c\xaf\x1a\xb2\xec\x5d\x4f\xb5\xac\x64\x9f\x88\x7e\x79\x15\x12\x01\xf8\x25\xf6\xe9\x41\x8d\x84\xa1\x15\x6a\x50\xa7\x43\x51\x52\xe5\xa0\xf0\x91\x46\x04\x10\x27\xb2\xd0\x5b\xb9\xcb\x34\x89\x96\x00\x19\x2e\x55\xc6\x91\xb6\x46\xee\x06\x05\xeb\xe9\x11\x0f\x07\xa1\x3a\xad\xf0\x1a\xd0\x3b\x86\xfd\x61\xd1\x85\xbb\x15\xda\x45\x0a\xa4\xed\xdb\xbf\xcd\x96\xbc\x7b\xd8\x80\xd8\xad\x0d\xa1\xfc\x34\xeb\xd3\x12\x05\x5e\xaa\xfb\x4b\x24\x59\x8b\xfb\xe5\x65\x8a\xfc\xb0\xd2\x32\x3b\x2d\xd3\x57\xf0\x81\x0e\x88\x01\xde\xab\xa2\x11\x19\xde\x64\x7a\xa7\xb2\x97\xbb\xb1\xe9\x68\x39\x82\xd3\x66\xea\x4b\xd2\x4a\x8c\x68\x26\x3a\x31\x3f\xc1\x1e\xfc\xd4\x47\xc5\xd7\x0a\x4d\x04\x14\xd1\xe7\xc1\x90\x7f\xf0\x24\x49\x04\x44\xce\x13\xa2\xbc\xa0\x28\x64\x8d\x4c\x56\x81\xe4\x13\x64\x8d\x20\x6b\x24\xb3\xe6\x98\x55\xb8\x6a\x9b\xcf\x91\xb8\xfa\x80\xcf\xb7\xe0\xcf\x14\xbf\xc8\x96\x79\xda\xe9\xe0\x73\x42\xad\xb9\xa1\x97\xe8\xf2\x98\x0d\x65\xb1\x11\x9f\xaf\x16\xe8\xb3\x19\x1f\x5b\xd2\xa8\x5a\x2a\xd6\x3e\x2a\x8a\x99\xb1\x9e\x76\x46\x00\x40\x4a\x08\x0a\x38\x71\x36\x10\xe6\x4b\x98\xe9\xa1\xa3\x70\x6a\x29\x83\x5f\x43\xb0\x9d\x95\xc8\xe3\xcc\x10\x6c\x67\x55\x82\x0d\x3f\x45\x7f\x89\x58\x13\x72\x78\x13\xee\x64\x83\x71\xea\x8d\x52\xb7\xb6\x4c\x16\x99\x97\xcc\x1d\x2a\x47\xbf\x93\x72\x69\xef\x5a\x4b\xab\xe1\xdc\x10\x3e\x48\x5d\x4b\xa0\xd1\x63\x09\x4d\xbf\x15\x2e\x6f\x25\xb0\x71\x7d\xc4\xe5\x92\xf0\x41\xfc\x33\xc0\x97\x8e\x10\xb6\x0e\x90\x03\x3c\xf2\x5a\xe5\xdc\xd3\x43\x51\xe5\xc4\x60\x65\x58\x91\xae\x43\x9d\x07\x98\xab\x5f\xd6\xe7\x4a\x14\x5f\xd6\x92\x2b\x7b\x6f\x4d\x76\xe5\x47\x6c\x4e\x2f\x3a\xf5\x87\xb0\x49\x13\x27\x62\x73\xc8\xe3\x1d\xb3\xa6\xa3\x1a\x3d\x02\x0e\x39\x6c\xca\x39\x8b\x60\x9e\x5a\x9b\x4a\x5b\x75\x68\xba\xb5\x58\x96\x02\x3d\xf9\x35\xe7\xb1\xf6\x6d\xa7\xbe\x6b\x87\xf1\x6b\x5b\x5d\x06\x09\x7a\x7a\x94\xa3\x9c\xf1\x2d\xa0\x40\x0c\x33\x86\x1e\x0f\x13\xba\xe2\xc3\xa4\xa7\xa9\x53\x32\x11\x0d\x1a\x4c\x06\x39\x25\xa8\x24\x01\x85\x6c\xb0\x4f\xdd\x85\xf5\xea\xd4\x0e\x9a\x2b\x48\x8e\x38\x56\x8a\x04\x24\xb1\x01\xb4\x2b\xaf\xa8\x81\x38\x26\x66\x97\xda\xec\xaf\x6e\x53\x01\x10\x71\x02\xe5\x20\x3f\xd6\x0e\x0f\xd4\xb6\x1d\x98\xd2\x71\xad\xc7\x68\x48\x8e\xa2\x4a\x34\xf8\xf5\xae\xcb\xb5\x4b\xde\x14\x50\xa5\x8f\xee\x4c\x5a\x9b\x76\x9b\x3b\x0d\xa0\x7c\x4e\xca\xf3\x36\x2d\x81\x26\xbf\x12\xa7\xa8\x41\x39\xa1\xe6\x77\x44\xb9\x92\x82\xe9\x57\xce\xce\x30\xab\x26\xbe\x61\xf7\xa6\xb4\x8f\xa5\x02\x34\x86\xee\x49\xd6\xcc\x67\x3b\x0a\x73\xba\x7d\x4d\xd4\xf8\x47\x74\xfb\x20\x49\x15\x94\x83\x64\x08\x93\x51\x23\x01\x39\x24\x9f\x90\x43\x14\x62\xb7\x42\x40\xdc\x4d\x59\x8a\xa2\x25\x33\x71\x3e\x1c\xe0\xdf\xdc\xcb\xd1\x21\xb4\x11\x94\x0c\x5d\xb2\xdf\x32\x33\x72\x6f\x09\x6f\x6b\x00\xc8\x0c\xd6\xc1\xab\x63\x3c\x6b\x33\x83\x7c\x50\xed\xd7\xbc\xcc\x86\x04\x9f\xbc\xbe\xf6\x21\x41\x53\x5b\x24\xd7\x8a\x68\xaf\x0d\x59\x8e\x12\x2e\x64\x63\xf1\x36\xa5\xa9\xe3\x51\x1f\xf0\x2f\xe0\xf9\x9c\x35\x93\x76\x4f\x88\xb4\x03\xb4\x7f\x03\x9d\x71\x0e\x86\xde\x10\x2f\xc6\x86\x78\x22\x7b\x1f\x2c\xea\x0f\x72\xc0\x2f\xe4\xd8\xc1\xbf\x98\x44\xb9\x81\x59\x9e\x23\xad\xa3\x5d\x76\xe6\x06\x41\x46\x2e\x9b\x0f\xa8\xf3\xc0\x54\x43\x3f\xe5\x24\x78\x0e\x71\x67\x03\x34\xfd\x82\xb6\x70\x36\xcd\xeb\x0e\x91\x75\xea\x3d\xb6\xc1\xbc\x84\x8c\x0a\x54\xe2\x31\x7a\xec\xd1\x3d\xb5\x75\xd1\x52\xf5\x17\x5f\x92\x3a\x63\x8b\x21\x12\x52\x8b\x27\x55\x9b\x4f\xc1\xab\x25\x82\x12\x5a\x4f\x24\xa4\x93\xfd\x05\x52\x2a\x9a\x3a\x0a\xfb\x33\xb3\xaf\x43\xf4\x01\xbe\x58\x16\x01\xbf\xad\x59\xa5\x77\x87\x99\xb3\x9f\x39\xee\x37\x8e\x58\x0f\xba\xe8\xd7\xa2\xbc\xa7\xa9\xec\x1c\x5d\x55\x15\xb3\x11\xe9\x12\x03\x2b\x00\x3b\x00\xb8\x60\xbc\x62\x40\x41\xa9\xa4\x14\x2a\x08\xee\x53\x13\x39\x56\x2a\x03\x70\x3d\x6f\xc0\x65\x09\xc9\x2c\x09\x72\x33\xb2\x2e\x14\x97\x25\xdc\xaa\xd2\x67\xf9\x9e\x0d\xd0\x2e\x92\xcb\xb2\xd9\x33\xc5\x65\x89\x6d\x64\xdc\x62\xa8\x05\xf9\x2c\x21\xf9\xac\x0a\xc2\x4b\x5c\xa3\x83\x85\x0a\x58\x80\x20\xbb\xe5\xed\x8b\x45\x4f\xfe\xd4\xa4\x82\x7b\x3d\xcb\xa9\x71\x3d\x6b\xc5\x30\x19\xad\x96\x35\x1d\xef\xe3\xa5\x3b\x17\x92\x40\x54\xf8\xa2\x14\x85\x11\x19\xae\x73\x48\x52\x08\x29\x98\xb8\x97\xd1\x5b\x4b\x70\xdc\xe4\x38\xed\x8f\x00\x8b\x20\xa0\x7b\x0e\x09\x22\x50\xe7\x03\x76\xc8\xd0\x92\x46\x94\x72\xcd\x48\xee\xd1\x39\xe9\x85\x44\x24\x83\xf6\x88\x56\xf2\x97\x84\x13\x63\x8b\x6f\x52\x48\x20\x3f\x18\x23\x36\x9e\xdb\x32\x0a\x58\xa4\x5c\x6e\xab\x39\x74\xaa\x2a\xb0\x80\x6d\xcd\xe6\x24\xb0\x70\xf0\x0e\x09\x65\xbb\x0d\x79\x0d\xed\x3e\xb4\xee\xd0\xbe\xc8\x1f\x2c\x5f\x7d\xa8\x63\xaa\xe1\xda\xe3\x79\x55\x3a\xd1\xaf\x3c\x67\x34\x91\xaf\x8d\x68\x7a\x6d\x49\x18\x22\x9a\x05\xb3\x38\x8d\xc8\x8f\xc0\x11\x3c\xcf\x8c\x33\x5e\x1f\x15\x3d\x33\x04\x54\xbf\x87\xcd\xab\x04\xbf\x87\x37\x75\x77\xd3\x09\xee\x8a\xe5\xbb\x83\x1b\xb5\xad\x81\xef\x6f\x59\x1c\x09\xa9\x28\x2f\xd9\xb3\xa2\xae\xbe\xd4\x23\xda\xcd\xb6\x01\xd6\x69\xae\xf0\xae\xc6\x74\x31\xed\x26\x00\xee\x28\xdb\x22\x11\x94\x13\x0f\xc4\x36\xf7\x3d\xb1\xed\xe3\x33\x5b\x61\x77\xcb\x4b\x78\xb8\xa8\xe9\x67\xad\xbd\x93\x9d\xd9\xc7\xa7\x05\xca\x2e\xbe\xb3\xb8\x79\xd8\xab\xf6\x53\x29\xd2\x0b\x70\x8d\x83\x22\xee\x01\x40\xb7\x51\xa8\x4b\x9e\x82\x35\x55\x07\xf8\xc7\x49\xba\xa1\xbb\x71\x8b\x6e\xe5\x1d\xa4\xdb\x94\xc0\x94\x93\xc9\xa8\xef\x4a\x22\x3f\x2a\x8a\x54\xde\x8a\xcf\x79\x36\xc0\x23\xaf\xaa\xaf\x69\x44\x89\x70\x08\xa4\x38\xd4\x21\x0c\x75\xd8\x9f\x0f\x12\x9e\xc3\x58\x43\x9e\xeb\x21\x1e\x67\xb0\x54\x0f\x32\x6b\x78\x46\x48\xbd\x52\x3a\xa9\x8a\xee\xfb\xb4\x18\x4d\xa3\x2a\x45\xc6\xca\xba\x33\x36\xe6\x9c\xf5\xd3\xc2\x7e\xf4\x46\x31\x18\x30\xd9\xda\x76\x73\x29\x77\x05\xab\x94\x25\xa4\x2c\x4b\x96\xfa\x6d\x73\x29\x4b\x72\x53\x2d\x87\x80\x28\x4b\x7e\xbb\xaa\x24\x12\x06\x2b\xca\x12\x55\x57\x2f\x66\xe5\x56\xd6\x5f\xf6\x3b\x43\xd6\x8d\xae\x7d\x80\xfa\xe6\xc0\xb2\x95\x47\x83\x74\x59\xe0\x11\xd7\x64\x03\x2f\xb2\xd2\x6e\x3d\x85\xd2\x5a\x8c\x24\x4a\x0a\x06\x19\xf8\x6e\xe6\x12\x1b\x91\xf5\xdd\x1c\x89\x21\x62\x22\x14\x5e\x24\xa5\xc5\xfc\x20\x3e\x48\x8e\x8e\xa4\xb4\x89\x12\x48\x84\x02\x99\x51\x0a\x07\xb1\xf0\xa3\x71\x4a\x6e\x5d\x00\x37\x74\xb1\x72\x91\xa3\x35\xf3\xec\x7e\x26\xd8\xcf\x0c\xe3\xf3\xb2\x9f\x43\xec\xa7\xdf\xcd\x5d\x92\x1b\xfb\x7d\x77\xa8\xaf\x7b\xcc\x16\x8b\xe0\x68\xef\x76\xb3\x3b\x39\x26\x46\xdd\x0c\x87\x91\x99\x61\x10\x5a\xc2\x78\xbc\x2c\xa2\x92\x56\x97\x2d\xa4\x1a\xa7\x95\xa3\xbf\x0e\x5f\x8a\xcb\x83\x83\xc1\x55\xd7\x0e\x29\x3f\x4b\x51\xc6\xcf\x6e\xbb\x0c\x88\xb0\xd8\x75\x6b\x6c\x9e\x75\x69\x45\x33\xac\xb6\x34\xf1\x5c\x01\xec\xb1\x9c\xe1\x11\x40\x0f\x40\xc5\xea\x4c\x78\x88\xed\x59\x04\x75\x8c\x4d\x63\x5e\x81\x16\xad\xf4\x49\x12\xda\xf2\x00\xb6\xae\xaf\xd3\x26\xd2\x4b\x73\x4d\x4b\x16\xc5\xb1\x65\x2f\xbc\x49\x9c\xd2\x2d\x54\x0a\x57\xe2\xdc\xca\x23\x78\x62\xfb\x76\xa7\x73\x9c\x3a\x2b\x4d\xa5\xad\x8f\xdb\x47\xd2\xff\x19\xe0\x2b\x2a\xd6\x20\x52\x2a\x33\x8b\xf5\x5b\x92\x51\x4d\x39\xe0\x98\x32\x7e\x7d\x5d\xac\x57\x9a\x10\xeb\xeb\x47\xec\x5b\x65\xeb\x24\xb6\x6f\x7d\xb1\xde\xad\x23\xba\x41\xaf\x54\x79\x54\xc1\xca\x04\xe1\xc2\x1c\x07\x65\x4e\x14\xab\x02\x0f\x08\x0b\x11\xda\x0f\x11\x5b\x33\x9d\xa4\x0d\x86\x40\x8a\x31\xc2\xa3\xac\xa2\x39\x39\x48\xbd\xc0\x6d\xda\xf3\x72\xdc\x7e\xea\x34\xde\x98\x87\x8d\xab\xb9\x7c\xe8\x1f\xfb\x4e\xee\x23\xbb\x45\xca\x5f\x66\x73\xb5\xdb\x74\xfa\x23\xd9\xc6\x11\x7e\xe4\xbd\x41\x23\xdc\xf8\xd7\xc2\xcd\x47\xdc\xa0\xc6\x06\x8c\x9e\x40\x6e\x18\x8c\xae\x77\x1f\x0d\x23\x07\xb1\x27\xac\xfa\xb3\xeb\x37\x56\x42\xa0\x15\x2b\x61\x3c\xac\x19\x69\x14\xa9\xbb\xa7\x33\x24\xfa\x7c\x45\xfd\xd2\x49\x1f\xc2\xc1\x37\x03\x12\x56\x0a\x85\x5a\x38\x05\xa1\xda\x85\xae\x16\xb2\x91\x70\x2d\x96\x17\x92\xc0\xff\xdd\x0d\xad\xfb\x95\xc0\xc9\xa1\x7f\xbb\x74\xe5\xd2\x4f\xb9\x51\x23\x9f\xc9\x3e\x08\x1b\x17\xe7\x69\x95\x15\xd4\x9e\x08\x4b\xa5\x02\xa7\x5c\x8f\xfb\xcb\x5b\xec\x84\xdf\x67\x17\x88\xbf\xee\xbb\xfd\x13\x44\x9b\x17\x07\x27\xb6\x99\xfe\x09\x6d\x3b\xbc\xf5\xb8\xe0\x80\xd4\x2f\xa4\xe4\x83\x85\x14\x21\x30\x02\xcf\x12\x97\x8d\x8a\xe2\x4c\x8e\xec\x05\x8f\x7a\xe4\xea\x04\x1d\x45\x07\x29\x3b\xe6\x97\x90\xeb\x05\x0d\xf5\xfe\x3a\x3f\x36\x58\x73\xfb\xbe\x2c\x70\x0e\xc4\xc0\x0d\xbc\x9a\x97\x0a\x93\xfb\x88\x70\x87\xeb\xf7\x11\xd3\x3e\xe3\x23\x60\xc3\x28\xfa\x25\x04\x31\x00\xdc\xe8\x2e\x04\x2f\x64\xec\xa9\x8e\xbd\xe8\x8b\x02\xc2\x7b\xde\x03\x26\x3a\xfc\x2f\x3b\xa3\xc1\x03\x6f\xcf\x65\x33\x54\x7c\xc2\xef\xa7\xc5\x2b\x98\xcc\xbf\x84\xed\xdd\xe5\x66\xd2\x76\xd9\x33\x76\xca\x5e\xb2\x73\x98\xb4\x7d\x03\x21\x77\xed\xfe\xf3\x17\xec\xee\x82\x36\xc2\x13\x3e\x46\xb0\x99\x96\x4e\x2d\xa5\x03\x9b\x27\x07\x0f\x8f\xe8\xed\x03\x98\x91\x97\x38\x23\x19\xcc\x07\x70\xc6\xf9\x9d\x8b\xf2\xf9\x27\x1d\x04\x0e\x9c\x2d\x6d\xc0\x68\x30\x29\x0a\x82\xf1\x72\x1f\x3e\x61\x17\x72\xff\x01\xa9\xdf\x39\x65\x63\xf8\xfb\x94\x4d\xe1\xef\x2b\x36\x82\xbf\xcf\xd8\x0c\xfe\xee\xb3\x33\xf8\xfb\x92\x4d\x78\x0b\x1a\xa1\x1a\xd8\x43\x6e\x6c\x45\x2c\xbd\xdd\x61\x5a\x53\x0c\xb1\x24\x53\x82\x77\x01\x77\x6f\xa3\x49\x70\xeb\x24\x2b\xe5\x22\xea\x85\x22\xa0\xa0\xd7\xd3\xd2\x62\xd1\x3c\xeb\xb7\xd6\xf6\x62\xbc\xcf\x3f\xf3\x01\x2c\xb3\xcc\x49\x36\xcc\x83\x7e\xae\xf1\x3f\x93\x58\x44\x41\x94\x5a\x17\x4a\x06\x51\x39\x35\xe5\xa3\x6c\x19\x48\x73\x8c\x1f\x96\xb8\x23\x42\x80\xcd\xba\x43\x3c\x70\xf3\x3b\xc3\xbe\x1b\x01\xc9\xc9\x53\xed\x53\x42\xca\x3c\x20\x0e\xcf\xff\x12\x94\xbb\x25\x57\xb8\xb4\x02\xc9\xc0\x2f\xa7\x3e\x54\xcb\xcc\x22\xb9\x02\x21\xcd\xbd\x5f\xc5\x83\x16\x77\x32\x5f\xda\x83\x46\xe0\xd9\x79\x45\x32\xe3\xbc\x2a\xc1\x5f\x79\x63\x2e\xa5\x30\xf8\xa4\x98\x7d\xfb\x3a\xd4\x40\xbc\x57\x3c\xc0\x8b\xca\x44\xe2\x1f\x36\x5c\x47\x49\x4d\x49\xb4\x8b\xce\x03\xcd\x24\xa6\xc0\x21\x26\x7d\x9d\x75\x21\xd9\x41\xec\xc6\x63\x12\xed\x4f\xf9\x41\xd9\x63\x94\xaa\x52\xaf\x69\xab\x8f\x3b\x9d\x31\x5e\xdc\x22\xcf\xf7\x2a\x75\xa6\x6c\x8c\x2f\x52\x4d\xf1\x38\xcd\xe0\xe7\x07\x00\x75\xfc\xab\xc0\x20\x1b\xe4\xc0\x9c\x1b\xc6\x01\x76\x6e\xb6\x3e\x84\x9d\x8b\x6c\x3c\x30\x37\x4f\x5d\x29\xa7\x87\x45\x99\xa2\xc8\x73\x4a\x3e\x4b\xe8\x84\x1c\x21\x87\xb1\x47\xb7\x14\xb0\x39\xf7\xa0\xc4\xf4\xe0\xb7\xda\xb0\x75\x90\xa7\x46\x4d\x60\x0a\x0c\xae\xfd\x45\x93\x34\x83\xbd\xb8\x93\x79\x6f\xcc\x56\x9c\x39\x23\x48\xb3\xd4\x88\xd2\xe6\xab\x0d\xa2\xdc\x82\x92\x72\x13\x25\x4c\xb5\x68\xb2\xf3\x16\x1f\xa2\xbd\x01\xe0\xfc\xe1\x76\x5e\x93\x69\xa3\x30\x4f\x91\x71\x57\x72\x6f\xa2\xce\x10\x6e\xce\x03\x39\x7b\x11\x3f\x66\x29\x09\xc5\x92\x41\xea\x8c\x61\x66\x01\xad\xa5\xce\x9c\x8d\x09\x2b\x34\x4a\xd1\x90\x31\x4f\x0c\x61\x36\x05\x9e\x69\x8a\x17\xe9\x0e\xd6\x3a\x3d\x62\x2d\xa8\x0c\xb0\xc9\x1c\x0e\x95\x31\xd0\x3e\x54\x97\x1e\x14\x19\x5b\xd0\x74\xae\xce\xa3\xa5\xde\x2d\x0b\x1b\x4c\x0d\x36\xa8\x71\x3a\x3f\x79\xf4\xf3\x5e\xb1\x14\xdd\x80\x03\x6e\x90\x6c\xc6\x23\xcf\x70\x07\xe8\x54\x1d\xfa\x4f\xbf\x68\xb7\xac\x0c\x47\x31\x4a\x05\x65\x91\x77\xa6\x48\x8b\x77\x83\x01\x2c\x75\x57\x78\x68\xd1\x33\xd0\x97\x62\x9e\xd5\xc0\x8f\xb2\x6d\x21\x4c\x29\xa8\x10\xed\xd6\x96\x55\xeb\x46\x2b\x56\x57\xca\xdd\xf1\x4d\x6b\xb3\xc0\xa4\x01\x87\xdc\xa8\x85\xf0\x60\x8d\x61\x21\x5b\x49\x75\x71\x69\x41\x61\x2d\xe9\xda\x62\x6c\xd6\x78\xca\xb3\x83\xf1\x11\x20\xdd\xf2\x2e\x69\x2a\xef\x8f\x64\x3a\x6a\x8b\xc3\x32\x9d\xd1\x6a\xf5\x47\x0a\x00\x46\x04\x00\x67\x6c\x86\xf0\x9b\x3a\x33\x76\x06\x81\x66\x00\x18\x51\xf6\x59\xa7\x33\x83\xe5\x3b\xc3\xe5\xc3\xdc\x66\x89\xe9\x12\x63\x54\x76\x75\x0e\xd8\x60\xce\x2b\x2f\xc8\x72\x3e\x95\xd9\x94\x97\x5c\x7c\xd3\xd3\x7e\xce\xf5\x12\xed\xd8\xca\x6f\xec\xfc\xa4\xc5\x2f\x01\x29\xd9\xb5\x84\xd2\x86\xab\x16\x85\xbe\x4c\x9d\x06\x4a\x76\xd2\xe9\x4c\x6a\x52\x98\x86\x5c\xd0\xc6\xa5\x9d\xeb\xd2\xbd\xee\x36\x66\x56\x3b\xa4\xe2\xc1\xcb\xcc\x7b\x96\x21\xd9\x88\x37\xe4\xab\x44\x76\x36\xc2\x55\x9f\x7d\xc7\x89\x07\xc9\x76\xee\xe5\xdb\x09\xa0\x16\x54\x4f\x84\x55\xc1\x9f\x10\x29\xb8\x84\xe7\x28\xf1\x40\x01\xa7\x25\x1f\x3c\x23\x07\x04\xa5\x16\x89\x74\x1f\x7d\xe2\x0f\x4f\x8b\xe2\xa9\x6f\x10\x3f\xc7\x5b\x98\xa7\xfe\x60\x16\x7b\x09\x4b\x07\x89\x2a\xe4\x59\x27\xc2\xa4\x52\x53\xc8\x8d\x61\x63\x51\x3c\x37\x47\x69\xc8\x91\x50\x7c\x0e\x35\x78\x21\x0b\x06\xa1\xae\xc7\xea\xd1\xe5\x4a\x1e\x75\x10\x97\x47\xc4\xb2\xc2\x21\xa9\x2e\x64\xe1\x67\x23\xc9\x08\xc9\x3c\x41\x6e\xf2\x36\x5a\x58\xa0\x49\x28\xf7\x2d\x97\x53\x14\xfb\x02\xdf\xda\x68\x7b\x62\xbd\x9a\x84\x86\x17\x10\x8b\xc6\x18\x82\x05\x5d\xdf\xad\x27\xaa\x72\x01\xf1\xca\x4c\xac\x97\xd2\x85\x2b\xb2\xf5\xf0\x02\x86\x8f\x29\xdb\x24\x37\xa9\xdf\x19\xeb\x72\xc3\xf0\x49\x8f\xcc\x16\x0c\xda\x7e\x2b\x00\xc4\x96\xb4\xe4\xe1\x58\xa9\x5c\x02\xd3\x44\xa3\xa5\x97\xa3\xde\xc5\xd5\x3e\x60\xe9\x01\xdd\x79\x2e\xe8\x1b\x7e\x2b\xb2\xed\xfb\x95\xde\xd8\x7b\x65\x59\x5d\xd2\x12\xdf\xd9\xa0\x2d\x75\xec\x3f\xf9\x50\x2f\x8c\xc1\x36\x9f\x5b\x22\xbd\xec\xfa\xd5\x02\x09\x85\x80\x53\x83\xfd\x48\xca\xd2\x6f\xc2\xca\x44\x30\xa4\x4e\x57\x27\x27\x42\xa6\x87\xea\xd7\x57\xbf\x99\xfa\xcd\xd5\xef\x50\xfd\x46\xea\x77\xae\x7e\xc7\xc2\xd3\x6a\x53\x27\xf9\x78\x5c\xbe\x32\x2e\xdb\x89\x07\xd0\x95\x04\xe0\x9b\x41\xfa\xa5\x08\xf6\xc7\xe3\x2c\x10\xc6\xc2\xc7\xd5\xb8\xbe\x86\xbd\x65\x61\xdd\xc7\x1f\x3d\x05\x9d\x32\x56\xfb\xbd\x3f\x16\xe5\x73\x70\x61\x2f\xf2\x33\xb1\xab\xd6\xcc\x84\x1b\x14\x43\x2e\xcc\x6a\xc5\xe4\xc4\x9c\xec\xd2\x81\x30\x6a\xc1\x9a\x63\x26\x7c\x0d\x2a\x1b\xc8\x73\xca\x93\x51\x0f\x02\x7c\x68\x46\xde\xe0\x9b\x0d\xfe\xc1\xd7\xba\x0c\x7d\xab\x20\x5d\x06\xb6\xce\x85\xf4\xb1\x4b\xef\x25\x53\xd4\x03\x13\x53\x14\x7b\xa8\xe8\xc0\x76\x32\xba\x7f\x6d\x52\xe2\x7b\x51\xe5\x28\x03\x8e\x7e\x3a\xcd\x15\xc9\xdd\x0c\x7d\xa7\x6f\xaf\x6f\x01\xe8\xfe\x66\x8b\x73\x74\x82\xb5\x6d\x5d\xf0\x1d\xa7\x96\x34\xb3\xb5\x1f\x56\x5c\xd0\x55\xf4\x79\x45\x55\xb4\x9c\xba\x72\x64\x96\x0c\xeb\x1c\x2f\x7a\xe9\x9e\x49\xe0\x25\xa6\xb4\x4a\xb2\x8c\x59\x52\x09\xc7\xe5\x8d\x48\x88\xb7\xb6\xe2\x88\x57\x1c\x28\x9e\xa7\xd7\x79\x66\x44\x33\x5e\x7b\x30\x77\xb3\x6d\xbb\xf0\xd3\xb4\xf2\x28\xa5\x74\x0d\x48\x1e\x18\x91\x10\xd8\xde\xf4\x94\xca\xae\xa5\x30\x95\x56\x04\xfe\x48\x7d\xa6\xf4\x40\x20\xe2\xbe\x02\x4f\x83\xd3\x62\x17\xb0\x1c\xb0\x75\x40\x96\x86\x85\x5f\xec\x17\x2f\x51\x3d\xbd\x73\x8a\xe7\x55\xda\x39\x25\x59\x74\x67\x57\x7e\xed\x22\x05\xe0\x0c\x51\x57\xde\x3d\xf8\x53\xbc\x3e\x01\x16\x9b\x3e\xbe\x47\xea\x0d\xe0\x66\x9b\x43\xd6\x74\xdb\xc7\x9b\x28\x1f\x43\x7c\x17\xc9\xe4\x64\x9b\xc3\x74\xa0\x78\x1e\x7a\xbc\xbb\x8d\x7a\x65\x40\x8d\xa3\x36\x9b\x36\x2e\xbb\xc3\x15\x54\x01\xe1\x6c\x74\x43\x50\xf5\xb3\xf3\x94\x2e\x1f\x6f\xa1\xa8\xef\x16\xf4\xbb\x80\xee\x3c\x05\x62\x79\x5f\x2b\xaf\xe0\x4b\x87\x35\x3a\xe2\x36\xea\x76\xdf\x3e\xe2\xb3\x41\x80\x34\xc3\x88\x09\xa0\x89\x5d\x0f\xb8\xe3\x91\xcb\x02\x08\x43\xca\xa5\x83\x59\xd8\x5b\x8a\xa6\x74\x0d\x7e\x58\xe5\xb7\x40\xa9\x40\xbb\x58\x19\x04\xf1\x0f\x14\x11\xba\xb2\xef\xac\xca\xbe\xd3\x95\x7d\x5b\x56\x06\xe9\x2e\xb2\x97\x38\x47\x23\xea\xfe\x9f\x1e\x71\x2a\x00\x9b\x00\xa7\x16\x62\xbe\xd7\xb4\x3f\x06\x07\x02\xfe\x78\x70\x2e\xe0\x07\xc3\x0f\xc8\xa9\x93\x7f\x38\xa2\x02\x3f\xe0\x0c\x20\xdf\x80\xb8\x5a\xaa\x3e\xe0\x82\xf2\xc4\xbe\xd2\xde\x57\x0b\x1e\x28\x5d\xd2\xd5\xf7\x46\x57\x8b\x8a\x4a\x59\x28\xaf\xb9\xc3\x35\x49\xbe\x38\x89\x96\xbd\xba\x0d\x77\xa7\xcf\x2a\x60\x85\x6e\x70\x94\x4c\xe8\x7a\xf5\x4b\x27\xa6\x7b\xc5\xda\x7d\xe8\xcb\x74\x95\x61\x13\xca\xbc\x32\xa3\xa0\x40\x8e\xd5\x38\x99\xb1\xf6\x53\xeb\x4e\x98\xae\x9e\xc8\x65\x04\xde\x01\xa3\x29\x07\xf6\xdd\x3b\x6e\x50\xeb\xdb\xa3\x0d\xa4\x2e\x2e\x0d\xc6\x23\x92\xef\x8c\x9c\x84\x96\x5a\x59\x2d\xfe\x01\xd8\x78\xeb\x40\xb4\xe9\x39\x57\x1a\xc6\x54\x88\xc3\x86\xa3\x0d\x1f\xab\x70\xe2\xaa\x71\x75\x1d\x01\xad\x9a\x3a\xc4\x79\x5c\x2c\x9a\x49\x5d\x40\xa4\x15\xc5\x95\x52\xd5\x2f\xb5\x8d\x90\x62\xfe\x8e\xf0\x6b\xe5\xce\x20\x45\x4e\xc3\x60\xb5\x12\xed\xfb\xb8\x37\x15\x92\x73\x48\x73\xad\x28\xc2\x5e\x9c\xc4\x0f\x01\x4d\xdd\x4d\x27\x59\xa7\x73\x9f\xb0\x8b\x96\xdb\x93\x4e\x62\x66\x00\x08\xd0\x04\x32\x6f\x8e\xbc\x8b\x1f\x32\x44\xef\x65\x27\x87\x6e\x79\xe7\x39\x34\x20\x65\x5d\x23\xec\xa6\x35\x45\x1d\xc4\x6a\x07\x47\x1e\x22\x4c\x7d\x42\x0e\xa4\x21\x5f\xe0\x7d\x42\x97\x1d\x5e\xe2\x57\x6c\xca\x4f\xed\x1a\x2a\x39\x2d\x75\xae\x0a\x06\xad\xd0\xdd\x70\xce\x29\x03\x60\x4f\xd9\xab\xdb\x86\xbd\x64\x14\xac\x6c\xcf\x19\xc2\x60\xc5\x8c\xd7\x6a\xe1\x89\x39\x72\x04\x87\x23\xdf\x9c\x40\xca\xe4\x43\xa0\x0b\x2a\xa0\xee\xf0\x6a\x7f\x8b\x6d\xd9\x97\xac\xb5\xcb\xce\x4d\x7d\x6f\x82\x32\x1a\x94\x0a\xa1\x4a\x0e\xdd\x6a\x2a\x77\x05\x9f\xe4\x0e\x4b\xbb\xbc\x24\xed\x2c\xb5\xca\xd7\x69\x93\x3d\x5a\xd5\x0e\x80\x68\x60\x5a\xc7\xd2\x30\x2d\x94\x86\x69\x21\xe1\x00\xa9\xbe\xd9\x84\x02\x3e\xa6\x96\xc0\x29\xc0\x9a\x96\x2f\x1e\xa0\xde\xc0\xc8\xdd\xed\x4b\x88\x80\x10\x36\x49\x6e\x49\x77\x05\xb6\x45\x45\x13\xf7\x12\x45\xc6\xe7\xd6\x35\x01\x6b\x6d\xb1\xd6\x26\x83\xfa\xec\xb9\xde\xa9\x53\x84\xb6\xba\xbd\xa6\x25\x06\x4e\xe3\x32\xd0\xcd\xc5\x96\xcb\x68\x16\x37\xb7\x51\xdd\x02\x26\x18\x1d\x8f\x95\xea\x41\x7f\x84\xea\x05\x4f\xd7\x69\xb1\x37\x75\x53\x2b\x1a\x7b\x7c\x5d\x63\x92\xda\x92\x4d\xaa\x47\xcd\x05\x0a\xcc\x91\x75\xbf\x4d\xd8\x50\xda\x7f\x92\x79\x42\x60\x79\x8e\x50\x4d\xa6\xdd\x2d\x6b\xda\xde\xfc\x8a\xa6\x24\x19\xb4\xbe\xb5\xd4\x26\x5d\x1a\xca\x56\xb5\x2d\x60\xb5\x55\x5b\x62\xf9\x36\x5d\xb2\x2c\x68\x98\xcb\x64\x80\xc6\x4a\x9a\x2a\x6a\x59\x58\xd4\xcc\x2f\xe1\x5d\x84\xdc\xc4\x65\x96\xb9\x42\x75\x2a\x3f\xa7\x4d\x0a\x36\x4b\x06\xce\x95\xc1\x68\xd7\x43\xd6\x2c\x5e\xe7\x7d\xe8\xd3\x75\x53\xd8\xb0\x3c\xbf\xa6\xee\x9f\x2a\x38\x6a\x80\xa7\x3d\x1c\x66\xa5\xbe\xcc\x57\x40\x65\x6d\xca\x04\xa9\x7f\xa5\x03\x69\x89\x50\x9d\xac\x47\xe9\x0a\x23\x70\xcd\x2c\xca\x52\xad\xcd\x6a\xb1\xe7\x5f\x0b\x43\xeb\x5b\x8d\x4a\x1b\xb1\x8b\x6e\x0e\xe2\x01\xa0\xc2\xb4\x1b\x33\xa8\x1d\x55\x96\xac\xd7\x8f\x14\x2e\x92\x1a\x21\xae\x56\xdd\xd0\x62\x67\xd4\xf7\x18\xe0\x5f\xdf\xf3\x5b\xf0\xd7\x1d\x84\x5e\xe9\x92\x4a\xfb\xa1\xb2\x14\x4b\xec\x39\xa5\x7d\x6d\x6f\x88\x77\x55\x5c\x86\xce\x46\x24\xba\x5c\x92\xa0\xa3\x76\x23\xe0\xe5\x89\xbc\xab\x0a\x39\x4f\x2a\xb8\xd3\x92\xb9\x23\x0e\x45\x0c\x97\x49\x0c\x97\xb9\xa4\x43\x67\xac\xc8\x94\xe1\x12\x1c\x96\x99\xb1\xae\xda\xba\xa5\xac\xab\x20\x12\xe8\x84\x85\x65\xe1\xad\x55\x26\x37\x51\x65\x52\xda\x72\x0c\xf2\x12\x93\xcf\xb1\x5b\x63\x9e\xe2\xed\xae\x51\x76\x22\x93\x0e\xb2\x99\x43\x83\x0e\xe6\x8c\x07\x8f\x84\x83\xf2\x53\x2f\x74\x50\x9e\xea\xde\xd9\x54\x1e\x31\x79\xdc\x5f\x5f\x17\x46\x4e\x97\x12\xfe\x1f\x3b\xce\x14\x4b\x4c\x65\x09\x3c\x14\x54\xa1\x52\xe9\x69\x81\x52\x6e\x33\xa6\xb9\x0e\xe9\x75\x98\x5b\x7a\x25\x5f\x04\xb3\x80\xae\x72\x6d\x48\xff\xf1\x57\xc0\x98\xc4\x2a\xcd\x0a\x42\xb1\x9b\x70\xa7\x0a\x6c\x40\x56\x92\x8a\x5c\x8a\x7e\xfd\xbb\x5b\x36\xdc\x25\x0a\xe6\x10\xe4\x55\xc5\xca\x93\xd3\x12\xf0\x85\x9e\xf4\xec\x34\x48\x10\xf8\x9a\x9c\x9e\x91\xfe\xb4\x14\x79\x27\x0a\x0b\x90\xd1\xa9\x95\x2d\x69\x40\x01\x41\x62\x3c\x8c\xd4\x6f\xee\xf1\xe1\x9e\x96\xa1\x88\x0c\x9b\x54\x9e\xf3\x9b\x00\xb7\x04\x9f\x69\xd3\x79\x2c\x90\x5e\xab\x2a\x2c\x55\x41\x96\x0c\x69\x58\x88\xb7\x93\xe4\x30\xac\x54\xa4\x44\x6f\xb3\x0d\xa6\x58\x22\xb1\x3d\x6c\x41\x61\xf2\xd6\xb3\x74\x78\x23\xb1\x63\x3b\x00\x4a\xbe\x80\xa3\xa5\xd1\xcb\x0a\x44\x6d\x7c\x08\xa4\xd2\x87\x40\xaa\x7c\x08\xa8\x4d\xe5\xb2\xb2\xd7\x80\x7c\xd1\x4b\x2e\xcc\x7e\x93\x69\x4c\x6a\x77\x7e\xa7\x8e\x17\x92\xe4\xab\x08\x80\xaf\x38\xb4\xe4\xb2\xa4\x8a\x06\x20\xc3\xac\x0a\x3a\x0d\x93\xfa\x01\x79\x86\xd7\xd6\xa5\xac\x54\xde\x84\xeb\x3b\x43\x85\x15\x3d\xa5\x8c\x96\xd0\x7d\x76\x65\x7e\xfd\x3f\xa4\x42\xc2\xf2\xb5\x3a\x49\x89\xbc\xbc\xe0\xff\xba\x19\xf9\x0a\x8a\x6b\x05\x19\x94\xff\x11\x1a\x58\xa6\xb9\x1a\x9b\x1a\x5e\xd7\xd4\x5f\x8c\xe2\xaa\xd2\x5b\xd1\xaf\x68\xe8\x0f\xa7\xb7\xaa\x77\xc4\xf3\xa4\x54\x43\x7b\x1f\x3b\xcb\xb4\xb4\x0d\x2c\xe3\x1a\xb0\x84\xcb\x5d\x0c\xcb\x2e\xb6\x4f\x92\x04\x5f\xbc\xae\x98\xb8\x4b\x13\x04\x21\xb5\x3a\x00\xd4\xd5\xea\xa4\xae\x54\x2b\x40\x5b\x7f\xa0\x41\x94\xed\x16\xaa\x7a\x68\x6c\x8a\xc7\xf7\x2c\x96\xca\x48\x2d\xae\x28\x3c\x9f\x80\x0f\xd5\x3c\xa0\x46\x44\x66\x70\xd0\x0e\xd0\x03\x1c\xac\x36\xe9\x0b\xdb\x67\xfb\x34\x69\x60\x74\x9c\xa0\x64\x73\x3b\x1d\x68\x87\x7c\x88\xfc\x88\x57\x7d\xa4\xff\x9c\x2a\xcb\x0e\x75\x7a\xe3\x91\xc7\x29\xcb\xe3\xd8\xb2\x7d\xb0\x25\x91\x33\x1b\x55\x90\x75\xf5\x27\x7b\x52\x2b\xbb\xef\x2c\xf9\xe3\x32\x47\x12\x6e\xd2\xc1\x65\x4c\xbe\x2a\x50\xee\x30\xf4\x85\x73\xa9\x2c\xbf\xbd\xd8\x48\x4e\x07\x30\x3d\x69\x15\xce\x27\xd5\xce\x2c\xd1\x34\xe4\xd0\x06\xc0\x29\x20\x67\x3e\x68\x67\x52\xe9\x8b\xd6\xd1\x48\x9c\x8a\x79\x79\xb2\xa4\xb5\x5d\xc1\xde\x24\x5f\xc2\x46\xd1\x97\x28\x6c\x45\x14\x28\xc0\x09\xe6\x92\x70\xff\xe0\xc8\xad\xc9\x9e\xa4\x37\x18\x12\xdc\x90\x1c\xca\x93\xec\x67\x08\x45\x80\xff\xc4\x57\x3d\x1a\x58\xd0\x87\x89\x25\xbe\xb6\x55\xab\x6c\x37\x71\x9b\x95\xeb\x09\xb3\x13\x35\xd9\xa1\x5f\x36\x0d\x2a\x86\x21\x27\xd7\xe4\xb3\xc4\xe7\xd6\x1e\x83\xbe\x90\xbf\x31\x4b\x72\x6d\xa5\x4a\x81\x02\x39\x29\x52\xda\xd5\x35\x77\x76\x56\xb9\xe3\x2a\x38\x33\xfd\xfe\x6b\x45\x8c\x64\xfc\x58\xdc\x45\x27\x1e\x30\x73\x61\xc5\xf3\x5d\xe2\x09\xa0\x4c\xe5\xd4\xa2\xfa\x42\x6a\xa7\x9a\x63\xb0\xee\x2c\xcf\x92\x52\x27\x2b\x3d\x9c\xf5\x9b\x85\x27\x4e\xdd\xb5\x59\xa9\xb2\x53\xf1\xc7\x26\x6f\x75\x50\xb8\x92\x06\x67\x41\x9a\x35\x4c\x85\x7a\x7a\x43\x4c\xd3\xbc\xe2\x05\xd7\x5c\x9b\x9b\x92\x0b\x6b\xda\x9e\x26\xb5\x07\xd9\xd4\x44\x57\x1c\xb6\xbe\xb2\x32\x3d\x8f\x97\x7c\xe7\x2d\xfb\x67\xb3\x04\xab\xc9\xf5\x04\x2c\x5a\x52\xc9\x47\xa3\x48\x92\xe5\x32\x32\x66\xf9\x12\x19\xf4\xec\x2b\x8e\x3b\xf2\xd3\x42\xaf\x96\x91\xc0\xcb\x72\xe2\x82\x3c\x1d\x60\xcb\x65\x82\x77\xb0\xcc\x5a\xc1\x9e\x6c\x72\x8d\xa5\x1d\x43\xde\x25\x79\x59\x8a\x16\x23\xe5\x5b\x8f\xd8\x31\x20\x02\xbd\x89\x3e\x6a\xe1\x83\x9e\x63\x2c\x65\xb7\xb5\xfe\x53\x6d\x83\x20\xf6\x4e\xf4\x35\x48\x93\x12\xb9\x68\x56\x57\x57\x94\x92\x39\xf3\x60\x78\x84\x64\x2c\xf9\x6d\x63\x73\x22\xf6\x5e\x98\x5b\x17\xab\xfc\x52\xf1\x07\xb6\x83\x62\xe9\x9d\x4f\x55\x64\x44\x06\x06\xf1\xc3\x50\x07\x78\xbc\x97\x72\x64\xbb\x66\xe5\x31\xe0\xa1\x7d\x0e\xed\x2e\x21\x8d\xe5\x02\xf7\xed\x02\xa7\x49\xe5\x6e\x8b\x7a\xf7\x9a\x8e\x1f\x4b\x60\x59\xab\xb4\xf9\x02\xb5\xd1\x18\xa8\xd3\x91\xd3\xa3\x9c\x90\x79\x74\xdd\xff\x21\xd6\x93\x6b\x89\x2c\xff\xe2\x6d\x28\xe7\x64\xde\xfd\x55\x6d\xbc\xae\x8d\x55\x4e\x47\xe5\x04\xbd\x65\xe7\xff\xd8\xb8\xd2\x71\xec\x3d\xf9\xaa\x95\xde\xa9\x36\x47\xb5\x3d\xae\x4d\xed\xbd\x25\x12\x59\x36\xe2\xc7\xde\x67\xd3\x08\xe6\xa1\x66\x52\xf6\x5b\xc0\x5d\xac\x7e\x7a\xde\xb9\x5d\x05\x82\xc7\x2b\x2a\xcd\x7e\x65\xa5\x15\x40\x79\xf3\xeb\xc1\xde\xba\x49\xb0\xfc\x60\xb5\x84\xfa\xb6\x31\xe7\x5b\x7b\x57\x34\xd1\xd5\x57\x0a\xa7\xf5\x6b\x2a\x8f\x66\xab\x6c\xc2\x4e\x79\x1b\x3b\x92\x9d\xc6\x1d\x23\x47\xfe\x39\xb1\xf5\xfc\xb4\xe2\x26\xb0\xde\x92\x1e\x97\xd6\x6d\x89\xc1\x65\xd6\xc9\x4e\x25\x4d\xb3\xab\x7d\xaa\x55\x68\x38\x35\xdf\xd4\x11\x01\x67\x62\x8b\x2e\x1b\x89\xb2\x43\xdf\x5b\x30\x2f\xc8\x79\xa3\x1c\xa3\xe1\x9e\xf9\xd3\xd7\xa0\x77\x74\x33\x86\x9a\x51\x2a\xd5\x12\xd9\x35\x2e\x50\x1e\x7b\x3f\xfd\x33\x41\x83\xef\xbf\xc8\x3c\xfb\xf2\xba\x7a\x40\x56\x7d\x96\xe7\x86\x25\xb6\x54\x6a\x40\xda\xd0\x53\xd7\x0a\x22\xbb\x04\xe5\xc8\xe1\x4a\x7b\xf1\xf6\x84\x4a\x61\x74\x56\x78\x29\xa3\xe3\xd6\xa3\x17\x12\x43\xe0\xc8\x6d\x43\xd1\x47\xd6\xdc\x1a\x50\xef\x1b\xaf\x42\xd2\xe0\x80\x2e\xa5\xe9\x86\x57\x18\xc3\x02\x54\xae\x84\x68\x65\x56\xdb\x4c\x66\x9e\x23\xb2\xd1\x27\xab\x1c\x77\x4a\xe3\x4e\xaf\xf5\x58\x51\xc2\x54\x52\x01\x27\x04\x1c\xa4\x83\x25\x43\xa0\xae\xa1\x8e\x3d\x60\xba\x20\x42\x3a\xb4\x88\xed\x79\x48\xd5\x04\xc4\xf5\x09\x98\x5b\x13\xf0\xbc\x8a\x8d\xf6\x9a\x10\xfd\x0d\x95\xa7\xd9\xec\x6a\x65\x42\xb3\xee\x2b\xda\xf6\x05\xe4\x60\xcd\x70\x06\x01\x3f\x01\xa0\xe4\x5d\xba\x15\xdb\x64\x96\xf2\xbf\x12\x3f\xad\x07\x77\xb6\x06\x2b\xde\xab\xd2\x7e\x6d\x2c\x91\x69\xfd\xb0\x5b\x09\x59\x81\x96\x32\x88\x81\xad\xdf\xaa\x6c\x5b\x5d\x46\x5a\xbf\xa7\xd2\x60\xbd\xf6\xc7\x86\xf9\x0f\x36\xc3\xd1\xff\xa3\xcc\x52\x6a\x66\x29\x5d\x69\xc3\x05\xd3\x02\xe8\x0d\xd5\x63\x9a\x27\x46\x8e\x93\xd9\x26\x23\x3f\x56\x58\xa3\xa7\x64\xb9\x57\x43\xf0\xdb\xb7\xf4\xd6\xad\x9d\x80\x00\xd0\x97\xc0\xe2\xfd\x98\xd8\xaa\xf3\x6e\x3f\x2e\xf8\x9e\x11\xaa\x4a\x9d\x38\x21\x8d\xde\x4a\x91\xa1\xf5\x96\xa7\xf4\x85\xb7\xd4\xe8\xd6\xa0\x91\x1c\xf5\x1e\xd5\x94\x46\x44\xe5\x6d\x85\xa7\xc5\xab\x3f\x64\x08\x22\xbc\x76\x08\x82\x8c\xe2\xab\x43\x88\x43\x0d\x53\xcd\xc0\xa4\x16\x8d\x26\xe0\x59\x23\xc0\x28\xa8\x31\x27\x53\xc5\x00\x21\xae\xf4\xc8\x76\x28\x9d\xfe\x8a\x86\x5f\xfe\xfa\x86\xd3\x95\x0d\x27\xa6\xe1\xb2\x2f\xc8\xac\x77\x3a\x79\xe6\x8c\x5d\x96\x53\x20\x47\x55\xdc\x31\x87\xa3\x73\x51\x51\xf7\x57\x9c\xef\xba\xf3\x3c\x73\xdc\xf5\x88\xd4\x67\x36\xb7\x39\x59\x81\xc3\xf2\xe9\xc2\xaa\xf7\xd3\xbe\xaa\x44\xe9\xd5\x3e\x97\xc6\xd3\xda\xc4\x07\x6f\x04\xd8\xb8\x28\xd0\xe5\x4c\xc6\xe7\x72\xe0\xca\x54\x6d\xcc\x47\x99\x93\x54\x84\x2e\x61\xa5\x9b\xaa\x62\xe7\xac\x28\x66\x2d\x25\x8a\xfb\xda\x16\x4a\x91\xa5\xa3\x3c\x0a\x96\xd0\x14\xc9\x3a\xe6\xc4\x85\xb2\x29\x3f\x43\x75\x6e\x60\x5a\x26\xe8\x96\x86\x1c\x38\xc9\x39\x98\x74\x3a\xad\xb1\xf4\x79\x02\xb5\x4f\xa0\x81\x11\x37\xcb\x36\x5b\x77\xa2\xf5\x11\x9e\x0d\x30\x39\xe4\x88\x6c\xd6\xf7\x07\x4e\x4e\xee\x73\x68\x86\x50\x57\x27\xaa\xf5\xd4\xf5\xb0\x9f\x39\x8e\x3c\xb4\x75\xd3\xfc\x4e\x67\x3c\x18\x73\x1a\xb8\x07\x7d\xc1\x7b\x00\xb4\x8e\x51\x73\x84\xd6\x59\x31\xf9\xc3\xc3\xb7\x15\xab\x35\xb2\x96\x5f\x14\xf5\x09\x60\x43\xa2\x96\xc8\xdc\x88\x4c\x08\xc6\x6c\x0a\xdd\xd9\x84\x01\xc2\xee\x3c\x53\xda\xf4\x5f\x85\xd3\xc8\x04\x45\xc9\x3a\xe9\xdd\xbc\xd6\xa6\xd6\x63\x86\x5a\xa0\xaa\x2d\xb9\x9c\xa4\x07\x07\x7d\x9c\x90\x5a\x88\x8f\xaf\xdf\x40\x6b\xed\x99\x7f\xf1\xd6\x0f\x05\x2a\x2b\xc3\x08\x10\x45\xc7\x3d\x15\x47\x66\x08\x2e\xf4\xa6\x2d\xd4\x83\xca\x94\x6b\x10\xf7\xf4\xb7\x77\x56\xea\x20\xf4\x86\x28\x16\x40\xe3\x09\x4b\x1d\x21\xb4\xf1\x13\x79\x41\xdc\x62\xb6\xf4\xcc\x82\x83\xb0\x72\x5a\x2a\x8f\x89\x36\x8a\xb1\xe4\xd1\xe1\xf2\x45\x09\x13\x15\xab\x9c\xd2\x4b\xe4\x12\x72\x5f\xb3\x2f\x57\x16\xf2\x76\x05\x5b\x7b\x15\xba\xab\x9c\x30\x5a\x75\x94\x5a\x36\x28\x4e\xa4\x17\x66\x1a\xcf\x08\x12\x75\x09\x20\x29\x64\x9e\xf2\x39\xda\xd4\x12\x33\x5a\x12\xf0\xeb\x87\x24\xef\x53\x61\x95\xff\x99\x8f\x4a\x5c\x3f\x2a\x72\xcb\xf1\x95\x63\x1a\x86\xd7\x11\x37\x01\xec\xa2\x46\xc3\x1e\xb1\x82\xb8\xb1\xba\xab\x14\xdc\xa1\x07\xc3\x69\x80\x4e\x0a\x56\x92\x30\xf5\x8b\xb4\x94\x1c\x8d\x97\xfe\x82\x52\x7c\x70\xdd\x49\xb4\x39\x62\xb0\x62\xd8\x26\x77\x86\xb9\x59\x88\x9a\xef\xa5\xe0\x91\xba\x41\xf2\xae\x61\xd8\xbb\x4f\x7d\xb2\x5f\xda\x09\xd5\xa3\x1c\xbf\xc6\xed\xe7\xd2\xfa\xb6\x56\x74\xcd\x9a\xef\xb9\xbd\xd9\x88\x72\xb2\x37\xcd\x38\x2c\xe9\xf1\x9a\x0c\x1b\xd0\x06\x5a\x7b\x8e\x6b\x87\xb7\x4d\x7a\xec\xa9\xc3\xae\x2a\x83\xff\x62\x95\xd3\x6b\xaa\x7c\xd0\x54\xe5\xc8\xaa\xb2\x91\x6e\xa9\x54\xb1\x7b\x1d\xed\x38\xfb\x0b\xcd\xbb\x58\xb6\xe7\xc7\x89\xaf\x98\x8f\x9e\x85\x55\x8e\xac\x85\xac\xc9\xaf\x40\xdd\x1a\x80\xe8\x50\x1b\xa0\x07\x19\x4f\x63\xe9\x94\xb7\x15\x92\x96\x38\xb7\xd5\x32\x58\x1b\xb8\x8f\xa4\x8e\x92\x31\xd9\x20\x65\xe0\xcf\xee\x09\x9d\x1b\xf0\x31\x7c\x28\x8c\x8e\xa6\x8a\xf0\xa5\x73\xf2\x84\x29\x5a\xe4\x9e\x3d\x71\x93\x2a\x2a\x2e\x15\xaf\xf7\x81\x03\x64\x44\xc6\x29\x70\x40\x9f\x53\x07\xb6\xf3\xff\xcb\xb0\x14\x84\x28\xb1\xd2\x1f\x7e\x6f\x84\xfe\x6e\x1a\xd5\x2b\x3f\xc4\xfa\x9a\x52\x7b\x40\xb6\xba\xf0\x30\x5c\x12\xc8\x35\x8b\xb6\x94\xc0\x4a\xd7\x82\xef\xf6\x5a\xd5\xdc\xb7\x00\xf1\x8c\xc4\x9b\x9a\x8d\x39\xae\x09\x7f\x4b\xed\x51\xce\x3f\x57\x9f\x6c\x3a\x09\x6b\xaa\xdb\xad\xcd\xa2\xa0\xdf\xad\xa2\x90\x6f\xf4\xd8\xa5\x7f\xaa\x96\xbe\xb0\x4b\x2f\xe7\x7e\x5f\xcd\xfd\xa2\xd2\x56\xa7\xb3\x45\x6f\x08\xe2\xc3\xce\xf8\x92\x6f\xa7\x53\xaf\xc0\xc8\x7b\xdb\xea\x99\xc6\x36\x0a\x7a\xab\x75\x1e\xeb\x2d\x54\x73\x78\xb7\xd9\xaf\x9a\x9e\xd4\xc5\xe1\x4a\x91\x94\xc4\xcb\x74\x9b\x85\x3f\xb2\x03\xe8\xbd\x52\xbd\x64\xeb\xba\x83\x96\xf0\x5a\xcd\xc2\x95\x73\x0b\x92\xe8\xcd\xd4\x6b\x41\xe1\x36\xfa\x18\xea\x74\x48\x55\x9e\x7e\x4a\xf7\x64\xe4\x55\x52\xdd\xb0\xc6\x03\x75\x85\xae\xd7\xb0\x49\xbc\x99\x0c\x76\x8d\xcf\xee\x56\xcb\x92\x4f\x3d\x5d\x5e\x8f\x65\xe1\xba\xb6\xe1\xab\xae\xd5\xa3\xea\xbc\xbe\xb2\x6a\x6a\x18\x57\xed\xe1\xaf\x7d\x0b\x14\xaf\x71\x44\x0e\xf4\x5a\xf5\x15\xb1\x6a\x2d\xcf\xc2\xba\x8c\x52\x1a\xf7\xd9\xce\x53\xbf\x76\x9e\xb7\x50\xff\x45\xa9\x63\x24\xa8\x9e\x94\x19\xef\x84\x30\xf7\x99\x99\x7b\xe3\x7a\x2f\x23\xd7\x7b\x7e\xc5\xd8\xc8\x77\x8d\xe7\x3d\xe9\xab\xc4\x95\xbe\x40\x42\x57\xba\x20\x41\x0d\x26\xba\x18\xc4\xfb\xc1\x23\x46\x6e\x41\xa8\x76\x63\x69\x2e\x3d\x70\x21\x09\x6d\x23\x80\x97\xf6\x32\xed\x86\xb4\x4e\x64\x42\x69\xdd\x28\x84\x0d\x6a\xc7\x80\x7d\xed\x25\x7b\x3e\x48\x32\x69\xb2\x52\x1a\xba\xb8\x9e\x02\x62\x65\xcc\x82\x60\x6d\xcf\xf1\x83\xe5\x7a\x6d\x4b\x8e\xdd\xf0\x3a\x33\x90\x26\x8c\xf0\xae\x5a\xff\xe9\xf5\x18\xe1\xc7\x6a\xee\xbb\x76\x73\x0d\xb7\x40\xcb\x15\x88\x1a\xcc\x3c\x59\x6e\xcf\xd6\xcc\xee\x74\x3e\x8a\x83\xb2\xfc\x51\xb5\xf0\x6b\xbb\xf9\xa6\xf7\x1b\x2c\xb9\x7f\xf8\x55\x72\x58\xf5\x9a\xd5\xc1\x51\x5d\x09\x7c\xc7\xee\x27\xb9\x85\x7f\x57\x93\x6e\xdc\xab\x1d\xd5\x1f\x33\xfb\xea\x78\x85\x14\x6b\x40\xaf\x3d\xa4\x8c\x36\x8a\xeb\x59\x2c\xfc\xe3\x66\xc4\xa8\xfc\xe5\x0b\xb4\x57\x58\xa6\x1e\x85\x52\x84\x8f\x5d\xf6\x63\x66\x6c\xb2\xed\x43\xe7\xcd\xf2\xd9\xb5\x74\x99\xf4\x2c\xae\x2a\xe7\xbc\xfd\x8a\x32\x2f\x6b\x65\x3e\xd7\xca\xfc\x7a\x39\x75\x79\xdb\xc3\x9a\xdc\x24\x7f\x5a\xee\x94\x29\xc1\x5e\x35\x14\xf8\xe9\x8f\xd9\x23\xe5\xa4\xd9\x12\x9d\x7f\x45\x77\x2a\x0e\x9a\x1f\xd9\x00\xb5\xd7\x04\x50\xcf\xab\x44\x12\x40\x6d\xe9\xce\xb5\x7a\x5b\x7a\xe3\x4b\x72\xa6\x9a\x75\xaa\x34\xc3\x2e\xd1\x32\xf3\xa5\xd5\x4e\x6a\x3d\xcf\x91\xc8\xe7\x0d\xd1\x7e\xbe\x2f\x4c\xd3\x3e\xcb\xdd\x81\x7f\x90\x1f\x69\x95\x4c\x0f\x3f\x38\xbe\xd2\x41\x81\xac\xe1\x7d\x8e\x77\xcd\x90\x7c\x70\xd4\xdf\x97\xc7\xb6\x13\x70\x32\xa7\x70\xeb\x67\xbe\x40\x02\xae\x76\xe2\xbf\xce\x9a\x6c\x47\x3a\x1d\x94\x25\xf4\x6d\x53\x1f\xdb\x86\x66\xb5\x6f\xea\x98\x9c\xb7\x6b\xdf\x34\xf4\xc6\x6d\x28\xe5\xf5\xe8\x63\x6d\x5b\x1a\xef\x0a\xe5\xb9\x30\xed\xb6\xdb\xa6\x8d\x4c\x3e\x96\x22\xcd\x52\x90\x6c\x07\xd8\xa9\x1a\x7d\xa3\xcb\x91\xa4\x62\xec\x03\xe7\x16\x1a\xbf\xa8\xb9\xeb\x2f\xeb\x0d\x7e\xa8\x21\x91\xd2\x04\xca\xde\x73\xcf\x9a\xae\x52\x52\xf5\x3a\x11\x7d\x2d\x5c\x5b\x1c\xf8\x63\x68\xdf\xc4\x55\x56\x41\xfa\xa1\x6a\x96\x79\x2b\x1e\xb8\x41\xcb\x8b\xee\x44\xde\x97\x8e\x8e\xc9\x3a\xec\x32\x76\x94\x59\x50\x29\xd5\xb2\x77\xc1\xb3\x5f\x79\x7f\x18\xf8\x4d\x86\x26\xf9\x92\xe1\x91\x76\x54\x28\x2c\xbd\x9f\x98\x9e\x55\xc2\xbb\x96\x83\x90\xa1\x86\xf7\x51\x83\x9e\x8f\xf0\xeb\x77\x0d\xea\x9c\xbe\x5a\x78\x4d\x04\xfd\x80\x46\x50\x62\x01\x8f\x86\xfd\x45\x8d\x54\xbf\xba\xa4\xf6\xe5\x8f\x71\x78\xd2\x68\x8c\x25\x99\x17\x40\x1f\x21\x5e\x3d\xa5\xfa\x10\xb4\x4f\x89\xd4\x6f\xbc\x16\x26\xdf\xae\x81\x92\xdc\x59\x37\xc2\xca\x31\x17\x3a\xb4\x50\xaf\x97\x19\x45\xa9\x8a\xd1\x73\xcc\x93\x81\xba\x19\x07\x56\x32\xc4\xf3\x10\x8e\x33\xe8\x07\x5a\xe7\x87\x96\x2f\x27\xe5\xce\xbf\x84\x53\x27\x69\x78\xc5\xa4\xea\xb5\x53\xfa\x2f\x5d\x7e\x26\x22\xb1\xde\x4b\x96\xfe\x29\xd5\xbb\x2b\xa5\xac\x6f\x29\x47\x1d\x67\xfa\xfe\x6a\x4c\x58\x91\xb9\xab\x55\x60\x89\x66\x3d\x4b\xa7\xdb\x28\x66\x4d\x80\xcc\xd5\x6c\xa5\xf5\x1c\x14\x1a\xe7\xb1\x80\x6f\xb9\xde\x72\xaa\x20\x0d\x43\x41\xfc\x39\x99\x63\xd2\x33\x57\x82\x23\xe2\x41\x56\x13\xef\xc8\xe8\x62\x7a\x00\x91\x58\xcb\x26\xde\xf2\xc8\xeb\xaa\x18\x08\xeb\xdf\x00\x67\x24\x7e\xb3\xa5\x17\x04\x5d\xc6\xea\xed\x85\xf6\x9b\xdd\x50\x3a\x90\xb5\x3c\xd5\xb6\xb7\x82\xf5\x76\xd7\x71\x42\x7c\xbe\xc7\x88\xf1\xd0\xbf\xbb\x30\x1b\xf0\x6d\xfd\xa0\xca\xfc\x0a\xc3\x48\x9a\x3f\xa4\xd3\xa8\x1e\x74\xde\x74\x7b\x22\x79\x3d\x9f\x07\xe9\x7d\x1f\x75\xa1\xba\x81\xf2\x15\x64\x8b\x52\xf3\x55\x95\xa4\x01\x09\x63\x9c\x7d\xc1\xc6\x56\xfe\xa1\x59\x16\x95\x59\x74\xb9\xf2\x5e\xb4\x7c\xef\x1f\xf3\x46\xf7\x8f\xe8\x05\x8d\xee\xf8\xcb\x77\x42\x00\xd1\xac\x97\x56\x9c\xdb\x68\xd9\x5c\x55\x32\x82\xc5\xb4\xa4\x64\xcd\x9d\x7e\x68\x28\xed\x41\xd9\xff\x09\x3a\x11\xb1\xdf\xfe\x9a\x37\x17\xde\x6b\x2a\xfc\x52\xb0\xf6\xe1\xe1\x8d\x4e\xbb\x52\xc3\x78\x69\x0e\xd0\xb3\x4a\x6d\x0a\x50\x7e\xb8\xec\xe8\x49\x11\x7d\x09\x07\x08\x48\xdd\x8d\x5b\x70\x44\x0d\x51\xc4\x08\x4c\x11\x5a\xf0\x59\x62\x9e\x61\xea\xb4\xdb\x2c\x23\x7f\x80\xc6\xc7\x53\x08\x8b\xd8\xb5\x26\x62\x5a\xc7\x7b\xe5\x78\x8c\x1b\x2a\x9b\x97\x19\xad\xce\x1f\x74\x4d\x09\x4b\x2c\xb6\x84\x57\x97\x94\xd6\x01\xa9\x65\x35\xc0\x3c\xf3\xed\xdb\x41\x80\x0e\x7a\xaf\xc1\xcc\x14\xdb\xa2\xf7\xe6\x83\xfa\xd4\xc4\xfd\x51\xb2\x26\x7e\x73\x4b\x7a\x24\xa6\xcc\x30\x37\x02\x9d\x9d\x06\xf0\xdd\x3f\x9f\x86\x51\x60\x39\xa9\xb0\xe6\x61\xb2\x62\x5c\xf6\x83\x34\x35\x88\x2b\x35\xe4\x2c\x0f\x08\x4d\xc0\x76\xe9\x3b\x35\x5f\x25\x22\x98\x01\x78\x88\xe0\x65\x20\x04\xf0\x49\xf4\x58\xf4\xb1\xf6\x43\x42\xb8\x43\xf9\xad\x63\xa6\x1b\xf3\xd8\x81\x7f\x57\x0b\x74\x70\x80\x46\xca\x2c\x8a\x95\x18\x19\xdd\xc8\x95\xc9\x71\x2f\x9c\xa1\xad\x6d\x06\x79\x74\x10\xf3\x4a\xf7\x3a\x39\x1a\xd7\x3f\x42\x6f\xe8\x43\xbc\xf2\xc2\xc7\x56\xd1\xd5\x86\x08\xd2\x79\x82\x1d\x2a\x8a\x67\x00\xed\x1c\x1f\xfa\x5c\xeb\xf2\xb5\x9b\x6d\x36\xe3\x3f\xf9\x8e\x13\xf7\x82\x6c\xe8\xcf\x29\xdd\x55\x0e\x21\xba\xed\xa2\xdd\x1d\xdb\x1f\xce\x18\x88\xa6\x0b\x31\x78\x01\x58\xbf\x9a\x0d\x2b\x40\xe5\x05\xd5\x84\x95\x76\xa3\xcd\xda\x93\x36\xdd\xfb\x6c\x6c\xfc\xc9\x9a\x8c\x7f\xfd\xe2\x09\x87\x42\x6d\xf3\xa5\xaf\x82\x4c\x84\xd7\x8e\x92\x91\x9f\x4d\xcb\xa9\xa4\x94\xec\xa0\xdd\x5d\xeb\x76\x5f\x8b\x6e\xfb\xa8\xed\x76\xdb\x87\x71\xbb\x5f\x6e\xc6\x59\xd5\x17\x26\xba\xed\x41\x22\x56\x2f\xb9\x74\x1d\x01\x5b\x69\x0a\xc0\xa2\x76\x0c\x3e\x62\x60\xca\xef\x0a\x36\x92\x57\x6f\x21\x4a\x5f\x21\x5b\xfb\xe6\x5a\xf7\x30\x3e\x3e\x0e\x9c\x76\x37\xee\xb6\x5d\xfc\xba\x09\xa3\xf1\xe9\x89\x0d\x9d\xa7\x0f\xdd\xe8\xfa\xdd\x76\x1f\xb3\xaa\x89\xa5\x53\xc1\x31\x55\x38\xce\xf1\xb1\x58\xe3\x6b\x50\x0f\x50\x96\xae\xbb\xc6\x39\x91\x20\x6b\x83\xb5\x9b\x37\xd7\xbc\x35\x48\x35\x95\xcf\x79\xde\x35\xa8\x0e\xcd\xb7\x4d\x23\x7d\x79\x13\x87\xfe\x95\xd3\xd0\x3f\x89\x82\x3e\xde\x53\xc2\x7a\x9e\x87\x62\xba\xe6\x24\x27\x1f\xdd\xb5\x2b\xec\xcc\x14\xa7\x66\x01\x21\x74\x9c\xe0\x64\x83\xa9\x19\xe3\x14\x10\x16\x20\xab\x69\x39\xea\x11\xc4\xdc\xd8\x6a\x97\x11\x33\x8a\xe8\x53\x59\x43\x1b\x41\xc7\x1d\x68\x0c\x05\x42\x38\xf1\xaa\x1d\x67\x32\x68\xb7\xe9\xf9\xb9\xb5\xa2\xa0\x0e\xc0\x18\xf1\x41\x3e\x6c\xba\xdb\xc6\xee\xc2\xc8\xd8\x1a\x4e\x0b\xcc\xca\x4d\x28\x11\x0e\xda\xf8\x1d\xc0\xf7\xb1\x82\x3a\xa8\x01\x72\x43\x37\x29\x05\xab\xb8\x9b\xa6\xfe\x65\x49\x7b\xf4\x3e\x26\x61\x0c\x75\x96\x28\x3a\x0d\xf1\x05\xe5\xb5\xab\x35\x35\xe1\x50\x4c\x71\x2d\x86\x3e\x83\xe6\xdc\x35\x9c\x03\xaf\x2d\xbb\x03\x93\xa2\x0f\xd9\xe3\x39\x4c\x8f\x9c\xce\x4b\x7e\xee\x3b\xcb\x17\x60\x6f\x7c\x67\xc8\xce\x4c\x09\x98\x52\xd7\x30\xd9\x11\xba\x54\x05\x94\x75\xa9\xe0\x95\x4f\xd9\xd3\xd0\xb9\xd4\x57\x63\x97\x1a\xff\x5c\x5a\x72\xe4\x1a\x65\xa8\x45\x6e\x0a\xed\xb9\x03\xa9\x35\x97\xd6\xec\xbc\x35\x98\xe2\x0b\xf2\x0c\xdf\x7e\xef\xa2\x6b\x72\x3a\x51\x99\x4e\xcb\x09\x97\xb2\x21\xfd\xa0\xd3\x79\xfb\x24\xba\xbf\xa2\x5d\x83\xd7\x4d\x13\xcd\x1d\xc0\x86\x3d\x6a\x01\x09\x8f\x4a\xd5\x27\x5f\xac\xfa\xfa\x31\x6d\x9a\x01\x95\x31\x43\xdd\x12\x45\x5b\xc2\xeb\x6b\x68\x3d\x8b\xd2\xbb\x0b\xf4\xd7\x13\x4d\xdd\x01\x7b\x83\xd4\x2f\x3d\x0b\xac\x29\xad\x76\x16\x00\x51\xe5\x6b\x7f\x5a\xf4\x9e\xaf\x8a\xf0\xc2\x3e\x5d\x93\xe0\xae\x93\x89\x66\x13\xa2\xea\x33\x5d\x93\x24\xb3\x30\xcb\x90\x51\xa0\x74\xe0\x1c\x7b\x3a\x06\x5d\x4e\x49\x37\xed\x92\xcc\xb3\x4e\x34\x38\xe4\x97\x6d\xed\x24\xe3\x9d\xae\xdb\xd2\xd2\xad\xed\xac\x34\xe8\x53\xd6\x9a\x66\x66\x32\xb7\xa4\x5a\xb5\x21\xcd\x5a\xde\x4d\x30\xf6\x34\xa4\x77\x0b\xb0\x49\x95\x3f\x03\x0c\x1c\xf8\x29\x7a\x9b\x52\x63\x27\xc5\x80\x6a\x7d\xc8\x6e\x85\xbd\x49\x94\x9c\xf8\x11\xbd\x9e\x03\x27\x41\xa8\xbd\x01\x39\xda\x1d\x50\x88\xcc\x2e\x6e\x66\xc0\xe2\xf8\xfe\x43\xe9\x18\x68\xb3\x3f\xe4\xa1\xcc\x34\x77\xfb\x2e\xfa\x75\x23\x82\xac\x9f\xf3\xdc\xb4\x23\x7b\x1c\x0d\x32\x0f\x76\xcd\x42\xdb\x48\x96\xa4\x1b\x1c\x6f\x6e\x8b\x2b\xa7\x61\xe4\x26\xdf\x3a\x6a\x43\xe8\x24\x39\xb3\x71\xec\x2a\xc7\x25\xcf\x09\x13\x60\xdd\x59\x34\xd3\x6d\x97\x4d\x74\xdb\x99\x60\x17\x15\x08\x3b\xfe\x22\x21\x53\x39\xb0\x83\xde\xcc\x27\x5f\x51\x45\x71\x8a\xe2\x00\xdb\x58\xe6\x9c\xfa\x21\xd2\xcb\xfa\x9d\xdf\xf1\xb2\xb9\xcf\xd0\x57\x1e\xa7\x54\xd6\xa7\xa1\xd4\x11\x45\x5e\xec\x31\x8a\x26\xac\x0b\xc2\xa7\x5f\xd9\x45\xba\x60\x7a\x46\xee\x2d\x66\x75\x96\xe0\x95\x3d\x47\xcb\x58\x2f\xb0\x9a\xdb\xaf\x4c\xa7\x25\xfa\xb7\xe3\x5f\xc7\x8e\xba\xef\xb2\x59\xb3\x97\x7e\x45\x9c\xa5\x5f\x1b\x3d\x23\x3d\xcb\x4a\xce\x3d\x7f\x49\x5c\x61\x10\x0a\xed\x5c\xe5\x6d\x44\x5f\x2e\x00\xa7\x65\xac\x42\xf6\x62\xe9\x46\xc9\xc1\xb7\xc1\xb4\x7b\x7f\x97\x20\xb9\x85\xf2\x03\xbc\xf8\x43\xe6\x4b\x1a\xd5\xc8\x07\xa2\xa8\x8c\x94\xc0\x6a\x4b\x32\x38\xc5\x95\x37\x12\xba\x48\x61\xc3\xf2\xb5\x28\x75\x97\xea\x5b\x77\xa9\x6d\x32\x31\x51\x0a\x2e\x8e\x8f\x6a\x03\x18\xe1\x6a\xff\xe1\x19\xfa\x40\xa5\x01\x44\x1c\xdf\x79\x41\xc5\xa3\x83\x08\x9d\xcb\x44\x47\x7c\x8e\xda\x58\xb6\x83\x64\x8c\x6c\xb8\x24\xae\x29\x27\xc4\xbc\x6a\xde\x42\xba\x74\x48\x26\x6a\xcc\xbb\x64\x85\x62\x4c\xe3\x52\xdb\x14\x05\x05\xc9\x4b\xe6\x29\xae\x14\x51\x91\xf6\x98\x47\x3a\x32\x99\x67\x29\x8d\xc8\xa7\x16\x60\xa7\xa0\xbd\x79\x69\x13\x05\xd4\x95\xd2\xd0\x3e\xb0\x2d\x65\x8c\xb2\xac\x79\xc6\x21\xb1\xb4\x0b\x98\x30\x4f\xb8\x25\x00\xd8\x80\x35\x9a\x5e\xcb\x7d\xe0\xdb\xde\xef\x8f\x79\x9a\xd5\xde\x9c\xdf\xc5\x0c\xd6\x35\x86\x0d\x8f\xfa\x85\x5b\xeb\xde\xa2\x11\xe2\xeb\x4f\xcc\x68\x19\x8d\x05\xff\x4f\xbe\x28\x5f\x30\x7c\x7e\xc9\x45\x6c\x29\xe6\x41\x5f\x72\x2f\xf1\xff\x75\xf9\x2c\xba\x69\xcd\x1c\x64\xf7\xdd\x0d\xb4\x27\x07\xa4\x80\x1a\xad\x8d\x8f\xa9\x20\x97\x13\x37\x48\x12\x5f\xdb\x9b\x88\xdc\x9b\x6d\x6d\x2b\xe6\xc9\xb8\x89\x50\x76\xa1\xaa\x55\xa8\x1c\x05\x0d\x6c\x2f\x53\x6f\x74\x18\xe1\xdd\x96\x6c\x33\xe8\xbb\x7b\xd9\x76\x3a\x40\xd1\x30\xc7\x27\x74\x3c\x7a\x47\x67\x59\xb0\xf6\xd1\x2f\x2f\x5b\xba\x5d\x61\x9c\xc0\x62\x74\x57\x2c\x02\x98\xd9\x77\xa2\x07\x1c\xbe\x9f\x47\x22\x73\x7e\x12\xbd\x7d\xba\x52\x74\x60\xf6\x18\xa4\xcc\xc3\xe1\x29\xc4\xb2\x27\x78\x27\xf2\x93\x64\x92\x77\x7c\x38\xa8\x88\x04\x64\xf7\x30\xf8\x00\xe8\x7f\xf6\x18\x43\x0f\xd3\x34\x49\xd9\x1b\x0c\xee\xa8\x1e\xb0\xb7\xf8\xf5\xd4\x07\x5a\xf9\x33\x86\xf6\xe8\x26\x8c\x7d\xc2\xb0\x6c\x8a\xfd\x84\xe1\x17\xc1\xe4\xe1\xc5\x9c\xbd\xc7\xf0\x4b\xba\xbe\x62\x8f\x30\x8c\xf7\xd9\xb2\xda\xe7\xe8\x27\xa7\xdc\x9b\xec\x86\xcf\x3f\xd9\xdf\xef\x7c\xee\xbc\xc3\x22\xe7\x70\x78\x25\xe7\x00\x0a\xef\xfc\xde\x28\x19\x12\x74\xb3\x0f\x3e\x7f\x63\xe5\xee\x89\x44\xb5\xf2\xa3\xcf\x01\x2a\x35\x65\x01\xc3\xce\xf8\x0d\x1f\x15\x87\xf6\xcf\xe3\x67\x69\x32\x0f\x52\x71\xc9\x44\x86\xd6\xdd\x94\x62\x0a\xa6\x19\xb4\x75\xcc\x92\x0c\x0f\xe6\xf6\xef\xda\xdd\xb9\xef\xc4\x59\x49\xa7\x6f\xe8\x9c\x85\xa1\x5f\xdd\xde\x37\x03\x67\xc0\x0f\x0f\x0f\x1d\xb7\x58\x83\x85\x5d\xeb\x75\x55\xc4\x91\xbb\x31\x41\xba\x1e\x72\xe0\x69\x7e\x03\x7a\x12\x66\x7c\x0f\x48\x87\x4c\xcf\xf6\x3d\xf2\x38\x88\x62\xbf\x8c\xf9\x94\x06\x7f\xc3\xac\xd3\x21\xc9\x60\x86\xf2\x22\x3a\x83\x21\x87\x9f\xb1\x2c\xe3\x6f\xfd\xde\x30\x08\x23\x96\x63\x15\xc3\x08\x28\x8e\x57\xe1\x2c\x48\x72\xc1\x86\x94\x38\x8e\x12\x98\xd7\x88\xaa\x82\xbf\x30\x9b\x93\x40\x3c\xd3\x53\xb4\x3f\x46\xdf\x6d\x19\x9b\x67\xfc\xb9\x7c\x4d\x8a\x8d\x69\x06\xe6\x6a\x56\x76\x33\x94\xfd\x07\x29\x72\x3a\x6c\x4a\xb5\x4c\xb1\x25\x60\xab\xa1\xe4\x34\x63\x23\xfc\xca\x02\xa1\x5b\x9d\x51\x4d\x52\x1f\x80\x9d\x51\x81\x33\xcc\xf2\x1a\xb8\x85\xef\x69\x88\x50\xee\x2c\x63\x13\x4a\x9a\x60\xd2\xdb\xc0\x3f\x7d\xea\xcf\x21\x7e\x92\xb1\xcb\xcc\xd6\x0b\xc3\x13\x5c\x02\x36\x64\xc6\xab\x0a\x12\xc5\x7d\xf7\x5b\x5d\x91\x50\x3e\x32\x85\xa3\xe6\x67\x0b\x36\xee\x26\xec\x20\x48\x52\x07\x7b\x0a\x88\xca\x08\x23\x00\xe4\x1f\x52\xc3\xf0\x17\x00\x0d\x11\xab\xac\xe8\x61\xc6\xee\x53\xc2\x7d\x9a\xa3\x61\x1a\x00\xc0\x43\xfc\xfd\x8c\x9d\x60\x1f\xc3\x6c\x27\x8c\x43\xd8\x03\x17\x94\xeb\x82\x72\x9d\x06\x97\xf8\x06\xd0\x45\xc6\x5e\xd0\x5c\xcf\xfc\x0b\x76\x2c\x43\x61\xcc\xce\x29\x27\xfc\xbd\xe7\xf7\x62\x82\xd5\xf3\x8c\x3d\xa5\x48\xf8\xfb\xd9\x37\x75\xa2\x82\x43\xc6\x5e\x61\x33\x24\x6e\xdc\x05\x50\xde\xa7\x6a\x52\x1f\xa0\x7c\xc6\x9e\x51\xf6\xbd\x87\x8f\xee\xbe\xda\x7d\xf3\xf0\x78\x77\x6f\x67\x77\x6f\xf7\xd5\x7b\xf6\x92\xe2\x9f\xed\xbf\xdc\xad\xc6\xef\x51\xe1\x79\x72\xee\xdc\x62\xb7\x6f\xe1\xeb\xb4\x0f\xa0\xd9\x0c\x7e\x77\xf1\x97\x1e\xd1\x39\xcd\xf8\x65\x36\xb8\xcc\x7a\xf7\xde\xbf\x7a\xf8\xf2\xf8\xd9\xc3\x17\xc7\x0f\x9f\x3c\x7c\xfa\x70\xef\x95\xb7\xc9\xee\x5a\x15\x7c\x7b\x1b\x2b\x78\x92\xf1\x89\x82\x42\x58\xa4\xd7\x59\xe9\x71\x0c\x85\xd1\x2d\x6b\xc9\x5e\x67\x96\x87\x49\xde\xc2\x9b\xf9\xde\xdb\x30\x7e\xf1\x8a\x76\x38\x8c\x55\x3b\x8e\x7c\xe1\x32\x95\x97\xfc\x4c\xf2\xa5\x1b\x6d\xd8\xcb\xe8\xb2\xb2\x8f\x40\x00\x39\x61\x26\xf8\x16\x2a\xc1\xbc\xd3\xeb\xf3\x40\x6d\xfc\x9d\xd4\x9f\xe0\xaf\xe3\x1a\xf5\x98\x92\xaa\x53\x25\x5b\x5b\x0b\x55\x8f\x75\x9f\xc5\x5b\xe3\xac\xce\xb3\x6e\xb9\x95\xb2\x95\xdc\x9b\x70\x62\x92\xb5\xc3\xb2\x7c\x89\x5f\x49\x46\xda\xbb\x0f\xc4\x8d\x92\xc3\x78\x27\x82\x59\x92\x1f\xef\x42\x30\x2d\x35\x00\x76\x9b\x29\xd1\x91\x77\x75\x8c\xae\x60\x09\xed\x7e\xac\x40\x7f\x79\x75\xe2\x94\x40\x6c\xd2\xe5\x59\x23\xbd\x61\x5e\x09\xeb\x56\x2d\xd6\x42\x77\xdc\x18\xfd\x4a\x0a\x7a\x3f\x2f\x45\x31\x81\x39\x08\x16\xb8\x33\x76\x32\xfe\x24\x1b\x58\xd7\x08\xe5\x09\xfd\x24\x23\x45\x49\xe2\x72\x83\x85\xb7\xef\xf7\x7d\x74\x0c\xfa\x63\x4c\xb8\xe9\xcc\x2e\x55\xfa\x8d\x45\xef\xa8\x4f\xb4\x27\x5b\x00\x36\x12\x14\x9e\x66\x2e\xf9\x2c\x8b\xbf\x39\x45\x4f\xc6\x6a\xdb\x0a\xc9\x5a\x99\xfb\x24\x88\xbd\x44\x3d\xec\x4d\xb4\xe5\x0c\xa9\x6d\x15\x17\x50\x5c\x79\xe3\xd5\x42\xda\xd4\x91\x45\xce\xb0\x48\x8a\x1c\x92\x2e\x70\xa6\x5c\x92\xa2\x59\x9a\x07\x84\xb7\x54\x56\xa7\xf9\xb9\x97\xf1\xfb\x19\xa2\xb0\x4a\xdf\x35\xa6\x80\xb2\xef\x91\x5f\x29\x4b\xb1\xc7\xb5\xe9\xb1\x27\x07\x75\x4e\x31\xf3\xae\xcf\xde\x64\x75\xc5\x56\xa0\x3d\x80\x0c\xde\x5c\xd2\x48\xb4\xe4\x95\xa4\x1f\x1f\xf2\x8f\xeb\x4e\xb2\x2e\xd4\x45\x52\xc2\xc2\xed\x4d\x5a\xe3\x6e\x37\xd8\xe6\xaf\x8d\x08\x56\xb2\x70\x41\x59\xe3\x4e\x46\x75\xd1\x22\xbe\xcd\x78\x9c\x3a\xf6\x22\x92\x0c\xdc\xdc\x89\xc6\xee\x00\xaa\x43\xdb\x7c\x7a\x09\x70\x0b\x88\xca\xcf\x5f\x2e\x42\xea\xc1\xea\x35\x56\x59\x10\x09\x35\x97\x7d\x6a\x2e\x4a\x77\xa3\x90\xfc\x53\xc6\xb3\xd4\x49\x63\x97\xbd\xa7\x50\x42\x6a\x0b\xec\xd1\xaa\x52\x83\x4d\x6f\xcb\xb4\xb3\x58\xb6\x6e\x3a\x38\x40\xf5\x44\x6c\xf8\x79\xc6\xcf\x01\x02\x97\x72\xd0\xaa\xdf\xf3\x5d\x5c\x11\x3c\x92\x00\xb4\xd9\x8d\x8c\x3f\xb4\xf3\x5e\xaf\x01\x63\xab\xcf\x7c\x22\x05\x98\xbe\x44\x21\x00\xef\x2f\x42\xde\x50\xcb\x4a\xdd\xbc\xd6\x87\x4c\x6b\x14\x49\x98\x7b\x97\xf1\xa7\x8d\x3d\x69\xf2\x21\x4b\xa4\xe3\xa2\x8f\xf7\x80\x1b\x17\x1b\xa8\x6f\x87\x8f\xff\xbe\xc2\xf3\x94\xbc\x50\xbd\x6a\xec\x4c\x45\xe3\x49\x35\xfb\x21\xe3\x51\x15\x72\x95\x07\xa2\x8a\x9f\xcc\xaa\x47\x4b\xdc\xc0\xc4\x51\xec\x8f\x61\xf7\xe2\xe9\x2b\xa5\xe6\x11\xdd\x06\x20\xd1\x60\xf9\xa1\x89\x07\x01\x47\x83\x95\x28\xa3\x76\x63\x8f\x3c\x74\x2e\xe0\x87\xfd\x98\xf1\x34\x75\xe6\x00\x02\x41\xce\x2f\x96\x7a\x11\xb8\xba\x31\x5b\x81\x20\xae\xdf\x52\xad\x70\x38\x5d\x55\x25\x28\x8a\x26\x25\x5d\x58\x51\x5a\x62\x80\x62\x72\xab\xe9\x49\x9f\x92\x17\x99\xd4\x3c\x5a\x78\x0f\x52\x26\x72\xec\xe4\x0e\x5e\xe3\xe4\x3c\x5c\x06\x4d\x73\xbd\x0e\x78\x3f\x79\x92\x9c\xeb\xdb\x3a\xe0\x06\xf0\x15\xba\x95\x97\x79\xc2\x5c\xe6\x79\x82\x94\x04\xae\xab\x9d\xea\x6a\xaf\x4b\x49\x6c\xad\x21\x58\xc8\xef\x5b\xfc\x55\xe6\xdc\x15\xdd\xf6\xe6\xf7\xe4\xb9\x74\xe6\xf3\xe6\x9a\x9a\xfd\x55\x02\x06\xf2\xe4\x0b\x94\xf8\xf2\x64\xc0\x1f\x92\x10\x45\xde\x0b\x01\x68\x3f\x2d\x45\x34\x5b\xdf\x79\x5b\x28\x21\x90\xc0\x93\x7c\xb9\xcf\xc7\x2b\xfa\xcc\xc2\x2f\x97\x5d\x53\x92\xe7\xaf\x99\x44\xeb\x19\x2d\x5b\x8b\xe4\x23\x3a\x97\xb5\x1e\x3c\x9a\x54\xd3\xe2\x15\x69\x36\xc4\xf1\x09\x7b\x6c\xd5\x71\xd0\x1e\x05\x51\x20\x82\xf6\x11\x7f\x23\x2a\x29\x88\x57\xf8\xdb\x5a\x1c\x30\x12\xfc\x73\x2d\x0e\x4e\x20\xfe\x49\xb0\xf7\x76\x1c\x22\x36\xfe\x1c\x28\x73\x65\x54\xc0\x1f\x0b\xe4\xc7\xc7\x40\x21\xf0\x1b\x09\x06\xd3\x4b\xfe\x8e\x02\x59\x16\x4e\x62\xfe\x63\x86\x61\xc1\xf7\x31\xee\x24\x00\x66\x22\xe0\x1f\x28\x0c\xec\x0f\xff\x51\x87\xee\xc2\x12\x07\xa1\xfa\xf8\x29\xb8\xe4\x02\x3f\xb4\xb7\x7e\xfe\xd4\x67\x42\x8a\x48\xf8\xc3\x84\x82\x79\x7c\xca\x9f\xa4\x18\x04\x1a\xcd\x1f\x0a\xfe\x5a\x7e\x90\x2b\x10\xc1\x5f\x51\x81\x24\x8f\xc5\xbd\x4b\xfe\x16\xfb\x20\xe9\x2d\x7e\x8f\xea\xcd\x53\xe8\x66\x6c\x82\xe4\xed\x9e\xa7\xf8\x3d\x0a\x4e\xa0\xd4\x30\xe0\x89\xfc\x92\x1c\x27\x7f\xac\xbe\x60\x98\xa1\x0c\x46\xfe\x25\xf7\x29\x18\x22\xbf\x13\x60\x99\x8f\xd8\x07\x74\xbb\xcf\x77\x74\x48\x56\x7d\xaf\xf2\xf9\x16\x6f\x18\xf9\x63\x1d\x27\x3f\xdf\xe0\xe7\x38\x84\x79\x78\xab\x42\x38\xa7\x7b\x38\xda\x31\x90\x5e\x22\x88\xf9\xfb\xb4\xfc\x78\x10\x04\x73\xfe\x48\x46\x24\xe7\x3c\x0b\x55\x48\xb6\x97\xd3\x67\x92\x3e\x84\x35\xe2\x77\x93\xf2\x43\x26\x3f\x51\x31\xbb\x31\xff\x1c\xea\xa0\x4c\xfa\xa4\xbe\x81\xad\xe4\x3f\x95\x61\x99\xf8\x9e\x22\xd4\x5e\xc8\xf8\x23\xfc\x9c\xa4\x49\x3e\x87\x49\xfe\x8c\x93\x4c\xf2\x58\xf8\xf8\x24\x3f\x42\x11\xfa\x11\xbf\x91\xd2\x87\x40\x57\x29\x54\x92\xbf\x93\x31\x67\xc0\x9e\xf1\x1b\xa1\x0c\x27\xa7\x01\x7f\x8d\xfd\x42\x96\x84\x07\xb9\x0a\xed\xa2\xeb\x60\x86\xd6\x02\x73\xfe\x31\x91\x81\x37\x88\xd4\x33\xfe\x41\xc6\x03\xa1\x0b\x1f\xcf\xfc\xf2\x43\xf3\xc3\xfc\x25\x45\x06\xb3\x24\xfc\x1c\xf0\x21\x65\x0f\xd2\x49\xc0\x05\xd6\x3e\x0b\x2f\x00\x9c\xf6\x30\x4b\x1c\x4c\x10\x36\x22\xcc\x91\xcc\x42\xc1\x7f\xa4\x10\x2e\xe9\x1c\x43\x73\x3f\x44\x36\xda\xa7\x60\x4a\x83\x1a\x87\xe5\x87\x9c\x9c\xa9\x89\xa1\x31\x3e\xc2\x29\x40\xb9\x04\x17\x54\x2e\xca\x21\xb8\x83\x23\xd0\x8c\x29\x3f\xf5\xad\xaf\xfd\x31\xbf\x4b\xdf\x88\xed\x82\x44\x85\xee\x02\xc2\xc6\x30\xb0\x51\xd0\xef\x27\x98\x01\xe0\x38\x9d\xf0\x51\x48\x41\xa4\x7d\xf9\x1b\xca\x01\xc3\x3c\x03\xfa\x58\x86\x33\x00\x67\x0c\x65\x53\xe0\xc6\x01\xba\x3e\xd3\x07\x22\x21\x9e\x50\x10\xc8\x76\x58\xa7\xf7\x65\x18\x77\xe0\x23\xfa\x9c\x43\x0b\x23\x3e\xc3\x06\xf0\x29\x08\x9e\x25\x2a\xa4\x60\xab\xf2\x29\x81\x77\xa8\xe3\xe4\x67\x24\x3f\xe7\xfc\x3e\x05\xa6\x80\x3e\x04\x44\x9f\x85\xf2\x2b\xe7\x27\x14\x1f\x22\xcf\xf4\x1a\xc7\x24\x12\xe2\x62\xf9\x47\xca\x91\x3c\x8b\x60\xa7\x4b\xc2\x9e\xef\x50\x14\x8c\x3f\x03\x48\x9c\xf1\x14\xb3\xe7\x31\xce\xf0\x3c\x91\xc1\x4f\x7c\x2c\x43\x9f\xc3\x39\x9f\x62\xf0\x4c\x02\x48\xe2\x9b\x30\x80\x51\x88\x5f\xe7\x53\xd8\xaa\xfc\x39\x66\xc2\xdb\x4e\x60\xf7\xf9\x8c\x3e\x52\xe8\xed\x04\x9b\xba\x00\x54\x7a\x86\x51\x58\xdb\x44\x05\x54\x5f\x2e\x09\x5d\x01\x42\xa2\x3d\x47\x9b\x6c\x98\x44\x11\x26\x11\x6c\x22\x2e\x4a\xb2\x40\xa6\x04\x66\xef\x05\xd5\x8d\x17\x5c\xc0\xfe\x1d\x49\xcc\x88\xc6\xfb\x00\x7a\x81\xc4\x70\xb3\x00\xba\x34\x52\x1b\x2b\xb1\xda\xcc\x02\x6a\x64\x4f\xce\x6b\x18\xc9\xc5\xc5\xb1\xe7\x01\x8e\x7e\xcf\x77\x04\x32\x36\x88\x6a\x91\xad\x13\xfc\x9c\x10\x20\xf0\x9e\x11\x9e\x41\xc0\x36\xd1\xe7\x3c\x14\x7e\x84\x9b\x21\xa3\x64\xf4\x32\xcd\x2f\x43\x1d\x24\x9c\xf2\x50\x61\x41\xc0\x8b\x3c\xc7\x5c\xd0\xd7\xec\x2d\xcc\x15\x1f\xd2\x17\xb1\x88\x3c\x2a\xc3\x52\x24\xc6\xe7\x14\x03\x5b\x1a\xb6\x1d\xa1\x17\xc4\xef\x0f\x74\x48\xde\xf5\x7c\x4e\xd5\x27\x62\xf8\x37\xa1\xfa\x78\xe2\x03\xb4\xee\x26\xd6\x97\xcc\xfd\x29\xb5\xa2\xb0\xc4\x5b\x5d\xe2\x2d\xad\xe2\xa9\x2c\x92\x42\xe9\x9f\x30\x2b\x9e\x61\xcf\x09\x9b\x8c\x80\x0d\x0e\x61\x83\xed\xfb\x84\x5b\x86\x51\x3e\x42\x14\x91\x30\xf3\x6c\x0b\x7f\x4e\x28\x08\xa5\xd2\x92\x69\xe6\xf7\x43\x15\x81\x70\x78\x83\xd6\x26\xbb\x27\x55\xb6\xf8\x89\x4c\x43\x09\x22\xbf\x90\x61\x65\xa0\xc2\x5f\xa8\x4f\x98\xf3\x4b\x7e\xac\x3e\x3e\xe5\x80\x21\xce\xd5\x07\xca\x0c\xf8\x53\xf9\x21\xa5\x25\xfc\x9d\xac\x5e\x0b\x1f\xf9\x2b\x99\xfa\x14\xd1\x17\x7f\x26\x3f\xf6\xfc\x3d\xfe\x52\x07\x45\x08\x5b\x7b\x4f\x7d\x21\x82\x78\xa0\xc3\x48\x73\xf3\x5d\xf9\xa5\xa0\x74\x5f\x7e\xd9\x9b\xe8\x83\x6c\x50\x2d\xd5\xa9\xcc\x20\xc5\x7e\xfc\xae\xfc\x42\xaa\x7f\x24\x47\xff\x44\xc6\xbc\xd6\x2a\x55\xfc\x75\x48\xd8\xf8\xc4\x3f\x21\x60\x4a\x11\x98\xf0\x86\x8d\x7f\x48\x55\x48\xdd\xb5\xf1\x1f\x53\x42\xc3\x17\xfc\xa7\x8c\x50\x2c\x1c\x5a\x18\x88\x93\xfb\x49\x3c\x06\xf4\x23\xf8\x03\x42\xb8\x09\x9c\x91\xbb\x32\x74\x0e\xac\x23\x61\xce\x11\x1f\x4b\x0c\x3b\x7a\x12\x8c\x01\x9f\xaa\x0f\xb9\x73\x46\x0a\xf9\x92\x6c\x89\xcf\x7c\x89\x13\x51\x2c\xe2\x4b\xa4\x38\xca\x01\xb7\xdd\x4b\x4c\x58\x16\x7b\x2c\x23\xe6\x70\xf6\xf3\x33\x99\x31\x83\x03\x9d\xc7\x14\xce\xe3\xdd\x18\x3a\x26\x60\x47\xf2\x17\xb8\xcd\x70\x6b\x7c\xa2\x0d\x17\x03\x32\xa3\xc1\x26\x39\xa1\xc8\x59\xc0\x7f\xd2\xc8\x32\x50\xe0\x1c\x96\x11\x25\xd4\xfa\x14\x89\x6f\xe4\x50\xf1\x30\xd7\x9f\x72\x13\x4d\x08\xdd\x29\xc9\x0b\xbf\xa4\xaf\x34\x9c\x01\x2d\xab\x42\x34\xf6\xfb\xfa\x4b\x8e\xe2\x44\x7e\x02\xb8\xf0\x0b\x89\xff\xd4\x36\x7c\xe1\x1b\x34\xb0\x3b\xe2\x1f\x09\xc3\x25\x29\x60\x90\x63\x0c\x02\xf5\x24\xf7\xa2\x1f\x5f\xca\xde\xa3\xc3\x5c\x80\x0a\xb5\x17\x46\x40\x1f\xe2\x8a\x48\x6a\x20\x1a\x45\x72\xfe\x30\x98\xca\x99\x9b\xe2\x49\xf0\x53\x5a\xee\x22\xbd\x89\x08\xaa\xee\x29\xc4\xb3\x24\x2c\x28\x95\x90\x9f\xc5\x76\xba\x7c\xab\xda\x22\x52\xd3\x23\x54\xe6\xc6\xdb\x81\x18\x89\xed\x00\xd9\x7f\x54\x7d\x84\x29\xf3\x61\x8a\x02\xfe\x56\x1d\x98\x9a\x24\x95\xb1\x0d\x4c\x63\xf5\x6e\x4b\x7b\x71\x0c\x06\x0d\x1e\xdc\x4a\x99\xd0\xdb\x04\xef\xf1\xa0\x65\xef\x6d\x52\x71\x8a\x07\x2c\xb7\xe8\xbd\x79\xf8\xe2\xe5\xee\xfe\x1e\x3f\x67\x1f\x84\x73\xd0\x46\xca\xb4\xcd\xda\x8a\x40\x85\x10\x91\x8e\xfa\x57\x3e\x98\xc4\xda\x8a\x24\x28\x43\x32\xe1\xa8\xe2\xf3\x05\x7d\x1b\x56\x1c\x33\xa0\xa4\x81\x1a\x91\x64\x1f\x94\x06\x32\x07\xfe\x9a\x23\xb5\x52\x41\xa9\xf4\x26\x38\xdf\x41\xbf\x7c\x9c\x3f\xee\x5b\x7c\x01\xba\x4e\xb4\xb2\x97\x2f\x09\xe3\x10\xd5\xdb\x02\xf4\xa2\xd4\xf1\xb1\x6c\x90\x7c\xce\x65\x14\xa1\x4f\xa4\x0c\x67\xd1\xa9\xc5\x90\xc3\x44\x7d\x75\x54\x29\xcd\xf1\x2a\xb1\x28\x52\xd4\xf6\x3d\x3e\x1e\x85\xe9\xf1\xf1\x9d\x4d\x96\xa9\x6b\x41\x5d\x85\x47\x2f\x72\xd1\xeb\xc5\xd8\x4f\x4f\xd0\x7b\x5d\x7a\xf0\xf4\x8c\x95\x1c\xf4\x8a\xf1\xb6\x8f\x8f\xdb\xdd\xa0\xdb\xbe\x8f\x94\x3d\x84\xd1\x30\xbc\xdb\x96\x33\xb4\x72\x02\x50\x69\x5c\xbf\xe6\x2a\xdf\x3c\x18\x66\xe4\xc8\x0e\xe5\xa0\x4a\x4f\xd2\x9e\x19\x94\x5d\x25\x95\xc1\xe9\xf9\xc3\x47\xed\xfb\xf4\xb2\xbd\x18\x1c\x4b\x77\x0c\x5e\xd8\x4d\x49\x9a\xa5\x4d\xcf\xa0\xe0\x59\x18\x9c\xcb\xe9\xb3\xbe\x68\xea\x7c\x35\x1f\x88\x68\xbc\x54\xce\x01\x30\x91\x49\x39\x65\x83\xb6\x7a\x7a\x0b\xaf\x1f\x2d\x5f\x93\xac\x32\xba\xae\xca\xd5\x78\xef\x4b\x63\x31\xae\x09\x61\x2a\x20\xcd\x72\x55\xd8\x58\x93\x02\x32\xde\x28\x3a\xad\x55\x98\x1e\x51\xaa\x55\x65\x09\xbd\x70\x18\xc3\x0a\xe2\x89\xb0\x6a\x05\x69\x75\x81\x59\xb6\x07\xba\x72\xe9\x2a\x5d\x80\x79\x07\x0e\x5a\x6f\x51\x74\x29\xa0\xdb\x55\x9c\x06\xb4\x8c\x94\xef\xaa\x96\x09\xbc\xa8\x65\x68\x54\x36\xfe\xab\x5a\x36\xcd\x11\x2d\x0f\x8d\x11\x31\xb9\x6a\x67\x0e\xf4\x5e\xf6\xe4\x5e\x86\x5d\x3a\x78\x1d\x7b\x8f\xe3\xd5\x1b\x75\xa9\x4d\xf2\xdf\x88\xcd\x56\x79\x7e\xc9\xf0\x36\x77\x55\x31\x8e\xce\xbe\x5f\x5d\x69\x8b\xd3\x6c\xe8\x6e\xa9\x74\x75\x26\xc5\x2e\xb7\x95\x33\x4c\x55\x9b\xa5\x11\x69\x2b\xe6\xe3\xeb\x49\x31\x6f\x05\x2a\x1a\x01\xb6\xd2\xa6\xe2\x4f\x1a\x81\xea\x2b\x9a\xb2\xed\x3d\x02\xf5\x5d\x6f\x42\xf2\x34\xd5\x16\x02\x63\x32\xb1\xe9\xd1\xd5\xba\xf2\xd6\xb0\xb9\xad\xcf\x03\xcd\xbd\x38\xeb\x81\x72\xf2\x89\xd3\x53\x9a\xdf\x35\xd9\x74\x69\xc9\x93\xbc\xaa\x47\xef\x26\x71\xc9\xd2\x3b\xeb\xc2\xf5\x62\xaa\x98\x6e\xe1\xd1\x4e\xa1\xd2\x4f\xcd\xe1\xac\x58\x35\x6a\x7e\x13\xc6\x06\x07\xa6\x55\xac\x62\x11\x61\x34\x83\xd1\xd0\x2a\xe4\x1b\xbf\x73\x06\x1e\xed\xb8\x02\xf7\x9b\x7b\x63\x43\x8a\xbf\xd0\x0b\x6b\xe5\x88\x5d\xf6\x52\xb1\xe4\x6e\xd4\xb7\x3c\x7c\x64\x35\x3d\x11\x96\xf3\x56\x6b\x85\x53\x55\x7c\xc3\xb7\xe2\x7e\x15\xdf\xe5\xec\x74\x5a\x39\xbd\x9a\x0d\x01\xa3\x8b\x16\xe1\xab\x36\x28\xa8\xc5\x77\x15\xf5\xb3\x9b\x95\x23\x97\x16\x69\xce\xeb\xd7\x30\x31\xb7\x7c\xff\x1a\x85\x90\x98\xf9\xa8\xba\xac\x1f\x05\x07\xea\x41\xbd\xab\x7b\x03\x51\xbb\xd6\x03\x8b\x06\xa9\x67\xb9\x7c\x65\x53\xe3\x4c\x63\x0c\xe5\xa5\x3b\x69\x54\x0b\x2b\x8a\x69\x55\x9b\x85\xca\x8f\x78\x25\x16\x75\x64\x2b\x7a\x30\x88\xd0\x47\xb6\xde\xcb\x49\x22\x15\x5f\x0e\xe6\x47\x46\xe5\x45\x94\x48\x5c\xfa\x9b\xc5\x57\x0c\x16\xf6\xd2\x13\x71\x32\x2f\xb1\x8b\x74\xa9\x0c\xe8\x05\xd5\x55\x91\x8e\xa0\x43\x11\x9b\x81\x9f\x6c\x1a\x8e\x31\x0d\xa9\x4e\xfc\xa1\x4b\xea\x36\x3e\xcd\x24\x53\xaa\x74\x86\x9c\xbf\xe7\x3e\xfa\x44\x48\x25\xc0\x60\x3d\x05\x96\x2e\x54\x11\x03\x37\x81\x3b\x00\xe4\x3c\x07\x7c\x85\x3d\x6a\xb3\x44\x16\xc0\x5e\x14\xd0\x87\xa2\x9e\xbb\x02\x65\xc1\x12\x94\x59\x4e\x63\x8c\xc2\x07\x00\x44\x15\xb6\x60\x0b\x95\x8e\x2c\x8c\x47\x62\xb5\x27\xf1\xa0\x69\x52\xb5\x31\xab\x8e\x94\xdb\x12\x76\x24\x9e\xf6\x46\x0d\x0d\xd1\x41\xc5\x03\x51\x89\xa6\xe6\x78\x2c\x2a\x14\xa6\x14\x32\x5e\x54\xc9\x4e\x40\xb9\x28\x15\x7a\x51\x8d\x05\x02\x0e\x58\x91\xe3\x6a\xa4\x6e\xeb\xbc\x1a\xad\x95\x2c\xf8\xd3\x5a\xf6\x1c\x3d\xba\xd9\xf9\x7e\x7c\x09\x24\xa7\xa8\x77\x13\x58\xab\xa5\x38\xfe\xaa\xde\x4b\x29\x8a\xb0\xe3\xe0\xe8\xa9\xe4\x21\x82\xde\x8e\x20\x04\x52\xa5\xb1\x83\xa5\x5a\x24\x6a\xae\x0e\x08\xa5\x10\xd5\x81\x63\x3d\x7f\x89\xf4\xb9\x8e\xd9\x39\x6f\xdf\xee\xdd\xea\x6d\xb6\xd9\x53\xbe\xc5\x5e\xf1\x5b\x6c\x9f\xff\x96\x3d\xe3\xdf\xb3\x97\x7c\xeb\x3b\xb6\xc7\x6f\xdf\x62\x0f\xf8\x77\xbf\x65\xbb\x7c\xeb\xd6\xf7\xec\x94\xdf\xfa\xf6\x3b\x76\x97\xdf\xde\x64\x4f\x78\xbb\xd7\xeb\xb5\xd9\x6b\xbe\xf5\xed\x26\xfb\x88\xb9\x77\xf8\x26\xbb\x07\xd5\x3c\x86\x6a\xde\xf0\x36\xb0\xb0\xd0\xc1\x60\xb4\xe6\x9b\x8b\xc8\x36\x7b\x8b\xb4\xa1\xd4\xf6\x3f\xb6\x28\x6b\xa4\x11\x3f\xf3\xf6\x81\x14\xa6\xac\x19\x76\xff\xa8\xcd\x3e\xd9\xd1\x80\x9a\x21\xea\xa7\x32\x4a\xb1\xfe\x10\xf9\xbe\x8c\x44\x01\x00\xc4\x3c\x2a\x63\x88\xbb\x87\xa8\xe7\x65\x94\xe6\xea\x21\xf6\x46\x19\xfb\xd4\x9f\x43\xc4\xbb\x32\x42\xb2\xee\x10\xf7\xa1\x8c\x93\xdc\x3a\xc4\xfd\x58\xc6\x49\x9e\x1d\xe2\x02\x51\x46\xbe\x0c\x30\x97\xb0\x63\x08\xbc\x20\x32\xb6\x22\x95\x5a\x0a\xc4\xa6\xa2\x36\x5a\xa9\xa5\x03\x29\x89\x95\x42\xaa\x29\xb7\x6f\xe9\xe9\x08\xeb\x49\x4a\x6b\x05\x92\x7c\x2b\x69\x57\xab\xc5\x40\x7c\x56\x8d\xdf\xfa\x4e\x27\xe4\xd5\x84\xb2\x91\xa1\x95\x50\x6a\xd8\x40\x42\x54\x4f\xb8\x1f\x01\xf7\xa7\x64\x14\x90\x3e\xaf\xa5\x97\x6d\x8d\x6b\x29\x65\x63\xc0\x4b\x6f\x1c\x9e\xa0\xb6\xff\x21\xda\x57\xdc\xec\x6f\x4c\xd8\x88\xe2\x1c\x15\xe9\xa2\x25\xc5\x61\x17\xe2\x67\x10\x0f\xb1\xc1\xa1\xd3\xfb\x66\x70\xe8\x16\x58\x4e\x1c\xba\x2e\xa4\x1e\xc6\xb2\xe8\x19\x64\xe9\x00\x8e\x84\x7e\x15\x91\x28\x26\xa2\xf8\x94\x27\xa2\xf8\x93\xdb\x3f\x14\x7f\xf2\xc3\x77\x2e\x66\x99\x40\x96\x83\xce\x9d\xed\xf6\xcd\x3f\x3f\x82\xcf\x4b\xc0\x22\xb4\xa0\xce\x99\x50\x4a\xd2\x2e\x7b\x68\x22\x27\x65\xe4\x7d\x28\x78\xe7\x37\xeb\xce\xc1\x61\x76\xf8\xf2\xa8\x3b\x70\x7f\xb3\x0d\xe5\x4f\x28\xb6\x16\x79\x41\x91\xbc\x16\xfb\x02\xc7\x75\xe3\xf0\xca\x39\xf8\xdd\xe1\xe1\xe2\xe8\x1b\xe8\xe7\xe1\x61\x4f\x7d\xb8\xdf\xb8\x87\x0b\xc8\x74\x8c\x99\xce\xbf\xb9\xb1\xc1\xce\x21\xf4\xbb\xc3\xec\x1b\xbd\xa5\x0e\xd6\x0e\xe3\xc3\xf4\x50\x1c\x75\x0f\xcf\x37\xd8\x53\x4c\xdd\x3c\xb8\x78\x77\xb4\xc1\x5e\x51\x4e\x3d\xc1\xbd\xee\xe0\x7e\x79\x0b\x75\x78\x04\x55\xed\xe3\x98\x0f\x2f\x86\x9b\xeb\x87\x17\xa3\xef\xe0\xff\xf7\x18\x08\xe0\xff\x18\x02\x63\x88\x19\x63\xcc\x78\x8c\x33\xf2\x0c\xa7\xf9\xc6\xef\xdc\x0d\xf6\x12\x8b\xf5\xbe\xe9\x0e\x7e\x77\xe3\x6a\xe1\xb8\xc5\xc1\xe1\xd1\xe1\xc6\xe1\x21\x66\xda\x33\x33\xf4\xb2\x9c\xa1\x07\xb4\x70\x78\x52\x1c\x9e\x6c\xb0\x5d\x2c\x7d\x93\xfa\x9c\xdf\xda\xbc\xf5\x3d\xfd\xfd\x41\x16\x3f\x15\xcb\xa7\x53\xfb\xe0\xee\xfa\x87\x43\xd9\x4b\xea\xa6\xec\x27\x76\x14\xb7\x16\xa4\xfb\xeb\x9f\x0f\x65\x9f\xa9\xd3\xb2\xd7\xd4\xed\x6e\x5b\x1f\x69\xaa\x57\xc0\x46\x5d\xdd\x62\x0b\x67\xc0\x91\x3d\x15\xdd\xb6\x5b\x10\x9f\x3a\x68\xe3\x87\x0c\x77\x8b\x83\xcd\xf5\x1f\xa0\x2c\x99\x32\xa1\xa4\xe3\x2e\xb4\xb2\xf6\xff\xfb\xff\x1f\x8e\xff\xaf\x7f\xf8\xff\xfc\xe3\x7f\x52\xef\xfa\x3f\xfd\xfb\x3f\xff\xd3\x7f\xf8\xf7\x7e\xf9\xf9\xe7\x5f\x7e\xfe\x2b\xbf\xfc\xfc\x57\x7f\xf9\xf9\xaf\xfd\xf2\xf3\x5f\xff\xe5\xe7\xbf\xf1\xcb\xcf\x7f\xf3\x97\x9f\xff\xd6\x2f\x3f\xff\xed\x5f\x7e\xfe\x3b\xbf\xfc\xfc\x77\x7f\xf9\xf9\x1f\xfd\xf2\x57\xfe\xc1\xff\xfd\xf3\xcf\x6d\xf6\x44\xf0\x83\x36\x81\x3a\xb4\x61\xed\x72\xf8\x42\xcc\x05\x3f\x84\xae\xe0\xd7\xde\xe8\xfa\x53\x6d\x6e\xfc\x34\x58\xb5\x6d\xf6\xb6\x0c\xab\x3d\x26\x3f\xca\xf2\xa8\x37\x09\x3f\x12\xa5\x41\x40\xe2\x31\x08\xc8\xe9\x81\x00\x20\x2c\xfc\x2b\xd5\xa3\x58\xfb\x18\xc5\x26\x96\xa6\x1f\x7c\x6a\x15\x48\x08\x6a\x39\xa9\x14\xa2\x90\xc4\x0f\x69\x1d\xa3\xa1\x07\x1f\x46\xdf\x12\xc2\x25\xd6\xd0\x1f\x36\xa6\x50\x71\x65\xcf\x2d\x8c\x00\x5f\x0a\x45\x22\x37\x47\xfa\x98\x18\x65\x54\xbd\x80\x9c\x7a\x4d\x66\xe4\x1f\x49\x47\xec\xa3\x38\x48\xc4\x11\x87\x9f\x50\xfe\xf8\xf2\x27\x93\x3f\xb9\xfc\x19\xca\x9f\x48\xfe\xcc\xe5\xcf\x18\x7e\x5a\x70\x9c\x89\x83\xcf\xf4\xfd\x89\xfe\xa6\x32\xf1\x27\xfa\xfb\x9e\xfe\x3e\xa2\xbf\xcf\xe9\xef\x0d\xfa\xfb\x8e\xfe\x7e\xa0\xbf\x3f\xd2\xdf\x40\x16\x13\xf2\x27\xc6\xaa\xa5\xc6\xc3\x0e\x75\x73\x87\x1a\xd9\xa1\x46\x76\x64\x23\x3b\xd4\xc8\x0e\x35\xb2\x23\x47\xb1\x23\x47\xb1\x23\x47\xb1\x23\x47\xb1\x23\x47\xb1\x43\xad\xee\x50\xab\x3b\xd4\xea\x8e\x6c\x6e\x47\x0e\x6f\x47\x0e\x6f\x47\x0e\x6f\xc7\x0c\x6f\x87\xfa\xbf\x43\xfd\xdf\xa1\xfe\xef\xc8\xde\xee\x54\xba\x79\x0f\xba\xa9\x1d\x87\xb5\xb6\x98\x72\x04\xe6\x6d\x32\xe3\x2e\xac\xb5\xb5\x60\x8f\x21\x57\xfb\xf7\x3f\x03\x3d\x7a\x17\x16\xe5\xf7\x7f\x45\x07\xfe\xaa\x0e\xfc\x35\x1d\xf8\xeb\x3a\xf0\x37\x74\xe0\x1f\x42\xc0\xc7\xc0\xbf\xaf\x03\xff\x81\x0e\xfc\x87\x3a\xf0\x1f\xe9\xc0\x7f\xac\x03\x7f\x0b\x02\xf7\x31\xf0\x9f\x42\x60\x88\x81\x7f\x09\x02\x0f\x30\xf0\xdf\x42\x00\xa5\x7f\xbf\xff\xdb\x10\x78\x88\x81\xbf\xa3\x03\x7f\x57\x07\xfe\x39\x1d\xf8\xcf\x20\x80\xc0\xfb\xfb\xff\x5c\x07\xfe\x0b\x1d\xf8\x2f\x75\xe0\x9f\x87\xc0\x2e\x06\xfe\x05\x1d\xf8\x7b\x3a\xf0\x2f\xea\xc0\x7f\x05\x81\x10\x03\xff\xb5\x0e\xfc\x37\x3a\xf0\x8f\x74\xe0\x5f\x86\xc0\x1e\x06\xfe\x3b\x08\xe0\x8e\xfd\xfd\xbf\x02\x81\x7d\x0c\xfc\xab\x3a\xf0\xaf\xe9\xc0\xbf\xae\x03\xff\x86\x0e\xfc\x9b\x3a\xf0\xdf\xa3\x01\x1e\x06\xfe\x07\x1d\xf8\x1f\x75\xe0\x7f\xd2\x81\xff\x59\x07\xfe\x17\x1d\xf8\xb7\x20\xf0\x1a\x03\x7f\x5f\x07\xfe\x6d\x1d\xf8\x77\x74\xe0\x7f\x85\x40\x8e\x81\xff\x4d\x07\xfe\xb1\x0e\xfc\xef\x3a\xf0\xef\x42\xe0\x3d\x06\xfe\x0f\x08\xe0\xb6\xfc\xfd\x3f\xd1\x81\xbf\x89\x6b\x4a\x53\xf6\x9f\xe0\x3a\x51\xe8\xdf\x83\xd0\x2b\xc4\x38\xbf\xff\x3f\x89\x5d\xc1\xd0\x3f\x80\x50\x96\xb5\x17\xec\x0d\xc2\x4d\x07\xbe\x3a\x80\x04\xfa\x90\x74\x07\xc3\x91\xc0\xe0\x36\x06\x27\x18\xbc\xd9\xbe\x09\x41\x3c\xae\x31\xfe\x26\xc6\xc3\xb1\x8d\xe1\x3f\xa7\xf0\x0f\xdf\xf5\xa1\xae\xb7\x54\x17\xd5\x03\x91\x90\x48\xf5\x78\x50\x25\x93\xf5\x78\x50\x25\xd3\xf5\x78\x50\x29\x53\xf5\x78\x50\x27\x53\xf5\x78\x50\xe7\x82\x7d\xc6\xba\x0c\xc1\xea\xa1\x63\x3e\x42\x93\x10\x5a\xb0\x4f\x98\x78\x78\x08\x59\xe1\x8f\xec\x0f\x96\x27\xbb\x43\x5c\xd5\x43\x94\x23\x21\xb2\x93\x27\x04\xce\x1b\xfd\xaa\x88\x1f\x54\xc4\x0f\xd0\xce\x4f\x82\x7f\x86\xdd\x2a\x85\x16\x12\xa9\x1d\x75\x3a\x32\xd0\xe2\x9c\x58\xad\x4e\x87\x18\x2e\xa5\x82\x3e\x90\xbf\xc4\x74\xb1\xf7\x76\xf1\xf8\x88\x74\x8f\x5a\xb1\xa5\x18\x16\xb3\x47\x76\x16\x01\x59\x04\x32\x76\x56\x16\xc1\x9e\x0b\xfe\x1e\x62\x1f\x89\x8a\xf7\xaf\xf2\x71\xf1\x7e\xeb\xb9\x28\x8a\xe7\x42\x19\x8e\x41\xbf\x9e\x43\xd6\xe7\xa2\x67\xfa\xa9\xbe\x81\x1b\x19\xd3\x17\xb0\xdf\x30\xb2\xe7\x42\xca\x09\x6e\x08\xfe\x88\xea\xef\x05\x17\xa4\x82\xca\x39\x35\xf8\x5e\xb0\x77\x40\x2b\x38\x6e\xbf\x41\xdf\x4a\x8a\x74\x1a\x7a\x24\x13\x7a\xfe\x6c\xd4\xe9\x94\xe1\x01\xda\x19\x1c\xf3\x77\x82\xc9\xb8\x06\xfb\xce\x77\xc0\xde\xbb\x9e\x1c\xe9\xe0\x86\x18\x38\x56\x87\xde\x09\x97\x4a\x43\xb2\xfc\x55\xb5\x2d\xdc\xd2\x4b\xa9\x6b\x7f\xb0\x26\xa9\x93\x9c\x9f\x81\xfc\xf1\x9a\x72\xe0\x0c\x0d\xf0\x4f\x63\xaa\x9c\x4f\xbd\xc2\x57\x28\x3e\xbb\x5a\x1c\xb1\xef\xbc\x83\xba\x4e\x53\xa9\x01\x4d\x22\xbe\x6b\xe6\xcf\x9a\x22\x35\x33\x07\xed\x34\xf0\x87\x28\x7e\x48\x5c\x6f\x69\x7a\x51\xbf\x4c\xcf\x4a\xe2\x04\x8e\xca\x8c\xee\xab\x7a\xbb\xf1\x58\xde\x89\x26\x4e\xda\x7b\x81\xf1\x40\x1a\xd1\x6c\x34\xe9\xe3\x4a\x25\x1e\x38\xde\xb3\xcc\xb9\x1a\x85\x19\x70\x7a\x97\xa8\x7a\x0d\x08\x53\xd5\x03\x7c\x41\x9a\xcc\x11\x0c\x33\xef\x6a\xea\xc7\xa3\x28\x78\x39\x4c\x81\x33\xf6\x82\xde\x33\x9d\x42\x3a\x2c\x90\x31\x00\xba\x67\x74\x0f\x6f\x5d\x5f\xa2\x40\xde\xce\x21\xb5\x19\x75\x9e\xbb\xa3\x11\x69\x75\xf8\xd1\xe3\x00\xc5\x7d\x4d\x59\x03\x79\x23\xbc\x32\x03\xdd\xbf\x7e\xca\xc3\x34\x18\x31\x75\x0f\x17\xa4\x5f\x95\x3b\x54\x63\x7b\x82\xbd\x0d\x26\x61\x7c\x2f\x11\x22\x99\xed\x8f\xc7\x40\x13\x35\x75\x25\x89\x77\xad\x22\xcb\x23\xc7\x21\xc1\x31\xfb\x72\x1e\xc6\xd0\x87\xff\x97\xbc\x77\xed\x8a\x1b\xc9\x12\x45\xbf\x9f\x5f\x01\x9a\x39\x94\xd4\xa8\xd2\xa4\xed\xb2\xab\x94\x25\xb3\x30\x50\x5d\xdc\xb1\x8d\xc7\xe0\xae\xe9\x43\xd1\x94\xc8\x54\x82\x8e\x33\xa5\x6c\x49\x09\xc5\x01\xfe\xfb\xdd\x8f\x88\x50\xbc\x94\xa4\xab\x7b\xce\x9d\x59\x77\x79\x99\x94\xe2\xa5\x88\x1d\x11\x3b\x76\xec\xe7\x01\xf4\x1c\xf5\x5f\xcc\x96\x60\x33\xc7\x45\xa3\xb7\x83\x07\xb3\x5e\x04\x1d\x9a\xc4\xa8\xc4\xc1\x00\x3e\x69\xa1\x0d\x94\x83\x36\x3f\x55\xf5\x1e\x6a\x84\x7d\x6e\xf2\x9a\xf3\x1a\x5f\x2f\xc7\x38\x8d\x34\x7b\x7a\x26\xab\xd0\x3f\xc6\x57\x79\x7b\xc0\xda\x57\x98\xd7\x24\xce\xe6\x33\x67\x57\xcb\x7e\xec\x1f\xdf\xc1\xf1\xfb\xc1\xa4\xb8\x11\xea\xd0\x16\x98\x8c\x26\xdc\xa1\x03\xa5\xb2\xee\x60\x87\xdf\xed\x3c\xd2\x08\x8e\x58\x30\x41\xa5\x13\xe7\x0a\x42\x38\x18\x97\x2b\xfe\x35\xd7\xe2\xee\x8a\xbc\x44\xcb\xb3\x16\xd2\xb3\xe7\x70\x73\x71\xab\xda\xcb\xd7\xd3\xba\xb3\xc2\xfb\x3f\x12\x97\x29\x12\xfc\x28\xdd\x0f\xf5\x52\xd7\xc5\x6c\x52\xe7\xca\xcf\x12\x95\x41\xc3\x9e\x10\xae\x47\x6d\xf4\x4c\x2b\x6a\x6c\x15\x15\xe3\xee\x9e\xd7\xc5\xf1\x74\x5f\xb4\x94\xac\x68\xbd\x21\x50\xa3\x1d\x82\xe8\x2f\x07\x86\x88\x05\x52\x20\x59\xfc\x09\x8a\xdd\x13\x33\xed\xb0\x9c\x24\xa5\x7f\x76\x51\x8e\x0b\xbd\xe2\x49\x3c\xad\x16\xb2\x49\x80\xd0\x4d\x51\x2d\x1b\x5f\x86\x85\x40\x7a\xf1\x45\x2b\x3a\x2c\x6e\x30\xb2\x85\x42\x34\x2a\x68\xde\xc7\x98\x34\x88\x4a\xe8\xc5\x2f\xc5\x6c\xf6\x29\x07\xf0\xdd\xe4\xd6\xfa\xef\xfc\x6e\x22\x96\x24\x4f\x4a\xdc\xda\x66\x4a\x56\x3e\xd6\xc8\x50\xe5\xd9\x4d\xf5\x95\xec\xc2\xea\xd8\x03\x1b\x95\x4e\x52\x5a\xef\xd6\x49\xee\xae\x3f\x21\x4f\xcd\xfb\xd6\x55\xd7\x94\x9d\x93\x56\xbb\x95\xdb\x22\xcb\x08\x00\xcf\xd1\x1e\x0a\x4b\x5d\xd9\xa0\x55\xe9\x3f\xd5\xd5\x5c\x4d\x4f\xd8\xa2\x8a\x6b\xf7\xca\x72\x29\x05\xd9\x83\x62\xf2\x79\x31\x31\x36\x24\x8a\xe4\x7b\x97\x1a\x81\xd5\x4a\x13\xf4\x53\xcf\xe7\x31\xcb\xee\x81\x39\xb3\xef\x51\x7e\xad\x23\x04\x34\xdc\x27\x05\x7c\xb9\xf6\x59\x79\xd5\xb7\xbf\x74\xdf\xe9\x74\x4b\x0d\xd5\xe1\xb7\x31\xa9\xf2\x66\xa3\xac\x5a\x78\xd8\xc8\xca\x3b\xa8\x5d\x5e\x6d\x90\x5b\x8f\xaa\x9c\xdd\xc1\x9f\x7c\x83\x9a\x19\x04\x16\x44\x9c\x0e\x99\x60\xbf\x77\xb6\x9b\x90\x09\x4f\xa1\x90\xca\xc2\x41\x03\x86\xfd\x00\x47\x47\x08\x74\xcd\xac\x50\x7b\xdc\xdd\x5b\x1e\x20\x79\x36\x9a\xa7\x94\x9c\xcb\x65\x9b\x9f\x56\x2d\xe0\x56\xbb\x67\x3d\x12\x36\x0f\xe6\xf9\x53\xff\xa4\x13\xf6\xee\xfa\xd1\xd3\xe6\xca\xf1\x37\xb2\xf6\xa3\xbe\xcd\x0f\xaa\xdb\xb2\xaf\xb9\x06\x61\x3d\x70\xa0\xf0\xa3\x96\x69\xc3\xf1\x31\xf6\xae\x41\x0f\xb6\x20\x74\x4c\xa6\x94\x61\xfe\xcc\xfc\x9c\xb1\xb1\xd1\x8d\xd0\x8a\xec\x3f\xa1\x33\xfe\x72\x7b\x45\x89\xb8\x12\xc7\x43\xf6\x3b\x7a\x6e\xf8\xd6\x2d\x6a\xef\x7c\xb4\x1b\x32\x4f\x94\x55\x13\x8c\x01\xa5\x3d\xdf\x77\x1b\xcd\xf4\x31\x57\xfd\xe7\x4f\xdc\xa4\xdd\x59\x55\xf4\x97\x1b\x59\x7b\xc2\x3d\x6a\x32\xe7\xa8\x69\xdc\x95\x9f\xf7\xad\xf3\x9e\x19\x86\xf5\x2e\x09\xc0\x9f\xbd\x14\x8f\x89\xbd\x74\xaa\x28\x7c\x72\x95\x0a\xd9\xbb\x51\x09\x85\x3b\x35\x14\xea\x56\x30\x74\x61\x9e\x95\xd9\x95\x28\x21\x0e\xb1\xc6\xc5\x17\x34\x02\xe3\xa4\xdb\xda\xd2\xf9\x7c\x61\x5f\x31\x3e\x7b\x98\x24\x02\x12\xa6\xe3\xf5\xe9\x97\xae\x5c\x03\xbe\x79\x72\x7a\x4f\x57\x84\x9c\x06\x98\x35\x89\x37\x67\x9a\x8d\x2f\xed\x58\x5f\x42\xf1\x6e\xec\x27\x44\xe5\xb4\xf8\x20\x27\x63\x8d\xfa\x0f\x90\x5c\xf9\x35\x7d\xb3\xc6\x6e\xf8\xb6\x9f\x52\xd3\xb3\x56\x5e\x22\x46\xad\x14\xcd\xf2\xdc\xf8\xa8\x08\x07\x2c\x0e\x09\x05\x10\xd7\x01\x6e\x92\xd7\x74\x08\x5e\x2e\x01\xcb\x76\x43\x38\x69\xef\x66\xb9\x8f\xb2\x7f\x92\x04\xad\x6e\xf2\x1a\x95\xb0\xff\x23\x09\xae\x8b\xc9\x24\x2f\x03\x95\xf4\xd7\x24\xe0\x39\x0a\x1e\xc5\x07\xb9\x8e\xf5\x31\xa5\x6d\x73\x7f\x5b\x4c\xda\xeb\x24\x18\xee\xec\xfc\xcf\x20\x16\x9f\xee\x10\x42\x1e\x6d\x07\x8b\xdf\xb1\x2d\xeb\x56\xc1\x3b\xdd\xd3\x7b\x81\x03\x92\x55\xf0\xdc\x0d\x2e\x67\xd5\xf8\x0b\x72\x77\xe0\x08\xc6\xd6\x61\xd3\x4f\xf2\xda\xbe\x24\xb4\x3a\x2e\x76\x10\xce\x9f\xfa\x70\x15\xc6\x9d\xee\x3f\xdc\xbe\xed\x69\x13\x10\x56\xd4\xdf\x64\x9d\xfa\x5a\x64\xc3\xa6\x55\x9d\x8c\x57\x7c\x8d\xa3\x33\xbb\x67\xa0\xb6\xe7\xd0\xb7\xe6\x60\x51\x91\xfd\xc8\xe1\x0d\xa9\x6a\x33\xcc\xd0\x7d\x8e\xbc\xcf\xdd\x77\x77\x49\xbd\x93\x32\x71\xd7\x97\x88\xf6\xcb\x80\x1a\xe5\x6a\xc1\xf5\x88\xf2\x4b\x5c\x24\x54\xdc\xb7\x56\x43\xbc\x34\x8a\x8d\x4e\x85\x7c\x98\xf9\x51\xef\x18\x7f\x61\x5e\x55\xed\xb5\x1a\xd2\x2f\xa4\x77\x53\xcb\xaf\x55\x6e\x85\xb6\x5a\x9c\x2c\xb2\x71\x57\xa6\xeb\x91\xb6\x98\x43\xb6\xc8\x73\x6a\x5f\xd2\xce\x5e\xa7\x01\xd6\xba\xb5\xaa\x9b\xeb\x3c\x78\x8c\x57\x2e\x64\x0d\xb4\x3d\xd7\x6e\xb6\x58\x46\x4d\x0d\x35\xd3\xc4\x86\x22\x2e\x50\x32\xfc\x61\xe7\xf1\x3c\x7e\x6d\xf2\xa3\x34\xc3\x71\xba\x8e\x77\xfc\xa3\x92\xf9\x57\xdf\xaf\x28\x2f\x03\x99\x09\x17\x29\x15\xba\x5d\x26\x27\x5e\xad\xe5\x2f\x03\x63\xee\x48\xcd\xd8\xb3\xea\x1c\x2e\x17\x14\xcd\xbe\xd0\x35\x9a\x88\xc2\xde\xda\xaa\x43\x38\x64\x0a\x19\x48\x01\xc6\x22\x7d\xe6\x30\x2f\xeb\xd9\xac\xb8\x7c\x76\x9b\xd5\x25\x8a\xb7\x70\x55\x1b\x19\x45\x49\x36\xf3\x18\xce\x02\x28\x9d\x7b\x84\x64\x31\x6e\x12\xf8\xf4\xac\xc0\x8b\x88\x7b\xc1\x13\x64\x90\xc6\xe1\xea\x10\x2b\xb1\x49\x50\xf7\xc5\x87\x33\x2a\xec\x67\xf0\x3f\x9b\x0d\xb1\x77\x9b\x8d\xac\xce\xc9\x85\x47\x0d\xe7\x4e\x5e\x6f\x00\x22\x9d\x16\x57\xcb\x3a\x23\x60\xd1\xad\x00\x96\xee\x46\x73\x5d\x2d\x67\x13\xba\x3a\x5c\xe6\x1b\xdc\x6e\x3e\x09\x62\x71\xfe\x28\xf9\xae\xde\x25\xe8\xc1\xa8\x9b\x98\x02\x26\xc6\x3b\xe6\x64\xf8\x7a\x27\xf6\x80\x29\x19\x7e\xff\x03\xcc\xe4\x0f\xf6\x4c\x0a\x77\xdc\x7d\x00\xb4\x80\x7e\xf8\x7b\x3e\x5e\x62\xe5\xc3\xf2\xa6\xa8\xab\x92\xa3\x86\x60\xe0\x2f\x38\xd3\x61\x5d\x23\x86\x11\x5e\x9d\x86\x31\x9a\xee\xe8\xd0\x42\x56\x67\xb0\x9f\x95\x38\xec\x65\x93\x6f\xfc\x5c\x34\x30\xc6\x3b\x32\xf1\xd9\x10\xf6\x41\x1b\xd9\x06\x34\x83\x93\x2a\xb1\x67\x3a\x8c\x99\x9d\x3a\xb8\xd6\xca\x87\x26\x38\x2a\x13\x1c\xde\x6e\x26\xaf\x5e\xc6\xbd\x20\x03\xd0\x0c\x77\x7a\x61\x33\x78\xa6\x38\x66\x04\x93\xfb\x31\x9b\x31\x08\xc6\xe7\x3c\xfb\x92\x7f\x84\x23\x2c\x29\x89\xe1\xa7\x33\x13\x31\xeb\x67\xdc\xe7\x6e\x16\x59\x59\x11\x11\x7d\x5a\x79\xb2\x85\xc7\x18\x34\x63\xf0\xe4\x5e\x55\x6f\x11\xba\x4e\xc6\x63\xac\x3a\xd3\x67\x93\x2c\xd6\x18\xf6\x7f\x20\x0b\x4b\x1f\xb1\x5d\x7f\xd7\xad\x8d\x85\x55\x6d\x63\x48\x76\x0b\x46\x55\xbd\xa4\xaa\xae\x0f\x79\x65\x6d\xad\xa0\xaa\x2c\x20\x62\x13\xc9\xb2\x0a\x67\x5b\xcb\xa6\xc6\x65\xa3\x4f\x6e\x32\x7c\x8e\x2b\x61\xf8\x15\x2b\x01\x8f\xe6\xfd\xff\xba\xcb\x01\x6e\x16\xfb\x5a\x17\x3d\x04\x94\xea\xae\x83\x7d\x64\x0e\x99\x09\x87\x76\x76\xd4\x8d\xc6\x5b\x13\x73\xfa\x6a\x1a\x83\x75\x6a\xeb\xb9\x7d\x2d\xe8\xf0\x70\x1a\xd0\x32\xfb\xea\x0b\x88\x39\x55\x39\xbd\xa7\xd6\xe3\x5a\xab\xe7\xf9\x1a\x38\x96\x75\x36\x84\xd9\xb6\x81\x67\x01\x9d\xaa\x16\xd1\xdf\x49\x78\x3f\xcd\x66\xcd\x5d\xdf\x86\x44\x07\x68\xbb\x1a\x73\xea\x47\x74\x7a\xfb\xcd\x9b\x8d\x79\x76\x47\xe7\xcb\x75\x76\x93\x03\x52\x0d\xbe\xd9\x6e\xb7\xbf\x09\x36\xf0\x48\xfb\xa6\x8b\xeb\x1b\x93\xfa\xb2\x8e\x45\x15\x99\x10\xf7\xf6\x36\x79\x85\x27\xc9\xf0\xc5\xd3\x44\x01\x6b\xdc\xc2\xf9\x2c\xce\xd3\xac\xce\xe6\x4d\x2a\x68\xd4\xbf\x2f\xd1\x7a\xb1\x74\xa9\x8d\xe1\xcb\xd5\x00\x74\x8f\x25\x1b\x9a\x95\xbb\x55\x0b\xd4\x58\xa4\x53\x99\x89\x47\xd2\x55\xcc\x6c\x4c\x0e\xbb\xe5\x13\x96\xd9\x6b\x0f\xf2\x05\xac\xac\xca\xd9\x69\x8d\x28\xb1\x2f\xd9\x79\xfd\x45\xf5\xaf\x35\x90\x9f\x91\x83\x5c\x7d\x73\x7a\x90\xc7\xd3\x95\x9e\xde\xd1\x66\x1b\x26\xe6\xd4\xb3\x06\xac\xfc\x1c\x92\x3b\xc0\xf3\xe8\x71\x1d\x26\xe5\xc5\x92\xb8\xb9\x26\x0c\xc2\x27\x38\xbe\x6b\xd7\x45\x6e\xed\xe7\x72\xee\xfd\xb2\x1c\x42\xdf\x0c\x28\x4e\x30\xe5\x72\x12\xc7\x54\x80\x2f\x78\x3f\xfd\x4f\xfa\x84\x62\xfb\x9c\x15\xe7\x11\xcd\x4f\x97\xdd\xc7\x7c\xf4\xcf\x87\xe4\x86\x0a\xc1\x2b\xce\xf2\x27\xad\x40\x8f\x54\xa2\x3b\xe3\xcc\xd5\xeb\xed\x6d\x77\x2b\xd8\x2d\x85\x80\x57\x18\xd7\x12\xc1\x4e\xdf\x89\x6b\xf4\x5a\x8e\xe1\x39\xd5\x6d\x23\xa6\xcb\x4a\x81\xf2\x77\xf2\x09\xa5\xe3\xc1\xcc\x83\x07\xe3\xf5\xf1\xc8\x77\x4f\xe3\x11\xdb\x11\x12\x7a\x09\x2f\x20\x19\x8d\x4f\x61\x53\x8c\x5b\xf6\x49\x52\x61\xa0\x86\x42\x77\xbf\x2a\xa3\x0a\x0a\x73\xb1\x7c\xc0\x66\x1e\x24\x30\x81\x51\x8d\xb2\x81\x71\x2b\xd8\xda\xb2\x12\xc2\x29\x33\x87\xae\xd3\x7b\xf4\x2c\x96\x4c\xc9\xc1\x58\x0c\xbd\xaf\x6a\x71\xff\x7c\x9b\x03\x8a\x2d\xaa\x3a\xd9\xdc\x9c\x0e\x7c\x19\x8f\xa3\x2c\x4d\xd3\x19\x7d\x7a\x37\xbc\x1e\xdc\xc2\x1a\x3f\xd5\x4e\x38\x40\xf1\x53\x40\x92\xf1\x54\xe0\x47\x78\x20\xd4\x18\x51\x4a\x7b\x9d\xf2\xcf\xc3\xc3\x74\x30\xad\xd1\xab\x50\xf0\xa7\x20\x4a\xa0\x21\x31\x5b\x90\x2f\xe7\xcd\xd3\xb8\xca\xdc\xda\x52\x8f\x4e\x29\xa7\x22\x72\xc8\xd6\xa9\x8a\xe5\x18\x42\x93\x94\xfd\xeb\x50\x4f\x83\x67\x14\x1e\x20\xec\x7a\x8e\x60\x43\x17\x84\x9b\x69\xba\x24\x48\xf0\xf3\x98\x9e\x79\x7a\xe6\xa9\x59\x7c\xb4\x40\x03\xf1\xcb\xa6\x9a\xc1\xea\x0d\xe7\xe8\x24\x76\x9e\x2e\xc8\xad\x78\x08\x94\x54\x14\x41\xaf\x09\x3e\x8b\x01\x00\x7d\x4e\x96\xf6\x50\x8c\x9d\x5d\x89\xac\x49\x8c\xb0\x1f\x8b\x2f\x86\x9c\xba\x9d\x22\x04\x47\xd7\x0c\x6f\xf6\x25\xb7\x40\x3f\x01\x35\xac\xd3\x8f\x2a\x4d\x94\x86\xfd\xbd\xb5\xb5\x27\xb0\x30\xfd\x86\xad\x56\x33\xe2\x51\xcb\x57\xe9\xf9\x23\xd4\xb7\x6a\x13\x7e\x3b\x84\xc1\xea\x1f\x54\xbe\x94\xf3\x28\xfe\xe6\xf4\x3a\xdf\x28\xf3\x06\x95\xec\x09\x1f\x6c\xe0\x77\x37\xe0\x5e\x19\x6c\x14\xcd\x06\x79\xab\x2e\xaf\x00\x6f\xe4\x9c\x46\xad\xe4\x78\xbd\x84\x1b\x73\x01\x97\x4e\x48\x80\xfd\xdb\xd5\xfa\x46\x40\x26\xce\x63\x9e\x11\xe9\x9a\xe7\x86\xdd\xa7\x85\xd7\x5d\xb4\x53\x02\x35\x7a\xc6\x17\x9e\x7c\xeb\x33\x4e\x3a\x8f\xbf\xf9\x6b\xb5\xdc\x18\x77\xd7\x35\xfc\x3e\xe6\x70\x27\xf0\x92\x3b\x87\xb5\x0e\xc9\x59\x49\xa2\x2e\xea\xfa\x37\xb1\x98\xeb\x58\x35\x94\xde\x44\xda\x2c\xec\xc2\x97\xda\x38\xf8\xf1\x43\xd5\xfe\x04\x68\x9e\xf1\x1b\x90\x2b\xcb\x46\xd1\x2a\x62\x38\x3f\x72\x16\x9c\xdd\xb2\x6f\xa8\xf4\xa4\xd5\x8a\x03\xec\xa1\x41\xe8\x98\x3d\xb2\x3f\xb2\x00\x90\xb9\xad\x4e\x15\x7b\xad\xa7\x5b\xaa\x75\x59\x2e\x88\x62\xab\x2b\xe9\x0d\x1f\x34\x09\x0e\x74\x69\x0c\x54\xa8\x55\x7c\xdd\x38\x27\x5a\xa5\xa7\x87\x69\x7e\x62\x8d\x51\x7a\xfa\xe4\x1f\xa4\xde\x0f\x35\xc6\xf0\x86\x8f\x2d\x54\x2f\xd2\x9a\xbd\x41\x4f\x7a\x37\x91\x1e\xab\x5e\xf3\x35\x5f\xa5\x67\xca\xae\x2c\xeb\xe4\xae\x72\xbb\xe4\x86\x02\x12\xba\xba\xfc\x0b\xe2\x61\x79\x34\x21\xee\x08\xf3\x54\x3a\xa9\x8a\xd0\xa5\x34\x99\x82\xa1\x51\x52\x5c\xe9\xf1\xe9\x73\xb4\x48\x84\xb3\xeb\x5e\x70\xd2\x70\x0d\xa2\xab\xb5\x8e\xab\x83\x88\x21\xef\x30\x95\x46\x9b\x32\x2e\xc8\xb5\x97\x87\x07\x1f\x66\x50\xed\x88\xc3\xdf\x87\xf6\xd3\xcd\xcd\xdc\x9b\x11\x0b\x65\x40\x0b\x51\xe7\x2e\x56\xf6\x14\x24\xc4\x6c\x17\xc5\x44\x5d\xb2\x84\x4a\x05\xe2\xe9\x51\x1c\x7c\x1d\xe9\xdc\xf4\x33\x7b\x96\x4c\x36\x2b\x6a\xac\x79\xa6\x2f\x94\x80\xe2\x95\x58\x05\x8c\xfd\x12\x60\x24\x13\xbb\xc4\x27\x71\x44\x53\x90\x0c\xca\x5c\xb6\xc5\xac\x79\x86\x17\xcb\x40\xbf\x7d\xdc\x33\x35\x42\x2d\x35\x38\x24\xd2\x4f\x53\xda\x29\x55\x4c\x39\x40\x83\x30\xb9\xd1\xd7\xcb\xe4\xf9\x8b\x78\x55\x1f\x93\xe7\xdf\xc5\x3d\x3d\x4c\x9e\xbf\x8a\xcd\xfe\x25\x2f\x5e\xf9\x29\x19\x97\x7b\xf4\x6a\x35\x19\xc3\x2e\xf4\xda\x2e\x7e\x2e\x79\xd4\xc7\x35\x44\x0b\x14\x37\xbd\x7c\x31\xfd\xea\xa1\x6b\x3b\xde\x6e\x28\x13\x90\x8f\x40\x35\x38\x26\xbc\x4a\xc6\x42\xa7\x4d\xad\x1d\x31\x8a\x17\xbc\x59\x91\x73\x0d\x4f\x9d\x0d\xff\x62\x7d\x8c\x7c\xbc\x57\x7d\xd1\x54\x5f\xc9\x21\x2c\xf4\x45\x00\xc4\xe9\x2f\xc4\xdc\xe3\xaf\x7e\xac\x78\x41\x63\xb4\x16\x8d\x73\x0b\x93\x53\xd5\x13\xb3\x88\x2b\xf9\x63\xc1\x82\x60\x2a\x02\xb1\xe0\x26\xa6\xf7\x52\x64\x66\x24\xa3\x39\x65\x11\x46\x9a\x12\x82\xf7\x23\x86\xdc\xe4\x1f\xf8\x16\x7b\xcb\xb0\xb5\x8f\x9c\xdb\x56\x2d\x0f\x03\x43\x29\x43\xce\x4b\x18\x21\xb9\xab\x73\x53\xf9\x33\x1b\x97\xa2\x80\xcd\x50\xfd\x8a\xbb\x9d\x10\x4c\x3f\xa5\xc5\x83\x6b\xda\x53\xad\xed\x6e\x5b\x1e\x19\x2d\x3a\x6d\xd5\xe4\x57\xb1\x8c\x70\xd7\xf6\x8e\x73\x44\x74\xa5\xde\xa0\x9c\x1d\x87\x3f\x33\x70\x26\x50\x17\x95\x69\xf8\x9a\x13\xd8\xb6\xd8\x62\xea\x88\xcb\xcc\xea\xe5\x99\xbc\x78\x1d\xff\xc3\xec\x66\x47\x08\xb3\x2e\xbb\x19\x19\x00\xac\xb6\xd0\xc3\x65\xec\x0a\x30\x32\x5d\x59\xe4\xa3\xc0\x3a\x4f\x14\xc2\x9b\xc9\xca\x22\xff\x8e\x77\x16\x4f\x09\x20\x9a\xc7\xe8\x50\xa9\x87\x39\x69\xb2\xaa\xfd\x97\x64\xb3\xb3\xa1\x76\xc7\xf6\x28\xaa\xf6\x55\xe5\xf2\xa2\xb2\x1a\xf4\x57\x7d\x19\x6b\xa8\x06\x08\x20\x5f\x51\x1d\xcb\x8b\xca\x0c\xaa\xb5\xeb\x52\x71\xac\xaa\x40\xb9\x0e\x73\x5e\x16\x96\x0c\xf2\x75\x38\x97\x4f\xc8\xf9\xb4\xb3\xa2\xff\x14\x91\xc7\x99\x1e\x2a\xb4\x16\xad\xc9\xf0\xaf\x4a\x46\xc8\x26\x6a\x21\xfa\xff\x8d\xe0\xcc\x12\xaf\x2d\xbe\x76\xa7\xa0\x3c\x32\x2d\xca\xf2\x1f\x6f\x4f\x84\xd6\x5c\xc5\x49\xcc\xdc\xfd\xd8\xb8\x54\x0c\x50\x4e\xf6\xae\x5c\xad\x74\x96\x09\x9d\x37\x73\x9b\xae\xac\xc3\x07\xbf\x0c\xa8\x13\x3d\xfa\xb6\xf0\x93\x1f\xc5\x52\x8f\xee\xbe\x76\xeb\x15\xe1\xbd\x21\x89\x66\xd6\x84\xf1\xd5\xbe\x55\x6c\x57\x65\x66\x46\xdf\xea\x2d\x54\xbd\x46\xbf\xee\x63\xe0\x9f\x34\x4d\xad\xee\x27\x06\x42\x17\xa4\x10\xde\x0d\xea\xd0\xe9\x6b\xcc\xfe\x87\x39\xf8\x12\x1c\x96\xa1\xdd\x25\xf8\x74\xe4\x65\xc1\x5a\x33\x99\x3d\x8d\x5f\x57\x15\x51\x93\xb3\xba\x10\xcd\xc3\xaa\x22\x0c\x6e\xb7\x84\x02\xab\x93\xb5\x0e\xab\xd8\x1a\xab\x3c\x84\xb5\x34\x77\xb4\x56\x21\x4e\xf5\x8d\xd8\xd3\x1a\x5d\xc3\x9c\x71\x3b\x05\x69\x02\xed\xb1\x5b\xa5\xfe\x9d\x27\x51\x0e\x9f\x2f\x62\xe2\xcd\x3c\xd3\x97\x3e\x06\xa5\x4b\xe8\x3f\xc5\xa8\x74\x64\xe7\x36\x76\xd4\xae\x97\xbc\x01\xb2\x4b\xf8\x3e\x5c\x63\x9a\x8a\xa3\xcd\x48\x56\x71\x0b\xf4\x61\xdb\xc9\x98\xbc\x34\x76\x8f\x4c\xa3\xbb\x4e\x8d\x6a\xdd\x53\x71\x7c\x4f\x1f\x33\xf5\x1a\x3a\x02\x52\xeb\x89\x54\x2e\xd3\x3b\x87\xae\xb0\xf7\xde\x1e\x7f\x3a\x0d\x48\x0c\xcb\x9f\xf0\xcb\x60\xa9\x1a\x79\x4d\x97\xf7\x7b\x74\xbc\x0e\xd7\x35\xa7\x78\xe7\xfd\x06\x3b\x2f\x1c\x05\xea\xce\x9d\x4b\xcd\xb9\x91\x4a\x2e\x88\x48\x84\x1d\x5b\xeb\x3d\x8c\x72\x0c\x2c\x26\x43\x91\x95\x3e\x36\x24\x46\x6b\xf0\x65\x60\x30\xbb\xb3\xea\x3c\x46\x5d\x5b\x4f\xb6\x60\xba\xff\xf8\x62\x6b\x0b\x0f\x77\x0e\xe5\x90\x45\xf7\x39\xfc\x11\x8e\xf3\x51\x6a\x8c\x71\x05\x2a\x3c\x84\x5b\x5b\xb2\xad\xb9\x0a\xc2\xa1\x16\x6a\xa8\xec\xaa\x48\x2b\x5c\xaf\x18\x6d\xd5\x3f\x5a\x97\x5f\x4b\x63\x75\x93\xc3\x8a\xfa\x83\xcc\x37\x27\x4f\x0e\xf3\xe5\x13\xc3\xac\xa3\x51\xc1\x3e\xc6\x4c\xb9\x9c\xbe\xf4\x92\xe1\x8b\xa7\x36\xcb\xf3\x1e\x65\x8a\xfb\x8f\x9f\x4f\x7e\x4e\x84\x7f\x9d\x4f\x87\x1f\xdf\xed\xed\x1f\x26\x81\x90\xd7\x06\xf1\xc7\xe3\x8f\x09\xb9\xe0\xd1\xb7\xaf\x10\x0b\x3e\x5f\x21\x95\x1f\x3c\x13\x8e\x82\x9e\xbd\xab\xc6\xa4\x6c\xb3\xc7\xef\x4c\x3f\xfb\x6e\x0f\xd6\x4d\xa6\x81\xfb\x12\xc7\xf0\x18\x67\x18\x32\x7b\x40\x1d\x15\xcf\xb2\xa3\x42\x11\x45\x6a\xea\x52\x68\x8f\xd1\x25\x40\xe2\xcb\x48\xd6\x82\x01\xe4\xbb\x76\xb9\x7c\xf0\x7b\x9c\x0f\xee\x22\x6f\x03\x3e\xa1\x72\xff\x78\x92\xe7\x78\x79\x78\xde\x23\x63\x7e\x62\xa4\xd1\xbd\xbf\x03\x1e\x60\x3b\xd2\x5d\xbf\x0c\x16\x7a\xba\xaf\xeb\x38\x29\x44\x65\x4b\x5f\xcb\x15\xd6\x84\x06\xff\x26\x26\x4f\xd1\x4d\x82\x6e\xb7\x34\xe3\x42\x3a\x50\x2a\x61\xaf\x16\x13\x31\x50\x0d\x48\x32\x1e\x8f\x15\x8b\x48\x24\x08\xde\x97\x2b\x92\x45\xa5\x38\x4b\x87\xca\x19\x40\xf2\x7d\x6c\xf6\xde\x90\x66\x21\x68\x1c\xf1\xb4\x7e\x0e\xa8\x2d\xbe\x43\x06\x26\x97\xcb\xb6\xad\x4a\x83\x12\x56\x4e\xd6\x36\x61\x5d\xcc\xf3\x36\xfb\xb7\xfc\x0e\x43\xab\x64\xb3\x56\x3c\x8d\xdb\x7a\x26\x1e\xc9\x0d\x14\x3c\x47\x22\x72\x9b\x06\x7f\x8b\x72\x1d\xff\x2e\xc9\xd5\xfe\x33\xa4\x11\x53\xf3\x01\xee\xd6\x57\x72\xbe\x96\x22\x91\x34\x8d\x15\x93\xcf\x9c\xbf\x59\x5a\xad\x98\xbf\x77\x45\xf9\xa5\x9b\xb7\x26\x5e\x1a\x33\x97\xd1\x89\xbc\xaf\x14\x41\xc7\x62\x12\x0d\xe5\x97\xca\x9b\xcc\x94\x1c\x64\xb1\x8d\x6b\x4c\x74\x5b\xf7\x5a\x95\xfb\x40\x0d\x7f\x81\x04\x84\xef\x3a\x46\x8c\x76\x5f\x02\x4e\x40\x8d\x60\x5e\x34\xdc\xa0\x23\x67\xa5\xa8\xf1\x23\x43\xdb\x9a\x4a\x92\x93\x3a\x37\x19\x1d\x09\xc6\x9b\x35\xb1\xad\x4b\x66\x5e\x43\x39\x8c\x4b\x88\x73\x3a\x91\x7d\xcc\x51\xc1\x36\x9f\x60\xc6\x0e\x96\x11\x81\xe8\xc9\x26\x05\x99\x2e\x5c\x0e\xb5\x60\x85\x05\x94\xa1\x35\xa5\x2b\xdb\x57\xba\x26\xb8\xa4\x7f\xbb\x14\x26\xc1\x99\x7a\x37\xb5\xbb\xcc\x8b\x82\x52\xe8\xfa\xea\xb6\x99\xd6\x54\x70\xb5\xf4\xaa\x73\x5b\xef\xd8\x52\x0e\x46\xe6\xfe\x99\x2f\x03\xfd\x5c\x48\x1e\xbb\xbc\xcf\x7e\x75\xdf\xec\xd6\xad\x45\xc0\xdf\x40\xc1\x41\x9f\x5a\x38\xc6\x0f\xbd\xd7\xad\x1b\xe2\xfb\x6b\xa5\xf6\x24\x40\x0a\xb3\x64\x69\x45\xeb\x00\x21\x4d\x66\x5e\x5b\x1a\x9f\x9e\x12\x3a\x3d\xdd\x8a\x34\x83\x29\x2e\xa0\xab\xfa\x1d\x99\xb8\x6b\x26\x70\x97\xb6\x93\x93\xe1\x8e\x07\x73\x75\x3b\x3b\x19\xbe\x5e\x53\x2a\x1f\x9b\x68\x25\x19\xbe\xfc\x1e\xf1\x9e\x23\xa8\xff\x4f\x3c\x12\x4c\x9e\xfd\x7f\xfd\x33\xc1\xe1\xfe\xff\x27\xc2\x46\xd1\x61\x3d\x60\x11\x80\x10\x60\x21\xd2\x5c\xbd\x01\xa2\x55\xcf\x1a\x48\x10\x44\xff\x1c\x40\xf4\x73\x35\xff\x18\x20\xf8\xd2\xa3\x29\xc1\xd0\x29\xb7\x12\x3c\x5f\xbd\x64\x5c\x78\xc0\x08\xfc\x4a\x1e\x15\xd9\xe1\xaf\x6f\x2f\x5f\xa3\xbc\xca\x00\x6c\xb6\x3e\x60\xed\x91\x27\xcf\xbf\x37\x81\xed\xf0\xeb\x7a\x81\xad\xb7\xf3\x1e\x21\x43\x00\x7f\x12\x8c\xf2\xcb\x3a\x34\x5d\x1c\x69\xb0\x1f\xfd\xaa\x4b\xa1\x85\xbf\x2a\x01\x05\xb7\x5f\x80\x6d\xcc\x41\x3a\xd7\xee\xee\x4a\x55\x6a\xb4\x57\xdd\xdd\xc6\x74\x35\x38\xe8\x73\x7e\x2e\x09\x89\x36\x5e\x28\x6e\xb7\x20\x26\xea\x47\x47\x60\x1d\x17\x71\xd6\x31\x17\x81\x9c\x89\xc7\x40\x00\xed\x50\x28\x6e\x11\x64\x6a\xf1\x66\x36\xda\xde\x9e\xd1\xe5\x0d\x88\xaa\xb3\xd9\x39\x90\x51\x55\xd8\x48\x9e\x54\x63\x4a\xf0\x1b\x4b\x71\x01\x3f\x10\xb3\xcf\xf4\xa5\x8a\x0b\x2e\x39\x7c\xc2\x53\x68\xd8\x00\x69\x46\x6e\x56\xd3\x63\x43\x04\xdd\x84\xcc\x64\x40\xfe\x95\x0c\xcd\x17\x36\xd0\x47\x6c\x55\xf9\x3a\x85\x43\xcf\xad\xd8\xaa\x8a\xbb\x75\xd8\x8a\x2a\x49\xe9\x2d\x5b\xea\x65\x4b\x55\x16\x45\x57\xba\xb4\xdd\xcf\x87\x75\x6c\x3f\x30\x08\x2f\x72\x65\x37\xd3\x94\xb8\xb1\x2b\x98\xbb\x99\x9c\xc8\xb8\xc2\x79\xe8\x67\x39\xa3\x04\x15\xdb\xeb\x1a\xd3\xe6\x2c\xd5\xb5\x72\x80\xa6\xdd\x81\x29\x5c\xca\xe9\x9b\xbd\x19\xc3\xf4\x8d\x23\x9a\xbd\xe5\xd9\x18\x16\xf5\x59\x83\x7d\x2b\xe1\xc7\xee\x1b\x8c\x12\x3b\xb2\xb5\x55\x84\x19\xc6\x40\xd6\xf8\xda\x8d\xae\x6d\x70\x29\xb5\x14\xe4\xc2\xcb\x1f\xa5\x65\xe1\x19\x3a\x84\x85\xc5\x23\xee\x72\x0f\x0f\x1f\x89\x4d\xd0\x18\xb8\xe5\xe1\xe1\x04\x08\x74\x68\xe8\x1a\xff\x7c\x60\x86\xd1\x01\xfd\x8c\x9c\x50\x97\xf5\xee\x38\xdc\x5c\x3c\x3c\x04\xe8\x1e\x16\x92\x61\x2b\xe7\xe5\xcd\xe0\xc3\xf1\xc1\xe1\xc5\xe1\x87\xbf\xb0\xce\x88\x66\x66\x82\x12\xc2\x6c\x83\x25\xaa\x1b\xb2\x1f\x38\x5d\x24\x1e\xdc\xc8\x3b\xc1\xd5\xc6\x65\x3e\xce\xa4\xbe\x8f\x30\x63\x41\x66\x82\xb4\x56\xf9\x92\x2f\x5a\xac\xd8\xdc\x95\x63\x36\x76\xc7\x82\xc2\x8e\x76\xe3\xf3\xa7\x77\x41\x94\xcc\xc2\x05\xf2\x6f\xca\x3c\x9f\x34\xd0\x3c\x51\xbe\xdc\x25\x4d\x9f\xe8\x7f\x36\x96\x8c\x12\xf5\x47\x6a\x98\x84\xf9\xc3\xc3\x29\xca\x37\xc3\x3a\xbd\x61\x08\x1e\xc1\xd4\x3d\x81\xa9\xc8\xf4\x4a\xc8\x8b\xe1\x70\x5f\x96\xa5\xf4\x33\x81\xa6\x45\xb3\x8f\x80\xb4\x20\xa1\xe3\x88\xe8\xf8\xeb\x03\x4c\xdb\x07\x8d\xb1\xf5\x3e\x12\xe0\x47\xfe\x30\xda\xd3\xee\xcd\x66\x2e\x8b\x9e\xd1\x9d\xbf\x75\xa9\x15\x6a\xe8\xcf\x74\x1c\x40\x53\x77\x48\x4b\x87\xf1\x70\x22\x2d\x04\xe6\x16\xf2\xeb\xd9\xf9\x63\x9c\x4d\x26\x76\x37\x60\xfd\xa9\x75\xb7\x2f\x28\x47\xa7\x2d\x69\x77\x2c\x10\x0c\x32\x5f\x74\x47\xc0\x8a\x8f\xae\x2c\x30\x3c\x5f\xe1\xd1\x1a\xc0\x90\x83\x54\xdd\x42\x65\x36\xa9\x0c\x5b\xe7\x0d\x49\xea\x28\x48\x94\x4f\x8e\x5e\x19\x1f\x77\xa0\xe5\x01\x54\x7c\x2c\xa3\x08\xb1\x44\x0c\xbe\xa6\x90\x96\x4c\x89\x56\x18\xc0\x10\x3f\x12\x31\xea\xb1\x29\x69\x88\x6a\x40\x7e\x9d\x0a\x61\xce\x9c\x37\x8d\xa7\xa7\xc3\x12\xdd\x63\xcf\x00\x21\x7c\xf3\xb9\x44\x3b\xc5\x8d\xb6\xda\xc0\x18\x39\x42\xe3\x8a\x14\xe4\x52\x54\x90\x7b\xf3\x0d\xf1\xe1\xe0\xde\x4c\xc2\x1e\x31\x68\x1e\x01\x77\xf6\x58\x04\xf6\x10\xf8\xb6\xc6\x88\x42\x2b\x4d\x70\xb4\x0e\x59\x76\x3b\x12\x53\xd5\xb0\xd3\x26\xbb\xc1\xbf\x04\xdb\x15\xda\x39\xae\x34\xc7\x99\x85\x12\xa9\x28\xef\x55\xb5\xb3\x47\xf5\x16\x78\xb3\x3b\x48\x24\x30\x82\x3a\xd8\x1d\xfb\xb0\xab\xac\x31\xc2\x0a\x3d\x50\x91\xd6\x56\xf5\x84\xb1\xcf\x5a\x7d\xd3\x1a\xe8\xed\x5a\xdc\x7d\xdd\xd7\x3d\xaf\xd9\x90\x74\xa1\xbe\x4e\x1f\xb8\x76\xff\xe7\x6f\xc5\x89\xf3\x06\x2e\xfe\x38\x39\x37\xbb\x21\x80\x80\xdc\x6f\xc0\xa5\x33\x09\xc7\x64\x40\x28\x6d\x93\x36\x6e\xb3\x66\x83\xc9\xce\x89\x8e\x86\xeb\x1c\xf5\x40\xcb\x4a\xa2\xe3\x6b\xd6\x25\x09\x28\x7a\x8b\xe4\x5c\xec\x11\xfb\x3f\x1f\x54\x25\x3d\x99\x41\x43\x61\xd1\xbb\x47\x88\xeb\xd9\xe4\x73\xc9\x6d\x4d\x36\x08\x19\xc2\x6f\xb7\x00\x36\x37\x98\x37\x9d\x6c\x04\xdb\xb8\x45\x74\xb3\xcd\xf7\x18\x57\x46\x4f\xb8\xd8\xed\x05\x3c\x5e\xda\x95\x8c\x4e\x4a\x07\x69\x65\x08\xd7\x2d\xdc\x05\xea\x11\x0d\x87\x9e\xcc\xe1\x70\xc7\x73\x59\x56\xf2\x48\xf7\xaf\x31\x6e\x9b\x8b\xb6\xf0\xb4\x20\x7e\x77\x2e\xd4\x62\x59\xeb\xf8\x31\x96\x19\xfa\x02\x2c\x9f\xc2\xec\xc2\x6f\x8f\x20\xc2\x2a\x11\xfd\xa0\x44\xc4\x82\xa7\x17\x10\x03\x28\xd5\xd8\xda\x2a\x53\xd4\xba\x44\x36\xb2\xe0\xde\xf8\xd4\x98\x30\x7e\x80\x16\x2d\x66\xce\xdd\x8c\x46\xe3\x90\xc9\xc3\x22\xfe\xe6\x83\x98\xf7\x0d\x11\x6f\xaf\xd3\xf3\x1d\x6c\xbc\x07\xb0\x6e\x34\x4b\x58\x20\x77\xb0\x30\x49\x7f\x53\x20\x22\x12\x43\x11\x22\xda\x40\xc2\xe9\x96\x57\x51\x89\xe5\x84\x75\x6a\x03\x18\x8a\x84\x22\x2c\x22\xa5\xa0\xc8\xf7\x82\x64\x59\xc6\x33\x20\x77\x25\x76\x7e\x78\x00\x02\xe6\x3a\x95\x1c\x16\xa2\x76\x26\xa9\x60\xaf\xd0\xdb\x3c\x2d\xf4\xb2\x37\xf0\xaa\x95\xbd\x82\x57\x55\x76\xb4\x10\x7b\x62\x37\x5c\xa6\x8b\x7e\x25\xb6\xcd\x2c\x9c\x43\x07\xaf\xe3\x9b\x78\x12\x5f\xa1\x9a\xe7\x2c\x9d\xaf\x2c\xbe\x30\x8a\xc3\xee\x5a\x22\xe1\x05\xb5\x78\x4c\x77\xa4\xfc\xfc\xbb\x64\xaf\x78\x6d\xc4\x50\x1f\x69\xf4\x21\xbd\xa3\x0a\x87\xa9\x8c\x24\x2a\xbb\xfc\xad\xa4\x20\xa3\xd1\x1d\x29\xe3\x87\xcb\xf8\xb0\xd3\x5c\xd5\x62\xb8\x3c\x3c\xdc\xe9\x02\x9d\xdd\x03\x76\x3c\x78\x04\x68\xe7\x4e\x98\x5f\xdd\xc1\x4e\x08\x67\xd0\xdf\x2b\xa3\x05\xbd\x64\xcc\x77\xf9\x3c\x66\x69\x00\x5c\x5a\xd4\xfd\xa5\x50\xf2\xfc\x58\x90\x9b\x73\x79\xcb\xb9\x11\x57\x9b\xab\xc7\x88\xfe\x01\xae\x5d\x9a\xaa\x6c\xb3\x70\x53\xf0\xd4\x04\xa1\x14\x0b\x22\x0a\xf1\x4c\x36\xc3\x88\x84\x77\x1b\x35\x67\x01\x96\x39\xd0\xe2\xde\xf0\x0d\x0b\xae\x17\x47\x03\x6d\xa3\x42\xc7\x81\x64\x82\x5d\x80\x94\x14\x13\x34\xa5\x31\x7e\x59\x7a\x8f\x89\x2c\x43\xd8\x95\xe4\x9a\x57\x46\xfa\x73\x9d\xd6\x88\x09\x3c\x54\xef\x51\xb7\x99\x6b\xa9\x8e\x5c\x23\x05\xc2\x7b\xff\x1d\x60\xc6\xbc\x44\x8b\x05\x4f\x62\x28\x3b\x61\xe2\x0b\xc5\x5f\x14\xb0\x40\xd7\xba\x26\x15\x43\xa7\x15\x3d\xeb\xe7\x84\xde\x15\x47\x45\x49\xda\x1d\x01\xa2\x5e\x7c\x05\xd1\x58\x8b\xc0\x92\xee\x68\x7c\xe9\x6b\x0f\x08\x7d\x9d\xc9\x1b\xfc\x15\x2c\xab\x43\x83\x27\xa2\x78\x65\x9f\x04\x23\xa8\x47\x29\xc2\xb0\x8c\x5b\x5a\x5e\x0e\xd7\xb2\x91\x5b\x55\xc9\x34\x5a\xd3\x4b\xfe\x11\x13\x38\xbb\xbb\x86\x29\x94\x48\xec\xef\x27\xab\x8a\xf4\xe4\x5a\x3d\x65\xe3\xb9\xd5\x0e\x08\xa5\x86\x4b\x7a\xbd\x96\xcf\x39\xdb\x1f\x18\xd4\x5b\xc3\x48\xee\x68\x80\x8b\x4d\xa8\x98\xc9\x15\xe1\xe9\x45\xad\x29\xba\x2a\xbe\x96\x47\x8d\xa7\xd3\xb2\x93\x60\xe9\x31\x3f\xd3\xb5\x71\x46\x1d\xff\x01\xc3\xae\x3d\xf6\xc3\xd8\x3a\x72\x51\x09\xb7\xec\x67\xc0\xfb\xe6\x2f\xdc\x51\x84\x6f\xbe\xbb\xb4\x8c\xd9\x94\x06\xbc\xc6\x4c\x97\xb6\x6b\xaa\xda\x91\x7b\xa3\x91\x03\x41\x04\xa7\x5d\x6c\x44\x6a\x14\x1f\x91\x20\x6e\xa9\xf3\xd8\xc6\x7d\x8e\x29\x66\xfd\x5a\xd3\x8b\xaf\xd4\x9a\x9e\x32\x23\xb4\x5f\xca\x7d\xcd\x05\xa4\xfa\x6f\xf3\xec\x68\x5e\xe0\xbc\xbc\x05\x4a\xa9\xc9\x6b\x39\xd1\x50\x72\xc2\x25\x25\x95\xda\x3c\xfb\x39\x6b\xae\xdf\x75\x34\xeb\xdc\xc9\x67\x72\x53\x2b\x72\x63\x17\xf9\xc4\xe8\x51\x2b\x72\xc5\x45\x3a\xf9\x84\xd8\xab\x90\x75\xc7\x59\xb4\xb6\xbb\xd4\x43\x91\x2a\xdd\xb6\x40\xd2\x7e\xc7\xfd\xa5\x84\xc1\x4a\x0b\x81\xf8\x92\x8b\x23\xa2\xd0\x92\xa1\x9d\xdf\x39\xa3\xc3\xb4\x90\xf6\xc9\x55\xec\xbb\xb0\x35\x6c\xe2\x5b\x4e\xf9\x59\xd1\xdb\xef\x39\x61\x9f\x10\xf8\x4c\x8e\xf5\x54\xd7\x08\x6c\x96\x0b\x62\x71\x76\x95\x8e\x3d\x0a\x83\x1f\xd3\xc5\xee\x24\x41\xeb\x93\x13\x78\xba\xa6\x85\xa9\xb1\x47\x1b\xc3\x53\x31\x54\xbf\x80\x05\x3c\xce\x1b\xe8\x66\xc4\xca\x18\x46\x17\x92\xd7\xb1\xd6\xcd\xe4\x87\xd8\x0b\xf9\x64\x38\x8c\x7d\x6a\x50\xa6\x5e\x47\x07\xef\x64\x48\x96\x12\xdd\x8c\x24\x43\xb2\x8f\x30\x26\x2e\x19\x22\xe7\x5a\x87\x6d\x32\xa4\xef\xaf\x50\x60\x88\xd7\x59\xa8\xc9\x73\xea\xad\x3d\x9b\xc9\x0b\x4a\xee\x59\xbd\xc9\x8b\xe7\xf1\xca\xb5\x9b\xbc\x78\x11\xaf\x5c\xb9\xc9\x8b\x97\x3e\xd5\xb0\xbe\xd9\x4d\x5e\x7c\x1f\xcb\xb9\x49\x5e\xfa\xe5\x6b\x5f\xaf\x1e\xbe\xc2\x81\xcb\x8b\x1d\xd7\x97\x74\x39\xd0\x35\x28\x9e\x32\xe2\x29\x07\x28\xaf\x77\x4a\x91\x10\x1f\x73\x0d\xd1\xdb\x93\x06\x3f\xe5\x40\x2e\x9f\x55\x96\x3f\x50\xca\xdb\x9a\xd6\x8a\x76\xa8\xfa\x8b\x75\xf2\x9f\x72\xa0\x4f\xfa\x13\xe8\x0c\x0a\x9b\x6b\xe0\x69\xf4\x86\x63\x32\x56\xc5\xd3\xe8\xae\x1c\xf8\x97\xf1\xda\x58\xb9\x1c\x48\x8f\x74\xa7\xd5\xa2\xaf\xb6\xa7\x88\x3e\x42\x1b\x5b\xc1\x5c\x2a\x24\x60\xa3\x63\x07\xe8\x24\x7d\x71\xc5\x6d\x52\x58\x04\xfd\xc3\x8e\x6b\xa8\x9b\x12\x45\x9c\x7f\x9e\xb0\x0e\x3b\x73\xb7\x30\xdc\x16\xe5\xc0\x83\x4c\x66\xec\xd5\x87\xaa\x84\x10\xbb\x47\x2c\x14\xe8\xa2\xec\xaf\xc0\x21\xab\x01\x98\x3c\x7f\x1e\x7f\x95\x3d\x19\xed\x94\xe4\xf9\xcb\x7f\xd0\xcc\xcc\xd9\x06\xc9\xf3\xd7\xbe\x74\x5d\xfa\x67\x43\x39\x79\xfe\xc3\xff\x0d\x6c\xd8\xcd\x5f\xf2\xe2\x3b\x44\x42\x8e\x2a\x9e\x57\x05\x4a\xc4\x85\x44\xe5\x46\xc7\x9e\xd3\xab\x12\x45\xb5\x1f\x1e\x4c\x6b\x6b\xe4\x6e\xe7\x1c\xeb\x1c\x3d\xa8\xd9\x7a\x50\x96\xee\x9c\x2e\x3a\x7c\xe1\x68\xc9\x69\xdd\x54\xdf\x9c\xe4\xe3\x6a\x92\x7f\xfe\x74\x14\x0a\xe5\x38\x09\x8e\x01\x2a\x79\x0c\x30\xe8\x5f\x1b\x06\xff\x12\x44\x67\xc3\xf3\x87\x07\x0c\x14\xab\x75\x5d\xd2\xa7\xc8\x17\x12\xc1\x2c\x9f\x05\x29\xfb\x30\x06\xc2\xb2\x05\x1a\x75\x77\x73\x27\x09\x17\x8a\x1d\x06\xf9\xdb\x39\x73\xee\x74\xc1\x23\xca\x91\xd2\xb4\x11\xfc\xa2\x50\x32\x1a\xb6\xd3\xa1\x14\x22\xdd\x0b\x0d\x78\x11\xcc\x37\x7f\x1c\x8d\xbd\xd6\xe6\xec\xa8\x4e\x17\xd2\xa1\x31\x19\xe9\x17\x85\xd9\xc3\x43\x83\x3a\x8a\x24\x43\xa7\x1b\x2a\xd9\x87\x2a\xc5\xb0\x7e\xfa\x52\x6a\x89\x75\xd8\x65\xcc\xdc\x95\xcd\x21\x10\xb3\xf7\xce\x65\xdb\xb8\x2c\x8c\xa5\xb1\x6e\x0c\x1d\x89\x67\x0f\x0f\x12\xd4\x50\x8d\xbc\x0c\xca\x5a\xbb\x3d\xe9\x61\x70\x0d\x0b\x7b\x4c\x5f\x08\xe2\x02\xa1\x27\x75\x29\xb3\xb6\x05\x08\x50\xe9\x30\xa8\x4a\xa3\x1c\x92\xe0\x9b\x3b\x74\x7d\x77\x6f\xcf\x66\x0f\xd3\xb1\x1b\x12\xb5\x63\xe7\x20\x5f\xef\x31\x8a\x77\xc8\x8c\x5d\x3a\xa5\x96\x83\xe0\xc6\xbd\xe3\xf0\x64\xad\x18\x8a\x56\xda\x3f\x14\xe4\xf6\x22\x24\x8d\xae\x67\x62\xd5\xc4\xce\xf2\x85\xfa\x69\x5e\xca\xd5\xad\xc9\x77\x9c\xfa\x42\xc1\xd5\x69\x42\x2e\x5a\x3b\x5d\xf2\x9e\xb6\xed\x8c\x06\xae\x53\xe3\xeb\x6d\x14\x41\xe8\x5f\xc6\x7e\x9b\x8c\x10\xea\xf5\xf1\xc7\x78\x29\xdd\xb9\xc5\xb6\x59\x5b\x2c\xa3\x38\xba\x97\xd3\xe0\x47\x1d\xcf\xbd\x09\x0c\x0d\xd6\x85\x50\x2d\x30\xce\x98\xa7\x14\x6a\x5f\xac\xf2\x66\xb4\x06\xaa\x78\x02\x20\x36\xba\xeb\xdb\xd1\x7e\xff\x11\xf6\x8e\xae\x68\x47\x17\xb4\x91\x3b\x23\xa6\x95\xdb\x37\x73\xb6\x2f\x8a\x14\x31\xd8\xec\x10\x36\xf2\x13\xdb\xb7\x51\xdb\x77\xf9\x47\xb6\x2e\xcc\x3c\xb1\x08\x82\xb8\xea\xdd\xb8\x5a\x19\xc4\x35\xeb\x6d\x5a\xb8\x27\xad\xb9\x69\x1b\x67\xd3\xf6\x75\xdf\xbb\x63\xf5\xde\x79\x37\xab\xdd\x7d\xef\x46\xb5\xdc\x18\x62\xbe\xf0\xee\xcb\x5c\xde\xc7\x38\x08\x62\x63\xd7\xc4\x59\x77\x0c\xc4\x34\xe3\xb0\xcf\x7b\xb6\xb1\xd5\xba\x28\xf2\xd4\x07\xb0\x51\xb1\xf9\xc5\x1e\xcd\x68\x43\x7e\xe5\x6e\x34\xe9\x0a\x6b\x43\x8e\xff\xd0\x86\xec\x77\x02\x36\xf0\x90\xec\xb5\xb3\xbe\x2b\xd8\x5e\x3d\x33\x30\x53\x64\xfd\x93\xc8\xb1\x0f\x21\x7a\x90\x5b\xed\x07\x9c\x6d\x4e\xb5\x0a\x8e\x16\xf9\x65\xc1\xb1\xf2\xc1\xd1\x47\xd3\x21\xf8\xd6\xf0\xaa\xe4\x89\x39\x84\x6a\x43\x25\x3a\x68\x63\xea\x40\x48\x76\xeb\x50\xa9\xb4\xc4\x12\x12\xe8\x8b\xbb\x53\x5c\x05\x02\x11\x68\xb3\xb8\xea\x0c\x99\xec\xeb\xc0\xc8\x31\x27\xb1\x09\x59\xec\xf5\x4a\x27\x0a\xec\x42\x81\x04\x8d\x1b\x33\x65\x37\x0e\x58\x8c\x5c\x24\x88\x89\xc9\x62\x93\xb1\x28\x09\xcb\x5d\x54\x7e\x42\x2c\x06\xdd\x0c\xc2\xb3\xbf\x3d\xdb\xfd\x97\xf3\xed\x28\x88\x92\xe0\x4f\x44\xaf\xa9\x7c\x8c\xf2\x9c\xe1\x9d\x35\xc0\x48\xa4\x54\xe2\xd7\x5f\xe1\x34\x83\xe1\xce\x90\x49\x79\xcf\x62\x38\x0e\x75\x2d\x02\x52\x06\x7f\x43\xaf\x7b\xc1\xbf\x62\x34\x45\x64\xee\x29\xc5\x23\x80\x92\x14\xfd\x63\xe5\xb5\x7c\x29\xfc\xbd\xa1\x74\xe2\x37\x04\xd1\x60\x9e\xd7\x57\x39\x2b\x42\xfe\x9d\x31\xf9\xb3\x24\xc4\x68\x99\x7b\xdf\xfe\xaf\x8b\x7f\x3d\x17\x4f\x3b\xdf\xfe\x00\x2f\x7f\x8a\x1e\xce\xfe\x34\x08\xa3\x5f\x31\x98\xe7\xaf\xdb\x0f\xf7\x8f\x7f\xfb\x57\x8c\xc8\xd9\xf4\xd7\xd9\x3d\xff\xd3\xd9\xee\xf9\x2e\x56\xc4\x92\xcb\xf4\xd9\xaf\xf8\x6f\xf7\x01\xff\xfc\xfa\x8c\x7e\x20\x7d\x0c\xe9\xbb\xe1\x60\x3b\x7a\x06\x74\xc8\xfd\x23\x92\x7c\x8e\x5b\x14\x9f\x96\x07\x3e\x6b\x8a\x58\x8f\xb1\xa1\x64\x96\xb8\x3b\xbc\x4e\xb1\x0a\x40\xa2\x15\xc2\xd0\x7a\x20\x00\xce\x11\xc4\xab\x48\xbb\x5c\x08\xd1\x69\xa7\x5c\x5e\xaf\x76\xc5\x44\x6e\x38\x70\x12\xab\xb3\x76\x7b\x78\x0e\x87\x43\x81\xee\xfe\x3b\x2d\x0c\xdb\xbd\x41\xda\x92\xc8\x52\x04\xb4\x57\xdc\x66\xb5\xda\xb4\xb8\x59\xe4\x91\x0c\x6d\xb9\xd0\xda\x54\x2c\xa2\x38\xd8\x0d\xe0\x14\x2a\x84\x18\xf1\xdb\x61\x14\xd5\x42\xb0\xdb\x9e\x15\xe7\xf1\x37\xef\x85\x6f\xa7\xe0\x9b\xed\x82\xdc\x33\x2a\xd7\x4e\xe8\x5f\x89\x05\xbd\xdf\x6c\xe7\x90\xf5\x4d\x67\x0f\x56\xa8\x06\x77\x62\x68\x52\x08\x70\xb1\x41\x01\x9b\x20\xa0\x1e\x67\xf2\x46\xc2\x9d\x49\x49\xc8\x6b\x79\xb2\xc2\x4a\xbb\x61\x46\xb5\xcf\xca\xed\xed\xf3\x58\x76\x30\x8b\x03\xd9\x3b\xaa\xbf\xf1\x2f\x1b\xe4\x5a\xd2\xd3\x33\x74\x7b\x44\xe3\xc9\x1e\x23\x05\x9a\x65\x0c\x37\x9d\x48\x4d\xb8\x65\x2d\xac\x45\x19\xe3\x69\x1e\x47\x9a\xe8\x80\xa4\xc7\x0d\x90\x3d\x70\xe5\x82\x26\x74\xad\x1f\xdf\x22\xeb\xe6\x63\x1c\xe3\xfd\x2c\x56\x4a\x36\x9e\x05\x56\x76\xbe\xbe\xa4\xd2\xd0\xa8\x64\x3b\x8e\xdd\x2a\x84\x73\x2e\x4a\x4a\x29\xe3\x2f\x84\x6a\x70\x31\xc5\x00\xe8\xf7\x70\x16\x00\xd4\x1b\x8c\x1d\xd4\xa9\xdc\xec\x2e\x6c\xad\x24\x0a\x44\xab\x48\xc5\xce\xd1\x61\x1d\xe1\x11\xdc\xa9\x1e\x79\x86\xe2\x5c\x1e\x1f\x63\xa5\x98\xb4\x7a\xe4\xcf\xfe\xf6\xeb\xb3\x3f\x3d\x13\x30\x47\x1f\x69\xd6\xd0\xdd\x0a\x50\xfe\x5f\xb9\xc2\x76\xeb\x10\xd0\x7f\x6f\x92\x17\x70\xbc\x18\xb8\x28\x79\xf9\x62\xa5\x47\x8b\x17\xab\xdd\x8a\x2b\x5d\xd5\xce\x6f\x09\x1c\x8d\x4a\x73\x50\xf8\x2f\x59\x08\xc5\x08\xc7\x21\xf4\xfd\xef\x92\xf2\x5a\x64\x57\xf9\x7f\x70\x24\x85\x87\x07\x19\xc8\x76\x20\x1f\x04\x8b\x41\x28\x57\xbe\xcb\xa7\x6d\x7c\xa7\xd7\xfc\xeb\x9a\x35\x31\x18\xc8\x3f\xd9\xf7\xcd\xe8\x7f\x58\x87\xe0\x3f\xe8\x42\xe4\xc5\x2a\x7f\x0d\x8a\x33\xc1\xcc\xb5\xaa\x1e\x2c\x9b\xbc\xde\xbb\x82\x86\x47\xd2\x4d\x10\xad\x35\xe9\x26\x28\xd8\x2b\x27\x35\x2a\x26\x3c\x1f\x04\xd1\xd6\x56\x5f\xee\xcb\xc1\x4e\x10\x3d\x3c\xd8\xd9\xef\xab\xcb\x62\x96\x6f\x9c\x64\x53\xe8\x23\x17\xd8\x34\x0a\xec\x5f\xd7\xd5\x3c\xf7\xe5\xb0\x8b\x95\x66\xe3\xe3\x35\x05\x1a\xd8\x35\x29\xd9\xad\xad\x40\x51\xca\x41\x51\x6e\x98\xb9\xb8\x17\x1d\xe3\xc5\x17\x8e\xca\x78\x57\x84\x39\xb9\x00\x4d\xc9\x8a\xa4\xe7\xe4\x25\xc2\xf3\xe5\x2a\x0f\xe0\x0a\x13\x28\x6a\xf3\x19\x21\x29\xd3\x87\x95\x2a\x45\xba\x1a\x90\x8d\x0a\xe6\xf4\x1d\x2e\x9c\xbc\x24\x8e\x64\xd7\x58\xf2\x12\x3d\x6f\xbc\x5c\xe5\x71\x5a\x50\x02\x68\xc8\x3a\xc9\x67\xc5\xbc\x80\xf3\x81\xe2\xa3\x4e\x48\x90\xfa\x5d\x4c\x02\xf2\x77\x98\x81\xc2\x15\x75\x86\x70\xca\x30\x7f\x01\xc7\x23\x23\xd4\xbf\x64\xb3\x65\xde\xa4\xd6\x9a\x11\x4a\xd3\x35\x9e\xeb\x68\xa8\xcd\x1c\x2f\x74\xfe\x26\x3e\x16\x0f\x9f\xed\x08\x0f\x55\x7a\xd3\xbb\xec\x45\x38\xb1\xd3\xd1\x6c\x63\x07\xe8\x14\x69\x73\x3c\xca\xde\x14\xa3\xed\xed\x82\x07\x05\x74\x2c\x1e\x15\xcb\x94\x56\x50\xe7\x08\x31\x38\x4f\x61\xee\xb5\x77\x78\x4d\xac\xec\xed\x21\xd2\x00\x54\x71\x19\xd5\x67\xe5\x80\xb1\x6c\xd8\x44\x90\x1b\x74\x6a\x9b\xe3\xb4\xcb\x52\x47\xe5\x32\x42\x1e\x8a\x93\xb1\xdc\x1e\xa2\x53\xd4\xb3\xf1\x79\x5a\xdb\x5a\xeb\xe3\x68\xf7\xec\x5c\x7a\xc9\xc5\x22\x91\x7c\x99\x45\xc9\x4c\x91\x76\x35\xdc\x1d\x18\xc0\x6c\x4a\x95\xda\x02\x1a\x24\x5c\xa4\xed\x80\xa4\x5f\x5a\x15\xbb\x8d\xd5\xfd\x29\x58\xc1\x23\x8e\x2f\x38\x3b\xc7\x53\xa0\x8a\x0a\x24\x6e\xf1\xb4\x97\x3d\xd0\x3f\x22\x55\x18\xbb\x51\x67\x69\x70\x46\x15\xcf\x76\xce\x61\xd7\x70\x23\x67\xca\x91\xfe\xf0\x7c\xb7\x12\x63\x1e\x76\xee\xf5\xe1\x3e\x5e\x01\x7d\x28\x23\x7f\x03\xfd\x3c\xdc\xc1\x2b\x6c\x10\x6c\x37\xa3\xcd\xa2\xf9\x90\x7d\x08\xd1\xc9\x65\x05\x7b\x36\xdb\xda\x5a\xa6\xf4\xd3\xbc\x49\x77\xe0\xef\x8f\x00\xce\x6e\xf1\xed\x86\xdc\xe1\xb3\x06\x41\xe9\xe9\x6a\x52\x9c\x65\xfe\xac\xc7\x4e\xe9\x40\x64\xff\x5b\x7e\xd7\xf8\xe0\x98\x4b\x3d\xd8\x67\x7f\xc3\x50\xfb\x40\xe8\x02\xd5\xfb\x0c\xa0\xf4\x2c\xfc\xf5\x4c\x26\xfc\x7a\x1e\x01\xcd\x8a\x2b\x30\x07\xbc\x8a\x27\x3c\xce\x80\xb0\x73\x53\x2e\x13\xec\xd9\xce\x90\xda\x90\x8b\xf4\xec\x7c\x84\xef\x30\x48\xbe\x16\x50\xa6\x32\x30\x58\x02\x31\xc8\x64\x52\x0a\xc4\x53\x21\x3f\x03\x70\x5a\xfe\x88\x2b\x0c\xf6\xe5\x28\xda\xde\x5e\xc6\xeb\x7c\x53\x3b\x92\xcf\x1e\x28\x82\x3e\x10\x31\x11\x72\x6a\xb5\x2f\x4b\xd7\x89\xaa\x43\x30\xd7\xdb\xb9\x98\xcf\x8c\xb7\x09\x50\x1e\xe7\xa4\xf3\xaa\x03\xb8\x11\xee\x7f\x1e\x35\x83\x7e\x8b\x22\x86\x25\x47\x64\x07\x7b\x26\xe3\x27\x2d\xba\x6d\x17\x4a\x58\xac\x5d\x58\xa6\x82\x32\x8e\x35\x2c\x91\x3a\xea\x5a\x5a\x26\x34\x4d\x1a\x3c\x74\x5d\xd2\xd2\xa3\x5d\xed\x05\xae\xd0\x1d\xce\x69\x19\x8c\x69\xc0\x71\x2a\xcd\x56\x21\x63\x57\xfc\x52\x25\x54\xcb\x69\xb5\xa5\xe8\xab\xa5\x2d\x54\xfd\x05\xea\x77\x2f\xb1\x8d\xcb\x7c\x0d\x59\x58\xd0\x4e\x48\x6a\x2b\x41\xad\x9a\xca\x05\x51\xbe\x6b\xa0\x66\x9a\x90\x24\x27\x54\x00\xeb\x57\xac\x9e\x2f\xb0\x17\xc2\x0a\x59\x76\x80\xc5\x52\xc9\x13\x1a\x2d\xdf\x34\x80\x56\x9b\x48\xa0\xbc\x0c\xf6\x1d\x20\x38\x6d\xff\x00\x39\x5c\xa1\x71\x4b\x0b\xeb\x1f\x76\x2a\xdd\x24\xc3\x22\x9e\xa9\xed\x56\x52\xb0\x2b\xa0\x2f\x42\xf4\x9a\xdc\x39\x3e\x43\x52\x0f\x4f\xa5\x7e\x4f\xf6\x2b\x4e\x25\x45\x25\xef\xe0\xb9\xa3\x4e\x3a\x73\x33\x57\xec\x0a\x0e\xd6\xc4\xdb\xe5\x74\x9a\xd7\xec\xf0\x07\x95\x83\x85\xcf\x26\x80\x82\xae\x50\x7c\x00\xa7\xbf\x28\x70\x74\x72\xac\xca\xc8\xf5\x4a\xf6\x0f\x01\x5e\xda\x1d\x00\xc3\x52\xb6\xa7\x10\xd3\xd0\x8c\x2f\xcf\x4a\x77\x71\x9f\x29\xd6\x4e\x47\xb9\xb7\xb0\xb3\x52\x8d\xa3\xdd\xe5\xe4\xd1\xb9\xb8\x84\x02\xc2\xc0\x8d\xb4\x62\xdb\x6c\x14\x6a\x25\x98\x53\x9b\xaf\x33\xb5\x23\xed\x20\xd8\xac\x06\x02\xca\xf6\x85\x0e\xc0\xa8\xc1\x3c\xcc\x69\xfa\x63\xd2\xbc\xb7\x53\xb7\x11\x83\x8c\x11\x65\x40\xbe\x8e\x81\xfb\xf0\x84\x79\x1b\xf6\x8d\x54\xdb\xcb\xbb\xda\x5e\x4e\xb4\x74\x20\x96\x44\xd7\x53\x77\x0e\x54\xde\xae\x7a\x4a\x6a\xf9\x34\x52\x6e\x64\x11\xce\x22\xea\xf5\xa6\x36\xa7\x72\x31\x74\xb7\x60\x09\xee\xc2\x06\x77\x06\xe0\x6e\x00\x9e\x02\xdc\xcd\x9b\x0c\xc0\x9d\x31\xb8\x97\x29\x1e\x53\xa3\x0a\x5d\x1e\xc8\x73\x57\x87\xdd\x12\x88\x17\x00\x87\x82\x58\xc5\x2e\xa9\x4b\xef\x0e\x7a\xe1\xd3\xd6\x20\x7c\x73\x5a\x39\xc4\x42\x47\x8b\xb5\xb8\xff\x4b\xe8\x64\xdd\xd9\x1c\xd6\x6f\x4a\xe8\x64\x19\xf9\xe2\x8e\xa3\x69\x1d\xde\x61\xe1\x27\x25\xe7\x67\x5d\xec\xa7\x58\x6c\x7c\x17\xe9\x2b\x6f\xa4\x1b\xb9\x17\xa4\x2a\xdb\x59\x62\x39\x1f\x41\x88\xaa\xce\x5a\xb4\x9f\x8f\xfd\x2d\xa8\x95\x9f\xa7\x67\xb9\x22\xa4\x00\x1d\xb9\x12\xde\x4d\x8b\x31\xc1\x26\x4d\x16\xac\xf0\x88\x1d\x75\xf4\xaa\x3e\xa9\x2d\xde\xc6\x76\x00\x71\xd6\x12\x5e\xc5\x9b\x0a\xe0\x55\x49\xdf\xef\x35\xfa\x00\x6a\xd2\x16\xe7\x36\x47\x3a\x04\xff\xec\x4a\xac\x88\x2f\x71\x03\x04\xa7\x9c\xd5\x1c\x01\xc7\xa4\xa2\x31\x43\xe4\x79\xc7\x92\x06\x69\xe8\x40\x3b\xcb\xb7\xf1\x20\xdf\x40\x85\x2d\x76\xb6\xa3\x5d\xc2\xd1\x9d\x90\x44\xbd\x9e\xc3\xf8\xe9\xb5\x0d\x33\x46\xbb\xf1\xec\x5c\x70\x2a\x5a\xcd\xdb\x2b\xd3\xc8\xe8\x02\x56\xd1\x9a\x67\x35\xed\x9a\x56\x09\x72\xec\x09\xd0\x02\x78\x31\xd1\x89\x04\x7c\x6e\x13\xf0\xfe\xa5\x57\x9c\x77\xee\x98\x91\x9f\xa4\xd8\xc2\x8f\x4c\x4a\x99\x7b\x8f\xe6\x8f\xdb\x6f\xbc\x17\x84\x65\x8a\x81\x14\x46\xb8\xd1\xd2\xee\x80\xa2\x7d\xd7\x46\xc6\xf4\x48\x82\x22\xf5\x30\x52\xce\x18\x88\x82\x43\x4b\xb4\xb0\x43\x8b\xc9\xc3\x86\x55\xed\x50\x04\xd0\x1d\x48\x9e\x36\x37\x9e\xa0\x8e\x76\x37\x87\x09\x39\x75\xd1\x5c\x92\xa2\xea\x82\xee\xa1\x54\x36\xdf\x97\x4e\xe2\x04\xbe\xc5\xbe\x74\x24\x20\x01\xf9\x79\x85\x2e\xc3\xe2\x18\x69\x47\xf1\xb4\x1a\x2f\x1b\x8c\x30\x2a\xbd\x85\x3e\xe5\xe8\x55\xf8\xc1\x58\xb6\xd5\x4f\x58\x15\x9d\x94\x48\x05\xdb\x2e\x56\xa9\xcf\x63\x64\xf7\xa5\x64\xf8\x1d\x6a\x82\xbc\x74\xe4\x0c\x46\x27\x3d\xfc\x08\x71\x7f\x47\xfa\x57\x31\x28\xc5\x82\xef\x40\x09\xd7\x17\x57\x38\x91\x0f\x6e\xf2\xba\x29\xd0\x83\x99\xba\xae\xa8\x34\xb8\x3f\xc1\xc5\xe5\xc7\x74\xf8\xdc\xab\x59\x12\x1a\x5e\x75\x3a\x57\x3b\xc2\xff\x0e\x22\xa0\xae\x08\x4e\x0e\x17\xd1\xd4\x4d\x06\xcf\x48\xd6\xb7\x5f\x11\x51\xd2\x6a\xde\x09\x28\x1d\x29\xfa\x8c\xf8\x2c\x9d\xb8\xb5\x87\x21\x24\x3d\x48\x9e\xdc\x95\xed\x75\xde\x16\xe3\xa3\x72\xb1\x6c\xa9\x95\xce\x09\x37\xec\x96\xe3\x29\x69\x59\x64\x1d\x03\x09\xc0\x72\x9a\xff\x2e\x8a\x2a\x5e\x08\xf6\x3d\x90\x4c\xac\xf7\x38\x39\x90\x25\xdf\x01\x75\x84\x74\xf1\x7d\xf1\x3c\x5e\x08\x87\x98\x64\xba\xb2\x7f\x9d\xd5\xfb\x38\xd3\xb3\x28\x9e\xc2\x59\xd7\x56\x8b\x77\xf9\x4d\x3e\xe3\xc0\x43\xd7\xe9\xfd\x65\x0e\x3b\x35\xa7\xbe\x25\xf7\x0b\xb8\xb7\xe4\x13\xd8\x4c\x05\x4c\x2d\x09\x80\x98\xe5\x7f\x7f\xb9\xbc\xbc\x9c\xe5\x93\x64\x19\xde\x57\xe5\x5b\xad\x0a\xa9\x5a\x43\xff\xb3\x05\xc0\xdf\x53\x60\x9f\x33\x44\xb9\x47\x64\x66\xa0\xee\x77\x39\x2e\xd0\x66\x1f\x23\x62\x2c\x08\xaf\x32\x3b\xf0\xb0\x9c\xc4\x94\x06\x93\xf2\xb1\xce\x9b\x86\xdf\x10\x1a\xd4\x1a\xbf\x7e\xcc\x9a\x36\x47\x5d\xfc\x09\xdb\xa0\xcc\x51\xbc\x7d\x93\xde\x93\x3b\x1d\x36\x64\xb8\x96\x0c\x69\x8e\x6e\x69\xfb\x72\x93\xc7\x05\x19\xde\x47\xc2\x29\x58\x2e\x9c\x82\x19\x1d\x48\x18\x57\x55\x83\xdb\xeb\x62\x7c\x8d\xe5\x97\x80\x72\x67\x02\xe5\x8e\xe6\x78\x2a\x66\xe9\x42\x77\x0f\x66\x76\x39\x81\x2a\x78\x45\x9d\x64\x6d\x46\x01\x12\x16\x5b\x5b\x73\x59\x9d\x6b\x09\x83\xd8\x84\x13\xc9\x4d\xdb\xbd\xaf\x4f\x34\xee\x84\x07\xed\x7c\x50\x75\x58\x74\x15\x96\x4b\x0d\xb7\x09\x38\x5f\x27\xde\xf5\x20\x8a\x45\x91\xd3\x92\x39\x1f\xf0\x3d\xee\xfc\x23\x52\xf2\x8c\x1a\x27\xb2\xff\x59\x3a\xc1\x64\x41\x52\xdd\xa4\x84\x5b\x3e\x22\xbd\x37\x09\xaf\x07\xda\xd2\x22\x98\xcb\x13\xe3\x86\xda\x4b\x33\x39\x7f\xc5\x20\x1b\xc3\x32\x5e\xce\x80\xfa\x3f\xbd\xad\x3e\xe2\x22\x3c\x10\x46\x37\x70\x59\xba\x89\xe2\x1b\xd3\x7b\xda\x0d\xa3\x29\x6b\xa7\x26\xdf\x91\xe6\x9c\xb3\x4f\x93\x57\xa4\xfe\xd6\xcf\x7b\xf5\xef\xd1\x64\xc8\x7a\x75\xbc\x45\x93\xe1\xeb\xd7\x88\x08\x1d\xd1\x65\x1f\x22\x34\xd8\xf1\xdb\x6d\xc7\xeb\x07\x10\x7f\xc6\x48\xa5\xfb\x30\xca\x30\x82\x9c\x66\x79\xc9\x84\x67\x38\x94\x2e\x22\x01\xb9\xcf\x96\xf3\x72\x9f\xd0\x3a\xac\xb0\xe9\x2c\xff\x5d\xfe\xfe\xb9\xae\x6e\xe5\xf3\xc9\x35\xd4\xfb\x42\x6f\x55\xd9\xfe\xc2\x61\x76\xe1\x6d\x06\x67\xd6\xfe\x2c\x9b\x2f\xe4\xcb\xcf\x2a\x0b\xe0\x32\x2e\xda\x3b\x7a\xac\xd1\x08\x83\x1e\x60\xe3\x97\x78\x97\x8b\x6f\x0b\x64\xd2\xe2\xd3\xff\xa1\x80\xb2\xf4\x54\x55\x73\xfa\x46\x31\x9b\x1d\x77\xd5\xa1\xd3\xd5\x97\xbc\x4b\x40\xb6\xe2\x59\xf0\x4b\x7e\xf9\xa5\x40\x99\xd8\xbc\x81\x3f\xef\xab\xff\x03\x7f\x8f\x83\xf3\x91\x4e\x1e\xd4\x91\x57\x01\xa6\x72\x53\x11\x86\x67\x68\x8f\x06\x37\x30\xa0\xed\x60\xd7\xcb\x20\x27\x70\x77\x46\x41\xfc\x55\x8d\xca\x98\x89\xf6\x7c\x34\xcf\xae\x72\xec\x5f\x97\xa4\x5c\xe4\x19\xa9\x9f\x00\x15\x65\xad\x99\xb6\x5f\xcd\x30\xc6\x0f\x8c\xe5\x92\xa1\x73\xcf\xbf\xbf\x50\x38\x63\x2c\x4a\xaf\x1c\xf6\x58\xbd\xda\xb5\x38\x0a\xb4\xac\xcb\x6f\x56\x0b\x9c\x68\xb5\xc3\x89\x76\x6b\x28\xdc\x90\x6d\xe1\xb3\xd5\x12\x26\x59\xed\x60\x92\xdd\x0a\xb9\xa9\x94\xcd\xd0\x8b\xd5\xce\xa7\x2e\x9e\xb3\x99\x66\xb7\x84\xb1\xd5\xef\xd5\xa3\xd5\x0a\xa4\x58\x6d\x9c\x22\x46\x91\x2d\xe0\x32\x4d\xee\xf1\xaf\x2a\x85\x2f\x7f\x61\x89\x87\xbb\x90\xa9\x24\x4a\xc5\x9c\x75\x8c\x39\x3f\x65\xf3\x62\x46\x4b\x0f\xd9\x28\xf7\x45\xf3\xb9\x2c\xda\x19\x20\xc1\x0f\xc4\x0a\x48\xea\xb8\xb9\x06\x84\x81\x26\x42\x92\x15\x07\x54\x22\x9a\x30\x00\xd2\x48\x0a\xdb\x21\x3c\xee\x6f\x47\xb8\xd5\x47\x8d\xed\x9f\x9c\xc8\x36\x3b\x51\x41\x0f\x25\x50\xa5\x21\xeb\x4a\xc0\x61\x8a\x32\x3e\x1a\x3b\x9e\xac\x18\x6f\x19\x33\x26\xa8\xfc\x54\x63\xf4\x7a\xcc\x21\x26\x11\xdc\x28\x24\xe5\x71\x7d\xb7\xb8\xce\x4b\x74\xf8\xa8\xd5\x13\xb4\xc7\x3c\x9f\x57\xd4\x22\x22\x90\xe3\x72\xc6\x3a\x5f\xfc\xb9\xce\x44\x29\xf3\x39\xf1\x26\x5f\x68\x11\x71\x81\xc7\x4d\xf3\xd3\xac\xca\x60\x84\xb5\x4e\x86\x30\xe7\x1f\x11\x7e\xaf\x10\x0d\x7b\x34\x90\xd5\x51\xa3\x15\x99\x5f\x90\xc6\xcd\xf1\x56\x1d\xcb\xa0\x1f\xef\xb3\xfa\xcb\x72\xf1\x53\xc5\xfb\xa7\xf1\xc8\x89\xb5\xdb\x3c\xf9\x2d\xc9\x23\x0a\xa0\xe1\xb8\x99\x91\x5a\x04\x78\x0b\x16\x2c\xda\x1a\x6f\xc6\xdb\x69\x03\xb9\xdb\x41\x12\xc4\xf0\x8c\x82\xde\x1a\xde\x46\x41\xe7\x31\x47\xc4\x65\x40\x8b\x35\x82\xb3\xaf\x37\x9d\x96\x42\xce\x23\xec\x58\x0c\xfd\xbe\x6f\x8a\x48\xde\x41\xab\xb0\x88\x49\xe4\x4e\xb7\xe5\x29\x41\x22\x95\xb6\xd7\x4b\x98\x8d\xa8\x86\xdc\x34\xeb\x78\xfa\x0d\x5c\x81\x56\x2c\x55\xbc\x28\xa1\x13\x9b\x48\x76\x63\x4c\xae\x59\x22\x12\x67\x08\x89\xc8\x06\xb5\x19\x04\x8f\x8f\x1e\xad\x2c\x63\xb5\x26\x2f\x5f\x3d\x75\x1e\xba\x0b\x35\x19\xbe\xa4\x53\xd4\xb7\x52\x21\x8f\x74\x94\x3c\xeb\x34\x19\xbe\xa2\x43\xd9\x5d\xa6\x70\xa0\x52\x25\xcb\xf0\xe5\xa5\x23\xec\xec\xbf\x69\x70\x58\x0a\xbc\xd5\x21\x02\x6f\x34\x0f\x2b\x17\xc2\x3d\x3e\xa7\xe9\xea\x4a\x4c\x9c\x90\x7f\x99\xce\xdb\xb2\xed\x40\x53\xec\x3b\x4d\x06\x3c\xaa\x4c\x2f\xcc\x79\xf9\xf7\x65\xbe\xf4\xc7\xc9\xe8\x3a\x64\xbd\x93\xd1\xbc\xd5\x3f\xf3\x55\x2f\x21\x6b\xa9\xcb\xbc\x59\x54\xf2\x66\x50\x75\xa0\x2d\xa6\x77\x7b\x7a\x08\x0e\xc3\x9e\xb2\x6b\x2a\x6e\xad\xef\x8d\x58\xd4\x02\x98\x40\xdc\xd1\x49\xfe\x27\x24\x58\x76\x47\x7a\xe1\xdb\x6d\x59\x97\x95\x55\x6e\x6f\x47\xb8\x49\x85\x9d\x1b\x31\xad\xd4\xc7\x76\xe2\x56\x3d\x52\xe4\x6d\xd8\x94\x6e\xb8\x92\x35\x26\x18\xae\x15\xf2\x8e\xed\xd4\xa7\x56\xd9\xd7\x31\x59\x8b\xe3\x0a\x40\x83\xec\x0a\x75\xc4\x1c\x75\x35\x8f\x97\x44\x73\xd1\x24\xaf\xc9\x74\xc5\x91\xd2\xbf\x74\xa4\xd1\xbd\x94\xa1\xe2\x5e\x9c\x1c\xbe\x3b\xdc\x3f\x65\x5d\x90\x12\x88\x72\xdc\x32\x0f\x0f\xc1\xd1\x87\x8f\x9f\xad\x54\xbc\x29\x17\xb3\x9c\x13\x71\x09\x7a\x35\x8d\x7f\xd7\xc8\xef\xd3\x01\x2b\x95\xc7\x1f\x31\xfc\xfa\xe1\x6a\x12\xbb\x8d\xe2\xcb\xc1\x25\xbd\x88\x08\x30\x0d\x7a\x99\xb6\x6d\x17\xee\x06\x62\xdd\xf3\xad\x0a\x17\xe5\xdd\x40\x98\xc5\x51\xd2\xbf\x63\x66\x18\x39\xae\xc3\x8e\x53\xe8\x47\xda\xc6\xc7\xb6\x1e\xbf\x54\x7c\xaf\x23\xdd\x33\x18\x54\x00\x5c\x79\x3c\x98\xe4\x3d\x85\xe3\x63\x5e\x0b\x1f\x85\x79\x83\xaa\xdb\xd8\x71\x73\x01\x60\xef\xe9\x52\x43\x75\x77\x4b\x19\x13\x57\xd5\x58\xca\x1a\xaa\x28\x31\x4b\x76\xc3\x0c\x65\xb5\x21\x4b\x34\x55\xde\xdb\xd9\x12\xce\x99\x4c\x1f\xe2\xd8\x1c\xe2\x09\x4c\xd0\x0d\xa2\xc5\xf8\x83\x64\x45\xc1\xa4\x68\x07\xc5\x41\xde\x8c\xeb\x62\x01\x4b\xd5\xe4\x21\x69\xe8\x25\xb8\x61\x0a\x40\xca\x15\x99\x09\xa5\x4e\x9a\x63\x59\x20\xfe\x12\xb9\x20\x5d\x88\x62\x12\x5a\x0b\xad\xaf\x33\x01\xda\x49\x3e\xcb\xdb\x7c\xe3\x58\xf4\xd4\x81\xb4\xdb\x86\x09\x71\x18\x25\xfd\x7c\xb0\xe1\xbf\x90\x6e\x68\xb8\x83\xb4\x5c\x65\x63\x14\xde\x5e\xe9\x83\x35\xf5\x58\x12\x11\x54\x76\x84\x8a\xdc\x27\xd0\xb7\x13\x00\xa2\x60\x90\xa9\x66\xa7\x7d\xd3\x4a\xf7\x35\xcf\xac\x5e\xf7\xcd\xea\x0c\x3d\xb8\xfa\x67\x75\xa6\xcf\xea\x44\x57\xbf\xda\x14\xe5\x4e\x00\x6c\x94\xcd\xab\x69\x6b\x4b\xe5\xc0\xed\xfb\xf3\xc2\x7c\x3f\xa8\x6e\xcb\x87\x87\xcd\xe3\x87\x07\x01\x66\xf8\xda\x89\x54\xa6\x80\x51\x4a\xe0\x7f\xd4\xbe\x3a\xd7\x90\x83\x17\x0b\x84\x01\x6c\xd1\xf1\x97\xcb\xea\xf7\x0e\x15\x00\xc6\xa8\xb3\x49\x51\x75\x29\x5a\x8b\x37\xbd\x1b\x02\xbd\xd2\x76\x90\xc3\x69\xb9\xea\x61\x80\xdd\xe9\x0c\xb0\xd9\xf2\xaa\x28\x7f\x5e\x5e\x76\xb6\xdc\x1e\xc6\xd8\xfe\x4a\x72\xf8\x52\x5a\x60\x67\xe3\x56\x60\x9b\xce\x7c\x5b\x5d\xc5\x25\xa7\xec\x93\xb4\xf7\xa6\x84\x13\xb6\xcc\xcd\x27\x9d\x25\x77\xd1\x28\x66\x8b\x58\x51\x9d\x4d\xb7\xe4\xaf\xbd\x4f\xaf\x2c\xd6\xd7\x29\x06\x75\x27\x47\x42\x4f\x73\xbd\x6e\x91\xa9\x25\xdc\x0e\xd9\x0c\x2f\x2d\x6f\x35\xaf\x4b\xad\xb4\x58\x43\x48\x71\x37\x17\x71\xb7\x4c\xe3\x6e\x6d\xc7\xfa\x72\x8a\xbb\xb5\x16\xfb\x16\x24\xf2\xc4\x56\xec\xd3\xf8\x20\xdd\x1c\x8e\xf6\x75\x0a\x3f\x3c\x48\x3f\xe1\x9a\xa2\x6d\x8e\xcc\xa2\x15\x3c\xc6\xc8\xa3\x4c\x87\x65\xde\x7c\x1f\x49\xff\x7d\x4e\xf3\x47\xd8\x7c\x81\x03\xf9\xc3\xad\xff\x20\x5a\xff\x42\xc1\x77\x3c\x2e\x2c\x3e\x20\x82\xed\xec\xe8\x23\xa2\xed\x8d\xbb\xc5\x09\xea\xb9\x00\x42\x46\x5f\x1b\xba\xc1\x3d\xf2\xe0\xf7\x0c\xbe\xe1\xe9\x2a\xbe\x61\x2d\xf9\x86\x45\x4c\x9c\x43\x64\x4f\xec\x1e\xec\x16\x69\x93\x64\xe9\x32\xb9\xc0\xd7\x23\x78\x9d\x26\x40\xe7\x63\x4c\xda\xeb\x28\x99\xb3\x8c\xab\xc0\xf0\xa8\x85\x14\xf4\x16\x22\x5e\x31\xb3\x1f\x29\x71\xe6\x3f\xbc\xc7\x1a\xdb\xec\x89\x33\x7c\x16\xc5\xb3\xc7\xc7\x0c\x4f\x27\x6e\xdd\xb8\x07\xec\x3d\xcd\x32\x53\x3b\x3b\x79\xb5\xf3\x47\x19\x69\xc6\x9e\x4e\x86\x6c\x73\x6b\x6d\xe9\x64\xf8\x82\x49\x28\x7b\x47\x03\x25\x25\x9c\x01\x38\x1b\x1a\xb2\x5e\x38\xcc\xb8\xef\x1c\x45\x3e\xcf\x65\x7d\x87\x64\x25\x6c\x84\x80\x9d\xfb\x54\x55\x2d\x73\xb6\xdc\x95\x04\xc4\xaa\x23\x0e\xc1\xef\x38\x6a\x7b\x2b\x48\x3b\x8b\x71\x7b\x65\x71\x54\x4f\xda\xac\x96\x9c\x5e\x98\xd1\xb1\x95\x33\xf2\x56\x42\x36\xac\xaf\x0a\xa4\xfb\x2b\x88\x28\x7e\xbe\x3a\x9c\x65\x07\xcf\x36\xce\x87\x2b\x0d\xe5\x60\x54\x3e\x00\x3a\xb2\x8c\x91\x0f\xe0\x04\xe7\xf2\x0d\x97\x10\x54\x22\xb5\x4f\x29\x24\xb2\x14\x5b\xaa\xc6\xa2\x91\x51\x1e\x3f\x25\xbb\xab\xca\x40\xcd\x89\x59\x8c\x39\xdc\x5d\xd2\x7b\xb8\x88\xe6\x54\xb7\x4b\x43\x14\x9b\x48\x7f\xb3\x16\x6f\x1d\x5d\x24\xe9\xb4\xa9\xbc\x22\xc0\x9a\x90\xc1\x7c\x1a\x9c\x06\x85\x57\xd3\x31\x45\x1b\x94\xaf\xea\x1a\x46\xa5\xe8\xf6\xab\x7c\xd6\xe0\x9a\x0d\xa3\x2e\x12\xab\xe7\x20\x6d\x7a\x0f\xcc\xe5\xca\x03\x73\xac\x1d\x98\xb4\x2d\x54\x87\xba\x58\xac\x6a\x93\xe9\xeb\x46\x1c\xa1\x22\x22\xab\xe8\x24\xf9\xf4\x28\xdb\xbd\x31\x92\xed\xe4\x5a\x60\x6a\x1e\x96\xd7\xe9\xd9\x0f\xf1\xf0\x45\xfc\xfc\x75\xfc\xe2\xf9\x79\x3c\x49\x9f\x3f\xff\x21\x9e\xa3\x73\x56\x4d\x42\xe5\x7c\x46\x09\xaa\xe2\x9b\x74\x13\xe3\x97\xf7\x61\xfa\xad\xad\x9e\x63\xa4\x27\xe3\xc7\x74\x38\x8c\xaf\xd2\xcc\x3a\xc0\xef\xf8\x4c\x3b\x14\x92\xd0\x6e\xa7\x3c\x7d\x9e\x4f\xe9\xcc\x36\x6b\xd9\xe7\xba\xa7\xcc\xea\xf3\x5d\x2d\xbe\xd8\xb3\x7d\x63\x7d\xa1\xc7\xc6\x72\x8e\xbb\x3d\x13\x9b\x8b\xfa\x5c\x78\x83\xd2\x31\xc7\xd7\x0f\x8e\xeb\x3d\x35\x3c\x2a\xf5\x47\x07\x48\x95\xff\x09\x43\x14\x68\xeb\xeb\xc7\x28\x2a\x3e\x35\x48\x2e\xf6\x47\x47\xc9\xb5\xff\xe0\x30\x1f\x47\x85\xa6\x92\x20\x76\x62\xea\x1e\x41\x0a\x1f\xf1\xed\xe0\xe1\x41\x25\x9c\x2d\xc2\x08\xc0\x65\x35\x73\x80\x92\xb4\x5e\x3f\x5a\x8c\x93\xe2\xce\x83\x97\x86\xda\xf8\x35\x2e\x53\x0b\xa1\x49\x95\x61\x5f\x15\x80\x53\x67\x1d\xc5\x72\x2b\x94\xcd\xc8\x2a\xe5\xb7\x6d\xc4\x8a\x63\xfb\x06\x55\x75\xb8\x8a\xaa\xca\xe2\xa5\xa0\x8b\xe2\x05\x12\x44\xf3\xdd\x31\x19\x87\x25\x77\xbb\x78\xc6\x2c\x23\xf2\x5b\x6e\x9f\x7b\x51\x52\xf7\x64\xd2\x62\x8c\xe2\x1b\xc8\xb9\x7b\x78\x18\xc3\x21\xe2\x66\xc3\x27\x52\xa7\xc9\xad\xad\x3b\xa8\xb3\x48\xef\x24\x5c\xc3\x48\x20\x19\xe8\x8b\x08\xa9\xdf\x46\xb0\xbc\xb8\xbb\xd3\x74\xa6\x51\x6c\x63\x1a\x87\x04\x0e\x5c\x05\xc3\x29\x4b\x39\xe1\xea\xdc\xac\x26\xdc\xa6\x80\x80\x4d\xa6\xed\xfe\x3f\x5b\xbe\xe9\x3b\x39\x92\xe1\x8e\x49\x9d\x39\x18\x1d\xe8\x37\xfa\x62\xcf\xb9\x91\x0c\x5f\x7d\xe7\xd2\x64\x8e\x32\xe9\x0a\x01\x29\x5d\xd0\x81\x36\x68\xf2\xba\x65\x9d\x01\x5a\x4d\xe4\x97\x10\xd5\x4f\x9a\xb3\x52\xc4\x51\x16\x82\x51\xc9\xb0\x3d\x20\x2e\xb4\x16\x39\x02\xc7\xf7\x1e\xce\xf9\x82\x3c\x48\xf1\x4e\x95\x0e\xbf\xb2\x27\x4e\xbf\xc6\xe1\xf6\xa2\x8e\x26\x7a\xfa\x48\x83\xb6\xab\x81\xd7\xeb\xe5\xae\x39\x36\xb8\x6e\x77\x05\xd2\xf6\x31\x71\x6d\x2e\x46\xf9\x60\x5a\xd4\x0d\xbb\xb6\x1a\x45\xb9\x72\xf1\x08\xaf\xa1\x9e\x47\xb7\x81\x4e\xf9\x76\x00\x68\x23\xaf\x0f\x94\x7e\x87\x3c\x11\xa1\xbd\x6c\x81\x08\x8b\x5b\x90\xbe\x79\x70\x68\xa4\xd1\xd3\x92\x4a\x8f\x10\xbb\x28\x6e\xfd\xec\xee\x13\x6b\xac\x61\x19\x74\x86\xca\xa2\x98\x04\x45\xfb\xab\x8b\xc4\x1c\x6b\x4c\x03\x5d\x52\xc7\x82\xe7\x27\x08\x7d\xcf\xa8\xd9\xdf\xc8\x92\x8f\xe8\x31\xff\xcc\xd2\x9d\x51\x46\x51\x14\x46\xb3\xed\x6d\x94\xa1\x64\xc4\xad\x40\xd1\xc8\xe0\xfd\xf1\x5f\x0e\x2f\x0e\xff\xe3\xe8\xe4\xf4\xe8\xc3\x9f\x1f\x1e\xb4\x9c\x4f\x87\x94\x87\x3e\xef\x19\x38\x0b\x20\x05\x50\x95\x81\xa8\x78\xa0\x5d\x32\x54\x85\x86\x7e\x61\xbf\xf5\xb5\xb3\x40\x6f\xb6\x32\xf3\xe8\x60\x44\x3b\x6d\x99\x2e\x49\xa3\x7d\x79\x76\x7d\x9e\xe2\x1f\x62\xb9\xe3\x03\x94\x4f\xa7\xd0\xd7\x31\xa5\x08\x5f\x26\x53\x5e\x78\xac\x03\xa1\x01\x0a\xdd\x17\x32\x7c\x50\xcf\x91\xae\x71\x72\xd8\x73\x18\xe6\xfc\x47\xe9\x3f\x64\x34\x87\xa1\x8e\xcf\xe6\xe7\x7a\x27\xf5\x25\x80\x79\x9d\xb6\xe3\x8d\x80\xd1\xcd\xf9\xe8\x06\x2a\x0a\xea\x9a\xa1\x21\x48\xec\x62\x70\xf4\xe1\xe4\xf0\xd3\xe9\xc5\xfb\xbd\x4f\xff\xf6\xf9\x63\x52\x86\x3a\x00\xe2\xc9\x59\x36\x98\x53\xcf\x08\x3e\xe7\x31\xd2\x4d\xf4\x68\x68\x7a\x58\x10\xb7\x5b\x59\x9e\x75\x80\x3b\x3f\xd3\xe0\xdd\xdf\xde\xe9\xe1\x7f\x9c\x5e\xec\x1f\x7f\x38\x3d\xfc\x70\x0a\xc8\xd9\x68\x2e\xd3\xf7\x89\x55\x4f\x9b\xdf\xc4\x2b\xbb\x12\x9b\x3d\xf9\xee\xbb\x78\xf5\x56\x07\x8c\xb6\x0e\xbe\x72\x58\xf7\xdf\x39\x5e\x41\xd6\x50\xea\x08\xf3\xad\x36\xa2\x08\xc8\x9a\x74\xc9\xb4\x1a\xbc\x7f\xff\xf9\xe4\xf4\xe2\xf3\xc9\xe1\xc5\xde\xe9\xe9\xa7\xa3\xb7\x9f\x4f\x0f\x93\x61\xac\x12\x3f\x7e\x3a\xfe\x08\xf3\xf8\xd7\xe4\x79\xfc\xf3\xde\xc9\xc5\xc9\x11\x06\x75\xf8\xe9\xa7\xc3\xfd\xd3\x93\xe4\x25\x25\xbd\x3d\x3e\x7e\x77\xb8\xf7\xe1\xe2\x2f\x7b\xef\x3e\x1f\x26\xdf\x53\xda\x87\xcf\xef\x0f\x3f\x1d\xed\x8b\xb4\xe1\x2b\x4a\xfc\x78\x7c\x72\x74\x7a\x84\x50\x34\x72\x5f\x72\x15\x00\xef\xa7\x77\xc7\x7b\x07\x87\x07\x56\x8b\x70\x38\xb0\x59\x34\x90\xf4\x92\xbb\xcc\x01\x6b\xbc\x26\xbc\xa2\x48\x91\xb3\xbf\x67\x8c\x6d\x01\x15\xf7\x5a\x80\xd3\xe5\xb2\x25\x0e\x25\xe7\x34\x9c\xf3\x51\x63\xfc\x72\xc6\x92\x33\xde\x2f\x5b\xa2\xea\xde\xe7\xed\x75\x35\xa1\x2c\x40\x6b\x45\xb3\xbf\x6c\xda\x6a\xae\x1a\xdc\xda\xca\x06\x17\x4e\xea\x4f\xa2\x67\x52\x30\xe6\xd6\xeb\xb6\xd3\x98\xc5\xb5\xf7\x75\xb8\x99\x41\x39\x38\xfb\xcb\x49\x56\x4f\xb0\x43\xae\x11\x18\xfa\xe1\x30\xcb\xa0\x78\x15\xee\x90\xcc\x9f\x19\xc3\xba\x7f\x57\xdd\x4a\xc5\x9d\x11\xe1\x2f\x22\x00\x9a\xa6\x00\xaa\xd4\xa8\x38\x3b\x4f\xc7\x40\xaa\xb9\xdf\x10\x18\xac\x80\xa6\x47\xfd\xd5\x17\x58\x9d\xb2\x0d\xe8\x62\x7f\x16\x1c\xc6\xd3\x9f\x39\x13\x6d\x6a\x80\xc7\xe4\xc6\x63\xf1\xd6\x40\x46\x22\x3e\x62\xce\x07\xd6\x58\x7a\x6a\x60\x04\x95\x44\xd9\xe3\x4f\xd3\x96\xc7\x30\x07\xe0\xc3\xad\x50\xf5\x05\xab\x97\xe1\x34\xae\x06\xee\xf2\x47\x10\x8b\xf2\xb2\x65\x4f\x71\xb9\x31\xb0\x34\x74\xe3\xa4\x98\xe4\x87\xd3\x29\x2c\xd3\xa6\x2b\x6c\xef\x18\x51\xf6\x2d\xdb\x1a\x10\x21\x6b\x16\x36\x56\xbe\x28\xfd\x01\x4e\x54\xd8\xe3\x9e\xd2\xc6\x3e\x12\xa5\x59\x8b\xe8\x26\xef\xaf\xe5\xdf\x86\xa2\xfa\xf1\x4d\x5e\xcf\xaa\x6c\x92\x4f\xfa\x3b\xd9\xb7\x53\xd1\x83\xcb\xa6\x17\xd4\x0f\x0f\x9b\x3e\x90\x62\x05\x5f\x3a\x15\x77\x60\x4a\xcd\x6f\xfa\x00\xb8\x2d\x92\xad\x31\xcb\xe4\xde\x31\xc1\x9d\x9d\x8c\xd1\x84\x85\xd3\xfd\xd1\x41\xb7\x08\x2e\x3e\xec\xbd\x3f\x4c\x02\xa4\x8e\xbf\x25\xb3\xe7\x62\x12\xc4\xe6\xc6\x4b\xee\x39\xfc\xbe\x67\x6f\x88\x2c\x63\xe9\xcb\xe2\xda\xb2\x17\x49\xe6\xca\xc6\x44\x1b\x86\x5a\x9a\xac\x8f\x49\x26\x8c\x44\x8a\x3e\x48\x91\xa4\x03\x46\x24\xf9\xd6\x89\xc8\xf2\xc3\x0b\x33\x57\xe0\xb9\x04\x35\xf5\xed\xdc\xc4\x6f\x4f\xb2\x33\x6a\x7f\x5c\x8d\x34\x05\x59\xd2\x02\x75\x21\x48\xcd\x95\xe5\xcf\xda\x73\x66\x75\xe7\x2a\xb4\xfe\xce\xa3\x62\xa6\x69\x01\xd2\xa4\x32\x8d\x02\xa2\xc7\xa4\x2c\xae\x53\xf4\xcb\xa1\x9c\x2a\x3c\x3c\x84\xe4\xa7\x03\x6d\x92\xe1\x96\x8a\xc8\x1a\xd3\xca\x4e\xdf\xc8\xf2\xf6\x0c\x0b\x15\x2d\x51\x4a\xf8\xc3\x8f\xd2\xaf\x07\x2a\xf7\x55\xb6\x3e\x97\xf7\xac\x5f\xad\x6e\xdf\xa3\xc0\x29\x7c\x6f\x60\xb4\x23\x7b\x8f\xe4\xe7\x5b\x5b\x9b\x32\xc7\xd8\x26\x98\xc3\x96\xb5\x28\xdc\xa8\x7b\x51\x08\x96\x1b\xbe\x91\x4d\xf4\x6c\x29\x2c\xc4\xb1\x45\x75\x7a\x43\x3b\x64\x3b\x6d\x96\xbc\x19\x67\x0b\x22\xd8\x61\x3a\x84\xaf\xcc\xee\xaa\xe4\x53\x18\xcb\x1c\x85\xb1\xc2\xa7\x30\x86\x3a\x00\xdb\xdf\xa4\xc1\x37\xa8\x35\xd6\x38\x4a\x5d\x47\x07\x3e\xdf\x15\x59\x58\x0f\x9c\xdd\x1f\x6d\x73\x5b\xd0\x54\x6c\xb5\xd2\xb3\x7e\x28\x40\xf6\xea\x13\x1c\xed\x8b\xec\x32\x00\x37\x36\x41\xa4\x56\x4c\xc7\x29\x68\x44\xe4\x1c\xa2\xda\xea\xf4\x4c\xf5\x9a\x73\xb4\xb3\x5b\x85\x45\x94\x64\xf0\x07\x06\xda\xf2\x40\x55\xb3\xce\x66\x43\x5b\x2b\xb1\xc2\x76\x83\x00\xaa\xe5\x5d\xb5\xc4\xd1\x56\xf3\x02\x48\x58\x5a\x3e\x05\xa2\xd6\x07\x22\xd8\x4b\xf7\x1a\x3c\x2c\x62\x80\xf7\x7f\x11\xa1\xcc\xaa\xd2\x62\xb3\x87\xf8\xcd\x48\x04\x74\x42\x6d\x02\xbb\x7f\x04\x71\x2d\xba\xb9\x73\x78\xc1\x77\x73\x94\xc8\x75\x70\xf0\xcc\x47\x7b\x1e\x07\xc1\x76\x65\xd8\xbf\xd7\x0e\x8d\x03\x9d\xac\xed\x63\xad\x45\xeb\xf8\x60\x9b\x8c\xc0\x50\xfe\x57\x61\xf4\x1a\x7c\xa9\xe0\x64\x62\x8d\x39\xcf\x54\x90\xb4\x8e\x27\xa3\xda\x95\x37\x35\x3d\x3b\xb1\xfa\xdc\x72\xff\x88\x8f\xe8\x03\xc3\xd7\xaf\xe3\x95\x93\x54\xae\x98\xa4\x32\xc2\x8f\xb0\x40\xff\x69\xc8\xdb\x43\xf3\x02\xdf\x08\x92\xe5\x83\x7b\x2c\x56\x4d\xcf\x29\x10\x76\xca\x0b\x24\xc9\xec\x9d\xa4\xea\x1c\x2f\xfb\x34\x45\xf0\x58\x3c\x35\x45\xbe\x99\x31\xee\x8e\x8d\xb8\x3b\x6a\x08\x32\xf9\x8e\xf8\x64\x5e\xf4\x98\x0c\x39\x73\x6d\x3d\xc5\xef\xd6\xb6\x88\xd2\xdd\xf8\x68\xaa\xfe\xb1\xe6\x1a\x85\xcc\x07\x35\xb4\xde\xab\x46\xac\x79\x5c\x23\x1e\x07\x7a\xc7\x67\xcc\xd9\x21\xf8\x7c\xbe\x68\xef\xe4\xf9\x6d\xb0\xbf\xb8\xe4\x2f\x75\xb6\xe8\xe3\x7a\x3d\xfb\x5b\xf8\xe3\xd9\xdf\x36\x7e\x7d\xf6\xe6\x1c\x7d\x80\x8d\x53\xa6\xd2\x98\xf5\xf1\x2d\xf5\x37\x40\xcf\x60\x3d\xbc\x10\xd3\x6d\x63\xa8\xe9\x12\x77\x57\xb2\x56\x7a\x16\xdb\x19\x2d\x7e\xec\x22\x6d\x22\xb3\x23\xc4\x8b\x0f\x72\xab\x4b\xf5\x94\xa1\x4c\xbd\x45\xef\x6d\xf1\x0c\x4f\x7e\xfc\x43\xfc\x19\x7c\xc0\x6b\x12\x16\x14\xf7\x11\x8a\x5e\xb4\x43\x1f\x6a\xd9\x79\x1c\xac\xfe\x99\xbb\xbb\x78\x23\x4d\xa8\x2d\xd5\xad\x39\xd6\x98\x60\x8d\x89\x5d\x63\x1e\x49\xf3\x96\xc9\xd9\xfc\x7c\x84\x7f\xd2\x1b\xdd\x01\xd6\xbf\x0e\x37\xd0\xc4\x1a\x4f\xc6\xed\x39\xfa\xf7\xfa\x26\x12\xfa\x34\x15\xb4\x46\x66\xc3\x68\xb4\x5e\x30\x10\x78\xe4\x57\x72\xe4\xdb\xdb\x0b\x6e\xfe\x2e\xbd\xc2\xb1\xdc\xe1\xe7\xb5\x2b\xb0\xf9\x0e\xf7\x30\xc0\x4f\xf3\x74\xfb\xce\xd8\xad\x90\x1c\xdf\x39\x5b\x02\x12\x9b\x70\x73\xea\x19\x4f\x3c\xc5\x41\xdc\xc5\xe4\x78\x58\x39\x38\x69\xc2\x6b\x0a\x66\x25\xf5\x3f\x9b\x70\xda\xa9\x85\x2a\xc7\x26\xf1\x14\x50\xdd\x53\x7c\x45\x73\x6b\x98\x4b\x21\x26\x7d\xc3\x26\x0c\xae\xdb\xf9\x2c\x20\x27\x41\x6d\x76\x45\x98\xd0\xb8\x61\x47\x42\x82\x0f\x47\x21\xc0\xee\x6c\xe7\x7c\x94\x9b\x4c\x34\xfa\xb0\x60\x83\x92\x32\x87\x13\x39\x7b\xb5\x92\xb3\x77\x1f\x25\xc3\x97\xe4\x9f\xdb\xdc\x46\x80\x1f\x86\xb1\xb3\x8b\x92\xe1\xab\xe7\x7e\x8e\xd2\x6a\x33\x21\xcd\x8c\x40\xca\x5c\xeb\xf4\xac\x0c\xef\x3f\xe5\xcd\xa2\xc2\xfd\xa4\x69\x64\x48\xa9\x16\x64\x9f\x14\xf3\xc5\x2c\xf7\xe7\x9d\x66\x0b\x7f\xc6\x61\x89\x1e\x2a\xf2\xec\xa6\xa7\x22\xab\x0e\xf5\x7c\x90\xa4\x05\x3d\xf5\x2c\x71\x81\x53\x40\xb3\x02\xf4\x17\xd8\x2b\xb3\xd9\x1d\xc6\xf2\xf4\x67\xb3\xaf\x29\x76\x35\x45\x1a\x52\x6e\xb1\x73\xd7\x76\xd5\x94\x46\xac\x6d\xce\xe1\xc8\xea\xeb\x5e\x59\x7d\x65\x09\xdc\x49\xca\x27\x45\xed\x86\x40\x02\xcd\xb7\x3a\x0c\x2c\xa7\x1a\x95\xfd\x4d\x51\xf6\x32\x2d\x70\x3b\xff\x84\xb2\x00\xaa\x89\xb1\x60\xc6\xe9\xfd\x9c\x5a\xc6\xf9\x4b\xe0\x0c\x31\xa5\xa1\x40\x26\xde\xc3\xf9\xdf\x95\x10\x80\x33\xa5\x99\x8d\x12\x43\x1e\x2f\xdb\x58\x7b\x03\x0a\x16\x2e\x4f\xf4\x01\x5a\x1b\x2b\x3f\xc0\x25\xfe\xc0\x07\x1e\x01\xd9\x9f\x71\x9c\x30\xf8\x73\x4e\xfe\x24\x3b\xb1\xe0\x78\xb5\x91\x66\xc6\x9e\x80\xc8\x7d\x94\xde\x2c\x20\xc0\x0c\x76\x3f\x4a\xd3\x26\xa7\x59\x7d\x85\x5e\xde\x98\x43\x2d\xee\x89\x91\xe1\x3c\x52\xc4\x0f\x36\x3a\xca\x9a\x9a\x66\xb3\x8e\xc7\xc9\x05\xdb\xd2\xb3\x52\x03\x72\x7a\xa3\x45\xda\x76\xf4\xd0\x34\x6d\x4d\x19\xcd\x68\x91\x4e\x77\xa7\x32\xbc\xe9\x5f\x8a\xfc\xf6\xe1\x61\x2a\x30\x16\x3b\x3f\x13\x0e\xea\xe8\x70\xb8\x8e\x27\x23\x77\x78\xcb\x76\x17\x90\x70\x1b\x4f\xd2\xa5\x6f\x90\x6d\x25\x87\xf8\xf0\xb0\x88\x12\x28\xba\x80\xa2\x2d\xaa\x6c\x74\x56\x99\xdd\x08\xe6\xe9\xf5\x2e\xad\xac\xa3\x83\xf0\x3a\x4a\x82\x20\x86\x33\x4c\xa5\x4c\x28\x05\x0e\x29\x5d\x8c\x39\xe8\x96\x44\x3c\x87\x29\x18\x5d\xb1\x24\x26\xa0\xf4\x19\xa6\x07\x28\xdc\xa6\x2e\xa5\xd7\xf0\x68\x74\x32\x9d\x88\x20\x7c\x9e\x46\x69\x99\xc6\x37\xd8\xa8\xe8\xe8\x9d\xde\x76\x5e\x52\x78\xdf\x3b\xd9\xf6\x84\x4e\x34\xbd\xed\x6b\x54\xe0\x57\x92\xd4\x0e\xaf\x69\xb2\x54\x0c\x7b\x36\x8f\x6f\x22\xa0\x0f\x76\xce\xd3\x2b\xf8\x19\xe2\x39\x37\xf3\xb8\x0e\xff\x4a\xf1\xaa\xb6\xa3\x93\xe1\xce\xab\xb8\x07\x03\x24\x43\x8e\xa5\x60\xa2\xa1\xd5\x46\x2d\xe6\x71\xf0\xbe\xc0\x50\x7b\x84\x81\x00\x09\x4a\x8d\x07\x16\xa4\x49\xc5\x06\xb1\x15\x2b\x2c\x21\x55\x9e\xd8\x38\x42\x2a\x96\x76\xaf\x88\x39\xbb\x37\x57\xe9\x25\xf6\x29\xa8\x79\x32\x34\x1d\x0b\xce\x21\x03\x8c\xf7\x79\xb9\xd4\xd2\x16\x77\xdd\xcb\xb2\x6b\xe6\xa0\x5a\xc2\x28\xcc\xae\x1c\xd4\xd9\x95\xf1\xa2\x77\x88\xdf\x25\x5a\x53\x29\xbf\x17\xad\x91\xd0\x21\x26\x99\x82\x3b\xd9\x48\x30\xc7\x73\x00\x13\xab\x5e\x38\xf8\xa8\x7c\x23\xcd\x5b\xf5\xd6\x59\xb7\xc7\x9a\x86\x9a\xf6\xce\xaa\x68\x5a\xc2\xe7\xae\xe1\x77\x55\xd6\x0d\xa5\xd3\x51\x33\x52\xde\x57\x5a\xcf\xe5\xe6\xb7\x12\xf4\xb1\x50\x8a\xf6\x0d\x36\x06\x97\x6f\x9f\xc8\x74\x46\xbe\x71\xfc\x93\xee\xd5\xd4\x12\xee\xd2\x97\x97\x73\x0d\xa0\x9d\xc9\xba\x4a\xa9\x96\xe3\x6b\x0e\x41\x65\xa6\xe9\x53\x45\x09\xc6\x68\x28\xc5\x84\xfb\x2f\xd7\xb9\x68\xe3\x91\x3c\xe0\x19\xe7\x5f\x52\xc5\x72\xc3\x41\x27\x49\x3d\xa2\x49\x6a\x7d\xc7\x16\xea\x6c\x17\xbb\x03\x36\xd6\x2b\xdc\x58\x8e\xd1\x8d\xb6\x97\xec\x8b\x50\x9d\xde\xcf\xc8\xd7\xbb\x13\x88\x58\xdd\xcf\x1c\x77\xf1\xa1\x9b\x46\xc1\x31\x37\x87\x11\x06\x21\x41\x7a\x5b\xd7\x23\xcd\xbd\x8e\xe5\x45\x85\xc7\x47\x64\x1e\x68\xd6\x1a\xd4\xba\x69\xbc\x11\x6c\x63\x87\xfc\x4d\x5b\x36\x1a\x5c\x14\x1b\x15\x2a\xfc\x12\x3d\x58\x4a\xcb\x5f\x3f\xbc\x1a\xa3\x16\x7f\xcd\xf0\xa8\x02\xf6\x44\xd6\x29\xc9\x9a\x0b\xe9\x09\x38\x1e\x85\x06\xa6\xd6\x8e\xcf\xe7\x88\x4b\x6f\xc3\xfc\xbe\x5a\x47\xc3\xd7\x36\x4e\x10\x7a\x63\x77\x36\x11\x47\x99\x9f\x85\x3f\xb3\x4a\x46\xda\x93\xc7\xc9\x51\xd9\x56\x1d\xfd\x26\x0c\xd1\xf7\x54\xf6\xa4\xa3\xe3\xf4\x2b\x33\x05\x70\x57\x6a\x0e\xfa\xf5\xb7\x73\x62\xd8\xa6\x35\x79\x0e\x84\x2b\x99\x3c\xa9\x10\x73\xd3\x01\x49\x7d\x7a\x5f\x4d\x96\x33\xe4\x9a\xf0\xdc\xe6\xd1\xa8\x42\x57\x3b\x56\x1d\x72\x5e\xec\xa4\xa2\x51\x9b\x95\x94\x37\x47\xe5\x31\x5a\x5e\x13\xc4\x90\xcf\xd0\x7c\x44\xef\x29\x38\x5d\x2d\x46\xdc\x37\xcd\x8e\x6a\x3c\xd5\x1b\x64\x42\x12\xb9\x46\x43\x01\x3a\xad\xe3\xab\x8b\x47\xf6\x31\x53\x0f\x54\xc6\x40\x4b\x17\x6c\xf8\x23\xe1\xca\x8d\x83\x19\x99\xc1\x68\xd3\x5c\x04\xcf\xf4\x17\xe9\x22\x72\x4b\x9e\xbe\x36\x6b\x34\x9c\x44\x7e\xd1\xce\x70\xcb\x37\x6f\x59\x08\xe4\xa9\x21\xb2\x1e\x63\x22\x44\xf1\x51\xc2\x8d\x25\xdf\x80\xd3\x07\x7d\x59\xb1\x4d\x23\xf3\xcc\x61\x95\x9e\x9c\x18\xd0\xa9\x27\xa8\x05\xa3\x9d\x2c\xdc\x2c\x1f\x1e\x3c\x2e\x70\x94\x67\xea\x86\xd8\x1d\x21\xfe\x50\xd0\xe6\x5a\xc4\xcf\xc4\xd0\x9f\xbe\x56\x25\xfe\x23\xb1\x8d\xa4\x06\xb7\xb6\x4a\x8a\xd1\xc9\xfc\xc9\xa7\xeb\x41\x05\x61\x1f\xa6\xd7\xdb\x9b\xcd\x64\xd5\xc6\x2f\x7c\x62\x9b\x64\x51\x15\x5b\xa2\xda\x2b\xed\x29\x0a\x5d\x5b\x08\xef\x45\x0b\x9e\x23\xd8\x52\x3b\xb0\x9f\x94\xb4\x6a\xfc\x66\x39\x5a\x4a\x89\xd5\x0c\xba\xb9\x24\x86\xe7\x4c\x8a\xd3\x67\x03\xe3\x33\xaa\xf5\x11\x2a\xe2\xa1\x41\x76\x16\x2f\xa2\x8e\xd1\x91\x41\xb7\x74\x43\x46\x63\x3c\x39\x59\xb1\x57\xe1\x32\xe6\x98\x0f\xb6\x79\xa3\x6b\x65\x0b\x7d\x13\x8e\x4c\xe0\xc3\x63\xb4\xb6\xdf\x5c\x42\xcd\x8b\x8b\xc5\xb2\xbe\x32\xca\x23\xba\xc0\x0c\x6d\xfe\xde\x66\xa5\x2f\x2e\x7d\xd3\x4b\xb1\x5a\x48\x2e\x79\x35\x8c\x7d\x28\x2e\x61\xd6\x84\x85\xe0\x92\xe1\x4b\xb2\xbd\xf0\xe0\x37\x40\xb9\xaf\xbc\xcc\x8c\x57\x6b\x9b\x3f\x10\xd6\xcb\x94\x26\x54\xce\x2b\x42\x20\xc1\x06\x96\x43\x8c\xd2\x46\xd3\x85\x59\x11\x96\x6f\xd0\xbd\xfd\xe6\x52\x4e\x3e\xda\x08\xdf\x17\x61\x6b\xce\x69\x14\xeb\x05\x52\xe9\x57\xb7\x1d\x74\x17\x4a\x53\xed\xa3\x8a\x8a\xb0\x0e\xd9\x33\x26\xcc\x0a\x8a\xa3\x4d\x9b\x07\x72\x35\x0b\x53\xd5\xbb\xdd\x3d\x6e\x07\xe2\xfe\xd2\xe4\x94\x6f\x24\xdd\x06\xf4\xa8\x30\x53\xf8\x78\x6d\xd1\x93\xc8\x33\x22\x2e\xbd\xed\x32\x56\xf9\xa8\xad\xc9\x4f\xa1\xf4\xf0\x6a\x09\x61\xc9\xd5\xbb\xf9\x91\xdd\xb0\x0a\xdd\x54\xaa\x8d\xe7\x34\xfa\xd2\x36\xad\x38\x14\x20\x7a\x90\x18\x0a\xd1\xe2\x55\xb9\x70\x61\x75\xb3\x0f\x34\x3e\x01\x95\xd1\x66\x0a\x0d\xc2\x75\x3e\x82\x16\xde\xc8\x38\x5e\x39\x7c\x99\x3c\x65\xef\xc5\xfc\xa3\x40\xbc\x17\x7b\xdf\x3f\xf6\x62\x69\x4f\x96\xde\x49\xcc\xef\x39\x79\x8c\x83\x3d\xdc\xcc\xb0\x67\xec\x5b\xaf\x53\xc6\x26\x1f\xbd\xd2\xc7\x5c\x5c\x62\xac\xab\xde\x73\xc9\xd5\xae\xda\x1c\x76\x1e\x0f\xfb\x1d\x5f\xd4\x91\xf4\x8b\x9c\xa3\xaf\x3f\x67\x85\xd6\xd1\xd6\x56\x03\x39\xe8\x12\x1a\x85\xeb\xe1\x26\xbe\x01\x99\x82\x69\x55\xdc\x52\xc4\xa5\x16\x1d\xc1\x71\x24\x2e\x1f\xfd\xe1\x55\xfd\x9a\x18\x50\x66\xc6\x88\x0d\x4b\xc9\x7e\xe8\x5f\x29\x6e\x1d\xa1\xde\x6b\x3a\xfd\x68\xfb\x76\x0f\xfb\xdd\xe8\xc9\xec\x77\x12\xb2\xaa\x43\x3d\x8d\xc1\x02\x3d\xe7\xbd\xaa\x9c\x7f\x6b\xcc\x15\x40\xe1\xe4\x55\x40\x9f\x59\x33\xea\x99\x31\x28\x81\x07\x9d\x1e\xa2\xc0\x5a\x1d\x97\xf9\xf9\x48\x21\x38\xe5\x14\x41\xc4\x04\xec\x47\x3a\x16\xe0\x22\xc7\x2b\x49\xd9\x7d\x03\x9d\x2f\x8c\x9e\x80\x48\xe7\xc4\x98\x31\x93\x83\x96\xaa\xae\x3d\x74\xb5\x69\x9c\x52\xcb\x1e\x9d\x8b\x57\xeb\xeb\x84\x1b\x76\x68\xf3\x41\x77\xef\x05\xaa\x55\xa6\xc8\x1b\xa8\x9d\xc4\x17\x55\x7f\xc4\x49\xb3\x39\xbc\xad\xda\xb5\x31\xcd\x72\x77\xe0\xad\xcb\x66\xdd\x66\x5d\xba\xeb\x3a\x4e\x0f\xa4\x22\xf7\x85\xdc\x3c\x8a\x7e\x22\x27\x19\x2a\xf9\xe8\x80\x8e\x05\xd3\x57\x27\xac\xde\xce\x55\xe7\xce\xa8\xfa\xb1\x54\xb1\xcd\x36\x89\xa2\xef\x2e\xcc\x27\xd0\x8d\x45\x3e\x09\xe1\xda\x00\x24\x12\xfa\x5a\x2f\xd1\x09\x2a\x4e\x8f\x90\x02\xa3\x15\x1f\x26\x5b\x6e\x16\x94\x06\xbe\x08\xce\x21\x59\x78\x03\x22\xe9\xf1\x7e\x42\x1a\xe5\x8a\x1a\xa5\x36\xba\x60\xec\x56\x35\xc2\xd4\xb5\xe5\x8a\x81\x7c\x8b\xf0\x2d\xc4\x05\x03\x57\x31\x21\xc1\xfe\x3c\x74\xef\x0c\x1d\x12\xf2\x00\xb2\x7c\x12\x90\x6d\xa4\xc7\x3e\xd8\x19\xd5\x3f\xb6\x6b\x40\xb2\x66\x05\x75\xf4\xa8\x4a\xf0\x04\x24\xaa\xb8\xab\xf0\xf2\x28\x85\xeb\xad\x80\x6c\x97\x3b\xd2\xf1\x84\xee\x24\x42\x8e\x03\x87\xd4\xc1\xd0\x19\xfb\x0a\x48\xb5\xba\x23\x87\xaf\x84\xcb\x75\xe8\xb8\xde\x55\xd3\xba\xcb\x43\x60\xdd\x4e\xb7\x67\x4f\xcf\x97\x3e\xed\x8b\x6e\xe7\x6c\x6e\xfa\x5a\x79\x64\xe6\xb9\x5f\xea\x72\xed\xd2\x00\x93\xf4\x9e\xaf\x9e\x4c\x62\x6b\x77\x51\xfd\xa0\x12\x8b\x36\x45\xa7\xbb\xf3\x74\x6a\x09\x58\x6e\xd0\x39\x18\xa0\x8c\xa2\xc1\x18\x77\x45\x83\x9b\x1d\x9f\x6b\xd6\x3b\xac\x5b\x7c\xa9\x62\x75\x91\xc6\x00\xbe\x12\xd3\x26\xb3\xd8\xba\x60\x27\x99\x9d\xa2\xae\xdc\x49\xd3\x9b\x85\x8b\x6b\xaf\x3d\xad\xe1\x06\x31\x46\x5d\xc0\xae\x40\xb2\xd0\xb4\xd8\x26\x31\x20\x19\x46\x71\x7c\x37\x01\x72\x6d\x5d\xd7\x87\x2e\xe6\xfd\x1a\xcd\x76\xc4\x05\x62\x45\x58\xe7\xfd\x8a\x53\x52\xae\x97\x39\xb4\x50\x47\x36\x85\x5d\x4b\x72\xa5\xdd\x9d\x0c\x24\x2b\x7b\x32\x90\x7c\xec\xb8\x40\x51\x3f\xd9\xd5\x8f\xd0\x3b\x56\xed\x5b\x74\x53\x6f\x32\x86\x4a\xad\xcd\x95\x68\x14\x84\x04\xba\xbf\x99\x18\x1d\x5d\x76\xac\x39\xb6\xad\xad\x85\xc6\xea\x70\x18\x17\x61\x34\x80\xd2\xe8\x95\x56\x99\x74\x85\x5d\xd3\x28\x23\xce\x6b\x18\x58\x6e\xfb\xc2\x11\xf1\x2d\xf0\x52\x6e\x77\xc4\xa1\xa7\x64\xa4\xb4\xa7\x0a\xc6\x55\xca\xe0\x47\xbe\x51\x58\xfa\x81\xe8\x4b\xc6\x30\x96\xa5\x0d\xc4\xd2\x05\xa2\x71\x68\xf8\xa1\x68\xf7\x69\x6b\xab\x70\xe1\xc1\xf8\xc3\x74\xd7\x13\xdd\x5f\x93\x66\x99\xe3\x91\x07\x17\xcf\xba\x53\xd0\xc9\x82\xd0\xe3\x5b\x5c\xc4\xb9\xe1\xbc\x68\x2c\x3f\x93\xb1\x62\xc6\xac\x07\xfb\x2c\x7a\x1c\x9d\x4c\x7b\x98\x85\xd7\x2b\x98\x85\x93\x74\x36\x70\xb8\xda\x80\x9a\x16\x03\xed\xf2\x8f\x88\x69\x95\x6d\x20\xa0\x93\x2e\xdb\x44\x4b\x24\x3f\x5d\x2d\x0d\x4b\x96\x5f\xe9\x34\xd5\xf6\x00\xf1\x75\xcc\x03\xc4\x37\xeb\x38\xb3\xde\xf4\x86\x4f\x60\xd1\xe8\xc3\xc3\xa6\xf0\x1c\xdd\x79\x36\xb6\x53\x4c\xa5\x60\xf6\x85\x2d\x95\x4b\x00\xbb\xf3\xf3\x2f\x15\xae\xb8\x26\xf1\xf9\x32\xe7\x3c\x51\xd0\xe0\x65\x37\x49\x89\x6e\x96\x37\x7b\xa2\xc7\x42\x9e\x1b\xd5\x36\x12\x0d\xa1\xc0\x17\x21\x4d\x4d\xc8\x72\x0d\xf4\x35\xc7\x13\xe7\xa8\xe4\xaf\x26\x9b\xa5\xc7\xc3\xc4\xab\xd5\xda\x64\x52\x79\xba\x5f\xe7\xb7\x47\x63\x0c\x95\xf3\xba\x1d\xe4\xda\x63\xc4\x99\xbf\x80\xb4\xc0\x80\x9b\xb7\x9e\xef\xd8\x51\xc0\xa5\xdc\xce\xd7\x8d\x32\xe2\xb1\x93\x6d\x58\x46\x50\x1c\x13\x33\xdf\x6f\x42\x01\x3b\xd3\x2e\xd8\x67\x2a\x81\x14\x60\xa5\x69\x1b\x09\x59\xbd\x5a\x3c\xa4\x42\x83\x4f\xb4\x2d\x47\x65\x3a\xdd\xda\x22\x15\xa9\x9f\x60\x51\xc1\xa1\x64\xbe\xa1\x92\x52\xbb\x48\x9e\x3d\xbb\xbd\xbd\x1d\xdc\xbe\x18\x54\xf5\xd5\xb3\xd3\x4f\xcf\x4e\xfe\xf2\xe7\xe1\xf0\xd9\x94\xcb\xfc\xcb\xdb\xac\x29\xc6\x27\xc4\x4f\x87\xd7\x20\x0e\x86\x83\x61\xc0\x98\xe6\x1a\x09\x0f\x5b\x75\x9f\x9d\xd5\xeb\x1e\xea\xf3\xa6\x1d\x5c\xc2\x8a\x09\x9f\xfd\x2d\x44\x8d\xbb\x07\x3c\xc6\xa3\x6f\x31\x82\xe7\x05\xc5\xf1\xfc\x75\x72\x31\xf8\xf5\xdb\xf3\x3f\xfd\xeb\xb3\x28\xee\xcc\xb0\x12\x44\x1e\xf9\x42\x90\x46\xfc\x8c\x0e\x9e\x95\x2c\x30\x23\xdb\xb7\x7f\xcb\xef\xe4\x2b\x91\x18\xfc\x3c\x9b\x55\xb7\x3f\xc1\xd3\x09\x2d\xd1\xa4\x78\x68\x38\xed\xb4\xce\xca\x86\xb4\x16\xc6\x77\x49\x01\x69\xb2\xad\xe6\xae\x1c\x23\x42\x5a\xb6\x15\x8a\x85\xf1\x0e\x28\x72\x20\xe5\xe3\x2c\xbb\x83\x4c\xb8\x80\xcd\x3e\xc2\xb6\xc1\xc8\xb7\x2c\x14\x81\x84\x13\x74\x11\xac\x12\xa0\x7f\x27\xd0\xbf\x22\x26\x4f\x56\x40\x0f\x64\xf0\xe5\x31\xfa\xd6\x3b\x3a\xc0\x54\x7c\x62\xe6\xfd\x6e\x01\x94\xd6\xb8\x9a\x35\xd0\xb9\x19\x3e\x40\x43\xa2\xf7\x63\x61\x8a\xaa\xbf\x1c\x4e\x8a\x36\x03\x0a\x43\x4b\x14\xf2\xe9\x82\xde\x6a\x6c\x89\x3e\x56\x55\xf5\x44\xc8\x6e\xc7\x75\xd5\x34\xc7\x75\x21\x75\x8a\x62\x04\xbf\x7a\xca\x4f\x0b\xe8\x48\x11\x03\x0a\x21\xda\x6e\x52\x08\x81\x2c\x1c\x6c\x19\x11\x33\x08\x36\xd8\xe8\x25\xaa\x83\x03\x1d\x37\xa9\xb3\xab\xab\xae\x13\x00\x43\x24\x40\xf9\x05\xd0\xe6\x1c\xda\xc2\x1f\x0e\x82\x2c\x5e\x0e\x45\x21\x7e\x13\x96\x2a\xfc\xf2\xa1\xfa\x4b\x36\x2b\x48\xee\xde\x50\x02\xdf\xb5\x30\x17\x43\x0f\xbd\x65\x1f\xc5\x45\x7c\xcd\x6e\x71\xe1\xa1\x98\x4c\xc4\x64\x5e\xd7\xf9\x94\x3f\x8c\x4f\xef\x32\x39\x01\xa8\x75\xf7\x93\x94\x7b\xe3\xea\x3e\xfc\xfb\xb2\xb8\x11\xd4\xf5\x58\x2e\x8f\x02\xe6\x25\x9e\x65\x97\x52\xf2\x3b\x53\xf5\x51\x86\x0a\x5f\x9a\x55\x18\x45\x1a\xbe\x33\xcf\xca\x62\x9a\x53\xda\x1c\x7a\x07\x07\x08\x77\x86\x0a\x73\x0a\xfb\x08\x16\x09\xbf\xab\x87\x77\x74\x0d\xc3\x7a\xf9\xa4\xc8\xe4\xef\x9f\xeb\x6a\x29\xc4\xdc\x73\x86\x05\x3f\xcb\x09\x9a\xa3\xed\x27\xac\x3e\xfe\x38\xec\x27\x5e\x41\x25\x2d\x19\x52\x35\xd2\x81\x06\x5b\x45\xd4\x83\x43\x11\x8e\x48\xf9\x82\xaa\x83\xd7\xd5\x6c\x22\x25\xec\x8b\xaa\x51\xda\x06\x8b\x3a\x9f\x29\x09\x3e\xb9\x56\xd3\xfa\x04\x67\xcf\x04\x15\x83\xe9\xa3\xb5\x04\x4f\x9d\x03\x10\x51\x33\x03\xd2\xaa\x19\xce\x25\x2a\x16\xd3\xba\x85\x87\x6e\xdd\x36\x40\xb9\x5c\x56\x02\x04\xcd\xb8\x92\x6b\x83\x83\x51\xaa\x4d\xd2\xe4\xd9\x1c\xfd\x18\xd3\x44\x36\x24\xbe\x17\xc3\x6c\xae\x33\x55\x07\xfd\x22\xe3\x17\xf0\x01\x8a\xc6\x0d\x7e\x06\x5e\x17\xb0\xe7\xf6\x71\x73\x89\x72\xf5\x58\x3d\x1c\x54\x63\x98\x57\x78\xe0\x2d\x48\xee\x1d\x80\x8e\x80\xb1\x8b\xe1\x91\xbb\x5b\x21\xb6\xcf\x2e\xd9\x51\x92\x78\xa3\x95\xc7\xcf\xe8\x65\x59\x3c\xaa\xe5\x8d\x7c\x95\x4c\xb4\x42\xbe\x2b\xa0\xbf\x4b\xf4\x27\x4e\x53\x7c\x3b\xaf\x26\x08\x16\xc2\x1e\xd9\x02\x76\x2a\x05\x3b\x55\xf8\x63\xbf\xaa\x91\xba\x11\x8b\xaf\xcd\xe7\x88\xe5\xa0\x3c\x3e\x9e\x10\x9c\x10\x14\xf8\x26\xf6\x8a\xf4\x2a\x28\x0c\x24\x1c\x43\x54\x89\x1b\x25\x3e\x0c\xf8\xf5\xdb\x31\xbf\x07\x1a\xa2\x09\xe8\x31\x50\x3b\x23\x80\x9d\x16\x68\x5b\x83\xce\x80\x6f\x71\x86\x6f\x02\xfa\x92\x61\xd8\x0a\x1f\x32\xc7\x14\xe0\xfb\x58\xbd\x07\x26\xc6\xe4\x5c\xf1\x16\x18\x63\x17\x59\xf4\xc2\x39\xac\x93\x42\xe9\x14\x93\x23\xe8\x70\x2d\x25\xc2\x32\xbe\x0b\x14\x96\x09\xe0\x01\xe7\x23\xe8\x76\x7c\x80\x4f\xb8\x77\x03\x7d\x21\xb3\xbf\x40\xf4\x78\xbe\x08\xf4\xe5\x12\xd0\x33\xe1\xe5\x40\xae\x96\x00\x7e\xe1\xf0\x0c\xe4\xa2\xc1\x77\x84\x9f\xc1\xf9\xbb\xee\xd5\xb6\xef\x53\xc0\x45\xa2\x67\x7d\x5f\xfa\xd1\xfd\x52\x18\x65\xe4\x22\xaa\x89\x38\x3c\xde\x15\xe5\x17\x19\x36\x47\x66\xd1\xe2\xc3\x8c\xc8\xe2\x05\x92\xfb\x26\xbb\x21\x2a\x0d\xb7\x31\x23\x51\xaa\xca\xd8\xf7\x47\x6f\x0b\xa2\x2b\x6b\xb4\xd1\x79\x9c\xb2\x7a\x3a\x40\xfc\x91\xa3\x23\x08\xac\x11\xe6\x42\x07\x8e\x0b\x44\xd6\xf5\x4b\x6b\x40\x83\x42\x5f\x13\xa2\x48\x24\xa2\xf4\x74\xda\xa9\x38\x53\xd2\x45\xc6\xd2\x65\xbb\x8c\xd3\x7b\xd8\x4b\x2d\x3b\xcd\x97\x4e\x27\xf1\xb9\x90\xfe\xf5\xc5\x59\x03\x4f\xb4\x9c\xe8\x81\xd4\x90\x30\x36\x00\xab\x16\xa1\xcb\xf7\x59\x7a\xff\xbe\xf8\x1d\xb0\xf7\xfd\x42\x7e\x31\xb9\x67\x04\x61\xce\xbe\x60\x1a\xe5\x24\xf3\x1e\x9f\xb1\x2b\xcb\x73\x54\x57\x90\xa0\xc4\x67\x89\x7f\xf1\x59\x9e\xc2\xd2\xab\x26\xfa\x68\x21\xa5\xae\x30\xf8\x6b\xb5\xdc\x80\xef\xdd\x14\x93\x7c\xb2\x91\x6d\xfc\x46\x1f\xfc\x0d\x93\x16\x1b\x6d\x05\x29\x78\x9a\x6e\x4c\x8b\x7c\x36\xe9\x62\x10\x97\x1b\xbf\xc9\x4f\xfd\xb6\x71\x4d\x97\xcc\x7a\xb0\x71\x0a\xf0\x86\x32\xb3\xd9\x46\x4d\xb6\x0e\x50\x19\x3b\xf1\x6d\x05\xbd\xe0\x16\x06\x1b\x47\xd3\x8d\xf6\x3a\x17\xed\x35\xd0\x1a\xfc\x5c\xe6\x1b\x70\x3c\x61\x07\x37\x70\x5d\xff\x36\xd1\x4c\x64\x7e\x1b\x6c\x1c\x43\x85\xfa\xb6\x68\xf2\x78\x03\x80\xb6\x91\x17\xf8\xae\x77\xa0\x82\x37\x39\xda\xdf\x06\x18\xc8\x56\x52\x4c\x2b\xe0\xf6\x4f\x01\x96\xf8\xce\x7f\x09\x70\xed\x8b\xbe\xfc\x21\x80\x29\x95\xb7\x66\x80\x30\x7b\x24\xa1\xd7\x5f\xac\xb5\xa7\x29\x48\x59\xdb\x72\x37\x44\xbc\x11\x3b\xe9\x62\x5f\x26\x46\x06\xb5\xbd\xef\xcc\x90\xd3\xba\xb6\x67\x49\x52\xdb\xb5\xaf\xef\x66\xeb\x0b\x22\x8b\xbe\x71\x2c\x07\xf5\x15\x43\x28\x9c\xa6\xb4\xef\x67\x5d\xa6\x04\x98\xcf\x96\xc2\xc2\x1a\xc9\x70\xe8\x77\xa7\xf1\x6a\xb5\xd2\xbd\x89\xd7\xa5\x4a\x59\x68\x18\x40\xd1\xa7\x84\x6d\x16\x5d\xb2\x0f\x01\x9b\xb4\x64\xc6\xfa\xcf\x53\xdc\x6a\xeb\x6c\xf1\x96\x79\x92\xb6\xe0\x13\x3b\x9d\x71\xb0\x2c\x64\x16\x2f\xe1\x2a\x31\xe9\x0c\x52\xea\x81\x5d\x95\x38\x56\x6e\x6c\xad\x11\xfb\x2a\x9f\x01\x35\x30\x33\xf9\x0c\x68\xd4\xd2\x97\x87\x52\xfe\x58\x45\xf7\xfa\x05\x76\xd2\xe7\x72\xee\x0d\xf0\xe5\xab\x8d\x8c\xb7\x95\x4d\x7b\xac\xe4\x7a\xc1\x9d\xb0\xd7\xcd\x7f\x86\x12\xc9\x6a\x15\xe8\xff\xb1\x86\x29\x86\xad\xcf\x59\x39\x76\x14\x85\x61\x5e\xc0\x37\xb0\x55\x16\x06\x85\xb2\x30\xa8\x4c\x59\x9e\x8c\xe4\x50\x88\x53\x74\x94\x6d\x6d\x6d\x66\xb0\x3b\xc6\xa8\xc2\x4c\x06\x08\xe2\x39\x45\x3f\xab\x1e\x55\x55\x3f\x9b\xcd\xaf\xe4\xe8\x28\xb1\x9a\x5b\x44\xc5\x5d\xca\xa3\xf6\x1a\x26\x69\x03\x31\x37\x0e\x51\x60\x6f\xc3\x65\xfd\x06\x77\x78\x63\xcc\xa1\xf7\x01\xa9\x62\x5d\x44\x8d\x1d\x23\x4c\x33\xc6\x4b\x55\xc4\xc5\xb8\x74\x23\xe7\x99\xb2\x5f\x98\x87\xe1\xa8\xfe\x11\xda\x27\x4e\x8a\x52\xce\xaa\xa5\x62\x56\x95\xaa\x3c\x11\x89\x10\xbf\xbd\x99\x4a\xaf\xb9\xf2\x63\x55\xd7\x01\x52\x80\x29\xa2\x92\xf5\x26\xe0\x7a\x10\x51\x7c\xcb\xec\x9c\xa2\x73\x76\x1a\x5b\xad\x1b\xfe\xfd\xf5\xda\xba\xa1\xfa\xbe\x37\x23\xfe\x31\x0c\x70\xbb\xb0\x4a\x83\x0c\x45\x8b\x86\x0b\xd2\xde\x4d\xc8\x71\xad\xcc\x45\xb5\x08\xbb\xf0\x9b\xdc\x7d\x34\x42\x8b\x4b\xa5\x28\x00\xb3\xd4\x52\xb8\xc1\x2a\xf5\xe9\xda\xc9\xaf\x96\xfd\x5f\x45\xde\x7f\xff\x57\x05\xd0\x6a\x62\x76\xc7\xb5\xfe\x5d\xfe\x10\xba\xdf\xb0\x75\x0e\x85\x80\x47\x7c\xbb\xee\xff\x76\x95\xd6\x2b\xbe\x5d\xf3\xb7\xab\x58\xe8\x15\x55\xfa\xd7\xa5\x76\x15\x7a\xfe\xb0\x76\x5c\xe7\x42\x59\xf5\xa1\xe8\xef\x03\x6e\xc0\xfe\x3e\x14\xdc\x87\x2c\xee\x9a\x8e\x33\xbd\x1f\x85\xf6\x51\x74\x4a\xd4\x33\xf3\xf0\xae\xc7\x20\x26\x61\x75\x17\x4f\x82\x64\x1d\xea\x0d\x9d\x29\xfa\xfa\xfb\x23\x6c\x1b\x78\xc3\x50\x45\xe8\x31\xd7\xec\x34\xc7\xef\x40\x0d\xa6\x21\x6a\x35\xd6\x40\x12\x7b\x95\xd6\xbb\x89\xd5\xeb\xa3\x5d\x6b\xd9\x59\xd3\xa0\x17\x8a\x31\x24\xc8\xcf\xa1\xbf\x0c\xf5\x82\xd1\x65\x4a\xa9\xd1\x9b\x02\xba\x47\x43\xdb\x7b\x3d\xe8\x45\x32\x03\xa2\x28\xdf\x13\xfb\x94\x9a\xc4\x38\x49\xed\x6d\x65\xa5\x55\x70\x9e\xd5\xb9\x5d\xb2\x88\xa7\xc5\x8d\x9d\x98\x79\x54\x15\x9d\x03\xe0\xf5\x6a\x2d\x42\x6d\xbb\x6a\xb7\xc8\x63\x0c\x1f\x89\x35\x1c\x8b\x3c\x9f\x32\x37\x1d\x63\x64\x0f\x0a\x94\xa7\x65\x8b\xa7\x82\xb7\x76\xe4\x40\x97\xde\x14\x6d\xae\x17\x68\x8c\x02\xc4\x47\xec\x2e\x49\x9c\xca\xaa\x0f\xc7\x68\xff\x65\x39\xe8\xed\x7c\xd0\xcf\x84\x5b\x0d\x3d\x59\xb0\xa6\xc8\xc0\xa7\xcb\x84\x21\x63\xbc\xa7\x45\x6a\x24\xe9\x5d\x9a\xea\x59\x4c\x19\x1f\x49\x7e\x78\x27\x89\x12\x7e\x1e\x75\x29\x59\x43\xb2\xa8\x2e\xf7\x5d\x7e\x95\x8d\xef\xba\x4e\xce\x3d\x06\x8b\x37\x5e\xaf\x8a\x90\x71\xa5\xdf\x1f\xf3\x7a\xda\x05\x07\x70\xae\x94\x87\x5a\xfa\x49\x5e\xdf\xe4\x35\x5b\x8a\xb3\x7f\x91\x7d\x2d\x97\x7d\xb5\x75\x43\xbd\xf4\x07\xe5\x11\xf1\x01\x26\xf9\xa2\xce\xc7\x82\xb0\x13\xb1\x01\xf0\x6a\x21\xba\x38\x9a\x0a\x39\x41\xc8\xd4\xda\x45\x3a\x36\xe5\x45\xf1\xad\x4a\xf9\x29\xc3\x2d\x7d\x37\xba\x48\x27\x83\x5b\xa0\xe8\xf6\x0d\x67\x33\x17\x18\x44\x40\xcf\x10\xc5\xc3\x5b\x6e\x19\x43\x0a\xcc\x61\x9f\x91\x94\x80\x06\x12\xc4\x01\x5f\x79\x82\x78\x3e\xe0\xa7\x08\xe3\x0c\xc8\x25\x99\xdc\xcf\x33\x74\xb9\x08\x7f\x63\x41\x3b\x25\x2a\xe6\x1d\x50\x7c\x48\xe2\x61\x34\x6a\xd4\xa7\xc7\x21\x25\x9f\x88\xdb\x04\x5b\x56\x01\x36\xb9\x8b\x8b\xb2\x68\x0b\xe2\x2c\xe9\x5a\x02\xc6\x5d\x60\x60\xaa\x10\xa0\xe6\x3d\x8f\x98\x42\xd8\x24\xd9\x40\x7b\x8b\x0d\xe8\x24\x17\xb1\x01\x9b\xe4\x36\x56\xb6\x02\x7b\x18\x32\xaf\xa4\x70\x77\x62\xb2\x92\xf9\x60\x45\xee\xaa\x9a\x6f\xef\x8e\x0e\x56\xd7\xc6\x12\x31\x03\x31\x79\x2f\x1e\x4e\x45\x24\xdf\xe4\x70\x60\x26\x68\xf9\x19\xda\xe3\xb1\x11\xba\x5e\xaa\x4b\x8e\x97\x4c\x4d\xab\x2f\xed\x91\x9a\x13\xf4\xc6\x9f\x11\x17\x0d\x6d\x5a\x86\xdd\x64\xa0\xbf\xca\x3c\x09\xbd\xf1\xc0\x4c\x88\xf1\xae\x2c\x30\x08\xdc\x41\xb5\xb7\xf8\xe2\xa2\x59\xe0\x65\x35\xb9\x14\x9d\xef\xa0\xfa\xbb\xbd\x9e\xba\xdd\xd1\xad\x30\x8a\x60\xf0\x3e\xb2\x2b\x2b\x10\xf5\x37\x22\x8b\xa8\x9c\x2e\x81\x1a\xb5\x81\xeb\xfd\x86\x06\xe6\xd5\x5f\xea\x0a\x1a\xdf\xd3\x93\x9d\xaf\x76\x99\x91\x82\xbe\x0f\x3a\x76\x5e\x97\x24\xf1\x1b\xb7\x6d\x4f\x4b\xf4\x38\xf2\xc9\x85\x2f\x2e\x3e\x1d\xee\xed\x9f\x5e\x1c\x1c\xfe\xe5\xf4\xf8\xf8\xdd\xc9\xc5\x9f\xdf\x1d\xbf\xdd\x7b\x77\xf1\xf3\xf1\xf1\xbf\x5d\x5c\x78\x83\x15\xaf\xae\x22\x50\xd1\xd6\xd6\x5a\xc5\x84\x49\x3d\x0d\xb2\x88\xf5\x13\x26\x59\xc6\xfa\x71\x90\x2c\x62\xef\x19\x99\x94\xb1\x85\xfb\x93\xeb\x98\x55\xa5\xe6\x71\x87\xc7\x93\x9b\xd8\x40\xb9\xc9\xfe\x63\x34\x3a\x95\x11\x96\xd3\x60\x67\x30\x7c\x3e\x78\x1e\x68\xb1\xb1\x4e\x1d\xf6\xae\x76\x30\x27\xdf\xbd\x5c\x65\x80\xb0\xca\x03\x83\x37\xd8\x96\x79\x8a\x27\xaf\x3b\x07\xc6\xdd\x3c\x27\xaf\xbf\x8b\x57\x9c\xe0\xc9\xeb\xd7\xb1\x7d\x7e\x27\xaf\xbf\x8f\xbd\xa7\x77\xf2\xba\xfb\x2c\x9e\xc3\xc9\xf7\x3b\xb1\xf7\x10\x4e\xbe\x7f\x1e\xf7\x1e\xc1\xc9\x0f\x5d\xa6\x0a\x5a\xf1\xc3\x77\x76\x5a\x77\xfc\x27\x3f\xbc\x8a\xfb\x4e\xec\x64\xb8\xd3\xd9\x1c\x9b\x07\x36\x64\xbd\xec\x31\x47\xb6\x8f\x6b\x48\xef\xc0\x40\xa7\x75\x32\x1c\x0e\xe3\x7e\x4e\x8e\xf7\xac\x86\xcc\x0e\x3e\xe6\x51\x9d\x0c\x9f\x53\x73\xda\x91\x0c\x57\x5a\x82\x5e\x77\x22\x27\xc3\xef\xf1\x92\xfb\x7a\xb5\x0e\xb0\x46\xfe\x31\xb8\xf0\xa2\xac\x13\x05\xb5\x87\x4c\xa9\xdc\xeb\x5d\x41\x41\x62\x04\x07\xc6\x63\x56\x53\xb9\x4c\x1d\x8a\x06\xff\x01\x2e\xaa\xea\x73\x47\x07\x82\x83\x82\x6e\xd7\xb1\xa1\xa3\x03\x76\xd0\x95\xd4\x4a\x29\xd6\x29\xe0\x63\x02\xf8\x86\x92\xfc\xf0\xba\x67\xfe\x5c\x92\x79\x7d\xed\x3d\x35\xc0\x27\xee\xf0\xc2\x3e\x21\x9e\x44\xe4\x6a\x69\x72\x9e\x4e\xb7\xb7\xe3\xd9\x19\x3e\x92\x89\x99\x7c\x36\xdc\x11\xd9\x0c\x99\xaa\x47\x4f\xaa\x58\x65\x8b\xa9\x53\xdd\x3a\x93\x89\x84\x03\x1d\xd1\x2d\xd5\x68\xde\xe7\x38\x4c\x4d\x38\x61\xd3\x83\xe3\xde\xb8\x50\xc2\xc1\xd0\xe6\x10\xa8\xe6\x1d\x8c\x71\x2e\x4d\xe4\x83\x4b\xf8\x1b\x68\x46\xf2\x32\xf2\x51\x67\x28\x1f\x10\x57\x27\xf0\xd8\xca\x07\x9a\xb7\x78\xd8\x1d\x76\x11\xb6\x77\xd6\x0b\x91\x70\xd5\x2e\x26\xac\xe8\xf5\x72\xec\x60\x3b\xb0\x8d\xea\x03\xa1\xc1\x00\xdb\x7e\x19\x28\xeb\x7a\x48\x5d\xdc\x05\xd2\xbe\x3e\x00\xd4\x1a\xd8\x06\xf6\xc1\xe4\x72\xd6\x8d\x82\xcc\xec\x03\xd4\x4b\x08\x74\x43\x7b\x4a\x91\xc3\xe8\xac\xed\x45\x32\x79\x62\xd0\x8d\xee\x39\xfd\xf7\xa2\x0d\x4c\xd3\x7b\x4a\x17\x5e\x21\x74\x0b\x7c\x4a\xaf\x6e\xb4\x66\x04\x7c\x30\xbd\x03\x0c\x99\xe3\x43\x5a\xb5\x08\x3a\x13\xfc\x40\x88\x3a\x95\x15\xbe\x08\x20\xa5\x1b\xe2\x07\x5f\xf2\x3b\x54\xbb\x08\x0c\x6b\x7c\x4c\x5d\xe0\x53\xd0\xd9\xe4\x63\xda\x92\x9b\xef\x2c\xf1\xd9\xe3\x84\x6a\xa0\x33\xc8\xe7\x0c\x64\x48\x07\x86\x5d\x3e\xa7\x57\xa2\x17\x9d\x75\xbe\x48\x97\x03\x95\x46\xfa\x9c\x2c\x3e\xcb\x96\xfa\xc1\x02\x7f\x02\xcd\x3c\x3f\x60\xa1\x7f\xe0\x33\xd1\x0f\x1a\x99\xa0\xad\xd0\xce\x40\x9f\xfc\xd2\x1f\x29\xa8\xe8\x76\xfa\x41\x8b\x2f\x63\x7a\x09\x0c\x83\x7d\xce\x91\x73\xde\x99\xed\x73\xba\x1a\xb3\x66\xbd\xcf\x39\xdd\x74\xb1\x15\x7f\x70\x8b\x3f\x01\x86\xdf\x0f\x2e\xc8\x81\xab\xe2\x2f\x1f\x1d\x04\xdb\x4c\x34\x86\xef\xb3\xf6\x7a\x50\xc3\x81\x56\xcd\x01\xc9\xb2\x75\x54\xf8\x1c\xef\x9b\xcb\x10\x7d\xc2\xc6\xf7\x1d\x26\x50\x36\xa9\x9a\x8a\x77\xd1\x59\x1e\x7b\x0a\x1a\x06\x9b\xe8\x90\x8f\x8f\xce\x53\xc1\x0e\x0e\xe7\x83\x6b\x23\x01\xbe\x3b\x70\x9b\x21\x6d\x71\xb4\xe3\x29\x59\x99\x47\x6f\xd5\x57\x7e\x6b\xcb\x97\x3a\xe8\x5a\x20\x36\x0f\x6a\x9a\x5b\xed\x29\x21\x5d\xb8\xe9\x6b\xe1\xe1\xc1\x9b\x3c\x50\x2d\x85\x68\x89\xca\xce\x0b\x4e\xab\x1e\x77\xfb\x55\xda\xa2\xbd\x5c\x58\x21\x2a\x2d\x9e\x32\xc7\x23\xcd\x3d\x93\x7b\x3e\x03\x64\xb9\xe8\x6c\x6e\x17\x6f\x66\xe4\xa7\x5f\x28\xd0\x35\xe8\xb7\x3f\xb3\xcd\x81\xa6\xd1\xd6\x56\x76\x36\x45\x23\xe5\x29\xc6\x47\x18\xc8\x55\xb2\x3b\x0e\xc5\x3a\x89\x76\xbd\x63\x73\x44\x28\x5d\xdd\x58\xd4\x8c\xab\x28\x81\x66\x68\x2f\xfd\xf1\xb6\xb4\xea\xd8\xe0\xd7\x37\x80\x0e\xcb\xb1\x8d\x13\xb1\x5d\xa1\x11\x35\x56\x4e\xc3\xc1\xca\xcd\xbc\xb9\xb3\xa2\x93\x22\xf4\x8c\xfe\x11\x6e\x21\x56\xf5\xbf\xae\x8b\x76\x6d\x6f\xd5\x5f\x8e\x3e\x1c\x1c\xff\x72\xf1\xf3\xde\x87\x83\x77\x87\x5a\xe7\x09\xdd\x3e\x3c\xa8\x77\x3c\x23\x77\x43\x18\x8b\x40\xc0\x38\x94\xf0\x6b\xc6\xc2\xc1\x0b\x65\xf5\xca\xbf\xe9\xfa\x2a\x53\xcc\x1d\x71\x42\x57\x11\xcd\x3c\x35\x84\xc4\x01\xfa\xbc\x5b\x1f\x28\x7a\x37\xa0\xf6\xca\x8e\xb8\xb5\xb9\x1f\x54\x99\xf0\x7d\x85\x8e\xe1\xcf\x54\x16\x7a\x84\x97\xef\xf4\x21\x4c\x88\x92\x6b\xdf\xce\x58\xef\xab\xd3\xf8\x1a\x76\x10\x71\xaf\xe1\x97\x4c\x34\x1f\xe3\x95\xc2\x49\xcd\x67\xc9\x7a\x9f\x90\xfc\x78\x07\xf4\x5f\xdd\xac\x39\x71\xb2\xdd\xbc\x44\x36\x18\x2f\x46\x12\xaf\xbf\xaf\xca\x02\x6e\x39\xc8\x88\xd0\x90\x60\x31\x0d\x37\x17\xd2\x6a\x1e\x23\x33\x4f\xe1\xb0\xbe\xd6\xaa\x35\x23\xef\x87\xe7\xdc\x9a\x56\x10\x05\x56\x40\xe1\x61\xd4\xe8\x5e\x4b\xe0\xea\xeb\xfd\x38\x54\x6b\xf9\x71\xa8\x06\xda\x9b\xe1\x8b\xa1\x32\x94\xfb\x2d\x87\x0b\xd5\xc0\x4c\xf0\x39\x56\x90\x65\xf4\x44\xb8\x9d\x77\x37\x8b\xf9\x1f\x8d\xe3\xe8\xf5\x1a\xd0\x7f\x01\x77\x29\xf4\xe4\x07\xca\xb5\xe9\xf3\x64\xf8\xe2\x87\xde\x68\x8e\x78\x89\xf9\x3a\x87\xdb\x74\xaf\x12\x2c\x51\x29\x28\x95\xa1\xf9\x44\xb2\x20\x92\xd3\xd6\xb1\xe7\xef\xec\x8d\xf2\x51\x65\xb7\x22\x24\x56\x56\x2b\x1c\x29\xd3\xb2\x87\xaf\x0c\xa1\xab\x54\xad\x10\x4e\xa3\x35\x59\x0c\xf9\x40\x1e\x2d\xc8\x84\xa9\xd0\x24\x2f\x61\xe1\x33\xfb\xa1\x31\xcc\x33\xf4\xd5\x04\x97\x74\x39\x28\x48\x50\xe3\x6c\x55\x92\x1c\x63\xe9\xd8\x6b\x6a\x63\x84\xfb\x56\xd5\x35\x08\x87\xff\xa6\x13\x71\xa2\xe4\x38\x15\xd2\x95\x40\xa5\x7f\x4e\x02\xa4\xfb\x9c\x08\x4a\x8a\x9e\x0c\x9a\x47\x4f\x50\xed\x3e\xa0\xa0\xff\x76\xb8\x14\x16\x1a\x64\x6a\xaa\xa1\xe2\x61\xa1\xed\x0d\x62\xb8\x42\x81\xa8\x8a\x74\xab\xc1\x65\x68\xf8\x5a\xb7\x4c\x77\xb4\x56\x96\x64\x44\x64\x98\xf1\x98\x21\xfd\x85\x0c\x45\x5a\x06\xed\xa1\x6e\xa3\x92\x08\x4d\x1d\x47\xe7\xb3\x81\x23\xfa\x42\x69\x0a\x24\xbb\xd2\xaf\xd1\xcc\x8a\x1f\x1f\x4f\xb1\x01\x23\xad\x88\xaf\x59\x3c\x30\x49\xef\x15\x8f\x3f\x46\xbe\x7f\x23\x38\xfc\x63\x9d\x51\x30\xe1\xed\xec\x09\x30\xef\x1b\x40\x32\xfc\xfe\x7b\x8f\x2f\xe2\xd7\x6b\x58\x8f\x78\x05\x54\x3a\x53\x45\x8a\xb2\x2a\x6f\x70\xe6\xc2\x7f\x07\xf7\x2a\xd6\x38\x8e\xec\x96\x69\x13\xde\xbf\x3f\xfe\xfc\xe1\xf4\xf0\x80\x49\xfc\xcf\x1f\xf4\x57\x0c\xd9\x87\xb7\x75\xe5\x7c\x88\xd5\xe5\x3d\x3e\x88\x34\x1e\xa2\x41\xac\x67\xe1\xe6\x98\xa6\x7e\x40\x1c\xfc\x23\x54\x51\x44\x55\x15\xe2\xdf\xc3\x32\x91\xac\xfd\xa3\x03\xf4\xf4\xaa\xb5\x12\x4f\x07\x6f\xb3\xf1\x17\xa0\x8c\x8f\x0e\x3a\x9e\x26\x54\xf0\xa4\x62\x27\xf1\xc0\x79\x57\x4c\xf3\xfd\xbb\xf1\x2c\x4f\x96\xb1\xa7\x18\x8f\x50\xa8\x3c\x2a\x46\x93\x87\x17\x25\xb4\x74\x64\x6b\xc8\xf6\xce\x89\x14\x13\xb0\xa1\xab\x09\xee\x64\x3b\xc0\x56\xa7\x3f\x30\xb8\x40\xa2\x1e\x96\x82\x98\x53\x11\x2e\xf0\x42\x58\x66\x8b\x54\x56\x43\x12\xfe\x72\xa9\xc1\xb0\xc0\x3b\x58\xc9\x4a\x5f\xa8\xb5\x80\xca\x02\x7a\x81\xa7\x75\xa1\xe2\x2c\xdc\x41\xa7\x98\xf4\x3d\x02\x2e\xdc\x30\xd0\x3d\xb0\xaf\x5f\x80\x34\xc7\x33\x94\x3b\xa3\x98\x47\xeb\xc6\xfa\x63\xc0\x4e\xc2\x81\xce\x5e\x7b\x78\x5d\x72\x10\x67\xec\xf9\x85\x04\xd4\x11\x72\x2e\xca\x6c\xe6\x01\x58\xfd\xd5\x00\x5b\x73\x0c\x80\xfa\x11\x98\xb5\x02\xe6\x8a\x8e\x2a\x79\x97\xb1\x7a\x3b\x85\x5e\xa9\x3c\x2c\x80\x48\xee\x45\xd1\x92\x9b\x1e\x62\xef\x82\x59\x0e\xd4\x66\x32\x41\xbf\x0f\xd8\xfd\x12\x96\xa7\x34\x1e\xf7\x8c\x53\x9e\x41\xce\x48\x49\xa5\xde\x14\x86\xf9\xbc\x57\xf9\x15\xe4\xaa\xd4\xf7\x2d\xa4\xf6\x3c\x2a\x41\xde\xa2\x3c\xde\x51\x8d\xa8\xb5\x93\xc6\x35\x9f\xf2\xe9\x29\x33\x70\xe3\x0a\xce\xdb\x47\x9b\x07\xab\x86\xe3\x80\xc8\x04\x50\xb7\x5a\x51\x97\xc8\x96\xfa\x19\x8e\x3c\x7a\x74\x00\xf3\xfe\x21\xf2\xf8\x72\x74\xe1\x2f\xc2\xbc\x19\x03\x40\xfc\x23\xa2\x8f\xeb\x93\x0c\xe7\x88\xcb\x52\x8e\x9d\x01\x6a\x33\xd9\xbf\x0c\x70\x27\x8f\xf3\x42\xfb\xf2\x1a\xbb\xd9\xbb\x0e\x44\x17\x01\xb5\xa1\xfa\x2f\x2f\xe6\xa3\xe9\x87\x1c\x8d\xca\xb2\x1a\x7d\x08\x3c\xc6\x7d\x99\x89\xe5\x0c\x8f\xe1\xe2\xfb\x8c\xae\x8c\xe3\x6c\x7b\x3f\x9e\x1b\x79\x57\x73\x19\x6b\x3b\xa9\xf4\xec\xa4\xd2\xdc\x49\x9e\x55\xcf\x39\xcc\x91\x55\xe0\x63\x65\xaa\xc7\xd8\x4a\x5e\x81\x95\x2d\x74\x12\xca\x0f\x6f\x02\xc2\x14\x8f\x0f\x0f\x48\x2e\x4e\x29\x05\x7e\x65\xd8\x89\x4d\x7e\x7d\x7a\xf9\x50\xb1\xb8\x55\xeb\x87\x2b\x97\xb2\x72\xef\xce\xa1\x12\xb1\xec\x10\xf2\x95\xcc\xe5\x2f\x8f\x4d\x67\xbf\x33\x12\xad\xf8\x7e\xf6\x29\x07\x54\x36\x2e\x66\x39\x59\x0b\x66\xca\x42\x5b\x50\x7f\x18\xe9\x41\x2c\x8c\x50\xdb\x73\xce\x47\x62\xb9\x13\x80\x80\x46\x2d\xb2\x15\x8d\x4b\xba\xb1\x46\x7c\xbf\x56\x97\x35\xef\x03\x44\x55\x1b\x75\xc8\x1d\xca\x0e\x12\xef\x15\x5f\x01\xe2\x02\x09\xe7\x7c\xf2\xf6\xce\xa7\x57\xad\xaf\xa2\x54\x78\x32\x3c\x29\x2e\x91\xe8\x7b\x7b\x07\xd0\xf5\x38\x4d\xd2\xaa\x28\x3d\x41\xd4\x0d\x03\xf0\x37\xbb\xfc\x73\x96\x73\x40\x35\x53\x83\x74\xca\x34\xe1\x8a\xbb\x99\x47\xbe\x28\x64\x99\xc3\xe1\x4e\x6f\x18\x7e\x53\xbe\x14\x07\x1e\x7f\xaa\xaf\xd7\xf6\x5b\x2f\xc5\xa3\x3a\xe5\x63\x8b\xe9\x48\x82\x4f\x1a\xf1\xcd\x72\x6e\x91\x96\x52\x86\x57\xb8\x1a\x45\xba\xa0\xc8\xb7\x14\x3a\x22\x13\x26\x41\xc5\xf4\x17\x40\x39\x2a\xf1\x2e\x93\x15\x4c\xcc\x7a\xed\x5a\x28\xa9\x41\x6f\x02\x50\xe8\xe7\xd3\xf7\xef\x48\x64\x34\x04\xf2\xf1\x07\x24\x3a\x7b\xbf\x9b\x64\x7e\x72\x2f\xee\x23\x2e\x8d\x45\x81\x4c\x83\x1a\xa8\xd2\x03\xe2\x11\xbb\x64\x6a\x52\x58\xda\x44\x9d\x26\x8c\x50\xcc\xd6\xe4\xe7\xc4\xd5\xb4\x1a\x08\x62\x7b\xc7\x02\xd6\x5d\xa2\x87\x9a\xb0\xa5\x20\x2c\xa7\x1c\x51\x75\x06\x34\x8f\xfe\xbe\x40\x11\xa8\x08\x4c\x33\xce\xca\x4f\x39\x19\xf2\x51\x68\xd3\x9c\x42\x35\x48\xdf\x36\xa3\xa5\xd6\xd0\x26\x56\x7c\x74\x52\xe2\x31\x46\xf0\x8d\x1e\x23\xcf\x82\xf6\x2e\x99\xe4\x7b\x4d\x9c\x6d\x2e\x98\x64\xb8\xf3\xdd\x2a\x51\xb7\x2b\xd2\xf6\xae\x16\x28\xf1\x3a\x7e\x7a\xb1\x24\x43\xd6\x49\x70\x77\x89\xb1\x54\xe0\xca\x85\xb6\x6b\xaf\xbf\xc6\xc6\x41\xf9\xe9\x91\x88\x5f\xf3\xb3\x43\x28\x41\x73\xc7\x6a\xbd\x92\x07\x8d\x59\x46\x96\x86\xbb\xc1\x06\xc1\x86\x4c\x67\x84\x6d\x0d\x5b\xc8\x6e\x54\xd3\x8d\xdf\x82\xed\xde\x9a\xdb\xc1\x6f\x83\x20\x09\x02\x8f\x03\x44\xc3\xe9\x9c\xc7\x7f\x18\x7a\x94\xbb\x0d\x3d\x9a\x2f\xe8\x1a\xc9\x66\x9c\xc8\x43\xf0\xc8\x0d\xba\xb2\x7b\x74\xd6\x8a\xe8\x91\xef\x7c\x01\x8f\x6e\xc3\x12\xd6\xe2\x87\x01\x9a\xf5\x7f\x42\x17\x02\x6f\xf7\x4e\x0e\x51\x13\x77\x45\xd9\x83\xc3\x9f\x8e\x3e\x1c\x5e\xbc\xdf\xfb\xf0\x57\x00\xaa\x9d\x74\xf1\xfe\xf0\xd3\x9f\x0f\x0f\x6c\xf3\x3b\x35\x19\x52\x02\x9b\xbf\x33\x28\xa9\xd1\x2d\x85\x14\x55\xa4\x11\xec\x16\x68\x79\x8f\x49\xc8\xa3\x0f\x7f\x8e\xe2\x5b\xc1\x04\xb9\x96\x0e\xb0\x30\xa9\xdd\xc4\x42\x82\x06\xc3\x62\x16\xe3\x86\x36\x18\xfc\xbd\x0d\x37\xaf\xa4\x36\x92\x54\x28\xc4\xa0\xe2\x90\x3e\xb1\xb4\x94\x94\x8b\xa6\x92\xaf\x05\x2c\xd0\x1f\x39\x53\x74\x02\x20\xf9\x32\x98\xe3\x85\x93\x38\x35\xe2\x31\x1a\x59\x73\x4b\x1a\xee\x9e\xe9\x45\xaa\xe4\x44\xd1\xe3\x42\x73\x1f\xb9\x1b\x40\x55\x7c\xf1\x78\x20\xfc\xc2\x4e\xb1\x0a\x23\x26\x97\x33\xe5\x35\x07\xba\x70\x53\x97\x69\xb1\xb5\x55\x0c\x2e\x58\x74\x78\x00\x1b\xf0\x6d\x51\x4e\x00\xfb\x7a\x16\x59\x01\x08\x79\x81\xa6\x17\xf0\xbf\x81\xff\x4b\xec\xda\x34\x2a\x65\xed\xbd\x65\x5b\x61\xed\xf7\xd9\x82\xf4\xa0\xdd\x64\xd2\x69\xf0\x65\xa0\x47\xc4\x82\x3c\x7b\xa5\x85\x8a\x95\x25\x9c\x95\x5e\xa7\x47\x08\x86\xdb\x10\xbe\x4b\x31\x71\x7c\x0b\xeb\xe1\xc1\xc9\x89\x38\x10\x83\xaf\xf4\x2e\x7d\x69\x1c\xe2\x0f\x5a\x63\x39\xe5\x90\xfe\xc3\x22\x33\x59\x24\x62\x27\x63\xdc\xc3\xc7\x47\x9b\x1f\x27\x16\x94\xe5\xff\x4f\x5e\x75\xd1\x33\x93\x6f\xbe\x4b\xe5\x40\x92\x2a\x7c\x81\x31\x6e\x56\x91\xe4\x6c\x92\xe3\x49\x4c\x2a\x60\xe7\x21\x17\xb0\xd6\x3f\xbb\x34\x42\x22\xc2\x36\x01\x5c\xb5\xb5\x15\x54\x44\xa7\x74\x73\x96\x7b\xd2\x60\x8b\x1c\xc3\xc1\xa0\x30\x26\xa1\x9e\xdb\x90\x2d\x11\x91\xa0\x42\x9f\xaf\xfc\xc9\x16\xe6\x2b\x37\xf8\x7f\xda\x47\x2d\xd7\xbb\xb8\x31\xb2\xc5\x62\x76\xc7\xa4\xad\xb2\x3e\x41\x3a\xa4\xf5\xe7\x8c\x8c\x88\x8e\xe5\x2e\xcb\x9c\xd3\xb4\xde\x2d\x93\x25\xad\xf9\x47\xc3\xcb\x9a\xff\xe3\x7d\x9f\xed\xf9\xe8\xe3\x23\xbb\x29\xf6\xab\xa3\x4f\xbd\xda\xe6\xd7\xfd\xda\xe6\x13\x2f\x33\x6f\xbe\xb6\xb6\xb9\xad\x5c\x65\x2a\x7c\x93\x55\x91\xd4\xac\xbf\x5a\xa1\x39\x7e\xe7\xe1\x1e\x1e\xba\xe4\xdc\xbe\xad\x20\x8e\x67\xf3\x34\xaf\xa9\xfc\xa5\x47\x7b\xfc\x5d\x35\x56\xf4\xe4\xef\xfa\xa0\xec\x02\x64\x7e\x6f\x8c\x4c\x31\x2c\x95\x6a\xb8\xcd\xb1\xbc\x90\x14\x21\x49\x4e\x0a\x28\xed\xcc\xc7\xad\x4b\x34\xbe\x77\x99\x9a\xa7\x66\x50\x9f\x63\xd1\x51\x21\xaa\xda\x07\xa2\xe8\x73\x93\xcb\xce\xcd\xb3\x05\x77\x04\x7b\xf6\x51\x50\xa0\x64\xf6\xca\x3d\x76\xfa\x70\xe2\x30\xaa\x4f\xc3\x7b\xc6\xeb\x82\x65\x1a\xc5\x1f\xd2\xf7\xe1\xbd\xc0\x20\xc7\x1f\xf6\x0f\x99\xf1\xa8\xa1\x14\x4e\x30\x4e\x54\xa7\x8c\x40\x4f\x92\x0f\x7b\x80\xd6\x26\x47\xa9\xfc\x94\x81\xa1\xd0\x5b\x04\x46\x6b\xb2\x52\x3b\xab\x6e\x33\x5d\xa8\x2f\x79\xb3\x90\xa1\xbd\xdf\x9f\xdf\xc5\x13\x64\x66\xa4\x0f\xa1\xb2\x2f\x79\x52\x85\xa7\x73\xbb\xb7\xd0\xbe\xf6\x31\x7f\x21\xa1\x65\xae\xf2\x10\x98\xa6\x01\x26\x2b\xd1\xda\xe3\x13\x05\x0e\x8a\xc9\xca\x7c\x6c\xe0\x13\x73\x64\x3c\xc3\x89\x79\x1d\xa8\xc9\x17\x0a\x62\x2b\x3a\x63\x97\x70\x7a\xb3\xba\x80\x6e\x50\x6a\x16\xb1\xf9\x1b\x16\x35\xf6\x18\x7f\x49\xef\x35\xaa\xd2\xe2\x7f\xe4\x3a\xc5\x09\x68\x3c\x16\x6b\xc8\x2c\x65\x1e\x5a\xe9\xce\xa8\x54\xfe\x38\x47\xe5\xf6\x76\x44\xc4\x12\x9e\x06\x8f\x9e\x55\x62\xd9\xbd\x13\x0d\x7b\x39\xd0\xcb\x21\xc5\xe8\xd4\x4b\x3f\x21\x83\xd6\x93\x21\x79\xb2\x4f\x7e\x41\x6b\xdc\xd7\xae\xdd\xa4\xbd\x7e\x6d\x40\x59\xf9\xa9\x93\xb2\x0b\xc7\x9e\x9d\x06\x55\x93\xf6\x51\xdb\x6e\xfe\xbe\x62\xbe\x34\x29\x37\x7a\xa9\x12\xa8\x8b\x72\x2f\x9b\x8d\x34\x92\xd5\xb5\x87\xb8\x45\xd2\xb2\x86\xcc\x46\xbd\x7f\x3a\xdc\x3f\x3c\xfa\x0b\xbc\x92\xb7\xb0\x13\x89\x41\xde\xa5\xf7\x1e\x2e\x37\xba\xf2\x23\x91\x48\x77\x45\xe9\x39\x42\xef\xd6\x2c\x47\xec\x95\x86\x78\x9f\x1a\x57\x54\xb0\xf4\x4e\xac\xf4\xb1\x14\xa7\x6a\x9c\x70\x3f\xf9\x2f\x78\xdf\xab\xe4\x36\x72\x24\xaa\x0c\x0b\x52\xb1\x59\xa0\xa6\x57\xb6\xbe\xa9\xdf\x24\x1c\x0e\xfb\xa1\x8f\x03\x60\x6a\xb6\x8b\x8b\xbf\x96\x60\x5f\xfa\x65\xef\xcc\x72\x5d\x17\xa5\xc5\xe6\x6a\x28\x74\xbd\x14\x05\x1d\xfa\x59\x8e\x14\xdd\x96\xa9\x64\xba\x8d\x36\x61\x64\x42\x5d\x4c\x0d\x07\x52\x10\xfb\x2f\xf4\x33\xfe\xd5\x4e\xd3\x38\xb9\x46\x75\x4d\x6e\x44\xb9\xc6\x42\x90\x16\xf8\xfa\xb9\xb0\xeb\x4b\x0c\xd9\xd9\x2d\xdc\xba\x5c\x52\x55\x35\x07\xf7\x0d\xcb\x65\xae\xca\xb2\x19\xe6\xf6\x7a\x93\xe9\x3f\x55\xf5\x58\x08\x81\x50\xc0\x29\xa0\x62\x1f\x2c\xc8\xa1\xf1\xe7\x84\xbe\xef\xc8\xe2\xda\x98\x8d\xfc\xbe\xae\xa9\x4e\xf3\x79\x97\x77\x67\x4e\x7a\x11\xea\x39\xd2\x7d\x56\x57\x40\xf5\xc3\x9a\x2f\x84\xd9\x53\x4b\x89\xee\xfc\xba\x04\xce\xf9\xbc\xcb\x9a\x85\x15\xba\x3d\xec\xcc\xab\x0d\xe0\xc8\xe3\x16\x39\x25\x92\xa7\x43\x09\xf0\x34\xb9\x0b\x23\x29\x7b\x0b\xfd\xd5\xa8\xb7\xa8\x7b\x10\xad\x94\xfc\x3c\xb5\x3d\x3a\x6c\xe8\x99\x55\x71\xbc\x8a\x2d\xe2\xcb\x0a\xd7\x81\x5a\xdf\x74\x39\x86\x6a\x61\xff\xcc\xb2\x44\x5d\xe0\x04\xbb\x9e\x86\xb8\x48\xd8\xcc\x84\x94\x79\x24\x78\xb6\x48\xae\x3c\x2e\x89\xef\x0a\xc9\x31\x6f\x2d\x3a\x6e\xdc\x25\x28\x24\xad\xb4\x68\x2d\x89\xb3\xef\xb3\xec\xc4\xc2\xbb\xcd\xf2\xd5\xa0\x33\x70\xec\xd6\xd6\xef\xbd\x42\x63\x13\x21\x79\x38\xf8\xec\x4d\x2e\x95\xb8\x4c\x71\xd6\xf4\xf3\x9e\xe3\x6e\xdf\xb7\xe9\xfd\xa3\xc9\x6f\x29\x23\x64\xa5\x50\x9c\x86\xce\x89\x41\xf7\x51\x9d\x28\xd5\xbf\xac\x0b\x0f\x2c\xe2\x55\x2c\x27\x2b\x35\x14\x5e\x46\x7a\x58\x7f\x0f\x0f\xbd\x67\xc9\xa3\xe4\x48\xf9\x71\xa0\x31\x62\x9b\x72\x8a\xec\xc0\x03\xb7\x21\x3f\xac\x51\x53\x40\x83\xc9\x12\x9c\x0a\xa9\x4b\xd4\x81\xc7\x26\x9b\x3a\xff\x36\x50\x86\x1c\xd8\x7c\xf4\x92\x41\x96\xc8\xa7\x07\x26\xaa\xef\x45\x7f\xa4\x8d\x22\x92\x2e\x08\xf2\xb3\xe2\x1c\x23\x10\xc7\x15\x29\x47\x4d\xc3\x4c\xf7\x16\x40\xb7\x65\x74\x0c\xc6\xbb\xe8\x71\x4d\x81\xa8\x21\xf1\xec\x61\x44\xe2\xf4\x58\x8b\x99\xdf\x2d\xca\xab\x93\x1c\x7a\x15\x1c\x3c\x79\xfa\x86\xf4\x1c\x55\x91\x21\xcc\x14\xab\x3d\x16\xe8\x9b\xa5\xaa\x7e\x19\xff\xa8\xbf\x1f\xd0\xc9\xca\x9b\xd1\x49\x78\x4d\xfa\xa0\xd2\x88\x81\xda\x47\x03\x54\x06\x01\xd0\x2f\xcc\x5d\x81\xc4\x2d\x40\x7a\x30\xb9\x7e\x6f\xf3\xa1\x73\x3d\x3f\x44\x19\xe6\xda\xa7\x61\xd1\x3f\x25\x84\x23\x47\x3d\xa7\xf8\x88\x57\x65\xdf\xdc\x3d\x3c\xb0\x56\x86\xf7\x56\x29\xdb\xf7\xe5\xa1\x1e\x0b\x6a\xec\x65\xbb\xe1\x93\x24\xcc\x85\x58\xe3\x76\x13\x15\xf9\xde\x46\x37\x28\x51\xe2\x25\xf0\x30\x06\x4d\x47\xd8\xd5\x3a\xed\x56\x58\x94\xba\x21\xb8\xaf\xa4\xb8\x1a\xa3\x67\xf9\x3f\xee\x08\x7f\xe3\x95\x3a\x26\x71\xa6\x2f\x67\x41\x64\xf2\xe1\xb4\x34\xd6\xfd\xc8\x73\x86\xd3\x07\xbd\xa7\xbb\x38\x63\x48\xf8\xbc\x52\xe5\x46\x90\xb6\xc6\x35\xc6\x84\x40\xbd\x42\x09\xc8\x56\x50\x40\x75\x98\xd8\xa1\x77\x64\x3f\xab\xaf\xa4\x93\xb8\x1e\x3b\x24\xe6\x6b\x57\xdc\xc4\x4b\xfe\x40\xf4\xa4\x76\x09\x45\x5b\xf6\x0d\xbd\xf3\xd3\x28\x26\x13\x5d\xec\x33\x61\x62\x37\x69\x5e\x57\x22\x57\xf5\x62\xad\xab\x92\x55\xc9\xbc\x2b\x75\x37\x25\xab\x98\xf5\xed\x91\xae\xd7\xe1\xd0\x57\x31\x29\x95\x58\x4b\xab\x4a\x9f\xa2\xa6\x11\xb7\x7f\x0c\x71\x89\x46\xee\xe0\xd1\xab\x8e\x26\x5b\x91\xeb\xb7\x53\x03\x42\x33\x1f\xfd\x7d\xe4\x52\x76\x2b\x28\xc2\x8b\xb0\x5a\x41\xcc\x8f\x58\x51\x78\x4d\x4a\xbd\x50\x5a\x4c\x9d\x4e\x15\x12\xee\x0b\x9f\xfe\xe4\x60\x82\x96\x6c\x75\xb5\x6c\x66\x77\x42\x83\x0e\xfb\xff\x4b\xd1\x5e\xb3\xe4\x17\x5d\x3e\x84\xb0\xd6\x30\x94\x28\x3a\xc8\x90\x78\xe7\xab\x4f\xce\x5b\x47\xc1\xc9\x27\xc5\xb3\x45\x76\xd2\x81\xa7\x26\xd7\xeb\xc7\x84\x3b\xb1\x97\xb0\x44\xd9\x7e\xef\xbc\xaf\xb7\x6a\x7b\xab\x6b\xeb\x57\xd8\x50\xc4\x6d\x3a\x95\x9d\x1d\xa9\x27\xeb\x3c\xd5\x69\xc5\x27\x2e\xdd\xd7\x46\x13\xa3\xb6\xbe\xbb\x17\x17\x4c\xee\x53\xc8\x6a\x46\x28\xb0\xe1\x10\x48\x9b\xc3\xdd\x30\x4f\xe7\x88\x5f\x4c\xa1\x42\x18\x91\x0b\x14\x8e\x00\xfb\xa4\x71\x35\x9a\x3c\xe1\x42\x5b\xb3\xf8\xe3\xb4\x28\x61\x8f\xde\xdd\x6b\x43\xd6\xfa\x4e\x1c\x1c\x25\xa5\x72\xa4\xaa\x78\x79\xcf\x61\x81\xf9\x38\x17\xfa\x0d\xd0\x88\xde\xd5\xc3\x04\x21\x99\xaa\x3f\xcb\x0d\xf6\x65\xae\x5d\x57\x20\x99\x9f\xd3\x59\x43\xb1\xf2\x7a\x58\x2b\xe1\xcd\xe0\x6a\x99\xd5\x68\x78\xb0\x8a\xc0\xdd\x0e\x06\xc1\x36\x05\xee\xf0\x8d\xb2\x67\x3b\x51\xcc\x20\xc6\xf9\x9d\x94\x0c\x5a\xf8\x9c\x6a\x40\x79\x1c\x7d\x0a\x3f\x77\xc2\x68\x79\xb3\x94\x5c\xbb\x78\x5f\xfc\xbe\x63\x44\xf2\xbf\xd3\xfb\x4e\x5b\x7a\x2f\x7e\x9b\x35\x79\xf2\xd9\xf0\x45\xe3\xf6\xc5\xf8\x9a\x66\xc9\x9e\xa2\x4b\xaf\xcf\xb1\x6e\xdb\xae\x0d\x1f\x56\xc0\x81\x34\xed\x08\x33\x1e\x07\xd3\x80\xa4\xaa\x4c\xfa\xc3\xad\xcd\x52\x25\xd5\x98\x89\xce\x89\x75\x8a\x84\x24\x9b\xd7\x3f\x2a\x1c\xfb\x98\x17\xa0\xa3\x48\x2b\x72\x56\xa2\x3d\xa4\x99\xc0\x1c\x18\x09\xd7\x2b\x72\x2b\x24\xe5\xff\x13\xd3\x1f\x11\xca\xfd\x1f\x5d\x2b\x58\xd6\x28\xd7\xe1\x75\xa0\x5c\x8b\x19\xfa\x63\xff\xfb\x29\xfd\xb1\x3e\x3f\x1a\x5f\xe1\x28\xe3\xab\x5d\x5c\xac\xf0\x82\xa0\x09\x1c\x93\x1f\xbe\x5f\xc7\xef\x85\x47\xd9\xad\xc7\xbf\x45\x27\x6b\x84\xbc\xe7\x8e\xef\x0b\x53\x92\x08\x45\x5e\xf4\x16\xa1\xec\x97\x2b\x94\xeb\xfa\x04\x8a\xc9\x90\x41\xff\x94\xfa\x5d\xac\xa4\x89\xf0\x46\xd0\xe9\xa4\x86\x90\x42\x80\xb1\xa4\x8b\xc9\x90\x7d\x95\xac\x10\x25\x42\x91\x57\x3e\x93\x91\xd5\xee\x38\x35\x45\x3f\x5b\x80\x8a\xd1\x56\x78\x55\x60\xbc\x4c\xdd\xbf\x91\xab\x0e\x5b\x51\x00\x12\x79\x40\xd5\x1d\x86\xc6\xab\x7f\x81\x54\x0e\x1e\x31\x40\x2e\x85\x1d\x4e\xef\x4a\x15\x12\x89\x57\xbe\x78\xe1\xce\xf2\xc6\x51\x39\x9e\x34\x3d\xa3\x52\xdd\xa7\x73\x62\xe4\xf8\x95\xfc\x7e\xb5\x5f\x49\xaf\xd7\x0d\x34\xa2\xaa\xbf\x7c\xa8\x4a\x5e\xb4\x72\x23\xd7\xd6\xc6\x46\x94\x6c\x7b\xb9\xed\xe4\xe9\xd5\xda\x02\x7c\x4b\x12\xaf\xb4\x28\x35\x31\x33\xd0\x88\x45\x78\x9f\x25\x41\x16\xc4\xd9\xe5\x65\x0d\x0f\xf0\x17\x9e\x27\x13\x76\x95\x20\x1e\x20\x05\xba\x08\xaf\xf0\x17\x9f\xdb\x02\x51\x75\x20\x1e\x20\xa5\x29\x26\xf8\x8e\x3f\xe8\x7d\x1e\x1d\x7d\x07\xf4\x13\xc4\x97\x49\x70\x09\x7f\x11\xa9\x07\xf8\x17\x9e\x27\x05\x3c\x4e\x0a\x7c\xaa\xf0\x09\x4b\x15\x57\xf0\x54\x5c\xc1\xd3\xac\x1a\x7f\xf9\xfb\xb2\x42\x6f\x08\xdd\x33\xa4\x57\x93\x3b\x48\x81\xbf\xf0\x8c\x5e\x3a\xa0\x9f\xc2\xf7\x78\xc0\xbf\x01\xc6\xd8\xb9\xc9\xa0\xdb\xfc\x1b\x50\xac\x7b\x44\x8e\x81\x78\x80\x94\x82\xfc\x6a\x14\xd8\xe2\x18\x15\x2a\x83\x31\x69\x45\x8e\xab\x19\x3e\xce\xe8\xe9\x8a\xfd\xdf\xcb\xa7\x80\xc3\x7d\x04\xf8\x97\x9f\x29\xba\x45\x20\x9f\x20\x0d\x5d\x65\x4c\x02\xb4\xd5\x84\x07\xb4\x21\xc7\x30\xfc\x80\xab\xf0\x8d\x1e\x20\x65\x0a\xfd\x80\x3f\xf0\x54\x64\xb3\x0a\xdd\x6d\xd0\x2f\xbe\xdf\xe0\xcb\x0d\x3c\x61\x75\xac\x8d\xad\x43\xbb\xf9\x3c\x09\xf2\x39\xfe\x5e\xe6\x13\x7c\x84\x1f\x20\xf0\xd0\x21\x36\x45\x2b\x90\x4f\x98\x76\xa5\x06\xdb\x3d\x53\x3a\x06\xfb\x0f\xf8\x17\xde\x81\x40\xca\x29\x78\x41\x45\xee\x3b\x28\xdc\x08\x86\x32\x80\xaf\x5c\x0f\x93\xe0\x7a\x08\xbf\xcf\xe1\xf7\x39\xfc\xbe\x80\xdf\x17\xf0\xfb\x12\x7e\x5f\xc2\xef\x77\xf0\xfb\x1d\xfc\xbe\x82\xdf\x57\xf0\x8b\x8e\xc9\x02\xfc\xcb\xcf\xd8\x2e\xff\x62\x6c\x01\x8c\x2a\xc0\xd1\x12\x30\x34\xc2\x1c\x46\x05\xb3\x0e\x73\x5e\x50\x50\x12\x78\xa4\x5f\x78\x9f\x03\x28\xe0\x0f\x3c\x19\x7e\x3c\x50\x2a\x0c\xcf\x00\xb9\x2f\x97\xf0\x19\xf8\x03\x4f\xf9\xdd\x55\xce\x7e\x3d\xe0\x37\x10\xa1\x47\x02\xfa\x81\xb7\x1c\x7d\x95\xc0\x6b\xce\x3e\x4b\x66\xf0\xc1\x59\x81\xbf\xe5\x17\x7c\x2a\xbf\x04\xf1\x3c\x2b\xd0\xb1\x47\x86\x16\xdf\x68\x6f\x07\x8f\x0b\x7c\xaa\xbf\xe0\x63\x8d\x25\xc8\xad\x0a\xfb\x53\xc1\xbf\x18\x4d\x82\xdf\xf1\x09\xd3\x70\x2d\xe0\x5f\x7a\x26\xf7\x1e\x39\xc1\xb2\xcc\x60\x1e\xe1\x0f\x3c\x55\xcd\xb8\x2e\x16\x30\x18\xf9\x14\xc4\xcc\x3e\x4d\x24\x1b\x35\xc6\x05\x87\xeb\xad\x5a\xb4\x62\xbd\xc9\x27\x4a\xa3\x99\xac\xc4\x2c\x56\xcb\x96\x40\xc3\xbf\x41\x0c\x85\xa1\xd4\x22\x03\x08\xa2\xcb\x10\xf8\x81\xb7\x82\x02\x0b\xc1\x7b\x21\x22\x0c\x2d\xe8\x8d\x9f\xaa\x2b\xde\xd0\xf2\x29\x88\xff\x9e\x04\x7f\x0f\xe2\x1a\xe3\x3c\x40\x5b\xe8\xc7\x03\xfd\x77\xd4\xcb\x4b\xd8\x65\xf8\x37\x88\xa1\x38\x94\x6b\xb2\x39\x94\xc1\xbf\x41\x2c\x47\x25\xc7\xd4\x08\xe2\x23\x10\x0f\x81\x08\x43\x22\x3d\x93\xc0\xfb\x3c\x23\x27\x26\xf8\x03\x6f\xd5\x12\x6e\x47\xf0\x4a\xbf\x01\xc7\x22\x09\xf0\x2f\x3c\xb7\x75\x85\xb1\x28\xf8\x37\x10\x31\x46\x02\xfa\x09\x30\x54\x00\x3c\x2f\x2f\xf1\x69\x3e\x47\x46\x69\x20\x1e\x30\x05\x3b\x48\x7e\x54\x28\xa8\x4e\x40\x3f\xf0\xc6\x28\xa3\x65\x9c\xd1\xa2\x6f\x13\xf4\x6a\x02\xa7\x10\x63\x33\xf9\x04\x69\xb8\x1d\x20\x01\x7f\xd0\x1b\x1c\x3c\x5e\xe3\x2f\x2d\xf0\x96\x57\x78\x8b\x41\x7e\x02\xfc\x1b\x88\xd0\x26\x01\xfd\xc0\x1b\x2c\x81\x16\x5d\xbb\xd4\x19\x3a\xd6\xa1\x9f\x20\x86\x45\x04\x2b\x68\x09\x83\x5f\xc2\xc8\x03\xc0\xe8\x41\x42\x7f\x63\xf4\xa0\x0f\x78\x8f\x7e\x82\xf8\x16\x91\xd9\x2d\x62\xb3\x71\x51\x13\x5a\xe5\x5f\xc4\x21\x53\x42\x20\x53\x98\x85\x7c\x36\x2b\x16\x88\x42\xc5\x43\x10\x03\xa8\xae\x68\x6d\xe7\xb4\xb6\x73\x7e\xce\xea\x3f\x63\x9c\x05\x3c\xb9\x02\xf3\x1d\x57\x79\x43\xab\xbc\xf9\x82\x6b\x07\x47\x89\x7f\x03\x15\xf3\x26\x10\x0f\x90\x52\xcd\xee\xae\x70\x5e\xc5\x03\xa7\xf0\xb7\xe4\x13\xc7\x0a\xc9\x66\xdd\xf7\xcc\xf7\x20\xe6\x70\x25\x1c\xa7\xa4\x69\xd1\x87\x0f\xfe\x85\xe7\x1b\x9c\xe6\x9b\x2b\x9e\x0b\x9e\x07\x78\xe6\xc5\x40\x3f\xc1\x23\x32\x19\xbb\x43\x37\xd3\x3d\x65\x7d\x2d\x51\xe9\x27\x11\x4d\xb2\x09\x4f\xf4\xb5\x5d\xcf\xee\xc9\x98\x2b\xd2\x29\x95\xc7\x1f\xbd\xa2\xad\x64\x99\xea\x29\x77\xb2\x85\xf7\xb8\xcf\x52\xcb\xff\xab\xdf\x74\xb6\xb0\x68\x08\xb8\xdb\xd0\x91\x28\x64\xaf\x63\xb4\xad\xad\x4a\xf6\xfc\xb4\xb9\x13\x57\xa5\xee\x0a\x8a\x12\x3a\xb7\x47\xdd\x2b\x39\xfe\xe9\x5e\x3f\x2f\xf8\x85\x6a\x09\x17\x0f\x4e\x6b\x46\xba\x6a\xd4\x4d\xc5\xb6\xdd\xd4\xcf\x8b\x2e\x0d\xdd\x8c\xa5\x95\xee\x85\x34\x34\x14\x8b\x02\x09\x94\xb7\xe2\xf4\x17\xaa\x44\x67\x65\x5c\x9f\x4b\x75\x2d\x9b\x19\xa2\x4b\xe0\x5a\x75\x67\x67\x19\xc1\x66\xf7\xec\x2a\x94\x0b\xae\x38\xe7\xca\x28\x19\x5b\x5b\x63\x8a\xa7\x11\x62\x58\x0d\x8d\x55\x0c\x6f\xea\x16\x47\x0a\xb1\x5d\xd5\xb1\x30\xd3\x46\xf6\x95\x1b\x3d\xc1\x5a\x5a\xc9\xcb\xee\x2e\xe1\x5f\x58\xc9\xeb\xe7\xeb\xfa\x38\xb4\xdd\x16\x5a\x1b\xc9\x31\xf3\xf9\xfe\x6b\x02\x72\xa3\xbe\xc1\x95\x0a\x79\x23\x07\xd9\x31\x73\x35\xae\xde\x89\x66\x29\x11\xc5\x5d\x25\xc2\xf4\x0f\x0f\xae\x20\x99\x73\x22\x27\x6e\xac\x66\xbb\x35\x1d\xc0\xcd\x60\xa2\x6e\xa8\x64\xac\xf1\x53\x55\x93\x1d\x0d\x29\xaa\x4b\x2e\x7f\xa5\x1b\xb5\x5c\xec\x56\x03\x62\x32\x1f\x88\xb8\x7f\x49\x35\xda\x47\x29\x5e\xf4\x48\x3e\xfc\x3e\x76\x0e\x3c\xfe\x9d\x98\xe0\x8a\x1d\xae\xe5\x48\xf7\x26\x66\x0c\xa0\x63\x66\x10\x9f\xc2\xf5\x05\x96\xc7\x55\xf8\x9e\xc2\xf7\x11\x5b\xe9\x14\x79\x37\xe8\xbf\xc5\x34\x39\xa0\x20\x1b\xcc\xd2\x69\xb3\x2b\x29\x01\x80\x47\xd2\x94\xcb\x07\x6d\xf5\x79\x01\x8b\x71\x1f\xcd\xdb\xf8\x82\x20\x70\xc3\xfe\xc9\x89\xd7\x13\x76\xe3\x8b\x04\xb9\x5c\xed\x3d\x7b\xbc\x06\x26\x9b\xf5\x68\x28\x2f\x9e\x8c\xca\x31\xf5\x98\x76\x5d\xf7\x79\x91\x9e\xb8\x4a\xc2\x73\xff\x65\x53\xe8\x25\xe7\x0d\x50\xbd\x39\xba\x3f\x83\x99\x17\x1d\xe8\x94\x93\x75\x45\xdd\x3b\x71\x87\xf2\x78\x05\xd4\xd5\x75\x51\x51\xb9\x47\x5f\x77\x61\x79\x69\x41\x05\xe6\xc5\x40\xfa\xde\x8a\x2f\xe1\xa5\xcf\x47\xcc\xef\xe9\x7d\xc3\xce\x77\x01\xed\x95\x4b\x20\xe9\x6b\x8a\x80\xf4\x29\xbd\x0b\xef\xbb\xc0\x6a\xc8\x7b\x4c\x87\xf1\x6d\x7a\x4f\xc4\x0a\x94\xa5\x2b\x14\xfe\xd6\x14\x6c\x09\xe8\x47\xf8\xe1\x9b\x01\xc6\x59\xaa\x39\xec\x12\x35\xcb\x94\x34\x3c\x08\x82\x19\x9e\x88\x08\x86\x5f\x22\x5f\xe1\x97\x89\x47\x0c\xc2\xc4\x34\x19\x3c\x31\xfd\x02\x0f\xb7\x97\xdc\xa5\xf7\xe9\xb3\xbf\x61\x5c\xc9\xbd\x6f\xff\xd7\xb9\xf8\x4d\x2e\x7e\x1d\xfc\xfa\xed\xaf\x13\x0c\x32\x89\x5e\xab\x1f\xe3\x63\xf8\x63\xa1\xcb\x51\x61\x68\x79\x2a\x44\xad\x31\xa9\x0b\x66\x01\xa6\xf7\x96\x72\xcd\xc4\x62\x7e\x9b\xb5\x56\xeb\xb5\x01\x36\x98\xad\xa3\xd7\x86\x76\xb0\xba\x72\x98\xb0\x47\xbf\x3d\x53\xbb\xef\x7c\x37\x00\x62\xed\xc7\x67\xc1\xb6\x4a\xda\x0e\xde\x04\x86\xaa\xd1\x05\x1f\x4c\xb0\x7d\xca\xd3\xec\x8a\x65\x13\x7b\xe5\x44\xc3\x0c\x68\x16\xb7\xad\x97\xdd\xe7\x10\x94\xc2\x6e\x0e\x32\x2b\x9c\xe5\xa7\xdb\xe9\x13\x6d\xb0\x58\xb2\x4c\x83\x1f\xb5\x8e\xaa\xe3\xad\xea\x37\xe8\xa9\xa2\xce\x92\xa7\xd2\x62\x70\x14\x58\xfa\xd2\x53\xba\x76\xf8\xeb\x68\x5c\xaf\x24\x50\x15\x20\xd3\x4f\x70\x02\x60\x78\x6e\x68\x93\x11\x76\x3a\x27\x1d\x1f\x89\xbd\x81\xc0\x91\x2e\xc5\x79\x90\xb0\x4b\x4f\x30\xab\x41\x35\x0a\x21\x51\x5a\xda\x25\xba\x4e\xa0\x29\x11\xf2\x62\xcb\xed\x34\xd8\x08\xb6\x51\xfe\x43\x2a\x19\x5e\x87\xd0\x92\x33\x4d\xb3\x86\x4d\x8f\xdd\xa6\x7d\x42\x83\x51\x57\x11\xbe\x31\xc6\xea\x8f\xb1\x6f\xf6\x56\x4e\x49\xdf\x69\xd7\x01\xba\xd5\xad\xdd\x07\x17\x17\x78\x41\x8e\x54\x9c\x10\x7e\x7f\x54\xc2\xbd\x32\xfd\xfd\x4c\x57\xba\x31\x29\x89\xf3\x5d\x4f\xa2\x08\x38\x99\x0a\x83\x6f\x76\x4c\xeb\x29\xd7\x75\xa9\x94\xdf\xbf\x11\xfe\x80\x38\xd9\x67\x1e\x2d\xea\x62\x50\x11\x05\xb1\x6a\xf0\xbf\xab\xa2\x0c\x83\x40\x85\x63\x09\x82\x7f\xaa\x14\x78\xf6\x47\xa5\xc0\x4f\xa0\x94\x27\xe4\xbf\xa5\x5f\x1c\x26\xb4\x4a\x66\x6b\x49\x87\xc5\xb1\xce\x85\xba\xa3\xb7\x80\xa5\xdf\x6a\xde\x55\xcc\x42\x0a\xca\x5d\x11\xc4\x16\x9e\x46\x7c\x2e\x06\x68\x7b\xea\xda\x0b\x84\x16\x4a\xa5\xca\xb4\xe9\x38\x69\x2c\x23\x0c\x62\xe2\x5a\x82\xe1\x4a\xc0\xed\xcd\x0d\x2f\xc9\x0a\x8b\x1a\x23\xfc\xb2\x8c\x96\x2e\xba\x20\x2c\x50\x3c\x3c\x20\xff\x16\xf0\x4b\x8a\x8b\x82\xcc\xd4\x1c\xd4\x52\x46\xbb\x87\x2e\x6a\x29\xa3\x24\x44\xc1\x2c\x6c\xe9\x72\x92\xd5\x13\x3c\x45\x48\x5c\x82\x89\x56\x9c\x64\xec\x22\x2e\x0e\xaf\x28\x99\xce\x68\xf9\x31\x12\x1c\x7b\xbe\xd5\x41\x46\x78\xc0\x1a\xa7\x19\x7c\x0d\xe9\x19\x61\x20\xe7\x85\xd5\x98\x4c\x99\x15\x74\xe0\x61\x0c\xe3\x86\xba\x3a\xf6\x1b\x63\xbc\x0e\x96\x12\x12\xb8\x16\xd1\xa6\x23\xf3\xab\x80\x42\x84\xaa\x63\x5f\xba\x03\xc7\x0e\xf2\xe3\xc8\x53\x63\x6b\x6b\x01\x05\xa1\x67\x63\xf8\xb1\xa7\x01\xd3\xc4\x44\x14\xe9\x78\xd4\x3b\x23\x1e\x64\x5f\xc6\x63\xb4\x2c\xf8\xa7\xcc\x0a\xaf\xe0\x27\x66\x05\x20\xf7\x58\xac\x6e\x81\x0f\x0f\x7f\xfd\x02\x25\xec\xce\x56\xea\xf7\xc5\xc1\x3b\xac\xee\xf0\x6c\xae\xa1\xd7\xdc\xc2\xaa\x55\x57\xac\xd4\x8a\x95\x56\xb1\xa2\xff\xda\x43\xe1\x82\xfc\x59\x02\xf9\x93\xf6\x46\x6f\xed\xde\x2c\x59\xbb\x11\x88\xbf\x66\xc4\xdf\x8d\x00\x2e\x00\xc2\xb7\x0e\xe7\x74\x9d\x06\xda\x5f\xd4\x91\xda\x80\x85\x70\xb2\x05\x85\x65\x52\x26\x94\xf7\x1a\xa9\x06\xb1\xdc\xd5\x55\x8d\x24\xca\x12\x32\xd5\x04\x96\xf5\xa6\xb4\x01\xe0\x22\xec\x1b\x9e\x0e\x52\x3c\x2b\x62\xd9\x19\x34\x2f\xae\x56\x94\xdc\xae\x58\x19\x1f\xba\xb0\x5b\x40\xd9\x6c\xf5\xda\x50\x00\xf1\x2f\x8f\x4c\x36\xb6\x34\x3e\xa9\xfa\xbf\xe4\x83\xe4\x29\xcd\x6f\x59\x40\x56\xeb\xee\x05\xba\x67\x46\x8f\xcb\x9e\xd9\x1a\xaa\xd6\x8f\xf1\x3c\x2c\x34\x21\xba\xa8\x23\x29\xe7\xf8\x5a\xfc\x8e\xa3\xd8\x71\x29\xef\xbf\x12\x26\x2f\x89\x19\xe0\x89\xbf\xbb\x32\x66\x43\xbf\x88\xf8\x69\x96\xc4\x8a\x70\x81\x2b\x84\xcc\x7f\x34\x62\x81\xf7\x06\x98\x0c\x79\x8c\xae\x64\xd5\xeb\x8c\xd2\x23\x60\x75\xc5\xa9\xc8\x1d\x59\xed\x76\x7f\x8d\x48\x85\xef\x54\xe4\xc5\xd3\x3a\x5b\xf8\xf8\x84\x7d\x37\x70\x27\x64\x95\xcd\x4b\xcc\xbc\xbc\xc4\xc6\xe1\x25\x2e\x15\x49\x2e\x19\x87\xe4\x3f\x73\xae\xd8\x86\xc5\x1a\xec\xb7\x9f\x48\x78\x24\x99\x6f\x95\x9f\xf9\xa6\x98\x61\xda\xbd\xeb\xd1\x63\x1d\x69\x6f\x31\xc7\x49\xad\x15\xcd\x11\xdf\x3e\x61\x3c\x61\x0c\x1b\x83\x92\x30\x41\x47\xad\x53\xef\x84\xc2\x0f\xc7\x01\x87\x21\x0e\x2c\x8e\xdc\x78\x95\x0f\x55\xdf\xdc\x25\xaf\x5e\xff\x5f\x61\xd6\xe1\xe2\x5b\xed\x2e\x55\x5b\x7c\x7d\xcc\xa1\x5a\xf1\x81\x24\xf6\x32\xb2\xab\xd5\x6c\xa2\xc2\xc3\xc8\xc9\x5c\x7e\x4d\xe3\xb2\x5e\x96\x5e\xc7\x3a\xe3\xf4\xbe\xe7\x40\x4b\x82\xdf\x7a\x72\x7e\xdb\x98\x03\xcd\x81\xb1\x2b\x31\xce\x2f\xfa\x70\xbe\xda\xf8\xcd\x87\xfd\xa3\xdf\x06\x4a\x9a\xf4\x1b\xfd\xae\xa8\xaa\x11\x15\x58\x8f\x02\x53\xbb\x04\x4b\x92\xb9\x77\x0a\xc3\x61\x8d\xbc\x56\xe8\x95\x5c\x2b\x3c\x96\xf2\x17\x2a\x5c\x08\xdc\xa6\x9a\x70\xd3\x21\xeb\x50\x39\x49\xde\xe3\x2a\xf4\x23\x4f\xce\x8d\xf5\xcb\x31\xfb\x51\x55\x7e\x81\x7d\xf9\x78\x79\x70\xe9\xe1\x35\x06\xe2\x56\xfa\x87\x06\xb2\xaa\x8f\xc8\x46\x8d\x62\x7b\x22\xd6\x06\x76\x57\xc5\xbe\xc4\x79\xfa\x57\xea\x80\x14\x7c\x08\x01\x26\xcf\x22\x5a\xbb\x0f\x46\x2d\x5f\x37\x4a\xb3\x1b\xe8\x4d\x42\xfb\xa8\x46\xf4\x7c\xd5\x67\xad\x7a\x6b\x7c\xb8\xf6\x90\x59\xa2\x2b\xeb\x68\xe0\xae\xb3\x70\xd6\x68\x66\xad\x8e\x3e\xd5\x90\xa7\xdf\x1f\x35\xb5\x56\xc0\x6d\x42\x0f\xeb\xeb\x3a\xed\x6f\xc3\xee\xb1\x69\xa5\x9e\xeb\x56\xea\x78\x3b\x1a\x2c\x32\x64\x1b\x60\x87\xf5\x61\x75\x39\xc4\x74\x1a\x08\x35\x5c\xf1\x0d\xb6\xaf\x8e\x3c\xd1\xb5\x9f\x22\xec\x3c\xc8\x3c\xf9\xee\xf9\x93\x24\xde\x5a\xce\xb3\xd6\xf3\x79\xf5\xfd\xda\x6e\x86\xff\x9b\xd1\x45\xc5\xfc\xea\xab\xc8\xa2\x23\x54\x69\x11\xe2\x9b\x24\x38\x7a\xff\xe7\xff\x4f\x69\xa4\x77\x55\x36\x89\x83\x19\xfc\xfd\x1a\x0a\x89\x94\x2e\xe3\x20\x67\x39\xf3\x7f\x23\xfa\x68\xb5\x87\x42\x4d\x74\x29\x40\xa8\x19\x01\x88\x1b\xa1\x66\x59\x60\x46\x9d\x77\xa4\xff\xeb\xd1\x4a\x18\x49\x3f\x9f\xd0\x81\x23\xdd\xe6\x64\x6b\x2c\xe9\xe6\xa9\x25\xbd\xf4\x2e\xe9\xb1\xb3\xa4\x67\x1e\x92\x6d\xe1\xf5\xe2\x3d\xf5\x4b\xd9\xae\x5d\x62\x6e\xa2\x98\xea\x72\x9b\x8c\x07\x24\x7a\x12\x1b\x65\x8e\xf2\xa1\x9b\xb4\x59\x67\xb7\xb0\xd2\x97\xdc\x21\xb5\xba\xe6\x66\xe7\x8e\x0f\x17\x47\xa6\xaf\x73\xde\x59\x2b\x9b\xe0\x3c\xfa\x1f\xbc\xa3\xee\x45\x30\x54\xf2\x8b\x97\x4f\x12\xb7\xb8\xc8\x79\x78\xd8\x1c\xca\xc8\xa9\xd4\x82\xe0\x12\xe4\xbb\x42\x26\xf7\xd8\xab\x56\x30\x55\xf6\xcc\x42\xa6\x94\x5b\x6d\xb3\xad\x61\x6e\x74\xb0\x33\xd5\x6b\xf9\x70\xe0\xa8\x15\x74\xff\x87\x06\x6e\x54\x99\xcd\xb4\xdd\x6d\x93\xce\x0a\x6c\xa0\x77\x72\xa4\x1d\x9a\xe2\x63\xa2\x09\x69\x0e\x3b\x18\x6b\x7d\x20\x69\x80\xa7\x2d\x51\x15\xba\x28\xe3\x4b\x09\xce\x3c\xc7\x48\xe2\xa4\x78\xd2\xa7\xcd\xb0\x1a\x4f\x31\x90\x66\xe4\x61\x41\xf0\x63\xba\x08\x7c\xe8\x2f\x79\x2e\x0d\x1a\x1e\xfd\x3e\x68\xfc\x73\xae\xb7\x11\xb7\xaa\x7d\xa0\x1a\x98\xc8\xdc\x98\x9f\xb5\xe7\x8f\x3e\xb7\x37\x4f\xb7\xa7\x9b\xa9\xca\xc1\x12\x84\xd0\x54\xce\x47\x84\xe7\x71\x20\x4a\x04\xb1\x5b\x0b\xd7\x56\xd4\x37\xd7\xe2\x53\x2b\x5a\xa6\xb5\x00\xf4\x49\xb0\x4d\x56\xe9\xfa\x9c\xb8\xa2\xa8\x58\xd0\xba\xc7\x62\x22\xe5\x72\x40\x4b\x86\xb4\xd6\x85\x13\xc8\x9e\x86\x2d\x9e\x11\x0d\x45\x85\x34\x61\x0f\xf7\xbf\x44\x5b\xe8\x62\x1a\x92\x7a\x57\x15\x48\x6f\xee\x9c\x89\xfb\x9c\x59\x81\xe4\xad\x5b\x05\xec\xf7\x4c\x4f\x93\x66\xa3\x46\x23\x87\x46\x51\x93\x1a\xef\xb2\xf2\x12\x92\xff\xbe\xcc\xeb\x3b\x0e\x77\x56\xd5\x7b\xd0\x5d\xd6\x0a\x3d\x2b\x49\x9e\xbc\xfd\xff\x9c\x1c\x7f\x18\xb0\x14\xbd\x98\xde\x31\x7b\x70\xfb\x9b\x73\xe2\xca\xa6\xa2\xa3\xe7\xdf\x20\x1a\xdc\x01\x74\xb6\x94\x44\xd9\xf4\xcd\x78\x34\x96\xc1\xaa\x00\x79\x9d\x8d\x89\xbd\x3f\x61\x7e\xe2\x84\x58\x1f\x30\xbe\x8c\x1e\xb8\xd4\x8d\x5a\x54\x93\x68\x74\x1d\xde\x30\x80\xae\xd2\xf9\xd9\xcd\x39\xbc\x5f\x69\xf0\xbb\x42\x0b\x0b\x65\xc4\x6f\x9c\x95\x37\xab\xb4\x7b\x56\x52\x66\xce\xb1\x91\xbc\x7a\xf5\x8f\x32\xe5\xfe\x31\x3d\xa1\x3e\x5a\x71\xb5\x23\x61\x3c\x94\x57\x7b\x43\xb5\xdd\x06\xf7\x9d\x88\xf5\x53\x27\x62\xe5\x3d\x11\x0b\xe7\x44\xcc\x1c\xef\x69\x95\x75\x9a\x15\x03\x56\xc0\xe5\xe3\x0c\x97\x70\xbd\xc6\x51\x76\x2c\x94\x76\x95\x3a\xda\xb9\xcf\x4d\x98\x6e\xc0\xd4\x4f\x0b\x66\x1a\x2d\xb8\x86\x16\x59\xa3\xe9\x49\xfe\x67\xaf\x03\xcb\x56\xe4\xfb\xd5\xb6\x22\x4f\x90\x5c\xc2\x57\x8d\x70\x2e\x12\xde\x13\xba\x4b\x0c\xc3\x4a\xda\x03\x8f\x96\xb5\x25\x1f\xa3\x3b\xb6\x6a\x98\x26\x5d\x47\xcd\x3c\xf6\xdd\x30\x47\x16\xf2\x62\xc6\x8e\xe6\x2d\xa7\x3d\x54\x4a\x69\x0d\xe4\xb7\xec\xb1\x21\x0c\x4e\xaf\x73\xf2\x99\xbb\x1d\xfc\xb6\x81\x90\xdf\x68\x96\x8b\xc5\xac\xc8\x27\x1b\x6d\xb5\xf1\x23\x2b\x39\xbf\x51\xdc\xa4\x0c\x26\x0c\x9b\xdb\x28\xa6\x1b\xbf\xc9\xcf\xfd\xb6\x51\x34\x1b\x6d\xbd\xcc\x07\x52\x0a\x0a\x9f\xff\x4f\xf9\xfa\x46\x03\x98\x1d\x71\x16\x02\xc5\xed\xc3\x34\x83\x8f\x63\x27\xbc\xee\x78\xd1\x14\x9e\x44\x56\xbc\xc0\x64\x4d\x94\x43\x29\x02\x24\x17\x14\x03\x7d\x20\x96\x1e\xc9\x24\x86\x17\x9b\x85\x9c\x9d\x14\xe4\xbd\xad\x44\xfa\xaf\x06\x1c\x5c\x01\x4e\x15\x38\xb8\x7a\x53\x8f\xb6\xb7\xeb\xa8\x3c\x03\xac\x9d\x9d\xd5\xe7\xa8\x0b\xc7\xb2\xc8\x32\xc5\x24\x3a\x07\xb8\x52\xa3\x57\xaa\x25\xe2\x5e\xa6\xc5\xae\xe3\x32\xb6\x81\x96\xb8\x5f\x51\xd2\x3d\x03\x32\x2f\x47\x4b\x40\xef\x94\xc4\x00\xc3\x03\x3c\x34\xde\xd3\xa5\xf0\xbd\x59\xf4\x50\xf8\x59\x2f\x09\xdf\xac\x81\xb0\x96\x4f\x21\xac\xb1\x17\x61\xcd\x1c\x84\xf5\x95\xe4\xfa\xd8\xc2\x66\x33\x31\x60\x41\x9c\x77\xc4\xfb\x2a\x64\x76\x22\xf4\xf8\x25\x32\x2b\xe2\x4c\x10\xe6\xcd\xb9\xe6\x65\xee\x5e\x27\x6b\x93\x3a\xe6\xfd\x5b\x3f\xae\xa2\xdd\x05\x71\xae\x6d\x75\x97\x84\x47\x0b\xc9\x2e\x47\x2e\xca\xdd\xb3\xf3\x84\x14\x4d\x9e\x40\xac\x1e\x54\xc1\x8e\xdb\x7a\xbd\x73\x18\xb4\xd4\xa6\xe7\xd3\x28\xb9\x55\xdd\xf0\x22\xad\x33\x8d\xb4\xa6\x94\xf3\xc7\x28\xf1\xb6\xb4\x99\x6b\x2f\xfd\x08\x50\x6b\xea\x6c\x07\x1a\xfb\x8a\x4b\x88\xba\x00\xac\x22\xe9\xf5\x8b\x46\x7c\xfd\xc7\xe8\x7b\x11\x36\x22\xb3\x08\xdb\x68\x35\xed\xad\x54\xa7\xec\x7a\x71\x99\x6e\x6a\xd0\x01\x1c\xb2\xe9\x9b\x8c\x91\xd4\xa0\x7a\x78\x28\x61\x93\xa3\x96\x50\xa5\xb9\x6e\x7a\x92\x48\xce\xd6\x25\x92\x99\x2a\x1e\x49\x3b\x6e\xb3\x17\x30\xfa\xf4\xec\xbc\x73\x17\x84\xba\xba\x59\x0d\x2d\x4b\x84\x08\x58\x62\x87\x74\xf4\x05\x36\x5b\xbe\x69\x46\x0d\x60\xb3\xe2\xac\xd1\x91\x52\xc5\x86\xba\x94\xca\x98\x8c\x8f\x8b\xaa\x6b\x90\x92\x4d\x2d\x44\x63\x75\x57\x16\x35\x1f\x5b\x74\xe8\x64\x15\x1d\xfa\x5f\x94\xd4\xd4\xe9\x4a\xa4\x33\x56\x5b\x6f\xea\x5a\xe9\x52\x45\x5c\xee\x02\x3c\x0d\x60\xa3\xc1\x4f\x6d\xd0\x0b\x72\x15\x4e\x84\x16\xf8\x40\x85\x55\x46\xb7\x43\x02\x49\x7e\xa2\x35\x12\x91\x2b\x0f\x34\x58\x11\x93\x09\xa7\x54\x39\x98\x2c\xe1\x54\x1e\x13\xa7\x68\x54\x0d\x30\x1e\xcb\x69\x25\x86\x82\xec\xf5\x90\xa2\x52\x51\xfc\xdf\xc9\xc7\xaa\x40\x7d\x06\x78\x22\x8d\x45\x34\xb9\x2a\xa5\x67\xed\xca\x68\x38\x4b\x8b\x6d\x19\x13\xe4\x9e\xa2\x2b\x27\x45\x8c\xf6\x6d\xd9\xa3\xa5\x6b\xce\xbd\xbf\x2d\xca\x49\x75\x8b\x2b\x5a\x85\x89\xde\xda\xf2\x24\xb2\x5f\x91\x4d\xd8\x33\x14\x99\x0b\xa3\x2f\x5f\xc1\xf4\xc0\x86\x8e\x34\xaf\xd7\xd2\x17\xdf\x20\x2b\xc7\xd7\x55\x4d\x61\x58\x2a\xf5\x7a\x3c\x9d\xa2\xc8\x15\x55\x3d\x29\x04\x2a\x65\x67\xf2\x4d\xe4\x0a\x3b\x79\x02\xdc\x5e\x1b\xee\xe0\x49\x88\xda\x6c\x5a\x8b\x56\x7b\x7a\x6b\x46\x5b\x78\x46\x2e\x77\x77\x12\x64\x4a\x8a\xc8\xd1\x91\x84\xd3\x0c\xf9\x4b\x18\x72\x4b\xcc\xd0\x48\x9e\x73\xd8\x8c\x90\x6c\x34\x38\x05\x33\x31\x05\x21\xa1\xd4\xba\x33\x14\x88\x45\x82\xf8\xd6\x88\xdd\x70\x97\x78\x60\x9a\xe5\x66\x7a\x39\x78\x83\xd9\xd0\x33\xe1\x55\x76\x77\x9a\x2e\xa0\xbb\x33\x4f\x77\xaf\xd3\xe9\xf6\x18\x0e\x5f\xb5\xd8\x8c\xe5\x35\x9a\x88\x33\xa0\x6e\xc9\xf1\x4b\x3c\x91\x9d\x86\x83\x97\x7b\x36\x4f\x27\x83\x71\x35\x9b\x65\x8b\x26\x9f\x98\xeb\x63\xbe\x7b\x9d\x4c\x69\x8d\xcc\x77\xa7\xc9\xf5\xa3\x15\x5e\x52\xa3\xf4\x3c\x6b\xdd\xec\x88\xb1\xa6\x83\x25\x9c\x37\x53\x18\xe5\x44\xf3\xfe\x86\xc3\xdd\x0d\x4b\xd2\xf6\x85\x8f\xe3\xc6\x80\x73\x8e\x5f\xde\x68\xb9\xf0\x40\x8e\xd6\x29\x23\x4a\x8c\x1a\x94\x8b\x9b\xa3\x67\xcf\x60\x32\x03\x03\x63\xf0\xd7\x80\x0d\xc8\xce\x72\xe5\x76\xaa\x64\x45\x84\x9a\x5e\xad\xfe\x56\x54\xc4\x01\x87\xde\xd0\x0b\x9e\xed\x22\x65\x52\xde\x9d\x84\x97\xd1\xb3\x71\x18\x9d\x77\xd8\x80\x22\x9a\xcf\x0b\x5c\xe8\x62\x94\x78\xf7\xec\x87\x60\x95\x68\x35\x08\x56\xbc\x3f\x4b\x40\xda\xb0\x74\xf1\x5c\x78\x53\x48\x2f\x73\xc5\x08\xb0\x04\x52\xd3\x8f\x42\x5d\x1a\x7a\x5e\x21\xa9\xb8\xe4\x50\x0b\x18\x9c\x60\x6b\x6b\xc6\xc5\x17\x7d\x6b\x6c\xd1\xad\xb1\x86\xcc\x61\x60\x03\x54\x62\xe1\x96\x22\xa0\xd4\x1e\xd0\x45\x58\x1c\xdd\xb4\x42\x07\x60\x2a\x31\x58\x14\xb7\xb0\xc0\x62\xdc\x3b\xd8\x23\xd4\xc0\x4c\x36\x00\x13\xbc\x90\x4b\xd6\xce\x8b\x8d\x36\x90\x5b\xc2\xa3\x60\x69\xd0\xef\xf9\x78\x89\x50\xd5\x23\xd8\x28\xe2\x59\x08\xce\x7e\xaa\xea\x7d\x39\xa1\xbc\xd5\x3a\xf2\x19\x8a\x68\xb2\xcc\xbd\x31\xca\xd3\xc8\x3a\x8e\x10\x44\x56\x7e\x6e\x50\x15\x70\x6b\xcb\x83\xe5\x17\xe9\x3d\x12\x02\xd4\x60\x93\xcc\x76\xeb\xa4\x42\x47\x97\x5d\x42\x01\x48\x57\x3b\x46\x17\x42\xf4\xe1\xeb\x72\xc2\x01\x62\xfa\x3b\x9c\x0c\x5f\xbd\x88\xfb\xfb\x0b\xd9\x28\xc1\xf8\x61\x6d\xff\x02\xff\xbf\x94\x60\x74\xd7\x9f\x85\xff\xfa\x33\x75\xa5\x15\xd7\x0e\xbf\xc7\x95\x5e\x48\x93\x60\xc9\xf1\x99\xac\x25\xbc\x38\x55\x86\xc4\xff\x54\xf9\x45\xdc\xa6\x3e\x8d\x7d\xc5\x2c\x0e\xbb\x40\xbb\xb1\xe5\x83\x38\xa2\x5c\x49\x4b\xfc\x98\x0e\x91\x3d\xde\xc2\xf5\x21\x8a\xf3\x94\x98\xc8\xc2\x47\x13\xda\xed\xe5\xa4\x58\xac\x49\x11\x74\xd6\xb4\x29\x42\xe1\xfb\x1d\x34\x10\x76\xa2\x04\xf4\x2c\xd3\x7b\x25\x59\xf4\x5c\x49\x54\xd7\xfb\x2d\x03\x3d\xb2\x12\xf3\xae\xb2\xfa\x5a\xa3\x6e\x32\xae\xc4\xe4\x89\x6b\x89\xec\xbb\x03\x8b\x8e\xa9\x14\x59\x1e\x58\x3b\xa9\x81\x9f\x83\xdf\xea\x1c\x7c\x02\xd8\x1f\x64\xe1\x33\xf4\xfc\x9c\xfc\xd9\x1f\xa7\xfd\xff\x3b\xf2\xa0\x9f\x8e\x5c\x67\xb1\x28\x7f\x58\x6d\xe1\xed\xe2\xd4\x3a\x17\xab\xa6\xf8\x3f\x7a\xb0\xb0\xd0\xf5\xcf\xd2\xe1\x23\x81\x4b\xcd\x48\x74\xab\x03\x23\xe7\xe8\xf5\xe8\x27\x19\xd6\x08\x31\xe6\x7d\xf7\xdd\x24\x8b\x81\xba\x6d\x72\xd3\x4b\x7e\xd1\xbc\xc5\x48\xf5\x30\x38\xf1\xe5\x74\x73\x88\xb1\x27\xbd\x35\xeb\xc1\x74\x06\x37\x4b\xaa\x91\x8b\xd5\xde\xb0\xf3\x2b\x0c\x69\x38\x4e\xcf\x96\x71\x73\x3e\x2a\xc2\x52\x53\x37\xae\x04\xfe\xc2\x93\x51\x1b\xcc\x2f\x75\x86\x56\xa8\x8d\x87\x57\x3d\xc6\xf5\x86\x80\x99\x91\x13\x2e\x3a\x56\x9d\x7e\x26\x9b\xc3\xf8\xd2\xe8\x48\x4f\x08\x49\xcf\x18\x47\xde\x71\xef\xc4\xf5\x2e\x39\xd3\x8c\x80\xde\x96\xe1\x24\xf3\x98\x55\xd0\x51\xa3\xcc\x73\x72\xf7\xaf\x5c\x7b\x51\x99\x31\xe2\x5e\x90\x72\x83\x39\x5f\xc9\xf0\x3b\x8c\x60\xff\xc3\xda\xd6\xd2\xd1\xfd\xc5\x40\x57\x88\x1e\xb0\xe7\x2e\x5e\xe7\x98\xae\x2c\x8b\x3f\x45\xb1\x28\xaa\xc2\xf5\x8b\xc2\x5a\xe2\x71\x8d\x3e\xf7\x9a\xde\xa2\x47\xc2\x0d\xf1\xcf\x84\x6f\xc2\xdb\xde\x82\xec\x4b\xfe\xfd\x3a\xdf\x6c\xde\xd2\x09\x18\xde\x9f\x14\xf3\xc5\x2c\xd7\x72\x92\x8f\xf1\x21\x86\x57\x7e\x97\x67\x37\x46\xfa\x32\x66\x44\xf6\xff\x92\xf7\xa7\xdb\x6d\x2b\x59\x82\x28\xbc\xfa\x6f\x3f\x05\x85\xee\xd6\x21\x4b\x21\x9a\x94\x87\x63\x83\x86\xb5\x9c\x1e\x3a\xdd\x79\x3c\x2c\x5b\xae\xac\x6c\xa5\xca\x05\x91\x90\x88\x36\x09\x30\x01\xd0\xb6\x4a\xe2\x93\x7d\x3f\xbe\x47\xba\xaf\x70\xf7\x10\x33\x02\x14\xe5\x73\xaa\xfb\xde\x75\x7f\xd8\x22\x62\x1e\x76\xec\xd8\x7b\xc7\x1e\xec\xb4\x52\x28\x34\x80\x44\x94\x95\x91\x8a\xb7\xe5\x79\xbe\xc8\x3e\xa5\x17\x70\xa4\xc9\xaf\x80\x9d\xbd\x12\x4c\x83\xdb\x69\x27\xe2\x4f\x19\x6c\x7d\x46\x8a\x04\x76\x06\xfa\x70\xff\x32\x7c\x07\x28\xcd\x36\x1a\xe3\x29\xfd\x77\x5c\xe6\x7c\xaa\x93\xf9\x92\x5f\x76\x57\x70\x4b\x02\x75\x7c\x2d\x5d\x10\x7d\x63\x4f\x3a\x97\x64\x81\x7b\x25\x0d\x70\x5f\x29\x47\x2e\x2f\x94\x5f\x94\x73\xe3\x7e\xe4\x07\xfb\xc6\x79\xd7\x67\xef\x38\x03\x76\xa7\x83\x9f\x19\x29\xe9\x90\xf3\x12\xf8\x24\xef\x25\x64\xfa\x35\x6c\x23\xcd\xa1\xe5\xf5\xad\x7f\x81\x65\x2c\x4c\x2e\x33\xad\x14\x20\x36\x2f\xf2\xcb\xfe\x62\xd7\x82\x9f\x08\x18\x1c\xa7\x6c\x0a\x18\x5c\x47\x8e\xc6\xcf\x0d\xd6\x50\x28\x46\x01\x76\x3b\xde\x62\x7f\xde\x1d\xc4\xb5\xdd\x82\x3a\xf3\x9f\xd0\x9c\x3a\xbb\xbc\xea\xcf\xb0\x0c\x86\x68\x7c\x03\x54\xc7\x0f\xb5\x37\xcc\xe4\x50\xb3\x2a\x0b\x48\x3a\x4d\xfa\x1f\x2b\xad\x2d\xb7\x48\xfc\x3e\x98\xac\xd7\xdb\x9e\xb4\xa1\xf3\xfb\x73\xe7\x12\x08\xc3\x9e\xb9\x0e\x5a\xb0\x6f\x2e\x05\x80\xee\xac\x68\xdc\xce\xcd\xdd\x10\x3e\x20\x96\x75\x3f\x93\x48\x3e\x3e\x30\x64\x75\xf0\x34\x1a\xfa\xba\x83\xed\x92\xb4\x36\x12\x62\x2d\xa8\x30\x44\xf7\xb6\x43\xea\x99\xfb\x77\x71\x07\xf3\x90\x33\x81\x40\x2c\x53\xd7\x1f\x80\x9c\xb5\x0f\x17\xc6\x45\x40\xdb\xd0\xd3\x0d\x5f\x66\xbc\x86\xb8\xd1\xcb\x94\x39\x83\x1b\xb7\x4c\x6a\xf3\xb9\x81\xcb\xb4\xd2\x92\x1b\xbc\xcc\x3c\x00\xbb\x71\xcb\xcc\x5b\x0a\xc6\x2b\x73\xd2\x35\xfb\xa0\xe3\x91\xb5\xef\x02\x13\x94\x8c\xf2\xde\x28\xbf\x8f\x26\x12\x99\x4c\xb7\x91\x7d\x6d\x82\x92\x39\x7a\x5f\x32\x2a\x59\x0b\x89\x52\x84\x32\x99\x55\x7d\xcb\xaa\x16\x50\xca\xa0\x64\x2d\xac\x4f\xb1\xc8\x38\xeb\x9f\xff\x7b\x08\x60\xde\x71\xae\x64\xb7\xe0\x6a\xfe\x90\x5e\xda\x4c\xa0\x75\x45\x4b\x47\x96\x31\x7a\x15\xbd\xee\x3e\x5a\xf1\x03\xa2\x04\xdb\x07\x2b\x7e\x40\xb7\x79\xf0\x58\xc5\x0f\x89\x2e\xec\x38\x54\xf1\x43\xd2\x73\xed\x3a\x52\xf1\x43\xa2\x7a\xc3\x07\x2a\x7e\x48\xc4\xeb\x36\x91\x40\xf8\x30\xc5\x8f\x68\x1e\x5b\x8f\x52\xfc\xe8\xf1\x5d\x49\xeb\x8e\x63\x14\xff\xfa\x48\xb4\xcf\x40\xfc\x78\x2c\x82\x87\x26\x7e\x7c\x24\xfc\xa3\x11\x3f\xbe\x2f\xbc\x83\x11\x3f\x7e\x28\x5a\xc7\x22\x7e\xec\x74\x25\x0f\x45\xfc\xd8\x21\xf2\xe5\x91\x88\x1f\x3f\x16\xa1\x03\x11\x3f\x31\x2c\x40\xd7\x99\x8f\x9f\x8c\xfd\x32\xac\xb6\xfc\xc4\x8c\xd3\x3d\x4a\xf1\x78\x64\x9a\x35\x27\x09\x92\xc7\xa2\xeb\x20\x41\xe6\xfd\x0e\xed\x97\x20\xc8\x03\xfd\x48\xe5\xdb\x67\x0c\x72\x1e\x88\xae\x23\x06\x99\xb4\x94\xed\x13\x06\x39\xd4\x5b\xd7\x11\x8a\xc7\x0f\xd0\x69\xcf\x93\xed\x66\x69\x41\xbf\x94\x24\x80\xbc\x58\x94\x65\xd5\x87\x95\xf9\xa7\x6c\x70\x0f\xfe\x04\xa2\x00\x93\x93\x23\x52\x56\xb8\xb9\x19\x0d\x0e\x8a\x0d\xeb\x8a\x05\xbc\xcc\xe4\x6d\x5c\x8d\x7b\xf2\xbc\x48\x17\x57\x75\xee\x4b\x8e\x14\x5a\xaa\xdb\x16\x44\xf2\x12\x93\x64\x3d\x6e\xc8\xbb\xf2\x3b\x1b\x0c\x7d\x01\xde\xf7\x2d\x6b\xf3\x53\xb0\xaf\xf8\xf4\x4c\x86\x7c\xff\xd4\xa0\x1f\x93\xd3\x11\x7c\x33\x2e\x41\x0f\x29\x63\xc1\x32\x72\x8b\x6f\x99\x0e\x75\x3e\x19\x31\x2b\x48\x50\x44\x95\x34\x15\x98\x2a\xa3\x01\xe8\x76\xe8\xf7\x2a\x25\x2c\xc9\x48\xd4\xc3\xac\x40\xa7\x50\x32\x37\x41\x07\x2a\xe4\xf5\xcc\xea\xb1\x55\x66\x4c\x2f\xe4\xbf\xa5\x75\xe3\x4c\x25\xc0\x5c\xb5\x7a\xc6\x20\x6f\x39\x30\x11\x3f\xa6\xc0\xdc\x01\xa9\xea\xc8\x10\x32\xf4\xbd\xdd\xae\x63\xeb\x1f\xea\x8a\x9f\xd8\x8f\x1e\x6a\x4d\xa2\xab\xe4\x72\x81\xcf\x8d\x30\xc8\x7e\x33\x5c\xa6\xab\x7e\x3b\xbe\xca\x75\xa4\xc1\xae\x37\x45\x3a\xb8\x87\x6a\x79\x11\x5a\x19\xab\x74\xe4\x0e\x44\x74\x52\x36\xe9\xa2\x97\x17\xb2\xa3\x1e\x3a\xcf\xeb\xf5\x97\xf5\x20\x8a\x0b\x8c\x9f\xac\x32\x06\x22\xd2\xa3\xe9\xd1\x16\xfa\x45\xb3\x1f\xa1\xa2\x32\xbc\xb5\x57\x56\xba\x5e\x16\xd1\x5b\xd3\x12\x00\x90\x8e\xc7\x12\x6a\xf6\x1e\x8e\x1d\x9f\xc0\x44\xf4\xd1\x6a\xb4\xa3\x1a\xf7\x60\xea\x28\x64\x51\xc7\x32\x09\x38\xe1\x81\xdc\x9f\x37\xc5\x4f\xee\x8f\xae\xf8\x13\xfb\x43\xae\x8f\x7b\xcf\x7a\x53\x83\x1e\x5a\x9b\xf3\xa6\x6b\x5b\xf0\xb3\x63\x4e\x42\x0d\x60\x51\x5e\xf6\xe5\xf6\xb2\x5f\x44\x41\x63\xa6\x94\x13\x48\x80\xc1\x0c\x9b\xf2\x75\xfe\x23\x9b\xf5\x8f\x06\x07\x51\x6f\x09\x87\x9e\x60\xdd\x9e\xae\x9c\xd9\xdb\x34\xe4\x4e\xa5\x63\x11\xc4\xde\xc8\x84\xfc\xfa\x5d\x0b\xf0\x57\x38\x75\xa8\x4a\x65\x66\xcf\x73\x0f\x4e\x5d\xee\x26\xd7\xd9\x65\x2b\x85\xbb\x57\xd3\x61\xe7\xdc\xc9\x29\xd8\xef\x5c\x58\x1a\x1c\xe0\xe0\xbb\x02\x19\x5e\xc1\xbb\x83\x17\x57\xbc\xde\xe8\xf5\x3f\x2d\x87\x6f\x5e\x7e\x79\x7e\x72\xf2\xf1\xcd\x9f\x3e\x9f\xbc\xfa\xf2\xee\xf9\xdb\x57\x67\x09\x9c\xec\x99\x60\x35\x23\x54\x5d\x40\x69\x52\x33\x4c\xab\xcb\x3a\xf1\xf4\x76\x33\x4a\x45\x49\xe5\xef\x5f\x81\x2f\x15\xb0\x92\xd5\xec\xaf\x55\x1e\x88\xf2\xa2\x7c\xd8\xb4\x17\xe3\xb4\x13\xa5\x1f\x8e\xcf\x86\xdf\xb1\xb5\x7a\x52\xa2\x72\x3a\xfe\x77\x73\x03\x97\x0c\xfe\x60\x55\x8d\x6b\x9c\x5b\xdc\xb0\x6b\xd0\x02\xe3\x4e\xd6\x28\x6e\xd8\x08\x79\x61\xb4\x44\x5b\xed\x18\xd1\xda\x59\x13\x86\xd4\xcd\xf1\x1a\x49\x74\xf8\x4a\xa5\x2f\x52\x3f\xcb\x27\xf9\xc1\xc1\x40\x2a\x88\xe8\xfc\xd3\xfc\x4c\x0a\xdc\xc4\x4a\x5c\x90\x8e\xb6\x0c\x0b\xf1\x2e\xfb\x8e\x34\x85\xa1\x0e\xf0\xa5\xff\xe6\x26\x0a\xc8\x01\x29\x6b\xd0\x79\xcb\xc8\x89\x6a\x44\x89\xee\xbc\x35\xde\x8e\x8d\xea\x2a\xfa\x3a\xc1\xa3\x52\x93\xbf\x6f\x5a\x36\xfc\x65\x3d\x97\xd0\x77\xa3\x76\x31\x46\xf7\x8e\x17\xc9\x1a\x7d\x26\x24\x85\x1d\xbd\xb3\x0c\x5d\xb3\xdb\xb7\x49\xb7\x8a\xed\x1d\x5e\x88\x15\xad\x45\xd0\xc2\x8f\xa3\x52\x44\xb7\x12\xca\x58\x8e\x9e\x84\xbb\xc6\xb8\x90\x7d\xb1\x4b\xb2\x37\x4b\x20\xc6\xde\x14\x4d\x89\xaf\x00\xbc\xa4\x32\x46\x7c\x2a\xd5\xc7\xcb\xd3\x31\xec\xd6\x74\x68\xc3\x69\x7f\x0e\x60\xb1\x00\x80\x1a\x49\xbf\x2c\x3b\x98\x1f\x62\xdb\xc7\x58\x43\xc7\x31\x08\x9e\x50\x7e\xa7\x80\xe3\x77\x51\x95\x4b\xa2\x2d\x29\x8c\x81\xfe\xb2\x73\x94\x75\x31\x39\x19\x34\x65\xe5\x6f\x93\x6a\x97\x33\x2f\x97\x5c\xd6\x7c\xbb\xb9\x56\x9d\x25\x19\x6b\x9a\xf6\xf9\x3b\xc1\x85\x39\x75\x72\xcf\x08\x02\xec\x75\xca\xb4\xb1\xa4\x90\x08\x65\x41\x16\x92\xb1\x57\x0e\xd7\x85\x96\x94\x9f\xc3\x4c\x38\x86\x1a\x58\xaa\x8c\x9f\x4b\x4a\x31\x1e\xe8\x1b\x64\xb5\xd1\x90\x12\x78\x91\xd8\x63\x60\xf1\x9c\xce\xa1\xcb\xaa\xfd\xfd\x96\xdf\x28\x99\xdc\x1d\x98\x65\xcf\x3a\x68\x1e\x34\x4d\xd8\x20\xc1\xef\x49\xef\x75\xdc\xf2\x60\xb2\x4c\xb6\xf4\x84\xf5\xc4\xb7\x60\x73\xe2\x12\x91\xa0\x21\x93\xc5\xd5\x5d\x91\x22\x9e\xad\xe5\x71\xd5\xbf\xe2\xbb\xb1\x16\x33\x58\xd0\xf8\xdb\xfe\xfe\x25\xe3\x8a\x51\xf7\xb9\x56\x67\x66\x39\xc0\xea\x3c\x7c\xa8\xbe\x60\x2f\x72\xa8\x17\xfd\x8d\x41\xf8\x55\x02\x8d\x95\xab\xfe\x60\x72\x79\x7a\x69\xba\x3e\x48\x16\x02\x6b\x6a\x6c\x84\x95\x0f\x5f\x0d\x28\x51\x63\x25\x6a\x91\x55\xe7\xda\xe9\x6a\xe3\xaf\x6c\x0f\x85\xf5\xe9\xec\xcc\x78\xfc\xdf\x16\x33\x45\x90\x37\x32\xb9\x1d\xf4\xfb\xd8\xfa\xdd\x55\x2b\x8e\x9e\xe2\xd6\xa1\x2f\xb9\x95\x1b\x85\x43\x1a\x51\x06\x5c\xb2\x74\xf2\x4e\xf1\x93\xdd\x4d\x76\x3d\xbe\x29\x1e\x3f\xbe\x8f\x3c\x62\xcb\x7b\x84\xcb\x16\x6a\xff\xb8\x70\x1d\x05\xcc\x9a\xe5\x03\x0d\x39\xc7\x6a\x0e\x92\xca\xa0\x5f\x63\xfd\xe2\xaa\xd7\x99\x06\xe1\x92\xeb\x6c\x11\x65\xa5\xca\xb7\x18\x05\xc7\x2c\xe5\xfd\x3b\x50\x3f\x50\x69\x3b\x84\xf5\x1a\x79\x4b\xe5\xb3\xb8\x12\x74\x27\x4f\x4f\x19\x4f\xc0\x8d\x2d\x11\x06\x5d\xce\x4c\x70\x6c\xd0\xb6\xba\x3d\xd4\xd2\x19\xaa\x50\xca\xeb\x93\xca\x0c\x56\xeb\xa0\x97\x14\xb2\x13\x2e\xec\x1a\xdf\xb7\x4b\x0b\x22\x4b\x8b\xad\xd1\x3a\xa1\x18\x0c\xb2\x97\x0f\x9a\xa4\x74\xc1\x2e\x3d\x53\x71\x2c\x44\x81\xcc\x75\x41\xbc\xf5\xb5\x43\xa8\x02\x7d\x61\x2e\xdc\x91\x30\x37\xf1\x48\xdd\xbd\x23\xbe\x7a\xe1\x4a\x85\xde\x39\x0d\x5a\x46\x57\x89\xd0\x9c\x4c\x38\x48\xac\xac\x81\x3d\x62\xab\xa8\x4e\xc3\xd2\x76\x81\x81\x3d\x2d\xab\x82\x4e\xc3\x0a\x76\x01\xb2\xa5\x21\xf4\x60\x95\xa6\x04\x2c\xa9\x73\x58\x86\x3e\x55\xea\xb3\x0d\x87\x44\x75\xc7\xf2\x0c\x9d\x34\x4d\x79\x87\x0b\xdb\xb1\xf2\x74\x58\xc3\x19\xea\x7b\x01\xce\x15\x67\xa0\xeb\x1f\x5a\x6c\x1e\xd0\x1c\xd3\x96\x52\x9c\xb6\xe0\xc7\xa8\x25\xb0\x84\xb0\xe5\xa5\xd9\xf2\x52\x6d\x79\x8e\x22\xf3\xd3\xf2\x0c\xf5\x89\xc8\xb5\x9b\xb5\xe9\x53\x7b\xd3\x1b\xf2\xbb\x96\xf6\xa7\x03\x03\x00\x2b\x9c\xd9\x62\x20\x15\x2f\xf3\xd3\xd5\x19\x37\x7a\x01\xd8\xd7\x81\x88\xd5\xd9\xa4\x48\x2e\xd8\x2b\x31\xd0\xb6\xcf\x7a\xd1\x81\x8e\x5f\x25\x2a\x0c\x11\x54\x91\xcf\x35\x0f\x46\x0a\xa6\x41\x2d\x48\xb0\x86\x04\x8d\xc2\x90\xb0\x1e\xf1\x37\x07\x89\x9b\x87\xb7\xad\xdc\x11\x53\x50\xee\x95\x95\x23\x6d\x24\xe6\x6a\xb3\xc8\x63\x5e\x35\xd0\xcd\xd2\x3e\xcd\x79\x9f\x30\x51\xef\xd3\x7c\xeb\x3e\x61\xd5\x43\x66\xbc\x60\x77\xe6\x8e\x56\x9e\xa1\x67\xe0\x34\xca\x37\xdb\xaf\xd9\x55\x0d\xf4\x80\xc4\x0c\xb0\x65\x35\x07\xae\x37\x9b\x91\x85\x4e\x60\xc9\xa3\xbd\x36\x5a\xda\x7b\x63\x91\xc2\x56\xa7\x4f\x0b\xb5\xd5\x29\xea\x64\x5f\xf4\x51\x2d\xb6\xc0\xa3\x99\x23\x31\xf2\xfe\x82\xbc\xa5\xe6\x68\xa5\x72\x5e\x65\xe9\xd7\xcd\x5e\x8e\x46\x00\x72\x5d\xca\xb3\x67\x23\xa4\x66\xd0\xbf\x1e\xfa\x74\xd6\x68\xc5\x52\x6d\xf3\x9f\xfd\xd7\xc9\x78\x78\x84\x22\xac\x36\xe9\x88\x81\x13\xf0\x14\x28\xa7\x0a\xe2\xcd\xbb\x4f\xaf\x3e\x9e\x7c\x79\xfb\xfc\xe3\x5f\x3e\x7f\x68\xe5\xbe\x7d\xff\xcf\xaf\xbe\xbc\xfa\x97\x37\x9f\x28\xe0\x7e\x84\x8a\x7b\x91\xf8\xf8\x8a\x92\xdf\xbd\x7f\xf9\x0a\xbd\xef\x73\xe2\xc9\xab\x7f\x39\xf9\xf2\xe2\xfd\xbb\x93\x57\xef\x4e\xb8\x19\x8b\x48\x8b\x44\xc0\xc5\x8d\x24\x70\x7a\xa9\xf2\xe9\x17\x85\xfc\xc7\x48\xf7\x30\x76\xa9\x96\xff\x16\xd5\x12\xf9\xde\xa9\xa3\xa0\x7f\x15\x7f\x66\x3b\xf9\x20\x89\x64\x68\x68\x76\xd3\x13\x90\x69\xc5\xa5\x08\x08\x11\xe2\x5c\x38\xac\x2f\x5c\x1a\x36\x83\x19\x17\x01\xc7\x1b\xa1\x40\x42\x4f\x76\x76\x75\x21\x09\x4c\x0e\x9d\xe5\x99\x30\xda\xc1\xb3\x4c\x78\x1f\xa3\xa4\x76\x0d\x10\x8f\x4e\x99\xab\xec\x82\x9d\xe2\xe7\x49\x3b\x88\xa9\xc8\x95\x2f\x08\x62\xba\x59\xf1\x09\x2a\xaa\xd8\xa1\x50\xd9\x0b\x96\x5a\xe9\x10\xb4\x1c\x48\xd4\x89\xb9\x9a\x6f\x26\x96\xeb\xb9\xe4\xfa\x4b\x5e\xdb\x6a\x38\xe4\x1c\x5a\xbd\xa6\xaa\x90\xa5\xce\xa0\xa4\x27\xcd\x1a\x35\x52\x36\xd2\xb3\x20\xec\x11\x69\x96\xdb\x4e\x70\x17\xc9\xb7\x32\x9f\xf5\xa4\x26\x7a\x76\x21\xfd\xd4\xe2\x4f\x59\x0b\x33\x60\x22\x9c\x81\x9a\x6b\xf8\x45\xc7\xba\x66\xff\xc6\x2d\xe7\xc6\xf5\x60\x7f\x7f\xaf\x0c\xa5\xf6\xd7\xa7\xf5\x59\xd2\xc0\x7f\x7c\xf1\xac\x5a\xbc\xf6\xe1\x11\x0e\x6f\x9c\xa0\x6b\xcf\xb5\x56\xb9\x4b\x52\x4d\xa0\xae\x9e\x8d\x0d\x12\xb9\x48\x58\xdd\x6e\x85\xef\x98\xa3\xc9\xea\xd9\x7c\x32\x07\x1c\x72\x71\x3a\x3f\x33\x2d\x9f\xce\x0f\x8e\xce\x26\x56\x63\x17\xe4\xb7\x98\x5c\x40\x5a\x21\xe4\x94\x51\xb2\x9b\x6a\x26\x3a\x1b\x84\x74\x88\x71\x42\x6a\x5e\x33\x9a\x97\x65\x45\x88\xf7\xdb\x14\x98\xa1\xca\x10\x19\xfa\xd7\x7a\x60\x76\x50\xaa\x3f\x26\x21\x19\x9c\xb3\xc7\x56\xc0\xbc\xcc\x12\xc2\x29\x98\xa3\x16\x51\x13\xff\x39\xba\xe2\xa7\x93\xc9\xf1\xf2\x42\x3e\x7e\xe4\x00\x99\x38\xcb\x70\x53\x45\x46\xdb\xae\x63\xd8\x66\x1a\x38\x85\x1d\x6b\x10\x3a\x71\x63\x35\x06\xc6\xbd\xd7\xdf\xc3\x18\xc7\xd0\x82\x0b\xb8\x66\xd0\x9b\xb6\xd3\x44\xe7\x90\xde\x16\xdf\xce\x57\x2d\xbb\x83\xc3\x11\xa9\x18\x69\x22\x9e\x49\xf3\x14\xbe\x55\x3a\xe2\xb3\xf3\x31\x69\x99\xb9\xc2\x0c\x6b\x28\x4b\x6a\x91\xcc\x05\x2a\x4f\x9d\xb4\xa4\x18\x99\xa2\x55\x02\x55\xa6\xf2\x3e\xe0\x4e\x98\xda\x17\x28\xf4\x45\xcd\x45\xfc\x82\x94\x75\x8f\x00\x95\xdc\xe1\x2a\x73\x56\x8e\x1c\xd7\x9b\xa7\xdf\xd0\xca\x74\x5d\xe4\xff\x58\x67\x3d\x0c\xc2\x14\x91\x59\xea\xf0\x17\xf2\x72\xec\x1b\x96\x92\x2e\x97\x0a\x7b\xb0\xbf\xaf\xbb\x2c\xe0\x5c\xc0\xb2\xb8\x5d\x47\x24\xe7\xe8\x71\xec\x87\xda\xe9\xb1\x28\x8b\x43\x59\xa7\x87\xb7\x7f\xaf\x2e\x7b\x25\xbe\xc8\xa2\xdb\xb6\xbc\x86\x21\x64\x35\xbe\xa5\xcd\x86\x91\x17\x89\x21\x67\xb7\xf0\x26\xc6\x33\xaa\xec\xa7\x2e\x11\x2e\x6a\x74\x91\x9b\x02\xa2\x9a\x63\x6c\x4d\xa4\xd0\x5a\x1e\x8d\x6b\x20\x00\xe8\x88\xa1\x93\xfc\x83\x24\x3f\x8e\x7a\xe4\x2d\xa3\xd7\xcc\xf5\x23\xc4\x92\xa2\x66\xf6\xe0\x4c\x46\x07\x39\x86\xd6\x8c\xdb\x85\xac\x67\x13\x60\xaf\xa5\xe3\xb9\xa7\xd1\x41\x7a\x10\x3d\x1b\x2a\x3f\xe5\x84\x23\x2b\x79\x08\xf6\xf7\xd5\x2f\xf4\x36\xac\x40\x86\xfc\x0c\x57\xb7\x30\x9d\x38\xd2\xa8\xf7\xa6\xe9\x7d\x4f\x61\x8d\x50\x5b\x69\x06\x9b\xc7\x9b\x8b\xa2\x1f\xf6\x6f\x3e\x44\x77\x40\x58\xf0\x53\x96\xf5\xe6\x4d\xb3\x8a\xef\xdd\xbb\x38\x1f\x2e\xb3\x7b\xb4\x59\x87\x72\x83\x0e\x69\xe1\x01\x19\xf5\x96\x00\x4b\x00\x1c\xc4\x56\xd2\x63\x59\x24\x00\x9b\x09\x43\x8f\xc6\xb5\x51\xae\xa5\x23\x13\x4f\x37\x46\xba\x8b\xed\xf5\x9b\xc1\xc6\xa6\xf3\xd4\x91\x28\x30\x02\x6f\x14\x4d\x66\xed\xa8\xa8\x00\xc8\x33\x0e\x9b\x21\x2e\x14\x1c\x31\xac\x7c\x59\xa6\xab\x2f\x0a\xb7\x46\x36\x10\xd6\xda\xac\xc3\xb3\xb6\x1e\x0c\xb6\x38\xed\x92\x90\x42\x9c\xe8\xd4\x8f\x0a\x9b\x03\x1c\x57\xfd\x1c\x65\x4f\xea\x42\x68\x95\x81\xe6\x83\x67\x4e\x5f\x21\x70\xd0\xdb\x31\x4e\x06\xd7\xb0\x0e\x9a\x5a\xad\xd9\x4f\x77\xd9\xaf\x45\x06\x70\x27\x9c\x05\x5b\x1b\xa9\xf6\x5d\x5c\xfd\x53\x14\x45\x76\xf8\xdf\x47\xf7\xe0\x19\x34\xb0\x99\xa2\x2c\xb8\x9f\x22\x7d\x9b\x6e\x72\xfd\xd6\x05\x23\x22\x13\x74\xb8\x48\xfb\x39\x00\x43\x5d\x03\x8d\x8a\x7d\x2c\xf1\x16\x5d\x9e\xea\x34\x77\x47\x2e\xd2\x7c\x91\xcd\xbe\xcc\x32\xd6\x05\x2b\xab\x2f\x38\xbd\x2f\xe4\x01\x25\x12\xd7\xb2\x4e\xac\x6b\xe3\x2b\x99\xe4\x00\x6f\xb3\x80\x6e\x07\xda\x74\xed\xa1\x3d\x32\x4a\xaa\x1e\xb5\xe2\x76\xb4\x6d\x00\xae\x5b\x78\x90\xa5\xda\x1d\x98\x0a\x32\xd1\xd3\x1c\x52\x35\xd2\xbb\xd1\xbd\x7f\xfd\xfb\xec\xe0\xbf\xde\x13\x97\xc9\xb5\x73\x59\x06\x9e\xb4\xa6\xde\x75\x6a\x49\xc7\x34\xb9\xa0\xb5\xcc\x2d\x69\x61\x63\xc2\xc8\x26\x47\x00\xb0\xad\x17\x02\x04\xdc\xda\x7a\x18\x28\xce\x04\xc7\xbd\xc9\xb4\xb4\xc6\x46\x0d\x13\xb6\xf2\x27\xd3\xed\xfd\xfd\x35\xfa\xf1\x37\x09\x42\xf9\x9b\x5f\xd0\x5f\xd4\xc3\x97\xd7\xb0\x53\xde\x4e\x13\x26\x3c\x34\xd4\x52\x81\xa2\x0d\x2f\x24\x1c\x3a\x23\xb0\x30\x97\x77\xa3\x33\x6c\xfa\xfc\xd2\xbe\xbc\xef\x12\x88\xb6\x3b\x74\x6b\x47\xfc\x54\xff\xca\xdf\xee\xce\xc4\xb9\xf2\xb5\x67\xb7\x14\xc3\x0c\x0f\x3c\xf1\xd8\x94\x31\x9b\x27\x89\x92\x8c\x15\x66\x7a\x91\x82\x94\xfc\x03\x73\x48\xba\xe4\x68\x4e\x98\xf3\xb3\x6e\xdb\xc0\x4c\x11\x66\x17\x4a\xc7\xca\x55\xe2\x74\xf6\x25\xd5\x86\x2f\x26\x2c\xe9\x66\x83\x2a\xdd\x9d\x21\xb8\x99\xd9\xf2\xda\x2c\xac\x10\xc5\x0b\x91\xd7\x7e\x9d\x5c\x74\xb5\x56\x05\xf4\xb6\x43\x9b\xd9\xf2\x33\xf3\x64\x97\xa8\xb5\xd7\x14\x21\x3b\x6e\xbf\x1d\xf7\xb2\x4d\x20\xdc\xeb\x93\xdd\xad\x8e\xa1\x21\x15\x25\x8a\xf4\x77\xc8\xf6\x54\x7b\x78\xa4\x24\x19\x4c\xca\x56\x20\x75\x35\xae\x89\x11\xbc\x66\x0b\x91\x13\xe9\x94\xcf\x7d\x4c\x24\x8e\x8f\x8d\x02\x2b\xb4\xc5\xab\x94\x96\x53\xad\xb3\x27\x05\x80\x9b\x33\x99\xd2\x72\xd9\x67\xfa\x8a\x1f\xe1\xaa\x8d\x47\x77\x89\x68\xcb\xc7\xd6\xf8\xdb\x12\x45\x42\x2f\xdc\x46\x9d\xe9\xe5\x6b\xa0\x31\xf8\xb1\x02\xee\x7b\x60\x79\x17\x9d\x21\xba\xd0\x2c\x93\xdb\x7a\x9d\x57\x75\xa3\xde\xed\xfa\x95\x09\x2e\xd2\x22\x7c\x99\xd9\xb5\xfc\x15\x2a\xa6\xb7\x20\xbd\x6d\x9a\xa2\x62\x7e\xe9\x2d\x1f\x60\xb8\x4e\x4e\xcf\xba\xc4\xbd\xa1\xfe\xe7\x40\x3c\x5b\xcd\x0d\x80\x0a\x61\x2b\x50\xb4\x5c\x9d\x54\x13\xb8\xe7\x75\xd3\x52\xee\x45\xf6\xe1\x7d\x2b\xee\x77\x99\x8c\xc8\xab\x8a\x29\x28\x51\x76\xfe\xac\x64\xd9\x62\x63\xe7\x62\x34\x1e\xde\x55\xed\x2b\x8d\x69\xa2\xa5\xb2\x6e\x52\xe0\x80\xac\x93\x35\x7d\xe4\xb9\x85\x3b\xdc\x8d\x87\x36\xa4\x91\xbb\x34\x72\x1d\x4c\x32\xa4\xc3\xb8\x33\x03\x82\x96\xbe\xe9\x4e\x86\x99\x1f\x4a\xa0\xea\x66\xa4\x0d\xef\x19\xed\xb5\x55\x51\xff\x28\x17\x84\x88\x65\xc8\xb5\x24\x39\x45\x30\xaa\xc1\xf0\xf1\xb9\x38\x2f\x91\x4d\x9e\x7d\x9a\x56\xe5\x62\xf1\x41\x6a\x79\x62\xdc\x8c\x7e\x65\x59\xb7\x00\x16\x53\x34\x73\xdb\x9d\xa6\x0d\x55\x6c\x46\xe2\x03\x96\x49\xf5\xf7\x35\x19\x21\x7d\xb0\x46\x43\x57\x5c\x1a\xb8\x2f\x4e\x4a\xb8\x2f\xd7\xc3\xe6\x7b\xf9\x5c\xde\xcf\xb4\x66\x95\xb2\xe6\xbe\xfe\xc2\x3a\x61\x14\xc5\xcb\xdb\x64\x0e\x24\xf1\xd7\x37\xef\x5e\xbe\xff\xeb\x97\x3f\x3f\x7f\xf7\xf2\xb7\x57\xb1\x65\xcc\x7a\xcc\x5b\xc9\xa5\xea\xac\xf9\x73\x17\xc2\x18\x5c\xb7\xe0\x27\xc9\x36\x82\xec\x74\xb9\x6f\xaf\xac\x1c\x12\x7a\xe1\x00\x86\xbb\x6e\x95\xd2\xd8\xd2\x94\xdd\x08\xdf\xa3\x68\x87\x65\x0f\xc5\x1c\xaa\x14\x6d\x93\xca\xa8\x69\xe4\xff\x79\x49\x54\x0a\xd2\xa4\xd4\x80\x43\x07\x0c\xb8\x03\x19\x1f\xf2\x4e\x3d\x4c\xb9\xce\x2e\x5d\xc8\xbb\x9f\xc1\x87\xad\x1d\x43\x62\x11\x87\x40\xd1\x53\x90\xd8\x01\xc3\xe3\x96\x18\xee\x16\xf0\x5e\x2b\x0f\x98\xd5\xfc\xdf\x31\x68\xec\x80\xb5\x23\xf4\x48\xbc\xe0\x24\xf8\xca\xaa\xd7\x56\x09\x4d\x38\x2a\x21\x1d\x39\x2a\x45\x34\xfd\x6a\xe8\x1a\x54\xf5\x4b\x62\x82\x75\xa4\xf4\x0a\x08\x09\x0c\x1a\x88\xa6\x50\xce\x75\xb0\xb4\xae\x03\xa3\x1c\xfb\xf0\xc9\x6d\x8a\xcc\x41\xeb\x29\x1b\x11\xc4\xbf\x8e\x7e\x46\x91\x36\x68\x80\xe5\x1d\xf6\x78\xfc\x68\x2c\xb6\x9f\x75\x28\xf2\x88\x2e\xb4\x9d\x03\xba\xba\xca\xab\xdd\x37\x72\xc0\x54\xe1\xce\x5e\x87\x1d\xf2\x28\xec\x41\xca\x8b\x9a\x68\xdb\x47\x7b\x56\x49\x1e\xca\x95\x4a\xb3\x36\x9e\xb5\xb5\xf7\xbb\x70\xed\xb5\x21\xd7\x4a\xa3\x05\x2b\xda\x73\x01\xce\xcd\x64\x5b\x8b\x16\x17\x56\xba\x47\x00\xa6\x76\x96\xb3\xa4\x71\xe5\x67\xc9\x39\xc7\x96\x2e\xae\xf0\x66\x1c\xaf\xad\x3c\x9c\x6f\x3c\xb5\x12\x8c\x51\xcf\xc2\x4a\x55\x86\x86\x2b\x93\x66\x1f\x83\x8b\xce\x37\xf8\x36\xa1\xf4\x3b\x03\x9b\xdc\x62\xf5\xea\x01\x47\xfc\xc4\x64\xf9\x1b\x0f\x67\xe6\x49\xf8\xcd\xbf\xa5\x51\x3e\x7e\xdc\xe5\x4b\x67\x3c\xba\x4b\x88\x57\x45\x8b\xf5\xb5\x07\x05\xf5\x43\x52\xe4\x18\xa1\xcc\x37\x8c\xd5\x3a\xfe\x6c\xab\x22\xcf\xd0\x94\x09\x40\xf2\xf4\x62\x4e\x90\x76\xfe\x62\xce\x0c\x1c\xf3\xe7\x53\xba\x77\x2d\x6f\xdd\x40\x18\xd7\xba\x51\xb8\x0f\xd2\xf3\x7c\x91\x7b\x81\xd0\x0c\x39\xbf\xbf\xdf\x8f\xde\xbc\xfb\xf0\xf9\x84\x74\xba\xc8\x25\x05\xf2\xc0\xfb\xfb\x1c\x77\x9a\x12\x91\x26\x00\x32\x0b\x1f\xc9\x9e\x7f\x7c\xf5\xdc\x2d\x09\x19\xe8\xbe\x8f\x13\xa7\xfc\x62\xf6\x6a\x96\x93\x92\x24\xeb\xb4\xea\xc1\xbc\x31\x72\xb1\xb6\x39\x39\x0a\x78\xa4\x7e\x2a\xcd\x34\x23\x91\x51\x9c\x09\xed\x88\x82\x5c\x63\xc4\x14\x7c\x38\x38\x3f\x98\xd6\x71\xed\xba\x20\xc9\x06\xc6\x33\x31\xc9\x9c\x74\x56\xc8\xcd\x16\x7b\x2c\x19\x5a\xdd\xe3\x8e\x0c\xdd\x01\x4c\x1a\xf4\xa5\xb5\xbf\x8f\x74\x2c\xba\xca\xeb\x1e\x0e\xe6\xb3\xd3\x32\x3d\x1e\x72\x5a\x93\x43\x8e\xb7\x32\xed\xd1\x90\x8e\x9e\xee\x99\x9d\xb7\x90\xd4\xab\x49\xa4\x3b\x1b\x6b\x60\x94\x4d\x9e\x6d\xac\xc4\x57\xc5\x6c\xa3\xa5\x6a\x6d\xb7\x1e\xb0\xc3\x81\x7d\x57\x57\xe9\x6d\x0e\x70\x26\x85\xd4\x39\x53\x72\xbd\x41\xc2\xde\x12\xf4\xf0\x0e\x8b\x0e\xff\x34\x87\xd2\x4b\x81\x24\x09\x07\x34\x6e\x59\xda\x77\x4a\xe3\x97\xdd\x48\xc9\x62\xc3\x77\xbd\x74\x41\xd2\xb7\xc4\x20\x37\x37\xb2\xff\x11\xb5\x0b\xf4\xa6\xa8\xc3\x0b\x6d\xc5\x38\x93\xbe\x68\x4a\xf6\xb8\x43\x4b\x1f\x78\x4d\x2a\x61\x7a\x65\x02\xec\x58\x70\x5f\xfc\xed\x48\x0a\xe1\x6e\x86\xf1\x7d\x53\x0a\x6f\x5a\x3f\xb9\x4d\xc8\x39\xf1\xae\xa0\x49\x90\xda\x99\x5c\xfb\x3f\xea\xef\x8d\x00\xda\xba\xdd\x04\xe5\xc1\x35\x2f\x0f\x29\x4b\x3b\x02\x62\x55\xb1\x61\x6d\x2d\x37\x49\x5c\x3b\x1c\xab\x3a\x28\x2d\x7e\x4c\x68\xd8\x41\x68\xf1\x98\x9d\x2a\x18\x7c\x16\x8f\x1f\x3e\x14\x21\x74\x06\x19\xbf\x12\x22\xfe\x09\xb3\x9d\x8b\x83\xcc\xf8\x97\xba\xff\xa8\xed\x03\xd5\x72\xff\x9d\x56\xcf\x1b\x60\xf7\x60\x89\x2f\x6e\x6e\x1a\x5a\x69\xde\x19\x8f\x1f\x56\x91\x3b\x59\x4d\x56\xd7\x1c\x51\x4d\x7a\xa0\xe2\x84\x4c\x2b\xe5\x0d\x00\x59\x5c\xb4\x74\x6a\x64\xd7\xfc\xae\xab\xf4\x28\x32\x92\x9e\xc3\x31\xd6\xc0\xee\x2a\x7b\xa8\xf1\x1e\x03\x58\xad\xcf\x61\xee\xfd\x11\x96\x4d\x6b\xbe\xca\xa0\x85\x8b\xc1\x20\x8e\xa2\x90\x88\x7f\xd5\x2f\xa9\xfd\x92\x82\xcc\xac\xfa\x3c\x0e\xf4\x76\x62\xc9\x51\x33\x4b\x8e\xaa\x06\x71\x80\x9e\xd6\x8a\x49\xfa\x54\x39\x4b\xd9\xdf\xdf\xc3\x41\xa6\x03\xd2\x07\x31\xd2\x47\x3d\xa4\x74\xe0\xc9\xe2\xd5\x29\xd3\xe0\xaf\xda\x16\x8d\x86\x7f\xa5\x57\x32\x50\x2b\x6c\xf9\x0b\x1c\x91\x22\x4a\xf1\x2c\x49\x95\x0a\x0a\x6e\x60\x2a\x57\x2b\x1d\x0c\x72\xeb\x01\x5a\x6f\x41\x8a\x2b\xdf\x98\xaf\x01\x69\xa7\xc8\x38\xba\xd6\x0a\xe6\x46\xd9\x15\xd6\xa8\x46\x37\xc6\x66\xfc\x53\x4b\x85\x60\x2d\x2d\x06\xa2\x08\x7d\xc5\xd0\xdf\x15\x07\x68\x1d\xc8\xa7\xa9\x1c\x37\x6f\x30\x59\xf5\xa7\x37\x37\x72\x81\xf5\x34\x16\xe4\x6a\x7b\x7a\x9c\xc6\x35\xf2\xe9\x93\xc9\x3c\xb9\x40\xfd\x66\xf9\xfc\xb0\xa4\x28\xec\xfb\xfb\x73\x86\xac\x35\xff\x82\x5e\xfa\xcb\xa4\x80\x72\x53\x01\x57\x86\x40\xef\xdb\x7b\xe3\x9b\x1b\xca\x93\x13\x5a\xf5\x17\x07\x07\x4f\x67\xf2\xa5\xe0\x16\xda\xd6\x96\x75\x5e\x24\xd1\x30\x42\x7f\x6b\x6a\x37\x66\x09\x1a\xfe\x2d\x95\x9c\xde\x92\x55\x05\x18\x5b\x74\xff\x16\xb2\x0b\xef\x93\x53\x4b\x93\x61\x57\x76\x4e\xdd\x41\x43\x37\x60\x50\x22\xe6\xdc\x86\x4a\x1b\xa0\x75\xd6\x78\xd8\xa8\x70\xc0\xd7\x77\xa6\x4f\xd2\x85\x18\x1b\xc8\x7c\x76\x38\xb6\x4f\x4c\x33\x88\xb5\x22\x26\x7b\x3b\x05\xb6\xf9\x5b\x56\xd5\x80\x07\x95\xe5\x6a\xcb\x40\xc2\x3c\x91\x32\x44\x4f\x30\xc6\x22\x8c\x0a\xe1\x23\xa7\x02\x7b\x63\x41\xc8\x96\xd5\x9c\xa7\xf8\x08\x26\xf0\x19\x69\x6f\x04\x59\x03\xd3\xc9\xc9\xf7\xf2\xc3\x3c\xad\xdb\xb6\x0f\x78\x77\x4e\xfb\x00\x54\xdc\x25\xd7\x13\xd8\x41\x14\x71\x0a\xf5\x60\x35\xf5\x5c\xc9\x56\x5a\x6d\xb5\xda\xd9\x88\x2f\x4a\x7c\x07\x34\x32\x30\xf1\xaa\x2e\xac\xf5\x9a\xf2\xde\xc1\x05\xf2\x32\xab\xa7\x70\xfd\xa5\x24\x5f\xae\x45\x5e\x9b\x52\xef\x2f\xe2\x5c\x7c\x7a\xf5\xe1\xf9\xc7\xe7\x27\xef\x3f\xc6\x17\x01\x3e\xb9\x83\xb0\x6e\xc9\x9f\xc7\xa3\xed\xd1\xd9\x5c\x17\x95\xb4\xff\x91\x4a\xb3\xbc\xc3\x99\x47\xca\xee\xc7\xbd\x62\xa0\x44\x1e\x8d\x0c\x55\x1b\x68\x49\x5b\xbf\x54\x2c\xb6\x68\xcc\xa1\xcd\xa5\x0e\x9f\xdf\x2e\xbe\x73\xf6\xcb\xd3\x1c\xb5\x0d\xd1\xc8\x04\x5f\x43\x93\x92\x2f\x4a\xfa\x5d\x6d\x24\xa5\xdf\xef\x7c\x82\xf3\xcf\xa3\xd1\x6d\x6a\xbd\xca\xf9\x4f\x72\xa4\xe4\x74\xbd\x01\xb4\x78\xbd\x99\xa4\xc3\xef\x28\xf6\xb9\x45\x53\x45\xa7\xe8\x13\x68\x56\x62\x4f\xaf\x29\x3a\x8a\x41\x27\x85\x52\x2b\xe4\x5d\x59\xfc\x96\x5d\xa6\xd3\x2b\xd9\x2e\x66\xb3\xe7\x2f\x53\xa6\xb3\xc0\xc6\xd2\x25\xb1\xc7\xd8\xad\x95\x62\x8f\xd1\xd9\x2a\x33\x40\x7d\x53\x75\xbc\x0d\x12\x3c\x98\x3b\xa9\x6b\x1e\xfd\x22\xd9\x62\x01\xa1\xdb\x13\x70\xa0\x8b\xd3\xd1\x59\xd2\x28\x35\x1c\xab\x57\x80\xad\xae\x55\x80\x45\xf8\x82\xfe\xe6\xa6\x5f\x95\x17\x1c\x36\x02\xc1\x7e\xbe\x2c\x4b\x0c\x77\xc1\x10\x81\xd2\xa0\x17\x46\x3d\x21\x41\x73\x90\x3f\x6a\x64\x9c\x40\x32\xb8\x9d\x5a\x1c\x03\x6a\x69\x6d\x59\x08\xa0\xaa\xd0\x21\xca\x54\xec\x8e\xf6\x4d\xd1\xb1\x57\xba\xb3\x82\x48\x1e\x76\xba\x1d\x5e\x50\x54\xbe\x73\xcd\xe5\x70\x7c\x68\x11\xe3\xef\x6c\x12\xe2\x70\xbb\xc0\x20\xc9\x45\x86\x0d\x49\x05\x85\xee\x26\x42\xf3\xc5\x0b\x28\x38\xd6\x04\x9f\x91\x74\xa3\xb4\xc5\xa1\x51\xf9\xdd\xe2\xfb\x21\x54\x03\xb8\xe1\xe6\x5e\xc0\xee\xfc\x95\x8f\xfc\x2b\x25\x6c\x1e\x59\x4a\x59\xe9\x2d\xef\xba\x6d\x6f\x5f\xbb\x3d\xdb\x8e\x47\x3b\x6b\x6d\xa6\xb3\x45\x56\xdd\x3f\x22\x91\xe0\xf5\x8b\x3f\xbf\x7a\xf1\x97\x4f\x9f\xdf\x92\xb5\x23\x19\x3a\xc6\xd1\x2c\x6d\xd2\x43\xd6\x93\x21\x1d\x87\x7a\xbd\x8c\x44\x3a\x9b\xbd\x90\x1f\x27\x25\x2b\xab\x06\x58\xf1\xc2\x62\xe9\x50\xef\x8d\xb4\xe5\xfa\xd1\xb3\x48\x44\xbd\xe8\xa0\x1a\xb6\xbb\x3b\xf8\x25\x89\x7e\x39\x68\x0e\x7e\x89\x9e\xfd\x82\x24\x48\x5a\x7c\xcc\x60\xe0\xad\x1e\x14\x3d\x5a\xb2\xfb\x5d\x13\x92\x3b\xd4\xe8\x60\x52\x62\xd8\x65\xe0\x74\x6b\xd4\x41\x46\xe3\xa8\x91\x72\x47\x6c\x0f\x31\xa7\x6d\xb7\x2f\xc5\x8a\xf7\x47\xad\x11\xf0\x3c\x63\x5a\xdd\x9d\x15\xe1\xf4\x52\xbc\xb2\xb9\xdb\xfd\xfd\x37\xfa\xe1\x2b\xe8\xa4\x19\xc9\x7c\x72\xc4\x8d\x17\xe2\xdb\x40\x84\x49\x45\x8c\x9f\x36\x67\x93\x82\xa9\x98\xfe\x79\x7f\xaf\xa6\x28\x81\x03\x81\xe9\x89\x72\xad\xcd\x1f\x93\x0e\x5b\x10\x5b\x31\xcf\x5e\x49\xff\xbb\xff\x9d\xde\xe8\xc2\xde\x76\x79\xc0\x05\x93\x4d\xf2\x4d\xff\x2d\x29\x68\x20\xc3\x69\xb5\x81\xaf\x05\x3c\x9e\x30\x5b\xd4\x9a\x2b\xb2\x3b\x75\xff\xed\x69\x86\xca\x1e\x40\x48\xe3\xaf\xe4\x8d\x79\x65\x45\x52\x93\x02\x99\x66\x34\x6d\x5b\x8d\xc0\xf0\x4d\xd0\xfe\x39\xb1\x4e\x89\xa6\xf3\x0b\xbb\x11\xef\xa9\xb6\x61\xf5\x94\xfd\xfd\x4b\x58\xce\x4c\xc5\xac\xd8\x1b\x49\x82\x73\x6f\xec\xb0\x46\x5a\x89\xc1\xed\x7d\x6a\x76\x13\x33\xac\xbd\xaf\x89\xc1\x38\x46\x65\xc7\xfe\x4b\x18\x4f\x6c\x37\xb8\xc0\x6a\x2f\xf9\xed\x6d\x39\x6c\x11\x89\xa8\xec\xaa\x90\xf4\x4b\xd5\xa6\x2c\xde\x48\x75\xdf\x80\xb4\x3f\xe0\xa4\xc8\x93\xbf\xcf\x6f\x23\x72\x5c\xb5\x0b\xd7\x53\x11\x23\x3b\x23\xbd\x5c\x6e\x7d\x21\xfd\xd6\x16\xe6\x5f\x06\x25\xa6\xd2\x3b\xd1\x2c\x5b\x55\x19\x3a\x69\x9e\x19\xe7\x44\x36\xcf\x21\xfb\x7d\x53\xe8\x6d\x34\xde\x8a\x58\xd7\xab\xc9\x15\x23\x63\x3f\x2a\x9c\xb7\xb9\x29\xe9\xb3\x88\x15\x33\x59\x8e\xdc\xaa\xf6\xb1\xa5\x5d\x35\x6b\x13\x46\xfd\xb9\xab\xec\x33\x40\xcf\x46\xcb\xa1\xa6\xbd\xc5\xf7\x64\xd5\xb6\x2a\x17\x6f\x91\x20\x3c\x49\xc6\xe2\x7d\xf2\x44\x7c\xc0\x8f\x4f\xf8\xdf\x3b\x34\x29\x93\xbb\xfc\x06\x15\xd5\x95\xed\xfe\x9f\xae\x6c\xfe\xee\x83\xe0\x37\xb9\xb7\x7c\x47\x78\xe8\x12\x85\x40\xe2\x0b\x9b\x25\x38\x76\xd3\x9d\x86\xe4\x52\x47\x4a\x81\xd9\x9b\xa1\xd3\x3c\x9c\x0d\x8b\x4c\xd0\xe8\x9d\x94\xa1\x01\xc5\x56\xe8\xcd\x2d\x23\x93\x75\x56\x7d\x09\xf7\x87\x27\x93\xad\x6b\x51\x28\x46\xaf\xd1\x49\x72\x72\x73\xe3\x7c\xbf\x87\xe5\xbb\x18\x66\x05\x1a\x6a\x5a\x8f\x96\x72\x20\xe4\x79\x5c\x1f\x6a\xd3\x9d\x04\x86\xbe\x51\x88\xfe\x80\x54\x7d\x26\x0a\x1a\x55\xc8\x84\x3c\xfe\xe6\xc5\x4e\xe5\xb7\x3b\xd1\x69\x72\xde\x11\x24\xf8\x85\xf4\xcd\x88\xec\xc0\x9b\x61\x7b\x09\x28\x08\xaf\xf6\x73\x3a\x74\x4d\x58\x95\x99\x0c\x2c\x22\x36\x29\xd0\xb7\x9f\xef\x79\x96\x54\x7e\x71\xed\xe6\x01\xcd\x4c\x19\xde\x0c\x66\x0b\x73\x27\x86\x49\x33\xbe\xe5\xf0\x8b\x54\xaf\x95\xe5\x31\xf7\x07\xf0\xb9\x1a\xcd\xc1\x36\x87\x80\x04\xa5\x9d\xd4\xe7\xe4\x4d\x2b\xa0\xff\x73\x8e\xf7\xaa\x15\x2d\x5e\xa1\x2e\x4c\x8d\xd1\xc6\xde\x10\x75\x85\x43\xcf\x66\x12\x56\x51\x3b\x6c\x9d\xd4\x68\xbd\x20\xa6\xbc\x38\xa1\x95\xa5\x19\xae\x6d\x5f\xb0\xd2\x11\xec\x14\xad\xdb\x84\x56\x07\x26\x2d\x7c\x47\xed\xb8\xe3\xb9\xfc\x23\xb3\xfc\x7a\x92\xdc\x2d\x6c\x04\x87\xfd\xe8\x6c\x8e\x6c\x70\xc2\x4d\x6a\x31\x2f\x3e\xdf\xf2\x72\x42\xe9\x19\x30\xac\xaa\x9b\x73\x54\x96\x79\x33\xdc\xd2\xbc\xdc\xc9\x8d\x68\xc1\xed\x2d\xf4\x14\x1d\x1a\x40\x29\x5b\xf4\x91\x80\x12\xc7\xd0\x32\x50\xa8\x25\x0b\xea\x43\xe6\x27\xba\x87\x91\x0c\x0f\x6f\x68\xc7\x00\x80\x4e\xfc\x80\x64\x87\xda\x99\xe3\x7e\x1b\x22\xd4\x30\x50\x89\x52\x45\xe4\xee\x61\x2d\xf5\x1b\xfb\x46\x41\x08\xde\x7d\xad\xee\x55\x6d\x0f\x51\x20\x3f\x9f\xb5\xba\xc2\x98\x88\x0e\xae\xa0\x75\x69\x3d\xdb\xa1\xf3\x35\x14\xb2\x92\x06\xfe\x64\xd0\x48\x0f\xf0\xf4\xd9\xb7\xb2\x60\x27\x3a\xc8\x82\xc0\x72\x6c\x59\x7d\xd2\x16\xfb\x64\xad\x53\x61\x35\xac\x88\x96\x40\x93\xdd\x54\x49\x66\x01\x2f\x96\xd1\x2b\x80\x7d\x13\x49\x81\x4a\x2c\xde\x69\xf3\x65\x70\xe3\x3d\xf5\xfe\x80\xcb\xa5\x28\x9b\xf1\x44\x75\xae\x43\x4b\x2a\x28\x3b\x6e\x1c\x91\xdd\x97\x58\x7a\x73\x72\x94\xc8\x9c\x5e\x8c\xb6\x59\x86\x56\xa2\x8d\x15\xfd\x10\xe9\xc3\x09\x8d\x23\x84\x18\x9a\x81\x51\x05\xc6\x1d\x34\xf5\x5c\x49\x5f\x6b\xf2\xc1\xd7\xa0\x77\x32\x26\xd7\x82\x94\xcb\x58\x28\x4e\xcc\x76\x09\xab\x57\xc9\xdd\x16\xca\x2c\x32\x19\x4f\x2a\x63\x23\x69\x59\x50\xa2\xdc\xfc\xb4\x3a\x38\x38\x9b\xa4\x13\x69\xee\xa5\x97\x29\x1d\x4c\xea\x63\x7c\x67\xa8\x8f\xf3\x24\x8d\x97\x43\x57\xd6\xd6\xc7\x08\x3d\x68\x16\xac\xfa\xc0\x01\x15\xd2\xbd\x89\x35\x08\x60\xf4\x43\xa9\xd0\x73\x3a\x2c\xb2\x1f\xcd\xa7\xfc\x1c\x55\xac\x36\x14\x71\x4c\xbb\x56\xd0\x2e\xb9\xf2\x8d\xf5\x01\x3c\xc0\x78\xe0\x8b\x64\xe3\x82\x0c\x04\x5f\xc6\x15\x3e\xa2\x91\x3e\xaa\xf4\xdc\x1f\xa7\x62\xb5\xae\x2e\x51\x58\xbb\xde\x4c\x14\x52\xd4\x8b\x9b\x5c\x79\xd7\xa0\x97\xaf\x53\x38\x16\xa8\x78\xa3\xdd\x52\x19\x16\xea\xcd\x76\xe3\xff\x5b\x55\x0c\xee\xa2\xed\xbc\x55\x0d\xc7\x25\x52\x21\xeb\x41\x58\xb5\x20\xf8\xca\x65\xd1\xa0\xf1\x98\xfd\x2b\xde\x42\x82\xc6\x63\xd6\x23\xea\xa6\x40\xa1\x44\x07\x93\xbf\x85\xfe\x04\x06\xff\x51\x90\xe1\xdf\x59\x51\x5b\x5e\x61\x33\xe9\x4e\x40\xf9\x1c\x89\x33\x61\x0e\x1c\x2b\xdb\xb1\x93\x81\xa1\x63\x9d\x2b\x2c\x17\x26\x00\xf1\xd4\x46\x33\x38\x1c\x0b\xcb\xd2\x96\x6b\x6b\xcf\x2b\xb2\xb1\x52\x7e\x6c\xfc\x37\xbc\xbb\x8d\xc6\xb1\x06\x76\x46\xc3\xa5\xba\x87\xd1\x84\xc7\x20\xe3\x03\xee\x3e\x02\xcb\xf4\xf8\x67\xfb\x47\x3c\xe6\x9b\x70\xdd\x65\x08\xb6\xa1\xf3\xf6\x31\x34\x9d\xfb\xe0\x8d\x01\x2d\x94\x66\xfa\x75\xb0\xbf\x1e\xfe\x29\x9d\x7e\x85\xd3\x6c\x3b\x16\x1a\xde\xea\xb9\xa7\x3f\x13\x4b\xa0\xfd\xfa\xae\x89\x92\x69\x19\x50\xd4\xd2\x28\x91\x22\x3a\x6d\x05\x0e\x0c\xa8\x7c\xbd\xc5\x20\x64\xd4\x13\x77\x43\xf6\x18\x46\x07\xec\x62\x91\x02\xde\x28\x5e\x68\xfb\x28\xf3\x50\xd6\xcd\xfd\x5d\xec\xc0\xea\xe1\x70\x67\xc8\x7b\x2d\xf1\xbf\x6f\xc9\x35\xf9\x21\x8d\xd9\xa4\x5d\x75\x17\xbc\x7d\x16\x4c\x28\xa1\x23\xad\x64\x34\x91\x8e\x6d\xe4\x7d\xa7\x2a\x26\x85\xfb\x44\x51\x28\x5d\xf7\xe2\x34\x27\xaa\xbd\x15\xff\x31\x1f\xa8\x2b\x68\xd5\x4f\x99\xc1\x98\x60\xe1\x84\xdd\x9d\xad\x13\xdf\x83\xce\x01\xfa\x73\xa8\x3d\xfe\xa2\xbf\x16\x52\x67\x9c\x5d\xe4\xbc\xcc\x56\xcd\xfc\x60\x0c\x97\x99\x4c\x60\x8f\x48\x25\xea\xf3\x23\x3c\x02\xc5\x5d\x1e\x1c\xe8\xa8\xbf\xd5\x46\xda\xb6\x5b\x81\x5d\x1c\x02\x60\x7e\x70\x20\xe9\x89\xbd\x11\xe9\x6e\x4a\xf5\x8c\xe0\x22\xe8\x25\xa8\xa4\x5b\x0c\x7f\xce\x95\x8a\xf4\xf2\x45\x51\x7e\x58\x53\xba\x66\x2f\xd0\x3f\x09\xf0\x24\xff\x59\x05\x16\xb4\xc6\x84\x3b\xd0\xa0\xf3\x49\xa5\x24\x3a\x3f\x3c\x14\x73\x24\x88\x8f\x01\x22\xe3\x14\x61\x54\x4d\xa5\x63\x2f\xd5\x4c\x0a\x35\x13\x39\x10\xa7\x0e\x15\xc5\x58\x7e\xed\x9e\x0a\xbb\xa7\x2f\x5b\xbb\x72\xc0\xa6\x63\xa9\x10\x24\x6e\x6e\x14\x7b\x2e\xd4\x9b\x3a\xae\x60\xc9\xab\x17\x02\x9a\x52\x03\x0d\x32\x51\xe8\xdb\x83\xd8\xaf\xda\xe7\x04\xd1\x14\x1d\x35\xf3\xd1\x1d\x18\x80\xc8\x74\x30\xa0\x61\x18\x2a\xb9\x16\xa9\xc8\xf1\xd1\x8a\x55\x00\xd2\x1f\x7d\x07\x60\x30\x0f\x6d\xf0\x29\xce\xa4\x01\xb6\x29\xae\x8e\x0b\x59\xfc\xce\x7f\x5d\x93\x0b\x91\xee\xc6\x3a\x77\x1d\xdd\x2c\x31\x93\x3b\x87\x83\x30\x95\x07\xc1\x82\x68\xab\xf0\x73\xf9\xa0\x3d\x17\x25\x0c\x1f\x58\xd4\x14\x40\x59\xaf\x58\x35\xd8\x6b\x3d\x0b\x96\x40\x2e\x16\xfb\xfb\xb8\x16\x37\x37\x9d\x63\xa0\x85\x2c\x09\x82\x8a\x0e\x74\xe0\x04\xbe\xe9\x06\xfc\x86\xcd\x20\x25\x04\x64\x24\xd1\x6d\x71\x39\x30\x9e\x00\xe7\xb3\xe9\x42\x2c\x44\x27\xeb\x9d\x6b\xbf\x52\xdb\x4b\xfd\xb4\x20\x15\x0c\xdf\xf7\x96\x53\x86\x14\xb9\x65\x88\xa0\x56\x8b\x83\xeb\xa2\x5d\xbd\x71\x1b\x20\x06\x37\x34\x20\x15\x55\xb3\xbb\xef\x01\xa9\x7e\x75\x21\x9b\x3c\x50\x1b\xe5\x5c\x1d\x70\xd0\x2d\xeb\xf2\x31\x67\x43\x16\x2d\xde\x8a\x03\x4e\x0c\x62\x4e\x67\xc0\xca\x07\x85\xb5\x5e\x14\xb8\x4c\x74\xec\x56\x38\xf9\xe6\x46\xc5\x14\x6a\x65\xb1\xfc\x5c\x04\xc0\xd2\x17\xf9\xb1\x57\x0c\x73\x84\xb3\x81\xf0\x86\xca\x21\x86\x02\x4c\xb5\x64\xd4\x3b\x47\xe0\x6a\xd9\x7f\x73\xbc\x0b\x84\xb4\x82\xc3\x77\x38\x90\xe1\xa4\x5f\xe0\x5f\xe1\x40\x64\xef\x48\x3d\xdf\x42\x2b\x13\x6d\xbc\x8b\xad\x1c\x51\x03\x5f\xb3\xab\xb7\x39\xda\x04\x47\x6c\xe3\x74\xed\x7a\xa6\xa1\xd5\x72\xdd\xd1\x50\x92\xed\x8c\x86\x12\x1c\x47\x34\x4c\x69\xb5\x5f\x95\x4c\x67\x40\xf7\xf3\x40\xef\x16\xf6\x53\xc9\xa1\x52\xeb\x7d\x81\x8d\x6a\xab\xe3\x7e\x09\xd4\x82\x50\x0e\x32\x30\x64\x5d\x81\x4a\x49\xa1\x74\xf8\x5d\xd1\x8b\xac\x92\xe0\x55\x61\xc3\xa4\xb2\x2d\x2f\xcf\x19\x80\x50\x85\x41\x68\xa7\xf6\xc1\x78\x23\xee\xa1\x45\xf0\x0d\xc7\x1a\x71\xb5\x9b\x81\xca\x21\x8b\xcc\xb5\x52\x67\x52\x1c\xde\xeb\xb2\x3a\x49\x2f\x1d\xc3\xcb\xda\x86\xc7\xf5\x96\x10\x38\x6d\x5d\x96\xf1\x76\xab\x40\x0b\x40\x28\x2a\x0e\xb7\x6a\x8c\x28\xec\x15\x29\x31\x1c\x10\x09\x64\xd9\x2d\x40\xfb\xd1\x98\xdd\x76\x04\xf4\x22\xb2\x21\x9c\x81\x74\x3a\xff\x98\x5d\x74\xe4\xcf\x32\x99\x8f\xaf\xcc\x33\x23\x04\x79\x5e\x43\xda\x49\xd9\xf6\xc4\xda\x2f\x87\xf6\x68\x50\x95\x06\xe3\x13\xaa\x6e\xa4\xd4\x48\x62\x08\xa7\x35\x14\x65\xed\xda\x5e\x95\x5d\xd4\x88\x93\xe8\x19\xb2\x30\xa3\x44\x78\x12\x92\x64\xd6\x22\xd0\x96\x25\x1a\xd6\x46\x0b\x54\x3d\x2a\x5f\xd5\xac\x8f\xfa\x04\xd8\x1f\x20\x39\x19\x71\x79\x62\x21\x6d\xaa\x9f\x24\xc5\xb1\xf9\xba\xde\xc4\xfa\x83\xfd\xda\x36\x1b\xa1\x87\xe5\xec\x89\x8d\xe6\x68\x1e\x99\x87\xd9\xa4\x39\xa9\xbd\xf1\x80\x9c\x02\xb1\xb8\x08\x90\x76\x0e\xbe\xe5\xfa\xca\x2d\xe4\xb9\xbb\x76\x3c\xa7\xb3\x3f\xf7\x12\xf0\xae\x4a\x28\x6e\x73\xba\x5b\x6c\xac\x13\x71\xed\xb8\x78\x77\x41\x71\xe8\x34\x0c\xe7\xb1\xf5\xee\x4d\xf3\xf9\x09\xd3\x09\xa3\x00\xc4\xf7\x2b\x2a\x6d\x25\x01\xa5\x2e\x54\x33\xc2\x27\xe2\x6a\x10\x57\x9b\x96\x5a\xef\x9d\xf4\xc2\xa6\xa8\x17\x56\xa1\x03\xbd\x76\x2f\xd8\x1e\x5c\xc8\xe8\xab\x2d\xce\xda\xf9\xe8\x3c\x86\x06\x88\x05\x36\xda\x3a\x9a\xe1\x2b\x88\x06\xf3\x70\x3c\xb3\xb4\x8d\x0b\xa4\xd5\xd3\xff\x2a\xf3\x42\x62\x37\x32\x74\xf2\x9f\x0f\x8b\xb0\xd7\xb8\x92\x82\x0a\xe2\x01\x1d\x90\x49\xbb\x72\xff\x11\x03\x4f\x87\xad\xb1\x4b\x3c\x8c\x89\x45\x2e\xc7\xe2\x35\xd9\xbc\x53\x88\xa1\x8b\xac\x92\x91\x23\xd0\x5e\x64\x0a\x40\x53\x5d\xb6\x42\xbf\x5b\x5d\xc1\xb9\x26\xff\x72\x03\x61\x9d\xd8\x46\xb6\x44\xf5\x1c\xe4\x62\xd4\x5f\xfa\xca\x8f\x11\x3e\xac\x53\x3c\x3e\x14\xd1\xb3\x67\x05\x2b\x1e\xa2\xf0\xc0\xab\xcb\xdd\x58\x38\xee\x58\x58\x46\x66\xaf\x2a\xa4\x3d\x0c\x09\xc5\xc6\xdb\x15\xce\xa5\x91\x7c\xc0\x12\x7e\x3c\xde\xae\xdd\xb8\x8d\x64\xc0\x29\x33\x15\x20\x7d\x44\xc8\x0f\xdc\xbe\x17\x56\xca\x6e\x24\xc1\x78\xbb\x22\x8f\x7b\x02\xf5\x57\xd3\xb7\x5c\xa6\xe1\xfb\x5f\x52\xde\xdc\xbc\x90\x5e\x8a\x91\x69\xd6\x2a\x78\x7d\x55\x4c\x5a\x64\x5f\xa2\xec\x41\x0b\xff\x91\x36\x20\x1f\x29\x28\x07\xfe\xc7\x3a\x07\x8c\xd1\x23\x4f\x3e\xbd\x7f\x8b\x0e\xaa\x83\xe8\xdf\xc8\xef\x4e\x51\x36\xbd\x7a\x95\x4d\xf3\x8b\x3c\x23\x9f\x4a\xd1\x41\x3f\x82\x02\x25\x14\x18\x46\x40\x62\x48\xbf\x4e\xca\x4c\xc3\xd8\x95\xee\x19\x0d\xdf\x82\x5e\x04\xb8\x0f\xb7\x0c\x6a\xc9\xf9\xbe\x56\x5b\x13\x55\x0f\x9c\x84\x52\xd2\x64\xd6\xe7\x40\xc1\xe9\x5e\xa2\xe2\x58\xd6\x30\x37\x62\x7e\x97\x7d\xa3\x2d\x6e\x4d\xf0\x4d\x41\x8e\x6c\x60\xf0\x35\xcf\xaf\xc0\xf9\xa1\xbe\x22\x5c\xbf\xf8\xbd\xc6\x6f\x9c\x5a\xbd\x5e\xad\x16\x38\xd5\xa6\x54\xeb\x20\x7a\xb0\x93\x14\x64\x03\x53\x32\x39\x71\x2d\x33\x29\x1c\x45\x9f\xd2\x56\xc0\x7e\x35\x6c\xe6\x69\xf3\x91\x3e\x5d\xb9\x59\x7e\xfb\x4c\xc9\x93\x93\xeb\xf8\x47\xc9\x88\x52\x9e\x6e\xcd\x4b\xb1\x6d\xba\x69\x60\xba\x72\x07\x6b\x4c\xdb\x3e\x5d\xe5\x3f\x8b\xe6\xab\xb0\xf6\x3a\x19\x4d\xd6\x4f\x73\xf5\x9e\xb2\x56\x2e\x87\x50\xa8\x97\x8b\x35\x4d\x03\xc7\x3e\x6d\x39\xe3\x19\x98\x38\x8b\xc1\xb5\x43\x31\xa5\xfe\xc8\x0c\x17\x87\x0b\xf1\xad\xf5\x16\x8e\x9e\x54\x15\x87\x77\x09\x60\xbf\x75\x1d\x4a\x5e\x87\xc6\x9f\xb3\x5c\x8b\xc2\x9b\x77\xcf\x7e\x86\xf0\x76\x3b\x73\x3d\x34\x85\xb7\x11\x87\x4c\x57\xa0\xb5\x06\x99\x72\x64\xc4\xbb\x97\xe2\x63\x1d\x59\xe7\xbd\xd8\x3a\xf4\xdc\xda\xc2\xc0\xd0\xbd\x2d\xd3\xc1\x3e\xa0\xc3\x7f\xa3\xfd\xdf\x06\xad\xeb\xae\xf1\x1b\xdb\x0e\x79\xe8\xd0\xcf\x68\xe6\xf9\x19\x45\x9d\x3a\xf2\x95\xcb\x6d\x4f\x9c\x93\xe8\x47\x4a\xb8\xd3\xb1\x24\xd3\x2b\x4c\xc8\x77\x3b\x97\x40\xdb\xb2\xe3\xb2\x35\x39\x04\x1b\x84\x67\x3b\xbd\x13\x7a\x51\x2e\xae\x00\xcb\xa4\x36\x96\xb9\x33\x7a\x91\x1b\x95\xee\x74\xde\xb8\x53\xf7\xc0\xb1\xef\x65\x5c\x70\x9f\xc6\x59\x0f\xfe\xa8\xb3\xb7\xb8\x1d\x12\x46\x93\xdc\x80\x40\xae\x8e\x3d\x80\xb1\x12\x69\x13\x7b\x9a\xea\xaa\xb2\xcb\xcd\x4f\x2c\x5d\x07\x9c\x77\x6f\xed\x6a\x0b\xea\x98\xff\xef\xc0\x15\x28\x59\xda\x82\x28\x2e\xfe\xcf\x80\x9e\x02\xbb\x1d\x6e\x36\xee\xf2\xdf\xda\x90\x97\x69\x10\x3b\x5d\xd3\x3e\x4f\x39\x61\x91\x4c\x1d\x98\x5b\x28\x10\x5b\x6c\x6c\x18\x13\x51\xab\x8f\xc8\x5a\x98\x39\x2e\x4c\xfd\x3d\x47\x2f\x6e\xc6\x95\xdc\x34\xad\xb3\xa8\x58\x2f\xcf\xf1\xb1\x95\x3e\x18\x93\x44\xb1\xd2\xd7\x9c\x50\xea\x39\xfa\x6c\x48\x0b\x9d\x9c\x71\xb2\x5c\xbe\x38\xe4\x39\x4f\xab\x2c\x67\xdf\xb2\xea\xaa\xcf\x96\x6d\xed\xdb\xc5\x68\x86\xfa\xc2\x5c\x1b\xa4\xb4\x8e\x85\x2e\x2c\x7d\x9f\xc6\x5a\x9d\xd4\x4c\x75\x66\x34\x41\xd4\x4c\xd5\x86\xfa\xa3\x3c\x8e\xe8\xde\x8d\xe2\xcc\x3e\xc8\x1f\xb3\xcb\x57\x3f\x56\xc7\x7a\x7a\x96\xba\xef\xd2\xf6\x8f\x93\x39\x40\xc4\xb1\x3c\x50\x53\xd6\x6e\xeb\x25\x70\x10\xca\x94\x0f\xc5\x6b\xd1\xc4\x2f\xc1\xbd\xa9\x32\x55\x76\x09\xfb\x18\xb9\xee\xa1\xbf\x05\xbd\x76\x5d\x6e\xf1\x7a\x47\x3e\xc2\xb7\xab\x7f\xfa\xcc\xd7\x8b\x24\x7a\xfa\x34\x2d\xca\xe2\x6a\x59\xae\xeb\x67\xcf\x22\x71\x4e\x76\xe0\x3f\x12\x38\xf4\xe2\x63\x72\x4d\x4b\x15\xc3\x59\xe0\x35\xc3\xc0\xb3\xe5\x02\xbf\x15\x74\x0c\x48\x93\x2f\xb6\xcd\x22\x30\xaa\x07\x42\x17\x26\x4a\x38\x1b\x08\x5e\x30\x4c\x2a\x95\x14\x88\xc1\x0e\x93\x24\x00\x02\x33\x58\x5c\xc5\x25\xba\xe1\xc4\xde\xc8\xea\x2a\x93\xfe\xf2\xce\x85\x5a\x3e\x48\xae\x05\x6a\xe2\xc4\x3f\x64\xab\x90\x32\x15\x70\x4d\xc1\xdf\x35\xff\xc5\x65\x89\x17\xa2\x9e\xa7\xf0\xf7\xc2\xb8\x9c\x8c\x95\x62\xc6\x50\x2d\x5e\x1d\x89\x68\x6a\xe9\x65\xc8\xfe\xa4\x62\xc6\xb9\xd2\x20\x44\xe9\x42\xb8\xb2\xc9\x87\x0f\x1c\x96\xac\xfa\x63\x60\xf3\x47\x1f\xbb\x5d\x94\x6d\xd9\xcb\x18\x38\xb1\x0e\x2d\x8a\x60\x98\xe9\xf1\xf8\x0e\x9e\x66\x89\xcf\x5c\x48\xcf\x2e\xc0\xa8\x7e\x58\x63\x04\x06\x5b\x90\xe9\xba\x6f\x2a\x6f\xd5\x85\x0e\x07\x32\xf7\x42\x87\x5f\x4b\xf7\x67\xd0\x9d\x72\x2b\xd3\x12\xca\x04\x86\x26\x9f\xf8\xcd\x43\x03\x3e\xf2\xc3\xa2\xfd\x25\xbb\x8a\x1b\xfa\xc5\xfe\x78\x0a\x8a\xc6\x65\xda\x76\xc2\xe5\x29\x6c\x93\xc1\x7d\x9b\x3d\x0d\xf5\x22\x6f\xe0\x4c\xdd\xc0\x32\x88\xbf\x5b\x0a\xc5\xc6\x18\x6e\xc9\xc4\xe2\x6e\x86\xf6\x13\xce\x50\x0e\x4c\xfe\xa2\x81\x0d\xd8\x09\x43\xd6\x96\xe3\x05\x47\x90\x8c\x50\xf0\xd6\xe9\x85\x8a\x5a\xea\x0f\xd0\x9b\x54\xe5\x7a\x93\x2a\x6c\x1d\xa2\x62\x8b\xbc\xa0\xcb\x25\x4f\x87\x62\x11\x41\xd7\x1d\x9c\x1a\x6e\x0f\x91\xaf\xfc\x8e\xe3\xd1\x39\x29\x3f\x35\x00\xf3\x53\xb6\x55\x41\xcf\xfb\x32\x53\xe9\x4f\xc1\xb0\x66\x57\x8e\x77\x23\x56\x11\x66\x41\x89\xd9\x05\x72\x9c\x97\xd4\x56\x39\x47\x2c\x8f\x36\x45\xe7\xe9\xf4\x2b\x15\x33\xf0\xec\x02\x79\x7e\x2b\x90\xa7\x8e\x8e\x3e\x74\x6f\x7b\x30\x71\x82\x54\x7a\x23\x33\xce\x7a\xdc\xf0\xff\xd3\xb0\xb8\x6c\xe1\x46\xeb\x1f\x76\x78\x12\x91\x51\xfc\xd3\xa1\xef\xe1\x83\xdc\x31\x5a\x2d\xb4\x9e\x57\xd1\x53\xb6\x34\xae\xea\x1b\x53\x9e\xa1\x71\xfb\x85\x2a\x71\xa8\x89\xce\x3d\x38\xef\x10\x76\x29\x02\xed\x8b\xae\xbe\x42\x7b\xa9\xc1\xd7\x6f\xba\xa3\x78\x51\x36\xc0\xe6\x3c\x5f\x2c\x10\xe2\xc5\x7c\x6b\x57\x3e\x3c\xdc\xd6\x57\xab\xbc\x8d\x3b\xa8\xbf\x59\x72\x3a\x17\x14\x44\x0d\xf5\x59\x30\x90\x80\xb5\x7f\x7f\xad\xd2\xd5\xca\xc3\x32\x72\x29\x67\x46\x9d\xd0\xcc\x25\x50\x2e\x34\x65\xaa\xea\x03\x50\x57\x5d\x7f\x0a\x5d\x98\xc3\x38\xfb\x0a\x75\x39\x08\x1f\x3b\xf6\x1e\xe7\xd6\xf4\x3b\xec\x3a\x8a\xec\x7b\x66\x32\x75\xf0\xff\x7a\x48\x72\x52\x54\x77\x2a\x6f\x47\x5d\xee\xa1\x8d\x1f\x3c\xbe\xb3\x8b\xb1\xdb\x14\x25\xbd\x33\x1c\x8f\x47\x26\xaa\x71\xeb\x08\xc3\x85\x4c\x5a\x84\xf6\x09\x8e\xc7\xf7\x1f\x13\x76\xdc\xc9\xb3\x68\x77\x34\x7a\xef\x9d\x21\xe4\x5e\x00\x9f\x1b\xd0\xdc\x30\x18\xa9\x9e\x76\xca\x3c\x62\x14\xc1\x77\x89\xbb\x78\x2a\x9d\x9a\x57\x2b\xdf\x48\xa2\xb1\xf4\x93\xda\x81\xf3\x5f\x1a\x7c\xd2\x38\xf8\x18\x11\x0a\xdc\x89\x1c\x77\xaa\xef\x61\xa4\x8a\xbc\x0b\x28\xeb\x0f\xdf\xb8\x03\x0d\xf4\x84\x09\xee\x99\x0e\x03\x96\x94\xfd\x12\x8e\x39\x35\xa0\x35\x8a\x2c\xc8\x1d\x6c\x7c\xcf\xba\x7f\xfc\xfc\x46\xbb\xcd\xaf\xcb\x82\x45\x4e\x72\xfb\x24\xac\x27\x16\x8f\x39\xc8\xb7\x9a\x8f\x39\x41\x95\x69\xbd\xd4\xfa\x79\x17\x97\x8a\x3d\x5d\xb0\x17\x7d\xf7\xb6\x5a\xdf\xae\x21\x38\x6d\xbd\xe8\xd8\x01\xdc\xcd\xa5\x4f\xd4\x7f\x21\x42\x54\x00\xbe\x6c\x6d\x27\x98\xb7\x7b\x0e\x74\xa7\x07\x79\xa6\xe2\x96\xd9\xc5\xe3\xa3\xd1\xcf\xa8\x1e\xe3\xc9\x3a\xba\x8b\x83\xdc\x9f\x26\x8e\xb2\x30\x92\x2e\x77\xa4\x8d\xf2\x2e\xda\x28\x48\xe9\xfb\x04\x53\xbe\x9d\xb8\x49\x43\xc4\x4d\x67\x90\xa3\x20\x3b\x3a\xfd\x3d\x54\xc4\x7a\xe3\xd1\x4c\x77\x25\x0d\xd6\x48\x32\x9d\x2e\xc4\xf4\x0c\xc9\x99\x9d\xef\xf9\xd5\xff\xd3\xee\xf9\xf2\xa7\xef\xf9\xfc\x77\xdd\xf3\xb5\x73\xcf\xa7\xf2\x9e\xbf\xd8\x89\x45\xf9\xfd\xf7\xfc\xce\x77\x75\x37\xf7\x7c\xf4\x33\x3e\x41\xad\xf0\xb1\x5e\xec\x26\x0b\x25\x6e\xc5\xd7\xfe\xe1\x90\x07\x29\xab\xa7\xe9\x8a\x94\x85\x5f\x97\x95\xa4\x62\xe8\x44\x59\x5b\xbd\x01\xe6\xba\xb6\x16\xbd\x92\x8b\x7e\xed\xde\x2b\x9e\x77\x70\x24\x2f\xa8\x9c\x77\xfd\xb0\xa1\x20\x49\x2f\xb8\x9c\xb4\xf5\x4f\xfb\xd6\x9b\xb4\xf1\x2f\x12\xc2\x50\xc7\x79\x1c\x3d\xad\x57\x29\xbe\x65\x2a\x9f\x79\x9c\xa3\x8c\xb1\x0e\xa2\x67\xf4\xf4\xf0\xf4\x1e\x16\xc3\xa8\x97\xbe\xea\x6b\xc0\xba\x4b\xbe\x8d\x93\xf3\x41\x33\x16\xb4\x58\x33\x61\xa9\x1a\x98\x7d\x48\xf7\xbe\xa5\x74\x4d\x66\xef\x6d\xc5\x4b\x94\x2f\x0f\xa4\x3e\x78\xe0\xcd\x1e\xe5\xc2\x18\x72\x83\x0e\x8a\xf7\x1f\xb0\x40\x93\x35\xfb\xe8\xa8\x45\x4b\x99\x2a\x0c\x2c\xf1\xc3\x6e\x77\xb9\x5b\xd4\x01\xbd\xbb\x30\x08\x24\x00\xcf\xc4\xaf\x1f\xed\xac\x85\x32\xb8\x9e\xf5\xbf\x0c\x99\xc2\xc9\xa6\x65\x31\xcd\x17\xf6\x9d\xb4\xbf\x7f\xe5\x18\x9f\xec\x76\x83\xcd\xf2\xca\x72\x58\x5a\xff\xc6\x82\x0d\xe3\x1d\x7b\x6a\x9f\x79\xf6\x10\xaf\xee\x26\x85\xa3\xda\x43\x49\xb6\x0c\xd3\xb9\xdd\x5c\x3b\x15\x7c\xaf\xc0\x81\x5d\xf9\xee\x90\xa5\x19\xa9\x6f\x52\xa2\x25\xd9\x96\xc2\xea\x61\x63\x7f\x05\x63\x11\x66\xe1\x49\x4f\x66\x7d\x34\x77\x5b\x6a\x9f\x8f\x4b\x8e\x7a\x98\x0f\x26\x76\xb0\x99\xe6\x59\x61\xc7\x50\x5d\xca\x87\xea\x6a\x88\xee\x74\xa0\x5f\x9c\x97\x71\xd7\xf4\x65\x05\x90\x0e\x18\x55\xa1\xce\x9a\xcb\xb6\x92\x79\xc5\x2b\x45\x96\xf2\xc4\xdf\x5c\xbc\xcb\xd0\x0c\x85\x62\xbb\x07\x17\x1a\x90\x96\x76\x32\xc5\x4f\x94\xa5\xfd\x44\x99\xb9\xdb\xa7\x82\x1a\xf4\xcb\xd3\x14\x55\x93\x36\x9b\x96\x3f\x09\xc5\x16\x53\x90\xcb\xa0\x4f\x2b\xc1\x3b\x94\xd7\x14\x84\x1c\xe6\x20\x37\xe9\xb8\x2f\x0d\xa6\xe0\x06\x22\xef\x0f\x68\xc3\x9b\xb5\x67\x7a\x1c\x48\x53\x96\x56\x71\x20\x2f\xa1\x77\x06\xa9\x66\xd1\x82\x0c\x42\x82\x6d\x6f\x7e\xb3\x7e\x60\x84\x30\x2e\xbd\x02\x64\xd6\x70\x89\x21\x3b\xd4\xeb\x61\x80\x96\x5a\x84\xe8\xae\xd5\x4e\xbe\x24\xd8\xf5\x83\x36\xc4\x71\xe9\xad\x79\xf8\x4a\x99\xb5\x95\xac\x96\x2d\x7d\xaa\xd3\x33\xf4\x31\xe1\x9e\xc3\x4b\x94\xc7\x49\xea\xe0\xd5\x56\xea\x2a\x7c\xda\x15\xc8\x77\x89\x5f\x82\xb5\xf6\xcc\x51\xc1\xad\xaf\x57\xe8\xb1\x09\x9d\xd7\x75\xd6\x18\x08\x74\xbd\x17\x5b\x26\x52\x1b\xf1\x62\xeb\x70\x5d\xe8\xbd\x45\x48\xe4\x16\x76\xc5\x51\xe7\xc9\xe9\x2b\xf1\xe2\x6c\x32\x77\x42\x08\x5c\xa8\x8b\x78\x67\x32\xf2\x7c\xab\xc0\x77\x0b\x2e\x9d\xba\x44\x9b\x33\xd6\x41\x08\xd3\x52\xad\x6d\x68\xd4\x23\x1f\x43\xb8\xa1\x1b\x3f\xb3\x0d\x85\x44\x36\x5d\xea\x96\x72\x79\x14\x4e\xb2\x08\x8f\xce\x86\x55\xd9\xee\x12\xec\xf3\x8f\x84\xe2\x0b\x2f\xc4\x02\xdf\xeb\x3f\x92\x95\xe7\xa6\x42\xb9\xbc\x16\xd1\xc5\x02\xf0\xc4\x9f\x1c\x0c\x10\x09\xef\xe9\x60\xa2\xe0\xeb\xe6\xe6\x72\x22\x9d\xf0\x4b\x8c\x2e\x65\xaa\xb6\x90\x1a\xad\x1b\x94\x28\x20\x55\x74\x82\x30\x42\x38\x20\x1a\xa0\x85\xcb\xc1\x35\x9e\x31\x69\xf8\xf5\x6d\xe2\x1f\xc0\xc6\x06\x37\x7b\xaf\x11\xc5\xd2\x13\x1d\x8b\x7c\x42\x1b\xe9\x2a\xec\x22\xf6\xdc\xb2\xeb\x46\xb5\x5c\xe1\x36\xa9\x0a\x79\xd5\x6e\x66\x16\x74\x82\xe6\x21\x50\x2a\xa6\x9e\x09\xad\x52\x01\xe4\x79\x45\x82\xad\x2f\xc9\x75\xe7\xe8\x58\xba\xe5\x76\x10\x97\x42\xe2\x5c\x4e\x88\x6b\x11\xd8\xc5\xf8\x87\x25\x14\xfb\x28\xd2\x3a\x5d\xa1\xcd\xb6\xa1\xd2\xbe\xfc\x51\x1c\x48\xa7\xc9\xb5\x63\x26\x1d\x62\x47\xda\x5a\x9a\xbe\x46\xe6\xd1\x2e\x1a\x99\xc1\x70\x05\x96\xf7\xfd\xe1\xdb\xcf\x9f\x4e\xbe\x7c\xfe\xf4\xca\xb8\xcf\x41\xbd\x7b\x59\x1c\x55\x5e\xaf\xa7\x3f\xe2\x4a\x4c\x31\xe8\x2d\x46\x4b\x9f\xe1\xd7\x0c\xbf\x2e\xf2\xc5\x42\xfe\x79\xbf\x4a\xa7\x79\x43\x89\x40\x4f\xbf\x4e\x97\xf9\x42\x7d\x7c\x42\x4c\x0b\x3f\xb1\xda\x05\x45\xce\xad\xd2\x59\x0e\x6b\xc2\xda\xb5\x88\x10\x4c\xda\x67\x40\xce\x35\x7c\xa3\x19\x6e\x56\xbd\x2a\x66\xfa\xf7\xdb\xdc\xfc\x26\xcf\xcd\xf0\x55\x92\xf3\x65\xfc\xa1\xbb\x5f\xa1\xe9\x4b\x55\x48\xaa\x5e\x35\x27\x53\xf5\x67\x99\x17\xfc\x43\x06\x82\x7c\x8e\x1a\x97\xcd\x47\xa4\xc2\x21\xb5\xc2\x7f\x38\x5c\x0a\xf4\x5b\x43\xa1\x74\xf6\x96\x82\x35\xe2\x67\x53\xae\x5e\x94\x8b\xb2\x92\xbf\xcd\xcc\x61\xdd\xcb\xaf\x99\xfe\xf1\x32\xad\xe7\xf2\xa5\x5c\xa6\xfc\x96\x17\x19\x50\xe6\xfa\xdb\xaf\xfa\xd7\x7c\xd6\xcc\x31\x1e\x3d\x50\xee\xcf\x8b\xe9\x9c\xfa\x68\xac\x55\x42\xf7\x55\x08\xb1\xf0\x2b\xcf\xbe\xff\xa9\xc4\x31\xfe\x18\xe3\x7f\x47\xf8\x1f\xfc\xbb\xc2\xaf\x2b\xfc\x82\x66\x37\x18\x71\x41\xfb\x0b\xa3\xd7\xe3\xf8\xda\xde\xad\x08\x3f\x0e\xe5\xe2\x45\xf6\xd6\x45\xf8\xfb\xf0\x82\x3e\x22\xb3\x8d\x9c\xcc\xe1\x48\xda\xdb\x18\xb5\x92\x22\x6f\x63\x23\xe7\x33\xb2\xb6\x39\xe2\x9f\x87\x40\x8d\x45\xd6\x8e\xab\xe4\x65\xae\x93\x79\xf3\x55\x06\x79\x29\x8f\x82\xdb\x1e\x05\x12\x23\x17\x14\x22\xfb\x2b\x0a\x82\x43\x14\x48\x8c\x5c\xa0\x88\xec\xaf\xc8\x82\x90\x08\x7f\x1e\x4e\xf1\x77\xe4\x00\x0b\x67\xe8\x85\xf7\x01\x26\xe2\x84\xc3\x99\x4a\x89\x3c\x08\x52\x05\x16\xfc\x1d\x79\x00\xa5\xb2\xbd\x0e\x18\xbe\x54\xe6\x77\xfc\x8a\x6c\x60\xa3\xf0\x06\x87\x29\x7d\x44\x1a\xc4\x22\xf9\x23\x0a\x59\x72\x78\x9e\x28\x08\x2b\xed\xee\xcb\x96\x9d\x9a\x06\x3c\xc7\xef\xef\xa7\xdb\x42\x1a\x48\x1d\x99\xbb\x38\xfd\x87\x8e\x38\x9e\x8e\xf3\x66\xaa\x58\xb4\x40\x96\x09\xbd\xc0\x0b\x42\x6e\x03\x9a\xa1\xf9\x10\xfc\x93\x1d\xc0\xeb\x1c\xfe\x14\xda\x91\x3b\x64\xe8\xdf\x9c\xaa\x2b\x58\x5f\x9b\x4d\xd0\xd1\xfd\xce\x91\x07\xe4\x48\x9d\xf0\x03\x71\x2b\x1c\x81\x60\x75\xf9\x21\x07\x48\x46\xc5\xfa\x21\xc5\xc3\x21\x7a\x68\x25\x16\xd9\x45\x63\x25\xfd\x06\x9f\x1b\xff\x79\x04\x75\xb1\x2e\xf7\xf7\x59\xf7\x7d\xb6\xbf\x3f\x4b\x92\xb5\xe2\x3f\xd1\xa3\xd1\x8c\x34\xa1\xf6\xbe\xdd\xdc\xec\xad\xfa\xdf\xd8\x97\x77\xd2\x4c\x98\x77\xb5\x5f\x45\xe6\x72\x2e\x62\x69\x05\x6c\x64\xcb\xb9\x44\x42\x44\x04\x74\x51\x43\x31\x7c\x92\x99\xc8\x87\xe9\x14\x16\x61\xbd\x40\xb1\x8d\x74\x18\xfd\x52\x06\x43\xa2\xb8\x12\xa2\xda\x38\xcf\x20\xf4\xb6\x47\x9e\x64\xe1\x0a\xb5\x5e\xf1\x39\x42\x0b\xc0\x6c\x7a\x99\xa2\x13\xc0\x1d\x5f\xef\x3f\x5d\x15\xcd\x3c\x6b\xf2\x29\xd5\x37\xd2\xea\x40\xb8\x11\xf5\xd4\x51\xa3\x04\x86\xda\x6b\x05\x28\xfd\x9a\x5d\xbd\xbf\x30\xae\x15\xe0\x94\x2f\x16\xe5\xf7\x57\xff\x58\xa7\x0b\xf2\xa6\x50\x3a\x21\xc5\xd0\x3d\xfa\x35\xaf\x49\x7c\xbd\xc2\x99\xcf\x3e\x92\x83\xab\xca\xa8\x05\xc5\xd7\xe7\x1c\x47\x2b\x5e\xf4\xaf\xe1\x20\x70\x69\x36\x8d\x10\x32\x9a\x95\x93\x27\xa3\x62\x29\xd7\x15\xc0\x67\x20\x27\x9c\x01\x8d\x05\x8d\x9d\x5e\xe0\x00\xfe\xb4\x58\xc3\x95\x3d\x24\x74\x46\xa6\x16\x6f\xb3\x62\xcd\x09\xaf\x11\x76\xf9\xe7\x5f\xb2\xab\x97\xe5\xf7\x82\x3f\xde\x96\x70\xd6\xbd\xcf\xcf\x2b\xfe\x30\xa7\x79\x8e\x60\x7b\x46\xcf\xe8\xec\x9b\x91\xff\x7c\xe3\x3f\x92\xbd\xbc\xce\x28\x88\x13\xce\x3f\x9e\x0b\x27\x60\xa1\x6f\x78\x5c\x6a\x8d\x46\xa9\xca\xd8\x33\x83\x8c\xfb\x53\x8e\x88\xa7\x22\xb2\x34\xad\x88\x2c\xfb\xfb\xfd\x59\xd2\xe0\x28\xe4\x10\x06\x13\x76\x24\x6f\x9a\xc2\xa5\x88\x43\xa3\x6d\x95\xd4\x2b\x10\x23\xbb\xdf\xca\xb6\x56\x32\xf6\x2a\x7d\x5e\x49\x25\xc6\x1e\xad\x40\xd5\x2f\x07\x56\x45\x6f\xf5\xac\xca\x72\x03\xdc\x14\xd3\x18\xb6\xe3\x5a\x0c\x5d\x59\x51\xbc\xcc\x09\x89\x1f\x3e\x16\xa1\xf3\x11\x3f\xba\xf5\x5d\xdc\x3b\x1c\x40\xc1\x8e\x3a\x63\x57\x88\xf0\xd1\x00\x1a\x97\xba\xe1\x93\x01\x5f\xbf\x0a\xff\x60\x00\xd9\xfb\x90\x2e\x98\x5d\xdc\xf1\x92\x27\x84\x55\xf9\xbd\x7f\x24\x1e\xde\x1f\x74\xbe\x8f\xb7\x59\x6e\xaa\x38\xcd\xf2\x45\x9f\x7e\x01\x25\x33\x2b\x97\xfd\xc1\x3f\x15\x83\xa0\x51\xdf\xd1\x76\xe5\x3a\x8b\x06\x6f\x21\xa4\x76\xd4\xb0\xcf\x4d\xbe\xb0\xde\xda\x02\xa8\x2a\xf7\xb0\xd1\x8b\x45\xbe\x3a\x2f\xd3\x6a\xa6\xd0\x52\xda\x81\xae\x7c\x34\x46\x67\xc3\xc3\x65\x3a\x13\xe0\xc7\x69\x74\xea\xe5\x13\xb8\xaa\xcc\x85\x97\xf9\xb2\x4a\x2f\x55\xde\xca\xcb\x3b\x29\xd7\x32\x76\x9d\x71\x1a\xa3\x33\x3f\xbf\x51\x39\x73\x2f\xe7\xaf\xf3\x2c\x5b\xa8\xcc\x99\x1b\xd2\x11\x8e\x03\x39\x70\x36\x9e\x52\x6d\x81\xd6\x37\x17\xdf\x5e\xb6\xed\x05\x5d\x4c\x8b\x6c\xe7\xf5\x39\x1e\xf6\xdb\x11\xed\x37\x44\xa6\x84\x18\xf6\x46\x36\x92\xd5\xe9\x0a\xc5\x62\xf6\x06\xc5\x48\xf9\xf4\xeb\xae\xed\xbe\xa0\xc2\x81\x86\x29\xc3\x6f\xd9\x42\x2a\xbb\xb6\x6f\x55\x09\xf5\x62\xb2\x5b\x7d\xad\xae\x76\xef\x04\xca\x06\x5b\x5f\x5d\xf9\xcd\xae\x77\xb9\xdb\xb8\x36\x14\x0d\x35\xba\x6e\xbc\x36\x67\xe5\x1a\x6a\xbd\xb8\xcb\xb2\xbf\xb4\xaa\x04\xfa\xb0\xb2\xfd\xbe\x00\xea\x77\xee\x04\xcb\x86\x5a\x87\xf4\x40\xb3\xc8\x1e\xdd\xa1\x65\x2c\xde\xd1\x38\x64\x05\xdb\xc7\x08\x7a\x77\xea\x01\x2b\x74\xf6\x81\x7e\x37\x03\xbd\xfc\xc8\x77\xde\xe1\x97\xaa\x7c\x57\x1f\x90\x17\xe8\x82\x03\x95\xdc\xa1\x0f\xae\xd0\xd1\x09\x65\x06\x7a\x79\xff\xed\x6e\xab\x45\xe5\x3b\xfa\xc0\xbc\x40\x17\xcc\xe2\xde\xa1\x0f\xae\xd0\xd1\x09\x65\xb6\x7a\x01\xf2\x7f\xe7\x0e\xa0\x6c\xb0\xed\x72\xe5\x35\x4b\x2c\xcd\xae\xed\x32\x79\x16\x68\x98\x32\xbc\x96\x73\x24\x16\x76\x6d\x99\x28\x8b\x50\xcb\x94\xe1\xb5\xfc\x55\x92\x4f\x3b\xb6\xad\xa8\xad\x40\xeb\x32\xab\xdd\xfe\x87\x2a\xab\x77\x5e\x96\xbf\xa8\xf2\xe1\x1e\x28\xaf\xdd\xc5\xe7\x9d\xb7\x93\x89\xc3\x70\xe3\x9f\xfd\x0d\x5d\x94\xe9\xce\xc8\xe7\x37\x2c\x1b\x68\x17\xd3\xbd\x66\x33\xb4\xa5\xda\xb5\x5d\x32\xbc\x0a\x35\x4c\x19\x5e\xcb\x4b\x4d\x7e\xef\xd8\xba\xa1\xd7\x03\x3d\xe8\xcc\x50\x2f\x6f\xcb\xdd\xb1\xcd\x5b\x5d\xa1\xab\x17\xcc\x0c\xf5\xf2\x7e\x77\xb0\x7f\xab\xca\x77\xf5\xf1\xbe\x05\xfc\xdc\xc5\x1d\x30\xda\x5b\x5d\xa1\xb3\x93\x36\x4e\x5b\x4a\xf6\xe6\x2e\x7d\x84\x61\x54\x66\x79\xed\xaf\xd2\xba\xd9\x79\x2b\x3e\x50\xe1\x40\xdb\x94\xe1\xb5\xcc\xd6\x19\x3b\xb6\xfc\x91\x0a\x07\x5a\xa6\x0c\xaf\x65\x76\xff\xbe\x6b\xd3\xec\xa8\x3d\xd4\x36\xe7\xf8\x8d\xaf\xcf\x97\xbb\x5f\xb7\x9f\xb8\x74\xa8\x71\xca\xf1\x1a\x6f\x90\x88\x7f\x81\x7a\x96\x3b\x0f\xff\xc4\xaa\x12\xe8\xc6\xca\x0e\xf5\x75\x07\x02\xe8\x44\x95\xef\xea\xa5\x4d\x02\x51\x17\x77\x39\xcb\x27\xba\x42\x57\x27\x81\xb3\x4c\xbd\xdc\xe9\x5e\x3f\x31\x35\xba\xfa\x09\xdd\xec\xdf\x91\x57\xda\xb5\x0f\x62\xac\x42\xcd\x53\x86\xdb\xf2\x06\xdf\xfa\x95\x28\xe4\x6a\x88\x4c\x12\x0a\x11\x99\x56\xbe\x1a\x12\x77\x23\x3c\x09\xc7\xd5\xd0\x62\x4d\x38\x13\x38\x02\x4c\x5d\x5d\xd1\x27\x20\x2b\xf8\x5a\x93\x38\xd2\xa6\xbd\xaf\x86\x16\xf1\x4e\x99\x48\x33\x43\x2a\xfc\x51\x9f\xb8\xcd\x9c\x02\xbf\x4c\x22\xd2\xa6\x2a\x19\x7e\xeb\x0c\xa4\x27\x65\x3a\xfc\x54\xc9\x4c\x02\x72\x3a\xfd\x56\x19\x84\xe3\x38\x1d\x7f\xaa\x64\xde\x10\x4e\x67\x69\x33\x65\x00\x85\x84\x69\xe5\x0a\x3f\xf9\xc2\xba\x1a\xd2\x2d\x27\xb4\x20\xea\x8a\x25\xbe\x98\xc0\x04\xca\xd5\x90\xa8\x1a\x61\xc9\x70\xae\x86\x92\x1c\x91\x89\x4c\x09\x50\x2a\xfd\x14\x5a\xba\x43\x69\x9f\xa9\x3f\xba\x78\xaf\x86\x78\x57\x0b\x47\x02\x75\x35\xd4\xd7\xa1\xce\x20\xc0\x95\x19\xf8\x5b\x67\xbc\xa7\x11\xa9\x3b\xc7\x24\xf3\x3a\xe8\x8b\x42\x58\xe2\x2a\x99\xcc\xa3\x60\xbc\x7a\x35\x24\x64\x8c\x09\x8c\x0e\xa5\x4a\x2e\x26\x48\x24\x76\x25\x43\x5f\x50\x12\xa3\x9e\xab\x21\x63\x2c\x4c\xb2\x71\xc5\xd5\xd0\x42\x36\x3a\x93\x37\x5e\xa1\x06\x9d\x2c\x67\xa6\xcf\xb3\xce\x50\x7b\x66\xce\x20\x66\x31\xec\x5f\x0d\xe9\xc0\x6c\xb4\xce\xd5\x0b\x34\x3a\x7e\x35\x78\x75\xfa\xe2\x6c\x68\xcb\x44\x13\x48\x20\x71\xce\xb9\x23\x99\xbc\x12\x19\xc5\xbd\xd7\xc2\xe8\x60\x78\x03\x54\xcd\xf2\xca\xc9\xec\x49\x49\x01\x2c\x49\x77\x09\x1f\x85\x94\xb8\x87\x55\xe6\x50\xc5\x91\x3a\x7b\xc9\x56\xce\x14\x4a\x72\xab\x28\x54\xfa\x60\xfc\x96\xbc\x42\x83\x44\x92\xc5\x0f\x2c\x6f\x76\x34\x83\xab\x89\x27\x2d\xbd\x1c\x6a\x98\x34\xdf\x04\x55\xe6\x93\x81\xda\x7c\xf3\xee\x9a\x6f\xb5\x93\x49\x6a\xcb\x3c\x2f\x87\x36\x1c\xcb\x90\xa6\x33\x0c\xf6\x6c\x0f\xca\x29\x6a\x64\x99\x97\x46\x96\x79\x95\xac\x5b\xcd\x12\x22\x32\x9f\xf2\x90\x25\x75\xab\x20\xa3\x14\xe8\xfc\x08\x3a\xaf\x86\xe7\xeb\xa6\x29\x8b\x8e\x01\xb4\xe4\xb3\x94\x6a\xa3\x26\x93\x6a\x0e\x9a\x97\x46\x90\xe8\xa5\xbd\x77\x16\xd7\x1c\x2d\x2f\x8d\xe6\x3a\x6d\x4d\x81\xd0\x9f\xfb\x89\xa7\xc0\x4f\x69\x9c\x06\x35\xda\x73\x93\x18\xe5\xb9\x69\xde\x50\x0c\xa6\xb3\xd3\x10\xc9\x25\x8b\xd6\xd8\xec\x03\xeb\xa5\xba\x63\x34\xa7\xd4\x4b\x93\x07\x34\x59\xb5\xda\x56\x28\x23\xb9\x68\x65\xc9\xf3\x9b\xcc\xdb\xfb\x8d\x97\x8c\xf5\xe9\xac\xbc\x44\x53\x49\xbe\x59\xf6\xaf\x58\x05\xe8\x45\x72\x65\xbd\x4c\x7d\xa3\x53\xa4\x9e\xa4\xca\xed\xef\x4e\x2f\x06\xe2\x85\x23\x17\x3e\xbf\x5d\xb6\x6e\x89\x7a\xe3\x47\x47\xdb\x64\xee\x5d\x62\xde\x78\x7c\xf4\xab\x08\xcb\x5c\x21\xeb\xc9\x16\x91\x7c\x48\xfe\x0b\x79\x63\xd1\x2d\xfe\x85\x6c\x77\x30\x96\xf4\x17\xf2\x1e\x88\x0e\x01\x2f\xe4\x3d\x14\x21\xf9\x2e\x64\x3c\x12\x1d\xe2\x5d\xc8\xfb\x55\x84\xa4\xbb\xf1\xf8\x61\x87\x56\x8c\xfb\x62\xd0\xd2\x91\xb9\xab\x2b\xff\xca\x53\x78\x2f\x1c\x9b\x98\x96\x5c\xbd\x4c\xae\xa7\x6a\x73\x5e\xa6\x4d\x1a\xf0\xec\x16\x39\x05\xe8\x7d\xfb\x38\x1b\xba\xb5\xe4\x03\xb4\x93\x08\x70\x55\x0d\xd3\xf5\xe5\x52\x39\xf4\xec\xe3\x4b\x57\xdb\x4c\x22\xb0\xd5\x34\xf3\xed\xa6\x87\x7f\xc4\xcc\x31\x9a\x21\x3f\x20\xfe\xbe\x91\xde\xd5\x53\xeb\x8e\x23\x75\x9e\x29\xe4\x70\x95\x4b\xbf\x9f\x1a\xb6\x07\xf9\x38\xf6\xfb\xbb\x9b\x78\x59\x6e\x0c\x66\x12\x83\x00\x86\xb8\xc8\x2f\x95\x05\x97\x4a\x7d\x4b\xaa\x2d\x89\xf4\x2b\x5f\xa4\xf4\x84\x86\xbd\x26\x85\x7c\x49\x67\x05\x4e\x13\x26\x75\xf8\x06\x51\xff\x45\x3a\x35\xf1\xca\xa5\x4b\x6e\x52\xff\xee\x70\x62\x9e\x26\xe8\x78\x9b\x7c\x7d\xc3\xdf\x24\x3d\x4e\xfb\xc5\x20\x46\x5f\xdd\xd2\x85\x90\x74\x71\x37\x94\x3e\x56\x3e\x30\x2d\x92\xcd\x8e\xdb\x49\x31\x6a\x88\x22\xb4\x93\x63\x03\xa2\x69\xd8\x89\x78\x5e\xbf\xf4\x8a\x62\x84\x17\xdb\x4f\xdb\x49\xb5\xce\x62\x27\xe5\x75\xba\xa8\xe5\x9a\xe4\xb5\x45\x11\x7d\x02\xfc\xbd\x82\x06\xda\x85\x6f\xb5\x5b\xbb\x9b\xe3\x49\x85\x7e\x4e\x48\xfd\x80\x9e\xcf\xae\x29\x5a\x04\x1b\x2a\x50\x6a\x9c\x0a\xe9\xf3\x9d\x4b\xb9\x53\x78\x47\xaa\x9d\x84\xd7\x29\xb6\x35\xab\x2a\x12\xef\x55\x4b\x1f\x86\x74\x63\x92\x0f\x11\x6e\x35\x5f\x66\x70\x11\x2e\x57\x21\xe7\x90\xd9\x50\x67\xdf\xdc\xa0\x2b\x99\x61\x51\x7e\xef\xd3\xb3\xbd\xbf\x0f\x64\xb3\x85\x8b\x5a\xab\xcf\xcd\xa4\x74\xbd\x6d\xb8\x44\x65\x5b\xaf\xd8\xdf\xb0\xbd\xd1\xc4\xf2\xbe\x6e\x01\xe4\xc4\x27\x50\x8f\xdb\x14\x6b\x9c\x39\x90\xa1\x5c\x39\x04\xe0\xa2\x05\x15\x1b\xe1\x91\xc4\x1d\xfe\xe0\xdd\x11\x79\x75\x8e\x03\x84\x75\x8c\x96\x0a\xb8\xfc\x7f\xa2\x1d\xa1\x38\xb2\xbb\x41\x1b\x0f\x0b\xd5\xb5\x81\xb1\x6e\xad\x1c\xd4\xe7\x1c\x3c\xac\x81\x7a\x76\x7e\x08\xe4\xc3\xca\xde\xd6\x4c\xb7\x9f\x79\xe9\x30\x89\x0e\x74\x73\xc6\xfa\x09\x21\x7c\x63\xcc\x6d\x3c\x94\x63\x32\x1c\xac\x43\xa6\x7c\xf8\x56\xaa\xbb\x4c\x6a\x74\x7d\x6c\xa1\xce\xc4\x45\x82\x26\x4a\x05\x9c\x34\x79\xf6\xf8\x01\xde\x86\x44\xe0\x7e\x30\x5a\x9e\x95\x60\x7f\x24\x4e\x96\x3d\xf5\x04\xc3\x3b\x9b\xb1\x90\xbf\x55\x6b\x70\x68\x6b\x91\xb9\xa3\x73\x07\xeb\x1b\x1f\xa2\x8d\x5c\x33\xaf\xb2\xec\xb9\x8c\xc5\x4c\x28\x84\x02\xc9\x79\x56\x8a\x1d\x05\x7f\xde\xbd\x4a\xd8\x43\xab\x87\x7f\xe2\xf1\x23\xb2\x45\xbc\x7f\x67\x8f\xc8\xbb\x5d\x94\xe6\xe5\xbd\x44\x5b\x6c\xa4\x75\x67\x12\xa9\xfd\xcc\x35\x69\x13\x7a\x34\xec\xdd\x1d\x1f\xff\x1f\xa6\x44\xee\x6f\xd7\xa8\xfe\x43\x16\xb8\x4b\x7b\x21\x77\x73\x80\x08\x6f\xdf\x47\x6f\xcb\x19\xfa\x85\x45\x1d\xd8\x26\xe3\x6b\x09\xc8\xdf\x38\x17\x0b\xe9\x22\x4a\x5e\x2d\x4d\xb5\x40\x1f\x48\xec\xa7\x63\x9e\x5f\x34\xfa\x2b\x5d\x98\xdf\xcb\xac\x49\xf5\x47\x95\xad\xe0\x78\xf2\x6f\x6c\x4d\x5d\x4b\xd0\xb5\xd3\x2b\x5e\x7b\x72\xd0\x21\x5a\x17\x86\x83\x0a\xb3\x35\x6a\x5a\x71\x68\xf2\x63\x8c\x15\x1c\x8f\xe8\x95\x6a\x4b\x2d\x20\x7f\x0b\x53\xe9\xe6\x06\xd3\xd6\x2b\xab\x99\x6c\xa8\x1a\x18\xa1\x94\x33\x77\x44\x2d\xb7\xf6\x7f\xe7\x2e\x02\x80\x54\xef\x0a\xf4\x5b\x39\x18\x7b\x83\x21\xed\x89\xe8\xdc\x5f\x38\xf6\x0c\x95\xbb\x6b\xd4\xfe\x3e\xa8\xfc\xe7\x3c\xfb\x8e\xb3\x7b\x9b\x61\xd3\x75\x1b\x28\x7d\xf8\x4b\x93\xeb\x1a\xd0\x7a\x56\xfc\x8b\x84\x35\xfa\xf8\x9b\x84\xc2\x05\x6a\x7a\xff\x8b\xfd\xf1\xb7\x9f\x87\xcf\x16\x1c\xe6\x82\x05\x39\x41\xcb\x60\xce\x92\x4c\x7c\x44\xd0\xc2\x8c\x57\x13\xa3\x10\xa8\x39\x3e\x8a\x1f\xd0\xdf\x31\x42\x13\x97\xae\xd5\x41\xb0\xf1\x5f\x90\x16\x73\x8a\xa0\xd3\xf3\x21\xc6\x05\x93\xaa\x6c\x04\x4e\x75\x35\x95\x9f\x00\x54\x4d\xa9\x54\x72\x9d\x82\xe8\x93\x2c\xbd\xcc\xfe\x25\x04\xc6\x94\xa1\x58\x45\x2e\x45\x2c\x23\x2e\xe8\x41\x39\x94\x84\x27\x4b\x47\x48\x51\x97\x9a\xfa\x5b\x57\x53\x7f\xb3\x9b\xfa\x9b\x6e\xea\x6f\x7e\x53\x27\xe5\x2a\x04\xf8\xe9\x5d\x00\xdf\x07\x22\x48\xdf\x05\xc6\x77\x77\xcd\xfd\xc7\x60\x5e\x1f\x94\x73\x7c\xdc\x58\xa3\x50\xc7\x26\xf2\x4f\xec\xa4\x29\x69\x5e\xce\x9c\xb4\x4e\x78\xdd\x02\xe3\x2d\x50\x2e\x03\x6b\x9e\xff\x0c\xb2\xe9\x58\xdb\xdd\x23\xec\xff\xe4\xfd\x1b\x66\x9a\x60\x49\xd1\x76\xc0\x0f\x9b\x9a\x0d\x31\xd5\xf8\x05\xc5\x2f\x69\xea\xa6\x42\xf5\x33\xe3\x49\x01\x4f\x59\x32\x42\x3e\x35\x75\x40\x53\xe5\xfb\x9c\xbc\xe5\xbf\x94\xca\xf1\xda\x57\xab\xe1\x4e\x11\x14\x6f\x6e\x94\x1e\xfc\x5f\xa9\x25\x29\x6a\xe1\x10\x16\xf9\x22\x7c\xc0\x39\xef\xe6\x26\x78\x0d\x6c\xdd\x99\x96\x06\x6c\x90\x8e\xfb\x0f\x12\x4a\xb5\x04\x1e\xd9\xa2\x49\x83\xf8\x85\x73\x14\x56\x90\xe5\x22\x7a\x0a\x79\x69\x65\x1d\x66\x43\x2b\x2d\x26\xff\x83\xf0\x2b\x88\x67\x38\xc7\x69\xf2\x6f\x76\x93\x7f\x0b\x34\xe9\x14\x08\xe4\xeb\x1e\xff\x27\x9f\x1c\xfa\xfd\x56\x05\x70\xfc\x23\xc4\x37\x3b\x47\x33\xb2\xb5\x4a\x2b\xa4\x92\x83\x6e\x0e\x5a\x1c\x61\xd3\xb6\xf3\x65\x4e\x2e\x6c\x03\xac\xbc\x1c\x7c\xe7\xef\x37\xd0\x07\x8a\x02\x8f\x43\x89\xda\xae\x39\x0e\xe5\x62\xb8\x44\xf6\x67\x91\xd7\x6f\x0a\xdb\xa6\x13\x83\x0e\xfb\x89\x18\x1d\xa5\xc3\x2a\x59\x0a\x14\xdc\xe2\x2d\xbd\xe9\xbd\xbd\x60\x67\x1d\x46\xbf\x14\x25\x41\xa4\xa2\x16\x6b\x74\xc1\xb0\x27\x99\x67\xa7\x6a\x5f\xba\xdd\x9a\x8a\x85\x15\x2e\xb0\x35\x99\x91\x98\x1a\xf6\x5d\x6f\x09\x5a\xc6\x8e\x48\x37\x59\x9e\x1c\xa7\x4b\xac\x62\x02\x0c\x62\xe3\xe4\x65\x59\xf7\x42\x06\xdf\xdc\xc4\x66\x4a\x8f\x75\xab\xc1\xf5\x06\xe3\xec\xf5\x5a\xf9\xba\x95\xae\xb5\xde\x68\x2f\xcd\xc2\x19\x5f\x47\x9c\xe7\x2e\xa8\x11\x00\x87\x93\xe2\xa9\xf6\x46\x6a\xf9\x84\xa0\xe0\x05\x7a\xf0\x1e\x1c\x60\x3c\x96\x72\xf8\xfe\x4f\x9f\x5e\x7d\xfc\xe7\x57\x2f\xbf\xbc\xfa\xf8\xf1\xfd\xc7\x20\x8c\x61\xc1\xca\x5a\xc2\x63\xfb\xc3\xe0\x9f\x01\x1f\x3d\x35\x6d\x8c\x25\xd3\xd1\x58\xd2\xea\xd7\xac\xb0\xbb\x53\xc5\xc1\x58\x2d\x74\x0e\x0b\xbd\xd9\x48\x9b\x7b\x7f\x95\x64\x68\xbc\x00\xa0\xec\xb0\x7e\x80\x2c\x27\x95\x59\xbf\x4a\xad\x1f\x46\xa5\x6e\x30\xf4\xa5\x3c\x98\xfe\x4c\x2a\x5e\xdb\x1c\xa1\xac\xde\x6b\x4f\x0a\x6d\xd5\x68\xb4\xfa\x87\x85\xac\x6b\xbc\x05\x2d\x58\xa3\xb0\xd3\x6d\x38\xab\xcc\x02\xac\x69\x01\xb6\x9e\x77\x58\x9e\x52\x85\x4f\xad\x84\x3b\x9a\xf8\x3a\x64\xa6\xd7\x76\x4d\x76\x7f\xbb\xcc\xdd\x42\x7c\x80\x16\x3e\x17\x64\x14\x96\xcd\x98\x4a\xfc\x50\xd6\xb9\x94\x97\xa2\x5d\x85\x4f\x8b\xc6\x23\xe1\x13\x95\x90\x54\x65\x17\xc0\x97\xcd\x39\x89\x44\x81\x75\x5b\xc6\x55\x48\x23\xbd\x01\x60\xf6\x56\xbb\x70\x96\x7f\x88\xaa\x45\xb0\x42\xf2\x55\xcb\x34\x63\xfb\xb8\xe1\x1e\x26\xc1\xc4\x83\xbb\x08\xef\x89\x76\xa9\x14\x69\x32\x10\xec\x7d\x3f\xf3\xa9\x12\xdf\xb3\x38\x6c\x95\x9b\xd4\x98\xc0\x0c\xfb\xfb\xe5\x31\x86\xf8\x59\xd7\xf3\x21\x6c\xf5\xe2\x8a\xfd\x84\x00\xbb\x5a\xa8\xf4\x3e\x7f\x97\xc7\xa7\xd9\x19\x8a\xc0\x00\x48\xd0\x71\xc9\x29\x14\x74\xdc\x32\x87\x1d\xeb\x15\x5d\xdb\xff\x60\x77\x49\x92\x8d\x9c\xc6\x80\x85\x46\x14\x85\xb7\x34\x91\x09\x4a\x38\x49\x4d\xd2\x6f\x0e\xb2\xa1\x92\x0c\x3c\x6f\xf0\x91\xe1\xbf\x55\x50\x1c\x0e\x77\x03\xbf\xb4\x87\xa8\x9b\xe2\xe9\xd3\xf1\x23\x39\xf4\x47\x0f\x1f\x1e\x8d\x03\x11\x83\x1e\xb4\x24\x46\xee\x88\x2c\x4e\x6c\xb5\x48\xa7\x59\xbf\x12\x6e\x71\xed\x8f\xaa\x29\x3f\xe3\x19\x7a\x81\xee\x11\x06\x1b\x45\x36\xdd\x3b\xec\x0f\x07\xf7\x2e\x43\x3d\xef\x2e\x01\xb2\x22\x3e\x99\x81\x94\x22\x5a\xd6\x87\xe8\xd3\xdf\xda\x9c\x69\xba\xcc\x10\xd7\x11\x55\x76\xef\x5f\x0f\xa1\xc4\xbd\xf6\x2e\xe9\x52\x31\xcc\x9f\xc6\xd2\xe2\xfb\x7d\x88\x54\xeb\x00\x84\xf2\x71\x46\xfc\xec\xde\x28\x46\x43\xcd\xe3\xbd\x31\xfc\x6d\x06\xc7\x54\xd0\x8a\xfe\x4f\xa2\x6f\x19\x94\xfd\xd8\xfc\x64\x67\x38\xe8\xf3\x1c\x4a\x2a\x8a\x5a\x9d\x97\xe3\xbd\xbd\xfe\xf8\xd1\x7e\x67\x7e\x1f\x23\x1f\x42\x87\x80\xe7\x6c\x88\x24\x23\x2f\x0a\xfc\x1e\x02\x49\x93\x0b\x30\x49\xb4\xd8\x83\x16\x0b\x18\x5a\xed\xbd\x3d\x98\xad\xe5\x6b\x5f\xb9\x90\x08\xba\x0f\x42\xdb\xbe\x88\xc1\x54\xda\x15\xef\xa1\xbd\x71\x43\xa2\xe2\x6f\xe9\x82\x12\xb1\x8c\x74\x49\x6f\x85\x07\x44\xaf\xed\xa8\xe2\x03\x9d\xf9\x47\x1a\xba\x42\x0c\x9f\x65\x54\x1d\xbe\xf2\x26\x5b\x72\x53\x9e\xb9\xac\x15\x9a\xe2\xb8\x15\x72\x20\x1b\xd6\xe4\xc3\x06\x4e\x37\x4a\xa8\x30\x58\x9e\x65\xbf\xda\x94\xcf\xd9\xbb\x7e\x1b\xb3\xa9\xac\x78\xfc\xf8\x57\x5a\xb8\xdd\xf9\x3b\x25\x21\x29\xa5\x34\xfe\x75\x8a\xf2\x74\xc2\x53\x45\xa2\xfc\xcb\x32\x31\x7d\x8d\x6f\x03\x8b\x94\x43\xa1\xb2\x67\x94\xd7\x80\xf2\x3e\xa4\x97\xc6\x2b\x5b\x74\x90\x19\x3f\xfa\x7f\xcd\x17\x8b\xcf\x1c\xfb\xd4\xc6\xec\x39\x7a\x78\xdd\x48\x8f\x9e\x21\x37\x86\xb6\x23\x39\xf4\xb6\xe6\x85\xf1\xf3\x9c\xe7\x01\xc8\x65\x3b\x7b\xd1\xdb\x8a\x15\xbb\xda\x8c\x59\x93\x20\xe4\x59\x2d\x80\x48\x5b\xac\x5c\x68\xb9\xb3\xe1\x92\x2e\xf7\xa9\xf1\x94\x07\x47\xf6\x74\x7c\x06\xf8\xe9\xb7\xf2\xbb\xc6\x4f\x36\xf4\xa8\x67\x94\x2a\x59\x4f\xea\xfe\xde\xde\x5a\x05\x6a\xc4\x76\x81\x82\x2d\x81\xde\xe8\xcb\xe8\x33\xc8\x21\xe6\x05\x30\xc3\x7f\x3e\x79\xfb\x5b\x32\x85\x86\x0f\xb2\x83\xe9\xe9\xd1\x99\x26\x8c\x16\x90\x3a\x3a\x9b\x2c\x0e\x0f\x27\x83\x0a\x76\x1a\xb6\x98\x63\xdd\x32\x59\x6b\x57\xcf\xa8\x9f\x15\xfb\xad\x91\x0b\x50\xff\xe9\xea\x24\xbd\xa4\x60\xcd\x51\x3d\xad\xf2\x15\xae\xe8\xca\x44\xb8\x47\x04\x22\x72\x20\x93\x87\xd0\xe1\xab\x14\x63\x8b\x58\x54\xd9\x45\x92\xf7\x01\xb8\xb0\x3b\x3c\xf1\xe8\x2f\xd0\x0c\x00\xc6\xe3\x84\xd5\xb5\xb2\xf4\x6a\x5d\x38\x96\xdd\xa4\x48\x97\xa3\x61\xff\xb7\xbc\x2a\x0b\x77\xcb\x19\x84\xe9\x80\x60\xd8\x4d\x47\x86\xce\x4e\x07\x91\x22\x34\x16\x91\x36\x5f\xb7\xc6\x73\x91\x16\x9f\xeb\xec\xe5\xfb\xb7\xc7\xda\xea\x9e\x9b\x54\x66\xf4\xd1\x2c\xff\x16\x0d\xa4\x90\x07\xb0\xf9\xdf\xeb\x7f\x7a\xda\xff\xfb\xf7\x83\xc1\xbd\xc9\x7f\x6e\x1d\xd5\xe0\x58\xe3\x47\xa4\x34\xe3\x8f\x14\xd0\xfe\x43\xd1\x1a\x28\xd0\x2a\x1d\xf1\x31\x1f\xb4\x78\xd7\x10\xbe\x6c\x63\xca\x63\xf9\x36\xf5\x35\xbb\x42\x67\x0a\xc3\x8b\x7c\x01\xd8\xd0\x78\x26\xb6\xee\x15\x0c\x4d\x3c\x18\x62\x74\xc0\x7e\xd4\x83\x49\x33\x0e\x33\x6f\x72\x98\xc3\xd4\x6e\x2a\x1f\xc4\x6a\x81\x05\x37\x81\x8b\xf5\x2e\x4a\x1e\xea\x01\x91\x69\x2c\x74\x0d\xd7\xf2\x19\x84\x89\x64\xce\x4d\xf2\x22\x15\x35\x25\x92\x0a\x12\x79\xfd\x2e\x7d\x67\x91\x5a\xd5\xcd\x0d\x6a\x1e\x42\xa5\xd2\xd7\x86\x40\xfc\x8f\x61\x4d\x8f\xa3\xe8\xa0\x89\x75\xdc\x11\xd3\x11\x7a\x94\x4c\x80\x92\xa8\xf2\x25\xb0\x1a\xa2\x39\x88\x56\x3f\x22\x37\x8a\xc0\xa7\x4f\x96\x7b\x1d\x54\xf6\xcc\x6b\x74\x29\xb2\xc8\xea\xfa\x1d\xdd\x2c\x6d\xec\x63\xd7\x89\x1f\x10\x39\xfa\xb0\x45\x8e\xfa\x92\x20\x0e\x61\xa4\x54\xd3\x36\x41\xcd\x06\xd7\xc0\xb5\xdd\x71\xf0\x65\xd2\x57\x9b\x7a\xd8\xa2\x0f\x83\x94\x4f\x1b\x9b\x67\x1b\xd7\x27\xe4\xa6\xb2\x5f\xb9\x13\x7e\x40\x75\x5f\xbd\x01\xa1\xa1\x0f\xf0\xca\x7f\x2e\xc7\xf4\x91\x97\x8e\x6a\x15\x90\xce\xfe\x8c\xdd\x1a\x70\x89\x24\x61\x27\xb9\x1b\xb7\xa4\x7a\xbb\x0d\x39\xf4\xcc\x36\xa2\x6d\xe3\xfd\x70\xfb\xfb\xe5\xb7\xee\xc8\x97\x0f\x7f\x82\x9a\x44\x58\x0c\x92\x11\x7d\x00\x50\x38\xae\x8a\xd2\xcc\x95\x14\x10\x78\xc1\x68\x3f\x8a\xa3\xfd\x74\xb9\x9a\x44\x22\x7a\x86\xbf\x2f\x1b\xfc\xf9\x14\x7f\x2e\xf0\xe7\x2f\xd1\x2f\xf0\xf3\x1f\xeb\x92\xd2\x7f\xc1\xf4\xff\xf2\xe3\xe8\xd7\x49\xb4\x01\xc4\x79\xef\x74\xff\xd9\xd3\xe8\x97\x33\x87\x22\xd6\xb3\xbf\xeb\xeb\x93\x3c\x18\xc8\xf8\xb6\x54\x8f\x0a\xba\xaf\x72\xe5\x41\x44\x1e\xf4\x14\x79\x6f\x79\xda\x26\x69\x62\x8e\x60\x52\x1f\x97\x48\x9a\x2a\xfa\x4c\xa6\xe0\x49\x1d\xc4\x8d\xa8\x50\xcc\x90\x06\x7c\x94\x78\xbc\x59\x26\xc5\xcb\xb0\x47\x2a\xa4\x05\x07\xb2\x85\xd3\xbc\xb9\xf6\x7d\xa7\xb3\x57\x58\x43\x61\xc8\x8b\xa5\xa9\x52\xf4\xbf\x84\xfc\xba\x8e\xac\x3e\x98\xb8\xa7\x6d\xd3\xba\x00\x02\x2d\xc6\xe3\x23\x7a\xe4\x0f\x35\x08\xe7\xef\x71\xf0\x3c\xde\x25\x72\x29\xca\x17\x32\x36\x36\xe8\x2b\xb1\x42\x83\x62\x85\x00\x80\xee\xe2\xbe\xc0\xd7\x68\x0f\x50\xb2\xfa\xd6\x87\xfc\x18\xd9\x11\xbe\x15\x0a\xf2\x82\x1b\xe8\x76\x1b\xd5\xc4\x13\x50\x9e\x41\xd5\x25\x9c\xda\x9e\x24\x6e\x6e\x74\xfa\x79\x39\xbb\x92\x73\x34\x67\xc8\xcd\x0d\xcd\x7b\x77\xe5\x48\x49\xc3\xa1\xfc\x4d\x3d\x0f\xab\x77\x45\xc5\xee\xb2\xe4\xba\x8f\x74\x9e\x4a\x12\x74\xdd\xec\xef\x8f\xef\x63\x38\x6d\xba\x42\xc6\xf7\x81\x4d\x6a\x00\x05\x36\xcf\x92\xfb\x47\x37\x37\x94\xd5\x1c\x37\xf1\x28\x34\xc0\xbb\x04\x65\xa0\x47\x15\x18\x9b\xa6\xee\x4f\xe9\xf3\xec\xe6\x86\xfe\x52\x70\x32\xb8\x8f\x66\xb0\x22\x14\x56\x16\xe3\xdc\x99\xe7\x14\xf4\x3d\x14\x78\x37\x57\x77\x70\x65\x85\x92\xe4\xd9\x1c\x47\xa4\x69\x1e\xc5\xec\xae\x9f\xde\x34\xd5\x33\x37\x9c\xf0\xcd\x1d\x1e\xf5\xf3\x53\xbd\xa8\x30\x5a\x77\x90\x71\x14\xd9\x97\x6c\x40\x65\x02\x30\xdf\xab\x7a\x1a\x47\xaf\xc8\xe1\x71\x24\x3e\xad\x00\x31\x9e\xa7\x55\x0c\x34\x88\x20\x51\x54\x04\x30\x5a\x7e\xc7\x9f\x91\xf8\xbc\x92\x9f\x9f\x57\x91\xf8\x98\x5f\xce\x55\x36\xfd\x8e\x04\x69\xf2\x73\x0a\xfe\x84\x84\x6c\x11\x47\x2f\x29\xa6\x79\x24\xfe\x9a\x43\xe6\xfb\x4f\x91\x20\xd3\x80\xc8\xb2\x13\x88\xc4\xf3\xd5\xaa\xf6\x92\xa4\xe2\x7a\x24\xc5\x57\xe5\xf4\x2b\xd4\x2c\xff\xfd\x03\x2c\x18\x39\x9d\xc1\xc7\x40\x77\xba\x88\x88\xaf\x1f\xc7\x11\xba\xab\xae\x71\x22\x91\x78\x12\x47\x27\xe9\x79\x24\xc6\x47\xd0\x3a\x90\x3f\x15\xfc\xbc\x1f\xcb\xd5\x17\xe3\x47\xd0\x3c\x3e\x2c\xc2\xcf\x5f\xb9\x7b\xe8\x0b\x3e\xa0\x91\xe7\x0b\x4c\x85\xfa\x1f\x52\x00\x9b\x48\x1c\x8d\xa0\x40\xba\xaa\x79\x20\x47\xbf\x9a\x35\xbb\x7f\x44\xab\x75\xff\x3e\x96\xbd\xcc\x70\x6d\xee\x3f\xe0\xdf\xbc\x0a\xf7\x1f\x62\x8f\x33\xf8\x01\xfd\xfd\xb9\x5c\x62\x9d\x5f\x9d\x85\xbd\xff\xd8\x5a\xd8\xfb\x4f\xdc\x55\x7d\x30\x72\xd6\x14\x98\xfc\xe8\x4d\x51\x67\xe8\xb4\x0d\xf8\x56\xbd\xbc\x18\x1d\x3d\x7a\x3d\x8e\x28\xce\x74\xf4\xfa\x28\xa2\xb0\xd1\xd1\xeb\xfb\x11\x85\x6d\x8e\x5e\x3f\x88\x28\x92\x59\xf4\xfa\x61\x44\x41\xa7\xa2\xd7\x8f\x22\x8a\xaf\x12\xbd\xfe\x35\xa2\x20\x26\xd1\xeb\xc7\x11\xc5\x5c\x88\x5e\x3f\x89\xc8\x71\x3b\x34\x38\x8a\xc8\xe5\x35\xfc\xc2\xb6\x8f\xb0\xed\x31\x36\xfe\x00\x1a\x07\xd2\x8c\xd7\x03\x45\x0f\xce\x4e\x1d\x1d\x41\xf6\xdb\xac\x49\x23\x1f\x7b\x75\x69\x76\xe0\x99\x7d\x74\x97\x70\x0f\x46\x5a\x2d\xf0\x29\xd3\x56\x61\xc4\x0b\x6c\xe8\x3f\x12\x6b\x7b\x95\x56\x0e\x9e\x4f\x3e\x27\x48\x3a\x68\x8a\xf7\x78\x6f\x0f\x83\x53\xa3\x54\xc6\xa1\xc8\x1c\xf6\x1a\x4e\x10\x80\x4a\x1c\xf1\x33\x76\x24\x24\x10\xc5\x91\x7c\xbe\x46\x70\x6f\xd2\x38\x92\x4f\xdb\x00\xd7\x08\x70\x71\xa4\x1e\xb4\xa3\x90\x4f\x9c\x47\x77\x11\x2e\x2a\x06\xb9\x91\xca\x14\xb6\xee\xc4\xcd\x0d\x8b\x83\xd5\x9c\x08\x61\x6a\xc9\xcc\xb1\x2d\xd7\x8a\x9b\x00\x12\x7d\xb4\x9b\x18\xb1\x04\xee\x3a\x1f\x88\x55\x9b\x33\x40\xdd\x8e\x24\xfa\x27\x64\x22\x83\x99\xb9\xc5\x36\x43\x31\xc4\x6b\xc7\xd1\xd3\x45\x5e\x7c\xed\xdd\x43\x32\xec\x29\x85\xaf\x7e\xf6\xf4\x1e\xff\x8d\x44\x0a\x3b\x94\xec\xe5\xc0\x73\x55\x8a\xc7\xa5\xb4\xe3\x15\xfc\xc7\x2f\x2b\x16\xca\xeb\xe0\x74\xcb\x36\xe7\x9a\xa3\xf0\xe6\x2e\x9c\x6b\x9a\x5c\x4f\xf3\x6a\xba\x40\xeb\x4e\x54\x22\x46\x77\x03\x22\x5b\x2c\xf2\x55\x4d\x49\xe8\xa0\x44\xa0\x7b\x41\xf5\x37\xad\xfe\xbb\xf4\xdd\x88\x29\xab\xb4\x99\xd3\xdf\x72\x71\x75\x89\xcf\x87\xfc\x53\x55\xc0\x92\xe9\xc2\xae\x50\xa1\x3b\x32\x7c\x41\x69\xc8\x99\x04\xbb\xa2\xdb\x1b\x6d\x80\xf2\x3b\x1d\x8b\x5f\x9e\xb2\x7b\xb3\xde\x72\xbd\x68\xf2\xd5\x02\x16\x9d\xdc\x75\x3d\xfb\x45\x60\x4c\x00\xca\x7b\x16\x61\x94\x63\x28\x1c\x3d\x25\x0c\xfa\x0c\xe9\xdb\x7b\xf2\xe7\x19\xb0\xe2\xa7\xf7\x75\xd6\xd3\x06\x2f\x7e\xf8\x53\xc9\x52\x15\xec\x81\x4c\x33\x55\x16\xdc\x5a\xfd\xed\x92\x4b\xd1\x8f\x33\x0c\x91\x06\x7b\x19\x63\xde\xf1\x53\x58\x32\xce\xa4\x1f\x67\x02\x00\x2e\xa5\xac\xa7\xcb\x74\xc5\x39\xf4\x03\x06\x00\xc7\xe6\xf4\xa8\x35\x04\xd5\x2d\x64\x5f\x56\xe5\x5a\xd6\xd1\x5f\xf6\x70\xb2\x4b\xf4\x5c\x48\x8d\xc3\xe1\x5e\xcc\xea\xac\xe1\xd2\xe6\x0b\x46\x97\x56\xe9\x92\x0b\x31\x67\xcf\x45\xd4\xef\x33\xd1\x54\x81\x61\xf0\x2a\xf8\x0b\x50\xae\x1a\x1a\x45\x5c\xe3\x4f\x7c\xd7\xad\xc9\x0e\x18\x7f\xad\x85\x1a\x23\xfc\xa4\x9a\xf8\xf7\xa2\x2c\x1b\xfc\x3b\xcf\xd2\x19\xfe\x9d\xc5\x53\xf8\x80\xff\x24\x30\x2d\x18\x96\x16\x1a\x94\x16\x00\x49\x0b\x06\xa4\x85\x0f\x47\x0b\x06\xa3\x85\x86\xa2\x85\x01\xa2\x85\x0f\x43\x0b\x06\xa1\x05\x43\xd0\x82\x01\x68\x11\x40\xcf\xdb\x44\x2e\x6d\x21\xca\xa3\xbb\x70\x68\xe4\xef\x19\xa8\xdb\xcc\x3a\xbf\x93\x41\x96\x38\xdf\x9a\x93\x74\xb9\x12\xae\x3b\x91\xc4\x5a\x01\xa3\xff\x94\x9f\xa3\x5a\xb1\x51\x84\xb1\x12\x27\xd8\xa8\xc1\x6e\x1b\x2f\x72\x81\x79\x93\x91\xe2\xc0\x3c\x19\x51\xcc\xf0\x92\x3b\xb8\x8f\xcf\x94\x0a\x4f\x52\x4a\x9a\xe4\x07\x25\x79\x7e\x94\xee\x50\xa5\xec\x0e\x89\x51\x60\xc7\xd2\x67\x9a\x20\xbc\xa6\x30\xaa\xa5\x72\xae\xdb\x1c\xe6\x9b\x49\x0e\x5c\x16\xf6\x84\xbe\xe4\x06\x36\x3d\x5d\x2a\x4c\x7b\x17\xa7\x9f\x6a\xc2\xc7\x46\xca\x8e\x86\x99\xa8\x35\x22\x11\x97\xa5\x2f\xa7\x17\xd6\xc6\x8e\x4f\x02\x3c\xc5\xa3\x9d\x59\x24\xfd\x94\x50\xee\xef\x5b\x68\x13\x88\xf4\x32\x89\xac\x25\x42\xb2\x5e\xa3\x52\x6f\x68\xc7\x4e\xc1\x38\xa2\x7b\x00\xf9\x3c\xc4\xcf\x3b\xe1\x70\xd6\xce\xdf\x15\x7a\x69\x86\x77\x91\xf3\xab\x45\x86\x95\xe5\x4b\xf4\xf8\xfa\x87\x32\x33\x23\x85\x42\xf6\x3c\x6a\x71\x52\xde\x0c\xa5\x95\x36\x92\x78\xe2\xca\xae\xf9\xb7\x1d\x6b\xa2\x32\x61\x0c\x9d\x66\x6e\x4b\x99\x95\x1d\xba\xb3\x6f\x11\xa8\x07\x9e\xfe\xa2\xc3\xff\x3a\x8e\x06\x9e\x28\x5d\x3e\xf4\xf5\x4f\x9f\x1f\xfe\xcf\xb3\xf0\x5b\xdf\xa3\xbb\x30\x81\xe6\xad\x6f\x60\x3f\xf6\x1d\xd2\x6b\x9f\xbd\xe1\xf3\xab\xd5\x3c\x2b\x58\xa9\x10\x5f\xfb\xc2\x8f\x7d\xa6\x54\x0c\x53\xa6\xd1\xfc\x84\x80\x54\xbf\x95\x24\x2d\xb1\xa5\x64\xb0\xd4\x9b\x8e\x0a\x8d\xf6\xba\xac\x4e\xd2\xcb\x3e\xe7\x0a\x19\x42\x07\xda\x8b\x31\x94\x0d\xa7\xf6\x65\x2a\x1a\x7c\x68\xa3\x0b\x7a\x21\xda\x48\xd9\x8e\xef\x44\x2f\xf4\x02\x63\xd2\x7e\xcb\x2e\xd3\xe9\x55\x28\xe7\x1d\x11\xbd\x96\xac\x45\xca\x53\xb8\x29\xb4\x8c\xb0\xf2\x36\xe1\x07\x9c\x50\x1c\x38\xaf\x6a\xfc\xc4\x3c\xe8\xb8\x83\x89\xc7\xa3\x07\xa2\x6b\x34\x90\x19\x94\x8d\xfe\xba\x9d\xcc\x0f\xc9\x4c\x8c\xf6\x11\xbb\xd0\x95\x74\xef\x9a\x42\xa1\x63\xa0\x11\x92\x16\x0c\xd6\x89\x15\x68\xfe\x6d\x5e\x10\x63\xd8\xcb\x7e\x4c\xb3\x15\xe3\xfe\x29\x29\x3f\xcc\x26\xbd\x35\xa9\x22\x65\xbd\xa2\x2c\x0e\x97\xaa\xe0\x2c\xfb\xd6\xcb\x0c\xda\xe8\xc1\x1d\x41\x85\x2e\x00\xd3\xf4\xc8\x19\x45\x6f\x89\xe1\x5d\x2e\xb3\x5e\x5a\xcc\x7a\xe9\x6c\x46\xcf\xb7\xe9\xa2\x37\xcf\x16\x2b\x28\xd5\x93\x53\xad\x87\x28\xd9\x5a\xd4\x99\x0c\x44\x7f\x6a\x4d\x00\xc9\xa6\xd1\xc4\x19\xe9\x1b\x75\xab\xf6\xfe\x39\x2f\x17\x6c\x87\xd0\x8b\x0e\x1a\x7d\x4e\xee\xfd\xb7\xfa\xde\xa5\x68\x0b\x67\xa7\xa7\x8b\x83\x83\xb3\x0d\x5c\x29\xcd\x1c\x38\xc4\xde\x7a\x78\x51\xa1\x97\x92\x93\xf2\x43\xb9\x4a\xc6\x62\xbd\x09\x09\x8f\x7e\xbd\x8b\x15\x0c\xaf\xb7\xf5\xac\x73\x73\xd3\xd0\x2b\x30\xcc\x9e\xb8\x2d\x15\x1f\xcc\x46\xf6\x56\x9c\x79\xde\xcd\xa8\x2c\xf0\xa9\x33\x4f\x8a\x9e\x55\x8c\xdc\x2b\xe4\xca\x96\x72\x2b\xd1\x3d\x49\x31\x3a\xae\xf6\xc5\xde\x2f\x30\x46\x38\x76\x31\x21\xe2\x3d\xf0\x74\x8d\x2a\x54\x52\x92\xb2\x07\x17\x74\xb5\xbf\xcf\xaa\x92\xc4\x64\xc0\x55\x95\x9b\x0e\xf3\xe5\x8a\x3b\xa3\xa5\x47\x46\xe5\x35\x8c\x80\x02\x5a\xb0\x93\x08\xd6\xa8\x04\x1a\xf0\xfe\x70\x84\x51\x62\x72\xc6\x57\x62\xeb\x83\xda\xa4\x74\xae\xc6\xaa\xab\xbf\xfd\xfd\xdb\x07\xb2\x4b\x99\x7e\x04\x03\x8c\x06\x7b\x49\xc2\x11\x33\xef\x70\x31\xfe\xba\x13\x9f\xb7\x07\xe7\xee\xe6\x66\x2f\x14\xa6\x02\x69\xac\x63\x27\x18\x3f\xf1\x94\xed\xb7\x33\xa3\x2a\x90\x84\x54\x05\x02\x58\x18\x33\xf1\xdd\x74\x10\x7a\x14\xfb\xf5\x27\xde\x07\x48\xfd\xe1\xcd\xbb\x0f\x9f\x4f\x58\x8e\xa6\x3a\x00\x18\x39\x65\x04\x8e\x92\xb4\x93\x57\xff\x72\xf2\xfc\xe3\xab\xe7\x6e\x19\x75\x51\x5d\x93\x4f\x7a\x62\xfd\xd2\x26\x53\x7f\xd1\xc4\x14\x7f\x47\xea\xe3\x90\x0c\x81\x22\x62\x0d\x97\xa8\x2c\x0d\x3f\x96\x40\xf2\x10\xeb\x27\xe3\xf9\x13\x33\x58\xd7\xdf\xcb\x6a\xc6\x9c\x1f\x3a\x27\x46\x46\x0f\x28\xfd\xe9\x9c\x59\xbd\x85\xc5\xf1\x09\xd5\xcb\xba\xa2\xe4\xef\x59\x46\xae\x36\x43\x07\x7d\xab\xfe\x8b\x73\x25\xef\xef\xdf\x57\xf3\xc4\x9d\x70\xf5\x50\xba\x75\x50\x94\xfe\x09\xa9\xdb\xfc\x7a\x17\x19\x7b\xc6\xa2\x81\x48\x86\x86\x15\x45\xa2\x5f\x40\x95\x5e\x14\x8a\x71\x9e\x8d\x75\xbc\xac\x2a\x19\x4f\x8a\x67\x15\x29\x1e\x36\xa6\x34\x6a\x1e\x52\xe8\x2a\xb8\x55\x8f\xb3\x83\xa8\x87\x72\xcf\xc1\x81\x79\xba\xcc\x42\x70\xb3\xb3\xd7\x61\x57\x6d\xb9\x65\x2a\x83\x0a\x7c\x9b\x09\x7c\xdb\xb0\xcf\x2f\x84\x80\x25\x7d\x41\x3f\xbf\xe8\x4b\x2b\xd3\xcc\x97\x88\x34\xe8\x48\xbb\x42\xc3\x53\xeb\xdd\x35\xa0\x98\xd7\x66\xc2\x7e\x6d\xd1\x7c\xfe\x25\x2a\x87\x6b\xf7\x4f\x7c\x54\x6b\x08\x46\x1d\xcf\xf2\xef\x12\x04\xae\xbb\xba\x47\xe0\x7b\xdb\xf7\xa5\x53\xe2\xfa\xa9\x2d\xce\x79\x64\x52\x5b\x1f\xee\x0b\x5c\x91\xf2\x34\x3f\x4b\xcc\x7b\x08\x7c\xc1\x45\x8a\x6b\xa9\x9f\x71\x19\x3a\xe4\xbb\xac\x79\x5c\x77\xe7\x16\x9a\xc2\x5d\xde\x08\xfc\x17\x30\x5d\xb1\xb0\xb4\xe5\x5a\xaf\x75\xc7\xa8\x5b\x1c\xe3\x7f\x89\xad\xd6\x5a\x0c\x42\xa4\xfb\xe3\xbb\xc8\x3f\xe1\xd4\x02\x84\xdd\x3b\xfd\xd7\xf4\xf0\xdf\x47\x87\x4f\xbe\x9c\xdd\x03\xee\xb4\xa6\x68\xcb\xbf\x43\xaf\xf1\xf1\x5d\x44\x8f\x5a\xfc\x57\x05\x42\x3e\x8b\xac\xa5\x7f\x64\x48\xd8\xb6\x04\xae\x43\xbd\xe8\x56\xfd\xa1\xc7\x3b\xbc\x2d\x8b\xad\xac\xe4\xc4\x65\x61\x0b\x15\xcc\x42\x2a\xde\xe3\x99\x56\x72\xd4\xe1\x12\xed\xcf\x5b\xa9\xdf\xb3\xf3\xaf\x79\x63\xe5\x38\xd7\xef\xcd\xcd\xf5\xe6\xf6\x2b\xf8\x71\xeb\x26\xb3\x90\x90\x35\x14\x18\x2f\x50\x0c\x05\xba\x2f\x00\x0c\x5a\x24\xe8\xcb\x40\x89\xaf\x29\x75\x78\x0e\x83\xc2\x77\xe2\x16\xde\xb0\x5b\x01\x5a\x9c\x70\xf6\xe3\xed\x72\x07\xdb\xfd\x7a\x98\x0f\x07\x16\xf1\x5f\x4f\x7b\x7f\xaf\xfe\x5e\xfc\xbd\xf9\xfb\xc5\xd9\x3d\x64\xd9\x9e\xf6\xf7\x0e\x0f\x6f\x50\x8a\x7b\x53\x94\xac\xed\x74\x83\x02\xf0\x1b\xf9\xbb\x6e\xae\x16\xd9\xc0\xd4\xfa\xfb\xbd\x67\x50\x31\xf7\x4c\xe0\x33\x4b\x36\xdc\x6c\x58\xa8\xaf\x37\x6a\x57\xa2\xd1\x12\x2f\xf7\x90\x3c\x82\xdb\xdc\x4a\x24\x32\xd0\xed\x95\xb0\xa2\x11\x1c\xa1\xac\xca\x7c\x29\x82\x9c\x15\xad\x32\x0e\x3d\x46\xa7\x8e\x22\x24\x3c\x25\x7d\x9a\xd3\xd1\xd9\xfe\x7e\xa9\x92\xdd\x79\x44\xff\xd7\xff\xef\xff\x0f\x84\xbd\x5a\x57\x5b\xec\x35\xc6\x97\xc1\xe1\xcc\xe8\xa9\x1f\x67\x8e\x5a\x17\x7a\x16\x41\xab\xa0\xac\xc9\x50\x99\xbd\x3f\x12\xe3\x01\xeb\x9e\xb9\x0b\x65\x93\x49\xf9\x0e\x70\x77\x17\xbb\x41\x5e\x1e\xcb\x96\x4c\x3a\xb6\x28\x08\x83\x17\xdd\xf7\x4a\x81\x88\x7c\x2f\x80\x1f\x6f\x6e\x32\xc0\x8d\xf8\x9c\x0a\x7f\x2c\xb6\x41\xb7\xd7\x60\x7b\x81\x8a\x80\xfb\x02\xbd\x98\x06\xd4\xf8\x42\x68\xf6\x2e\xe6\x7c\x8e\x8e\x30\x42\x43\xc3\xd2\xb6\x86\x7e\x60\xc2\xd7\xec\x8a\xbe\xe1\x2f\x7e\x7e\x21\xa3\x3a\x4a\xe1\x9f\xa8\x52\xbc\x37\x0e\x8d\x63\x47\xd5\x47\x43\x0e\x55\xfd\x16\x49\x71\x17\x5d\x5e\x80\xd6\x7e\x8b\xfc\x6e\x30\x55\xea\x76\x35\x87\x63\xde\x43\xe1\xaf\xed\xc0\x52\x29\xf0\x95\xd8\x48\x0b\x57\x5e\xd9\x4a\x5d\x02\x2e\xc5\x8d\x11\xb1\x2a\xc5\x7d\x14\xb3\x4e\x9a\x67\xf9\x24\x07\x1a\x8e\xee\x75\xbc\xce\xfd\x8b\xfc\xa7\xee\xad\x9f\x10\x45\x5d\xf8\x8a\x42\xee\x6e\xb3\x86\x0d\xed\xef\x71\x2e\xf5\x03\x62\x54\x88\xe7\x57\xfb\xfe\xfd\x47\x6e\x3c\xdc\x0e\x35\xa3\x39\x5e\xf6\xba\x5c\x6e\x29\x16\xfe\xd7\xe8\x00\xab\x39\x31\x6f\x9d\x80\x8e\x52\x0b\xe7\x78\x14\x23\xb2\x01\xf6\x6e\x64\x4c\x17\xeb\xe0\xbd\xba\x76\x22\xf1\xb8\xc1\xfc\x4d\x60\x1d\x8b\xa4\x5d\x24\xeb\xe1\xa7\x57\x1f\x9e\x7f\x7c\x7e\xf2\xfe\xa3\x58\x25\x40\x3c\x63\x9c\xf6\x08\x7f\x24\x23\xc0\x98\x43\xfc\x31\x86\x1f\x31\xfe\x38\x8a\x36\x62\x9e\xdc\x3b\x4d\x86\xf1\xd9\xbd\x4b\x31\xf3\xc5\x34\xa5\x48\xa5\x64\x46\x5c\x40\xc1\x11\x02\x6d\x8b\x08\x56\x70\xb1\x84\xfc\xa5\x31\x83\x58\x2a\x83\xa2\x6f\x00\x15\xcb\xb3\xc9\x3a\x69\x0e\xfa\xcd\xf1\x2a\x5e\x0c\x0e\xa0\x82\x58\x62\xc4\x8b\xe2\x60\x2e\xe6\x07\x09\x7a\x99\xc3\x2e\xb0\xbf\x8d\x16\xb4\x5c\x6a\x50\x17\x57\x09\x2b\x37\x8a\x57\xc9\xd5\xf1\xe2\x00\x37\x77\x04\xbb\x37\x31\xba\x4d\x8e\x4e\x64\x72\x39\x28\x55\x3c\xc9\x57\xb0\xc4\x30\xf6\x31\x09\x70\x7a\x14\x60\x4b\xab\x53\x5d\x42\x2d\xa3\x4a\x05\x5f\x75\x80\xf2\xc1\x96\xb2\x40\x33\xfa\x98\x42\x6f\xd7\x53\x62\xa6\xc7\x7b\x36\xd7\x35\x70\x9d\x68\x06\x58\x84\x17\x78\xde\xed\x85\xc9\x21\xe9\x60\x85\xf3\x3b\x7d\x71\x06\x53\xb4\x97\x88\x92\xd4\x2a\x0d\xb4\x1d\xdd\xdc\xa6\xe6\xd3\x5b\x24\x81\x3e\x10\xc5\xe3\xd1\xfd\x0e\x42\x6c\x67\x83\x28\xdf\x67\x14\x10\x2e\x6d\x62\x25\x1c\x4c\xfe\x49\x8b\x42\x36\x15\xa9\xed\x45\x7e\xce\x03\x8f\x06\xdc\x8e\x49\x88\x7f\xe5\x26\x5a\x14\xae\xd7\x44\x5d\x4d\x55\x65\xfc\x19\x1f\x8d\x28\x6a\xce\x93\xbb\x3a\x61\x21\xad\xfc\x8b\x42\x39\x27\x93\x8e\x7c\x95\x57\xb2\x12\x16\x15\x69\x43\x5f\xbb\x60\x63\x05\xbc\x1d\x7e\x21\xcf\x4e\x75\xc2\x22\x4e\x61\x67\x2d\xa4\xd8\xad\x76\x98\x3c\xe4\xb1\xd8\x90\x92\x6b\x42\xfb\xf6\x27\x20\x3c\x79\x43\x9e\x92\x6f\x53\x2f\x0f\x46\xab\xb2\xdb\x39\x67\x96\x8d\xe0\x48\xb0\x6f\x22\xbb\x84\x7c\x0e\xab\x48\xb0\xc9\x67\x1d\x88\xd0\xe2\x59\x33\x69\xe0\x60\x33\x5b\xeb\x56\x81\x24\x68\xd7\x70\xba\xce\xfc\xb2\x65\xde\x04\x85\xc0\x77\x98\xa4\x14\x3f\x92\xcd\xaa\xdf\x39\x20\xc3\x90\xc0\x21\x70\x6f\xae\x71\x59\x54\x7c\xac\x35\x6d\x1c\x90\x02\x1c\x2f\x17\xc9\x33\x25\x00\x85\x41\x62\x51\x81\xd2\xb7\xa9\x74\x0c\x3b\x56\x41\xa4\x30\x87\xaf\xc8\xb5\x82\x84\x01\x94\x64\xa7\x9b\x47\x5b\x4a\x09\xab\xdc\xfd\xad\xe5\x10\xdf\xa8\x92\x0f\x6e\x29\x29\x2a\x53\xf6\xe1\xad\x65\xd1\x2a\x5c\x95\x7e\xb4\x43\x69\xb4\xf0\x07\xca\x0b\xe1\xa5\x4e\xc6\x22\xb5\x40\x62\x7a\x38\x1e\x4c\xa6\xcf\xea\x49\x0d\x40\x91\x9e\xd6\x87\xe3\x33\x4b\x94\x53\x03\xd6\xc7\x66\xd9\x96\xcf\xb4\x6b\x23\xf9\x05\xdc\x52\x6b\xb5\x63\xdc\xc5\x68\xb2\x92\x2d\xaa\x5d\x82\x96\xb6\x6f\x14\x16\x68\xed\x95\x4c\x95\xb3\xc2\x0f\xb5\x55\xb6\x8b\xd4\xa3\xee\x72\xc2\x2d\x79\x7f\x5b\x49\xf4\x5d\xcc\x65\xa5\xb3\x05\x74\xb0\xbb\x97\xd2\xed\xb8\x08\xaf\xda\x62\xb2\xa0\x55\x5b\xb8\xab\xb6\x80\x55\x93\xfd\xc8\x85\xb3\x3b\x4a\x35\xe6\x47\x6d\x11\xfb\x88\x95\xde\x2b\x4b\xa5\x7c\x2d\x63\xc7\x05\x9a\x7c\x03\x45\x88\x16\xcb\x13\x4b\x17\xdc\x1c\x3a\x07\x7b\x24\xd7\x1b\x69\x79\x6f\x8e\xd8\x71\x1b\x89\xf8\x49\x89\x8f\x68\x44\x79\x16\xfb\xd5\xc8\x8c\xb3\x1c\xf8\xe9\x49\x29\x94\x72\xba\x3d\x27\x40\xab\x3b\xcd\x0a\xf7\xfe\xff\x45\x13\x73\x41\xb8\xa5\x52\xbc\x33\x4e\xa4\xb9\xda\x5e\x30\xed\x21\x26\xf2\x5a\x40\x39\x24\x4c\x4a\xfe\xd9\x23\xde\x00\xbe\xf6\x2a\x5a\x5f\xb4\xf7\xe0\xb1\x23\x16\xc1\x12\x86\xa6\x63\x3d\x8a\x4a\x9d\xcf\x54\xd2\xfa\xfd\x0a\xe8\x7c\xb7\x29\x4c\xf0\x5a\x83\x24\xcb\x6f\xb0\xe4\x82\xfd\xc5\x19\x93\x5d\xbc\xcc\x2c\x81\xd9\x8e\xcb\x98\xd9\xe2\x9e\x3f\x9f\xae\x55\x7c\xbe\x58\xfc\x16\xbc\x3e\x03\xe0\x70\xdc\xcf\x8e\xc3\xcd\xc7\x1e\x98\x08\xb6\xee\x0f\xc0\xe4\xc5\x45\xd2\xbd\x95\x4e\xd1\x74\x36\xd3\x5b\xec\x82\xb5\x53\xac\x46\x0b\xa7\x1f\x81\x39\xb4\xcc\x36\xe8\xfd\xea\x15\xdc\xa5\x0d\xb6\xe8\x25\x1c\xb5\x52\xee\x43\x4a\x5b\x1f\xf1\x49\x4b\x36\xd5\xb7\x57\x6d\xcf\xca\x23\x07\xea\x05\xee\x13\xfe\x77\x73\x03\x24\x8d\x88\xd0\x84\xfc\x22\x2f\x48\x6f\xda\x18\x05\xe9\x7e\x8e\x2d\xfe\x0e\xd7\x35\x70\x07\x73\xfd\xfd\x7d\xfe\x3b\x4c\x97\x33\xf5\xbb\xdf\x9e\x3b\x36\xb2\x19\x6c\xfa\x11\x90\xcd\xcb\x1c\xb5\x77\x43\x23\xc8\x8e\x33\xda\x2b\xfb\x59\x35\x4c\xd1\x65\x92\x39\xc7\xdd\x61\x03\xf3\x15\x20\x89\x15\x50\xd8\x17\x18\xc6\x20\x07\xf0\x37\x34\x5c\x63\x2b\xbc\xab\xae\x26\x2e\x43\x07\x4c\x84\xe4\x05\xf6\x50\xb5\xdd\xcc\x77\x0f\x29\x42\x52\x83\x6f\xe6\x19\x5c\xe7\x81\x95\x40\x7d\x77\x9b\x66\x54\x61\xf4\xd9\xfe\x7f\x34\xc9\x9e\x32\xb5\x39\x87\x71\xa9\x53\x98\x21\x01\xc6\x82\x67\x3c\x3d\x54\xa0\x46\xcd\xd7\x63\x53\x16\xf1\x51\xbd\x9e\x4e\xd1\xcd\xbc\x9b\x7a\x91\xe6\x8b\x75\xa5\xa8\x58\x99\x3a\x98\xb4\xba\x49\x46\x2e\x33\xad\x7d\xe9\x03\x3d\x40\x1e\x20\x0a\xf2\x6a\x7b\x8c\xd6\x8a\x38\x79\x60\xa9\x97\xf5\xe5\x20\xee\x03\x6a\xc6\x9c\xd1\x31\x25\xc4\xf2\xb6\x94\x34\x2f\x17\x12\x25\x79\x9e\x5f\xf1\x86\x9a\x26\x90\x6b\x92\x8f\xe8\x72\xb3\x0f\x69\x48\xbd\xe9\xd5\x74\x91\x45\x03\x68\x3d\x4f\xc8\x96\xfe\x38\xe7\x66\x4b\x81\x95\xeb\x72\xf1\x2d\x13\xaa\x99\x41\xac\xd3\x48\x3f\x8b\x45\x18\x29\x1a\x85\xca\x7e\xf0\x12\xb5\x78\xfd\x4a\x99\xdd\xac\x81\x8c\x24\x84\x8a\xf8\x77\x8a\x26\x6e\x97\x97\x59\x95\xcd\x80\xa4\x30\x1f\xe4\x63\x05\x5d\x2a\x01\x3e\x9d\x26\xf4\x6b\x40\x0b\xd2\x4f\x61\x6c\x15\x8c\xad\xcf\xea\x00\x75\x7f\x8a\x8a\xb2\x34\xce\xca\x86\xcb\x52\x5d\xec\x42\xdf\xfa\xc0\xa1\x58\x05\xf2\x50\x01\x9c\xfd\x14\x97\x0f\x0e\xf5\x94\x37\x1c\xe8\x8a\xa9\xb3\x69\xcf\x46\xfb\xfb\xf8\x9a\x3e\xd5\xd3\x5e\x60\x6b\x4c\xaf\x00\xa6\x56\xa3\x5a\x0c\xec\x50\xc6\x79\x5f\xdb\xd6\xd2\xec\x2b\x33\x59\x80\xdf\xca\x9d\x7a\x25\xa7\x8e\x18\x0d\xa7\x0e\x09\x38\x26\xb8\x88\xe5\x98\x8e\xd0\x29\x45\x60\x4c\xd5\xa0\x2d\x1b\x41\x98\x32\x72\x25\x74\xa3\xd0\xd8\x6e\x14\x0c\x2a\x2a\x51\xf0\xaa\x36\xb5\x39\x2d\xcf\x06\x74\xa6\x1c\xc4\x05\xa5\xd0\xbe\x06\xda\xdc\x60\x8c\x57\xdd\x57\x4d\x46\x40\xd2\x93\xaf\xe2\xdf\xac\x39\x59\xc7\x6f\xad\x8b\x4a\xd8\x54\xc5\x79\x6a\xa3\x76\x5d\xeb\x1c\x69\x17\x43\xb8\x1e\x0c\xef\xa6\x65\x8c\xba\x7b\xed\x70\x24\x06\x79\x0e\x58\xdd\xc3\x82\xfe\x77\x65\xd3\x4b\xf5\x9b\x54\x44\x56\x62\xa3\x3d\x79\xd6\xbf\x7c\x79\xf7\xe1\xfd\x97\x2f\x5d\xb5\xe4\xc8\x23\x79\xa6\x65\xe9\x64\xac\x5e\x15\x00\x06\xd6\xec\xba\x86\x0b\xe0\x3a\x9a\x2b\xa7\x41\x8b\x4a\xbe\xfa\xaf\x15\x02\xe9\xc2\x5b\x23\x21\x91\x49\xa8\x44\x79\x5c\x22\x66\xd3\x16\x66\x7a\x45\x71\x00\xbe\xf3\xde\x7e\x4b\x6a\x1f\x58\x27\x47\x0e\x7a\xb7\xd5\x53\xa0\x83\x66\x78\x12\x09\xa0\x6c\x5d\x43\x2a\x11\x2c\xc0\xe6\xe0\x1a\x4b\x38\x56\x40\x2b\xf4\xc8\x99\x24\x38\x8d\xe8\x60\x45\x67\x9d\xa4\x06\x01\xa6\xc2\x77\x68\xef\x85\xfe\x6d\x1c\x2c\x68\xd7\x2c\x15\x82\xc8\x6c\x1c\x90\xe9\x63\x4b\x19\x16\x12\xd3\xc9\x88\xc4\x24\x07\x45\xd2\xb9\xd6\x83\xa9\x12\x6d\x8a\x59\x12\xba\x31\xd1\xef\xc3\x72\x99\xcd\x72\xbc\x39\x02\x73\xb1\xf3\x51\xae\x19\x43\xc2\x49\xbe\xcc\xca\x75\x43\x53\x92\xfd\x71\xbb\x5a\xa4\x05\x84\x53\xf4\x23\x12\x48\x66\x2f\x5a\x0c\xbf\x6e\x3b\x5c\x17\x4b\x01\xec\x2d\xd6\x59\x5c\x88\xef\x15\x87\xa3\x46\x30\x9b\x92\x9f\xe6\x75\x45\xdf\x15\xaa\xc4\x8c\x31\x04\x13\xaf\xc9\x72\x70\xed\xf7\xe4\x58\x6c\x27\x85\x40\x85\x61\x9b\xaa\xf2\x69\x01\x4f\xb6\x53\x67\x8b\x0b\xed\x6e\x1e\x85\x3c\xf2\x30\x4b\x3a\x40\x54\x3a\x14\xfe\x6c\x66\x3c\x38\x90\x30\x83\xcf\x57\x46\x1f\x02\x5d\xef\x51\xfd\x2a\x86\x7f\xe8\x51\x42\x54\xaa\x2d\x41\xa4\x46\xc0\xad\x35\xbf\xe9\xc3\x1d\xba\x92\x45\x51\x4b\x3a\xd3\x5c\x27\x05\xf2\x07\xac\x8b\x0a\xd1\xd8\x36\xe0\xf1\x3e\x3f\x18\x7e\x4b\x16\xb4\xfa\xd6\xb1\x8a\xc4\x54\xec\x8d\x35\x11\x3e\xb5\x9c\x49\x7f\x13\x00\x8d\x22\x92\xd8\x01\x65\xd1\x68\x74\xbc\xe8\x4f\x51\x13\x8b\xce\x4a\x24\x5a\xfa\x06\xf2\x7a\xd0\x32\xf5\x90\x42\xd0\x98\x34\x6c\x64\xbb\x40\x94\xd1\x71\xb7\xac\xe9\x25\x7b\x13\x3a\xc9\xc1\xf3\x5d\xec\x70\xbe\x91\x4a\x03\x80\xd0\xe3\xa7\x41\x89\x00\x4c\x2b\xdc\xf3\x1f\x3c\x9e\xc2\x19\x0f\x6c\xdb\x2d\x6b\x19\x9d\xf2\x42\xb2\x7c\xe0\x0c\x3a\x9b\xab\x07\x98\xe3\x26\x40\x1c\x51\x87\x70\x89\xb2\x47\x94\x41\x3c\xa2\x35\x57\x1c\x96\xbe\x27\x4f\xcf\x06\xfe\xf2\xd3\x21\x0c\x4f\xb7\x08\x4e\xb7\xda\x61\xba\xd2\x62\x58\xc9\x0c\x73\xf9\x40\x54\xa2\x53\x89\xd1\x24\x85\x35\xce\x3c\x7f\x44\x39\xb2\x14\x8d\x38\x38\xa8\x91\xfd\xdb\xdf\x2f\x00\xf9\xd2\xc5\x6d\x36\x91\x2c\xfe\xfe\x43\x57\xed\x7f\xc7\xd2\x84\x26\x8f\x2e\x25\xf4\x64\xa7\xf8\xbf\xa5\x4a\x12\xc2\xd4\x97\x8b\xf2\x3c\x5d\x1c\xf3\x9f\x38\x8c\xcb\x17\x17\xc7\xf8\x5f\x30\x57\x2a\xbc\xf3\x9f\x18\x50\xb3\x62\x04\x5b\xda\x02\x86\x75\x23\x25\x07\x2a\xe4\xbd\x28\xe3\x79\x29\xe4\xfb\xfc\xec\x13\x20\x19\x8c\x05\x76\x26\x74\xd2\x73\x2a\x29\xd3\x28\xd6\x99\x83\x79\xd1\xec\xc3\xab\xae\x28\xbe\x81\x9f\xbe\x2a\x57\x7d\x7e\x44\x99\xf8\xcd\xb7\xeb\xa8\x0c\xaa\xa4\x07\xdf\x7a\x1b\xb6\x1e\x2e\xd6\x32\xbc\xbc\x7c\xa2\x44\xe7\x1d\xf0\x39\x54\x9a\x5f\xff\x03\xbe\x5f\x60\xdb\x25\x6a\x86\xda\x90\xa8\x25\xe7\xe4\xfe\x8b\x55\xc6\x9e\xf6\x33\xf6\xe8\x52\x65\x00\x2d\x70\xf2\xd4\x08\x0f\x0e\x00\x63\x24\x26\xf3\xb4\x38\x13\x78\x2d\x29\xe5\x30\xfc\x6d\xe9\x87\x39\x7a\x13\x96\x9a\x92\x56\x9b\xe3\xa7\x24\xa9\x2f\x91\xb1\xa3\xbe\x12\x08\x03\xb1\x4e\xf2\x3e\xd2\x74\x90\x94\xa4\xba\xfc\x14\xcb\xaf\xb9\xfc\x22\x59\x9f\x4e\xcf\xb0\xc4\x01\xde\x26\x2b\xb8\x60\xd1\xc1\x16\x30\x04\x67\xc9\x42\x3f\x28\x35\xf6\x83\xd2\xf5\x3c\xad\x95\x60\x22\xec\xa1\x91\x65\xc4\x44\xbb\xb3\xa4\xad\x5e\x9f\xb3\x62\x08\x6e\x87\xb7\x14\x25\x49\x96\x2a\x00\x0e\xed\xbc\xad\x55\x05\x88\x7b\xf9\x1c\x82\xd7\xfd\x40\x34\xf8\xc8\xfc\x54\xcb\xa0\xf0\xf9\x01\x9f\xfd\x12\x5c\x3d\x81\xac\x66\x86\x3e\x6d\xad\x71\xa2\x3e\x8d\xf5\x89\x6f\x78\x5a\xbd\x41\xbd\x24\x6c\x04\x77\x71\x52\xbe\x4d\x8b\xab\x80\xcf\x6c\x7c\xd9\x75\x17\xbd\xd1\x92\x47\x3a\xae\xe7\xe9\xf4\x2b\x39\x00\xaa\xd0\xa5\x0e\x51\x86\xe5\x19\xd0\xbc\xf4\xab\x3a\x3b\xae\x62\x79\x7d\xa7\x52\x6a\xad\x3a\xec\x93\x77\xc5\x94\x89\xc9\xf2\x20\x92\x71\x3f\xa2\x33\x16\x64\x9e\xa6\x4e\x12\x52\x79\xe2\x1b\x3e\x49\x02\x90\xf3\x94\x80\xa4\x0b\xba\xe9\x95\xb2\x80\xe3\x48\xcd\xbc\x97\xd7\xbd\x02\x31\x12\xac\x63\xaf\x29\x7b\x3c\x02\xfc\x95\x37\x88\x2c\x22\x60\xce\xf3\xfa\xb5\x6e\x4a\x0e\x11\x1d\x18\x38\xcb\xe9\x7c\x32\xeb\x60\x75\x32\x4d\x0b\xec\xc4\x34\x8e\x05\x7a\x66\x07\x7b\xe7\xd9\x14\xad\xae\x7b\x80\x89\xd0\x2c\x6e\xbd\x40\x50\x2c\xcb\x55\x24\x57\x28\x46\x35\x4f\xa8\x02\x34\x76\x0d\x73\x03\x04\x2a\xdb\x5a\x66\xcd\xbc\x44\x4b\x70\xb5\x74\x71\x50\x14\xcc\x8a\xf8\x49\x1b\x92\x02\x49\x08\x8f\x5a\x7c\x33\x24\xfc\xfd\x46\x3e\x9c\xb5\x16\x99\xd4\xde\x98\x34\xcc\x80\xd0\x7c\xc3\x3e\x3a\xa5\x8d\x31\x72\x06\x74\xe7\x51\x69\x6a\x01\xe0\x11\xb6\x90\xe5\x86\xf6\x31\x56\xa4\x1d\xba\xf9\x9c\x65\x3f\xde\x5f\xc0\x69\x9d\x98\xce\x0f\x89\x62\x12\xd1\x49\x85\x46\x0b\xb0\x7e\x2c\x50\x54\x8b\x90\x2e\x00\x07\xcd\xae\x7a\x97\x65\x91\xf5\xd0\xb5\x40\xcf\x99\x10\x15\xdb\x43\xff\x4d\xc3\x7a\x45\xfe\xd3\x32\x01\x84\x5c\x89\xc1\x70\xd0\x1d\x3d\x5a\x07\xe6\xc2\xec\x46\x8c\x51\x64\x98\xdf\x01\x9c\x91\x72\x48\x19\x3d\x65\x67\x89\xed\x43\x5e\x91\x9f\xc3\xae\xf5\x7c\x5a\xda\x6e\x44\x51\xe4\x9c\x94\xa4\xc8\x6b\x1d\xe4\xc4\x76\x0e\x49\x21\x68\xfa\x68\x51\x63\x56\x81\x7c\x89\xaa\x15\x6a\x06\x22\x7a\x0d\xcc\x65\x68\x45\xb6\x2c\x82\x73\xc2\xbd\x99\x39\xde\x53\x2d\x29\x9b\x68\xba\xe6\x05\xd4\xb8\xbe\x67\x50\x0f\xac\x3d\x6a\x95\x8f\xef\xfe\x87\xe3\x9f\x19\x32\xf0\x7c\x3e\x70\xc5\xde\x9d\x4c\x8e\xbf\x35\x7c\x59\xc2\x7e\x56\xa2\xb3\x4e\x30\xaa\x1c\x7b\x47\xfa\x12\xbd\xfb\x99\xb6\x07\x0a\x89\xb5\x72\xe0\xa6\x2d\xbd\xda\x25\xcb\x2d\x8f\x4b\x4f\xd6\x82\x74\x02\x0b\xa8\x2a\x47\x40\x15\x37\x16\x21\x53\x22\xe2\xc2\x3b\xf5\x04\x18\x1d\xb4\xe1\x8c\x81\x3e\x42\x57\x66\xb0\x4d\x98\xfc\x1b\x40\xb5\x4c\x25\xb5\x39\x99\xfc\x82\xae\x05\x4c\x45\xb2\x99\xd3\x3e\x91\x08\x17\xd3\xa4\x30\x77\x20\x35\x30\xf9\xca\x8e\x8f\x46\xe4\xf5\x9d\xef\xf3\xf8\x68\x4c\x0a\x0c\x4f\x3a\x94\xa8\x43\x57\xbf\xc2\x65\x6f\x09\xe1\xd4\xae\x8e\x12\xfc\x82\xcc\x59\xff\x3a\xe8\xd9\xaf\x1a\xb6\xc1\x8c\x88\x3b\x1a\xa0\xdf\x70\x0c\x14\x49\x60\xa8\x2d\x6d\xa7\xf6\x50\xed\x3b\x79\x55\x65\x28\xe0\xb7\xa1\x19\xa0\x7d\x5e\xae\x17\x33\x3f\xdd\x3c\x15\x32\x24\xb6\x61\x8b\x6f\x1d\xdf\x4c\xab\x40\x79\x1b\xef\x31\xe9\x28\x89\xca\xe1\xfd\xe8\xc0\x64\xfc\xc8\x60\xbf\x72\x30\x26\xa5\x37\x94\xdf\xd2\xf3\x6c\x81\x8f\xd8\xf6\x68\x74\x1d\xef\x09\xb7\x72\xeb\x60\x0c\x73\x96\xb9\x04\x6e\x66\xe5\x23\x82\xe5\x6e\x4c\x54\x69\xbc\x11\xe1\x26\xe1\xf3\xce\x2c\x1a\x3c\x4b\x46\xf2\xea\x6d\x17\xbb\xa0\x83\x4a\x65\x48\xd8\xab\xb8\x3a\x63\xc6\xf5\xcb\x87\xf5\x39\xac\xd9\x1c\x6e\xb8\xe5\xba\x6e\x7a\xf3\x14\x8e\xb3\xd5\x3c\xd9\x8c\xa9\x76\x7a\xd4\x43\x6f\xa5\xaa\xd4\xbf\x0c\x26\x59\x5b\x42\xa9\xd1\x9f\x6e\x86\x18\x45\xa0\x07\x95\x50\x29\x5c\x9c\x7b\x61\xa6\x52\x6e\xe4\xf3\x62\xf6\xa1\xb5\x44\x6e\xa8\x29\xbd\x59\x6a\x93\x85\x45\x87\xd8\xa7\x99\x55\xf9\xfd\x05\x88\x5e\xfd\x58\x01\x07\x05\xe8\xcc\x70\x34\x3d\x6e\x92\x6f\x69\xb9\x45\xbd\xf3\x75\x03\xb7\x53\xd3\x43\x3d\x39\x89\x9d\x8c\xfb\x3b\xc4\x34\x0a\x8e\x4c\x18\xd1\x42\xc9\xd4\x94\x1d\x00\x60\x0b\x81\x5c\x91\x14\xad\xb6\xe5\x22\xa6\x45\x89\xae\xe5\x21\x50\x8d\xe3\xf4\xa0\xfb\x2c\x31\xf6\x83\x28\x7c\x20\x45\x35\x59\x13\xfd\xbf\x36\xb1\x45\x7a\xca\xdb\xdd\x9c\x1c\xb7\x31\x09\x3c\x0a\x64\xf1\x6f\x0b\xbe\x33\x33\xe6\xe7\xf5\x55\x31\xbd\x7d\xe0\x13\x96\x09\x9d\xe4\xd3\xaf\x2e\x46\x95\xcd\xe8\xd5\xe2\xdd\x96\xa9\xad\xbd\xb6\xc3\xa0\x09\xcb\x7e\x46\x54\x7f\xf0\xc9\xa8\xfe\xf8\x93\xa1\xc9\x68\xe2\xdc\xe4\xd4\x3c\x46\x5c\xdd\x52\xba\xd9\x16\xdc\xa2\xec\xb4\x8f\x5e\x36\xe1\x42\xe6\x63\x94\xa3\x0a\x36\x75\xbb\xad\x70\x45\x85\xf1\x78\x5a\xfb\x66\xf9\x9b\xde\x58\xa6\x28\xf2\x9e\xf1\xd0\x75\x4b\x35\xae\xcd\x36\x1f\x8d\xb6\xa8\xb6\xb9\xe9\x8a\x10\x29\x2c\x26\x43\x3a\xb1\x0f\x88\xd5\x2b\x7c\x69\x0d\xa9\x63\x67\xec\xb0\x9e\xcc\x05\xd0\x68\xc4\x38\x20\x94\x03\x6a\x29\xca\x39\x66\x51\xb0\xfb\xe6\x3e\x6c\xdf\x39\x6e\x4d\x29\xfe\xf4\x28\x88\x80\x33\xdb\x6a\x3b\x31\x72\x6c\x1f\xd6\x36\x41\x02\x97\x2b\x4b\x78\xfa\xc8\xea\x9d\x06\x4a\x9c\x0d\xd0\xc1\xbb\xf1\xb9\xfb\x32\x9f\xbd\xf5\x1d\xee\x56\xea\x02\xe7\x8b\x63\xe8\xdd\xc9\x0a\x1c\x29\x37\xb7\xd1\x87\x94\x05\x37\x3e\x51\x86\x32\x7b\x95\xdc\xf7\x86\x78\x36\x40\x81\xbf\xc3\xee\xa1\xdd\xd3\x26\xec\x16\xd8\x1a\x0c\x7a\xaf\x1f\x86\x0a\x29\x18\xe4\x2d\x42\xf5\xc5\x16\x01\x71\x34\x6a\x29\x33\xfe\xec\xde\xda\xfe\x34\x93\xca\xa5\x2d\x01\x79\x96\x62\xdb\xa6\x53\x70\xd5\x5b\xa8\x4f\xbf\x8c\x31\x51\x2b\xed\xa0\x2e\xed\xad\x1e\x48\x12\xe5\xd6\x62\xea\x8a\x39\x76\xb7\xa6\x60\x58\x91\xa0\xfb\x87\x00\x4d\xce\x40\x93\xfa\x3a\x9b\xfe\x04\x73\x03\x2e\x72\xf4\x6c\xf1\xa6\x95\xe0\xf4\xac\x30\x7d\x92\x77\x41\x17\x9a\x54\x6c\xda\xe0\x95\xfe\x87\x83\xd7\x36\x63\x26\x8f\x94\x56\xd0\x26\x4d\xc2\xfe\x92\x65\x2b\x0e\x7d\xa4\x88\xd6\xb1\x4d\xa9\x8e\x37\xde\xea\x65\x28\xcd\xa1\xf0\x95\x79\xcd\x8f\x44\xca\xed\xd4\x35\xc7\xaf\x20\xf7\xdb\xd9\x66\xe0\x06\xf9\xac\x86\x2c\xfe\x53\xdb\x43\x96\xe8\x24\x64\xab\x86\xfa\xb6\x92\x99\x28\x6f\x6b\xd1\x3a\x2f\x58\x88\x01\x34\x69\x55\xe5\xb3\xac\xf7\xfc\xc3\x1b\x29\x7e\x40\xcb\x7d\x94\x4f\x14\xbd\x8f\xd9\xc5\x62\xfd\xc3\xed\x69\xd8\xfb\x5c\xa3\xfb\x80\xb2\xa1\xeb\x90\x6b\x14\x30\xc6\x5e\x59\x99\xd6\x72\x68\x59\xd7\xf7\xc7\x43\xa6\xa6\xc0\x0c\xa1\x93\x01\x35\xa9\x5a\xdb\xde\xc0\x34\xea\xf0\x34\xea\xbb\x4e\xa3\xe6\x69\xa4\xf2\x41\x1a\x2f\x5f\xf8\xf1\x07\xcf\xc0\x08\x3a\x13\x57\x20\x8a\x21\x48\xf1\xa6\xfd\x98\xd5\xeb\x05\x59\xf8\x86\x4a\x2a\xda\xec\xd4\xa2\x27\x84\xa2\x25\xce\x2c\x1f\xda\xeb\x04\x23\xdd\x5c\x6f\x26\xeb\xa7\x56\x6d\xc9\xad\xaf\x95\xed\xc1\xc2\x16\xbc\xae\xcf\x26\xd3\xd3\xc5\x59\x92\xf6\x17\x6c\x74\xb1\xb2\x98\x3b\x43\xd3\xc5\x11\xaf\x50\x24\x24\xe5\x47\x0f\x05\x85\xa3\x58\x85\x01\x83\x18\x0e\x62\x56\xc3\xf4\x97\x44\x78\x10\x89\xb6\x65\xee\x13\xe4\xe9\xc5\x10\x97\xe3\x38\x92\x64\x48\x14\x47\x36\x41\x12\x9d\x49\x92\xe4\xc2\x66\xb1\x0d\xfd\x2c\xc7\x7d\x21\xa6\x62\x05\xa7\xad\x25\x05\x47\x01\xcf\x05\xf4\x19\xb0\x0e\xa0\x33\x09\x9c\xa8\x34\xc1\xdc\x72\xee\x5b\xef\x03\x77\x3f\xf7\xf4\xb5\xcc\x7f\xc0\x04\x29\x3e\x62\x17\x1a\x90\xda\xfa\x48\xbe\x84\xb8\x70\x47\x2a\x65\x94\xb3\x8c\xd9\xf6\x48\x2b\xc0\xbb\x22\x40\xa5\x93\x21\xf7\x32\x09\xec\xa5\x47\xd3\x27\x11\x07\xb6\x8b\x44\xad\x38\x01\x13\x4e\xc9\x93\x90\xe8\x74\xc5\x2c\xe0\x6f\x15\xb4\xca\xc8\xbe\xea\x01\x3f\xea\x7a\x62\x6f\xbb\x80\x1f\x8b\xc7\x41\xf2\x28\xa3\x26\xb1\xf1\x60\x23\x11\xa4\x39\x07\x8c\xfe\xe8\xc5\xc4\xc6\x7e\x29\x80\x3b\x29\x7c\xb6\xf0\xc6\x1a\xf5\xf8\xfc\x0b\x0d\x52\x07\x77\x44\x27\x6b\x07\x2b\xda\x03\xf8\x23\x50\xca\x3d\x95\xe3\x0d\x34\x84\x2d\xa7\x06\x5b\xa6\xa7\xd3\x8e\x69\x4f\x83\xd3\x9e\xde\x79\xda\x53\x9e\x76\x8d\xf3\xfd\x43\x91\xe8\x2e\x33\xce\xe8\x5d\x42\xe8\xe3\x6f\xa9\x7b\x88\xd6\xe4\xc2\x68\xc9\xde\x28\x21\x19\xf6\x05\x2b\xe5\x18\x65\x5d\xef\x1d\x0e\x91\xc9\x62\x20\x16\x9b\x00\x02\xb1\x4f\x2c\xa0\x91\x51\x1b\xa9\xf0\xe9\x87\xaf\x27\x01\x14\x13\x7c\x5d\x74\x50\x27\x23\x06\x27\x29\x1a\xb4\x49\xb2\x0e\x49\x1e\x14\xf4\x17\x41\x86\xc5\xf7\x52\xa9\xa8\xbd\x38\x32\x98\xa0\x95\x42\x45\x64\x98\x02\x1a\x8e\x13\x62\x41\x3e\xf9\xea\x22\x54\xd3\x2e\x41\x09\x91\x74\x23\x55\xa0\x0a\x12\x67\xf2\x87\x9d\xf1\x9a\x42\x10\x38\xd9\x9c\xe4\x4e\x1c\x89\x3a\x6f\xda\x98\x44\x85\x14\xea\x50\x76\x54\xfc\xe5\x64\x21\x56\x71\xb3\x31\x25\x52\x32\x1c\xe7\x51\x14\x55\xa2\xf2\xa9\xf5\x24\x3a\x29\x86\xb6\x70\x17\x23\x8a\x2f\x16\x89\x11\xf1\x72\xb6\x14\xf2\x26\x96\x90\x97\x33\x58\xa4\x9b\x58\x22\x5d\x99\xc1\xf2\xdf\x44\xc9\x7f\x95\x6e\x81\xcd\xb9\xb8\x7b\x50\xef\xfe\x5e\x9a\xf3\x7b\x69\x8a\xef\x0c\x8a\xba\xcc\x07\xc7\x55\x9c\x4f\x9a\xd3\xf4\x2c\x71\x1b\x46\x95\x04\xfd\x24\x0a\xa3\xab\xa5\x9f\x5b\xa5\x7e\x6d\x54\x48\x82\xf2\x5a\xf7\x92\x49\x54\x13\x52\xda\x71\x7b\x6d\x55\xd0\xab\x28\x23\xd4\xdc\x5e\xdf\x11\xae\x70\x2b\x4a\xee\x74\x7b\x65\x5d\x92\xea\x7d\xf9\xf2\x15\x4e\xbc\x73\xb1\xab\x1b\xd0\x52\x37\x43\x44\x70\x73\x83\xda\x47\xe5\x22\x1b\x66\x8c\x4a\x3b\xca\xf1\xb3\xe4\x37\x80\x1d\xbc\xfd\x86\xbd\x57\x9f\x1e\xf6\xea\x79\xbe\xec\x55\xd9\x3f\xd6\x79\x95\xcd\x86\xbd\x79\xd3\xac\xea\xf8\xde\xbd\xcb\xbc\x99\xaf\xcf\x91\x77\xb9\x57\xaf\xca\xfc\x6b\x76\xaf\x22\x34\xf9\xbf\xea\xff\x92\xd5\x0f\x95\x69\x9f\x8b\x1e\x00\x37\x91\x1f\x33\x07\x51\x75\xc9\xe2\xdd\xb3\x03\xa9\xe4\x1d\xad\x85\x1e\x20\x83\x5c\xd1\x3b\x08\x01\x12\x09\xa9\xa9\x33\x0c\x48\x6e\x2c\x5a\x87\x16\x52\x8f\x84\x8f\x28\x20\xf1\xbe\xf0\x70\x03\xa4\xd1\xb8\xdd\x77\x0d\x7d\x78\x21\xe1\x57\xe1\x1f\x57\x48\x7c\x1c\xc0\xab\x8f\xda\x78\xd5\x51\xe7\xb6\xb5\xe4\x3c\xa1\x22\x3e\xe7\x17\x2e\x19\x05\x84\x5c\x79\x6c\x5e\xe7\xb2\x41\x7c\xc8\x46\xfd\x6b\xf7\x19\x33\x6f\x3f\x63\xe2\x5c\x76\x7e\xc4\x44\x3a\xce\x27\x84\xe0\xc8\xe2\xdb\x94\x7a\xde\xcc\xd1\x51\x82\x67\xa9\x9d\xd9\xa4\x14\x9f\xb8\x99\x65\x6f\x95\x0d\xd9\xc8\xf7\xfd\xc5\x6f\x16\xc5\x85\x0c\x49\x75\x59\xdf\x5a\xce\xb1\xf6\xb6\x6c\xca\xbd\x55\x2b\x92\xda\x0b\xfd\x42\x5a\xbb\x4d\x60\x68\x28\x26\x92\xa6\x6d\xf8\x12\x5a\xc1\xfe\x5f\x5e\xb1\xd9\x9a\x42\x87\x71\x8b\x28\x61\x8c\xc9\xcb\xc9\xfc\x90\x7e\x58\x57\xc6\xa3\x3d\xad\x98\xdc\x6b\xbe\xa3\x11\x3f\x9c\x65\x6a\x94\x70\x72\xdc\xd0\x7c\xc9\x98\xc3\x32\x6b\x23\x3c\x6b\xf2\xf8\xb2\x2f\xa4\x2f\x8a\x8e\xd1\x53\x84\x51\xdd\x1a\xb5\x40\x1e\x12\xd4\x5c\x8e\xd1\x4b\x4e\x81\xca\x4f\xf6\x56\xa5\x6e\xf0\x3c\xd4\xea\x08\xae\xb8\x52\xf1\xd8\x0b\x6d\x2b\x72\xef\xd2\x55\x5c\xa6\xf5\x30\x94\xf4\x56\x9b\xd1\xca\xbd\xc5\x77\xf0\x4c\x19\xd8\x07\xfd\x1c\x28\x13\x7b\xc5\xcd\x4c\x43\x17\xf6\x02\xdf\xd1\xe9\x09\x32\x32\x77\x57\x24\xe8\x46\xe3\x24\x79\xcf\x45\x02\x57\x9a\x93\xd4\xcd\x18\x89\x14\x1d\xdf\x9b\xbb\x2d\xda\x00\x82\x6d\xdd\xa7\x21\x6d\x62\x0f\xc2\x9a\x00\x84\x29\xcd\xce\xfe\x35\x72\x1e\x7e\xb8\xdd\xd3\x05\xec\xcf\x99\xfd\xaa\xd1\x28\x06\xc4\x65\x36\x51\xae\x84\xaf\x6e\x45\x48\xfb\xe9\x96\xa1\x19\x14\xe0\x5b\xe0\x3e\x05\x04\x27\x69\x69\x5e\xd0\x5e\xca\xf0\x0b\xb0\x3f\xef\x61\x34\xa0\x5e\x03\xac\x56\xef\xc8\xd2\x16\xa9\xf7\x8c\x0f\x31\xb8\xa9\x5b\x33\x46\x43\x5f\xd6\xf1\x82\x6d\x51\xbe\x55\xd0\x47\x75\x00\x90\xe2\x85\x50\x10\xc2\x6a\x39\xc8\x03\x4c\x85\x02\x12\xb6\x17\x52\x30\x8b\x8a\x11\x17\x68\x31\xc7\xac\xda\x68\xb2\x90\xb6\xce\xeb\xdb\xd4\x44\x52\x84\xc9\x41\xab\xde\x85\xd4\xb2\x40\xbb\x68\xf9\x1c\x91\xf7\x1b\xe4\xd6\x49\x43\xc4\xbc\x32\xf4\x57\x18\x6d\xee\xda\xd2\xd1\x48\xe9\xce\x6f\xca\x15\xd0\x41\x85\xb8\x90\x2a\x25\x01\xee\xb6\x53\xe3\x4a\xee\x72\x81\x5e\x4a\x25\xd5\x1e\xba\x68\xbc\x4b\x63\xdb\x93\xb9\x64\xf0\xbb\xe4\xc6\x5a\xb7\xfb\x7a\xab\x5c\x55\x1b\x7b\x20\x59\xd6\x16\xab\x4a\x1e\xfe\xb4\x44\x1f\x32\xad\x6c\x34\xfb\xb8\x36\x45\x98\x71\x43\x08\xfb\x45\x3e\x42\x31\xfb\xb5\x92\xef\x22\xbd\x5f\xa2\x83\xf2\x20\xfa\xa5\xf7\x7d\x9e\x15\xbd\x35\xe9\x16\x49\x16\x4b\xdd\xa0\x7b\xd1\x44\x36\x16\xec\x6d\xe3\x8b\x5a\x1b\x7a\xd9\xbf\x4d\xd8\x2a\xb9\xe0\x80\x62\x40\x4b\xd8\x4a\xcb\xbe\xed\xf9\x7f\xdb\xb2\xdf\x6d\xc9\x9b\xed\x4b\xde\x84\x97\xbc\xb1\x96\xbc\xd9\x69\xc9\x9b\xed\x4b\x8e\x44\x8b\x5a\xf6\x26\xb4\xec\x8d\xb7\xec\x24\xfc\xc8\xfe\x03\x96\xbd\xf5\x8c\xb7\x55\xeb\x22\xc0\x65\x10\xca\x3d\x3d\x13\x4a\xa6\x05\x3f\x2d\xa1\xd6\xe9\xd9\xc6\x72\x31\xc8\x84\x0a\x73\x56\xc6\xeb\x5c\x36\x5c\x22\xd5\x59\xa3\x8e\x1d\xff\xd2\xa1\x83\xec\xfe\x34\xbf\x5f\xd1\x85\x86\x6f\x9d\x56\x52\x36\x10\x76\x08\xbb\x66\xd0\x6e\x83\xd4\x39\x02\xaf\x86\xf8\xca\xc8\x68\x0a\x9f\x0f\xb1\xdd\x6a\x63\xc5\xb7\x69\x48\x9e\xa5\xec\xb8\xc6\x24\x58\xc1\x94\xb6\x6e\x9b\x46\xd0\x13\x59\xa7\x35\x84\xc6\x68\x0d\x49\xa9\x9a\x34\xb1\x45\x83\x6c\xfd\x9a\xef\x74\x25\x13\x43\xf6\xb0\xba\x02\x10\x3b\xeb\x69\xd6\x0f\xea\x40\x78\xba\x01\xb2\xae\x7e\xe1\x2b\x8e\xb3\x18\xbd\xca\xf2\x9b\x29\xe3\x58\x5b\x9d\x09\x86\x65\xa9\x06\x38\x23\x33\xe9\xdb\x96\x42\x2a\xdf\x38\xcd\xd4\xe5\x32\x0b\xc4\x16\xdc\xeb\x5c\x9b\xdb\xb6\x16\xc0\x83\xac\x40\x8d\xd3\x0e\xd2\x2c\x46\xfd\x7a\x74\xca\x31\x92\xbb\x1a\x78\xc8\x86\xff\xdb\x4c\x82\x72\x3d\xa7\x18\xe4\x00\xdc\x7b\x66\xb0\xf6\x23\x35\xc5\x26\x34\x8e\x71\xd0\x69\xe6\x5e\x86\xf4\x0e\x03\x6b\xcb\xb9\x89\xa5\x9c\x0b\xed\xd9\x3a\xc5\x65\x32\x06\xa6\xa3\xed\xd3\xe3\x59\x49\x96\x81\xd7\xb6\xcb\xd0\xf2\xcc\x76\x30\x46\x0f\xe1\x8d\x71\x17\x8c\x41\xec\x6c\xa1\x6d\x00\x81\x86\xdc\x6b\x61\x25\x87\x83\x07\xbc\x40\x42\x62\x29\x49\xbe\x4f\x22\x8b\x36\x4b\x0d\x8d\x1a\x43\x29\xf2\x53\x84\x2d\x19\x6d\xeb\x60\x98\x3d\x8a\x93\xf5\xbc\xe9\x8f\x06\x6e\x84\xe6\x03\x15\x14\x77\x2c\x5b\x31\x7a\xc7\xa1\x69\xa0\x5b\x66\x47\xb3\x3b\xa3\x6a\xa5\xbf\x93\x8e\xda\x01\xda\xba\x33\xdf\x95\xd9\x7c\x57\x71\x8a\xc2\x92\x33\x8a\x05\x6f\x62\xd0\x0a\x23\x98\x80\xf5\xe0\x28\x3d\x87\x52\x97\xe7\xb0\x2c\x16\x57\x96\x00\xac\x25\xea\x70\xed\x70\x74\x4b\x72\x94\x96\xa6\x4e\x70\x6e\x01\xdf\xc3\x56\xd8\xe1\xa0\x27\x62\x9e\xce\xc6\x28\x6c\x06\xbc\x03\x4a\xf1\x2f\x73\x59\x18\x70\x87\x94\x0b\x9d\x9d\x06\x2e\x1f\xf8\xf7\xd0\x64\x21\xe7\x3e\x9d\xa4\xed\x7e\x36\xf5\xc5\xc2\xa2\x0b\x62\x74\xd1\x69\xfc\xa2\x9c\xa5\xf5\x5c\xfa\x80\x1f\xde\xab\xcb\xe9\xd7\x0c\xdd\xbe\x8b\xd2\x93\x45\xd5\xfd\x53\xe2\x20\x22\x11\xad\x52\x8c\x15\x05\x73\xfe\x96\x63\xa0\xa8\xe8\x6b\x8e\x11\x9a\xd0\x7f\xf7\xe7\x1a\xc3\x60\x45\xcc\x77\xb7\x3e\x9e\xa3\x15\x12\x7c\xa3\x54\x5a\x66\x02\x9c\xe2\xaf\x9a\x7f\x9e\x94\xab\x7c\xca\x3f\xdf\xa2\x1f\x60\x01\xc3\x4b\xf1\xd1\x0d\x78\x6f\x0a\x6c\xda\x42\xc7\xcc\x0d\x0f\x6b\xbc\x86\xe4\xf0\x00\xf6\xab\x6f\x48\x5a\x0b\x7c\x44\x29\x80\x89\xc4\xc7\xda\x8d\x28\xd1\xed\x62\x73\x4b\x13\x3c\xb5\xee\x26\x78\xce\xc1\x46\x48\x9a\x21\x9b\x51\x4b\xa3\x1a\x2a\x54\x43\xd0\x24\xec\x4a\xa5\x9a\xc3\x95\xbb\xb5\x31\x5e\xde\xed\x4d\xb9\xf1\x3f\xac\x9d\x8c\x8f\xee\x1f\x09\xde\xe4\xf8\xa1\xe0\xcd\x07\x90\x19\x13\xc8\xec\x12\x45\xd3\x05\x99\x36\x4c\xc0\xae\xd3\xa6\xc2\x9e\x11\x4c\x40\x3e\xf9\xfc\x12\xd1\x2c\x53\xbf\xcf\x7c\xdf\xa1\xde\x38\xb6\xfb\xdc\xfe\x43\x40\x17\x97\x92\x61\x14\xfe\x3f\xaf\x00\xac\xa6\x28\x91\xc0\x11\xa3\x0b\xd3\x08\x8d\x16\x97\xcb\x94\x0a\xc1\x54\x30\xd0\xef\x5f\xf3\x59\x33\x67\xe0\xc3\xda\xb7\xee\x13\xec\x4b\x63\xef\x53\x53\xc2\x16\x49\xf7\xfe\xbf\x67\x97\x76\x74\xa8\xba\x75\x97\x80\xe0\xc2\x93\x3b\x5d\x94\x75\x76\xeb\x76\x6c\x77\xe0\xb9\x5b\x87\x45\xfa\x2d\xbf\xc4\x60\x1a\xb7\x75\xb6\xa3\xdf\x6c\xab\x33\x77\xbb\x83\xbb\xad\x84\xa1\x00\x84\x79\x6d\x3e\xbe\xcf\xcb\x1c\x51\x4d\xfa\x3d\xbd\xe2\x7d\x7e\xc7\xa8\xcb\xa0\x19\x59\xf8\xf6\xcd\x56\x8d\xaa\xfd\xce\x44\x91\x23\x93\x4f\x87\x12\x31\x1c\xf0\x05\xea\x27\xda\x64\x68\x97\xec\x80\xc5\xe4\x4f\xd8\xe8\x74\x21\x8b\xaa\x9f\x64\xbe\x01\xf8\x06\xee\x8b\x05\xfa\xdc\x19\x0b\x59\x80\x33\x25\xde\x30\xb3\x0a\x0c\xd4\x0c\xf2\x1f\xeb\xdc\x1e\x21\xd7\xa5\x45\xb8\x05\x0d\xca\x85\x32\x78\xd0\x46\x5a\xb8\x7a\xb7\xd4\xe7\x05\x36\xd5\x9d\x53\x40\xaa\x6b\xef\xba\x30\x9f\x69\xa4\x70\xf0\x5e\x03\xd7\x5f\xf6\x3d\xda\xe5\x20\x79\x10\xd6\x12\x29\xec\x04\x61\xf7\x2a\x20\x9e\xb2\x0e\xf8\xe2\xf8\x67\x0a\x37\x2c\xba\x00\x86\xf9\x56\x69\x72\x18\xfd\x17\xe5\xcc\x77\x32\xc0\xe8\xd5\x8a\xaa\x9a\x54\x43\x75\x58\xfa\x11\x87\xa5\xbb\x87\xd1\x74\x55\x18\x78\x37\x33\x30\x79\x39\x52\x20\xa9\x5b\xa8\xc3\x61\xeb\xbd\x89\xff\x67\xe9\x0d\xd6\x42\xa4\x92\xf3\xa4\x87\xe5\xfa\x9e\xbc\x67\xcc\x8a\xb0\x52\x8a\x9d\x51\xba\x19\x72\x9b\x8d\xd6\x85\xca\xe0\x3d\x34\x91\xdf\x55\x7a\x93\x9e\x73\x58\x0b\xc6\xbd\x6d\x9d\x59\x74\xb4\x37\x90\x31\x4f\x0c\x21\x4a\x82\xf8\x86\x02\xa0\x0b\x0e\xa3\xef\x86\x1a\x9a\x48\xd1\xf6\x42\x4a\xb4\x09\x92\x62\x0c\xc2\xbf\xbf\x9f\x2b\xe8\xeb\xe3\x37\xb4\x6e\x0b\xa2\xe9\xc0\xc4\xb9\x75\xbe\xfa\x6e\x01\x22\x31\x64\x4b\xc0\x84\x51\x1c\xf6\x53\xfc\xc4\x96\x44\x2a\x81\xa1\xbf\x16\x98\x36\x70\xaa\x12\x69\x41\x55\x8f\x2b\x22\x45\x4c\xc5\xb8\x46\xf5\x2a\x4e\xab\xfd\x31\x2d\x61\x6b\xa7\x16\xef\x57\xca\xe3\xf1\x9f\x9e\xbf\x38\x79\xf3\xfe\x1d\xea\x03\x98\x85\xd1\x81\xe1\x0f\xa2\xff\x14\xd1\xe2\xd9\x4d\x35\x44\x5f\xc5\x4a\xf1\xe8\x52\x52\x5c\x30\xdc\x7a\x30\x59\x1d\x97\xe4\x8f\x48\x1d\xb8\x35\x5e\x60\xb5\x3e\xba\xab\xcd\x20\x46\xfa\x07\x6f\x4b\xb4\x32\xee\x51\x63\x3d\xba\xf6\xa9\xbe\xd5\x8f\x24\x7f\xe4\x3a\x4d\x4f\x8f\xe0\xff\xf5\x71\x25\xa9\x27\x5e\x78\x4c\xc5\xa9\x73\x19\x5a\x00\x3b\xdb\x1f\xfa\x57\x6b\x0b\xa9\xf0\x57\xbd\x85\x7e\xd1\x65\x7d\x19\xa1\xeb\x3b\xbd\x68\x47\x0c\x41\x17\x09\x15\x9f\x27\x6a\xbd\x8e\xac\xf5\x92\x97\x7c\x7f\x2e\x2e\xa0\xb9\x8d\xd5\x5c\x0d\xa8\xcc\x69\x6e\xcc\xcd\x99\x76\xc6\xc1\x76\x6a\xaf\x1d\xc6\xa9\x1a\x0a\xe9\x33\x04\x83\x84\x3b\x01\x06\xf1\x6f\x28\x1f\x23\x03\x45\x66\x2b\x4e\x01\x1d\x50\xe0\x58\xc0\x0f\x24\xd9\x7e\x2a\x8f\xe7\xb3\xde\x61\xef\x7f\xd0\xcb\x57\xcf\x1c\xd8\xe8\x1e\x42\x59\xef\x54\xa6\x9c\x41\x99\xdf\x32\x14\xa2\x61\x54\x22\x0a\x65\x54\x34\xa8\x30\x82\xac\x07\x3e\xe2\xa8\x9a\xc2\xea\x05\x4f\x53\xef\x29\xfe\x8f\x5d\xbc\x20\x4d\xa5\x1e\x1d\x31\x6c\x1f\x8f\x10\x24\xbf\xd4\x27\x88\x1f\xdb\xec\xf6\x25\x36\xb0\xdb\x5c\x66\xbd\xa7\x12\xd2\xb0\xd1\x4f\x19\x46\x43\x62\xa9\x95\x41\x2a\xd1\x3d\x86\x39\xc8\x9f\x03\xbf\xc4\x1f\x2a\xa4\x92\x6a\x3c\x34\x62\x80\x88\xde\x53\x0e\x67\xfa\xac\xdd\x8f\x8a\xc0\x44\x76\xa3\x99\x3f\x75\x5c\x0d\xbc\xfd\xa2\x81\xdd\x22\x00\xc5\xad\x0d\x59\x23\x6a\x68\xf4\xb8\xa3\xbd\x53\x59\xea\x8c\x6a\xd1\x62\x4f\x31\x90\x70\x8f\x72\xd5\x64\xcf\xe8\x4c\x6d\x36\xf2\x6d\xd9\xc7\xbc\x80\xeb\xe9\x91\xd7\x47\xbc\x90\x7e\x5f\xb4\xf1\x2e\x24\x3f\x12\x1e\xda\x85\x34\x7a\xc9\xf5\x90\x3d\x5c\xa0\xf7\x35\x25\x4a\x77\xc8\x8e\x5e\x78\x2b\xf6\x91\xcb\x77\x85\xbe\x4b\x4b\x9d\x75\x48\xb7\x54\x45\x77\x43\x39\xfc\x88\x1f\xec\x02\xb8\x22\x6d\x88\x77\x7c\xcb\x41\x27\x4a\x0f\xef\x24\x3d\x47\x19\xea\xf0\x7f\xd5\x3f\xb4\x1f\x6a\x33\x05\x75\x3b\x4f\xf5\xed\xfc\x62\x01\x64\x55\xff\x1a\x50\xf7\x6a\x91\x5e\x91\x92\x6e\xf4\x7c\xb5\x8a\x04\x4b\x35\xe3\xd3\x54\x54\x46\x90\xbe\xd6\xf7\xaa\x30\xb4\xea\xe0\x4c\xa8\xdf\x8e\xb2\xbd\x74\xb9\x94\x16\x35\x85\xe7\x3a\xa1\x27\x3d\xb8\x6b\x8b\x99\x6b\x27\xa4\x55\x23\x03\xb1\x03\xd8\x15\xb4\x9f\x55\x53\xf2\xa0\x95\x9e\x73\x3a\x42\x80\x45\x3e\x4f\x25\xb1\xe3\x2e\x02\x5d\xfc\xde\x82\xc5\x47\x47\xbf\x0a\x5a\x77\xa0\x05\x46\xc2\xdd\x82\xf8\xfe\xc8\x23\x14\x8e\x76\x09\xa0\xe6\x6c\x72\xdf\xde\xe5\xd6\x1e\x6b\xca\x00\xb0\x43\x73\x92\x37\x8b\x4c\x6e\xa3\xa4\x0b\xde\x32\xbc\xfe\xa9\xfc\x21\xd3\x53\x27\xfd\x4d\xb1\x5a\xab\x8d\x97\xd0\x80\x52\x82\x2d\xe0\x40\x84\xc4\x2d\xc0\xf0\x82\xf8\x33\x05\x0d\xa8\x86\x06\x05\xcf\x5c\x99\x7e\xeb\xe9\x02\x45\x84\x32\x28\x07\x32\x09\xe8\x88\xcd\x58\x3d\xe1\x0d\xfa\x01\xa3\xbf\xd6\x7d\x56\x3b\xa6\x33\x74\xbc\x56\x64\x00\x7a\xca\xc1\x03\x28\x80\xf6\x3b\xd0\xf9\x83\x58\xa5\xc3\xad\xe8\x17\x45\xd1\xcf\x1f\x01\x58\x65\x27\x60\x5d\xe3\x1b\x04\x4c\x52\x05\x20\x51\x4b\x8e\x89\x9b\x76\x85\xb4\xa3\xa1\x7a\x27\x08\xb5\x31\x8d\x0b\x0b\x00\xa1\x84\xc2\x3c\x50\x80\xe4\xfb\x22\x04\x09\x90\x41\x50\xee\x00\x02\x24\x3e\xb9\x0b\x98\xef\x2c\x23\xeb\xc4\x65\xc3\x00\x79\x9c\xbb\x19\xbc\xa3\xd9\xec\x84\x60\x32\xbd\x15\x26\x69\x4d\x6c\xc0\x54\xa4\x67\x29\x22\x25\x7f\x8a\xc8\x51\x98\x4c\xcf\x45\xe4\xf4\x71\x26\x6e\x35\x83\xba\xd6\x82\xac\x12\x81\x56\x5a\xaa\x08\xab\x19\xa0\x38\x4c\x46\x10\x08\x2d\xb8\x27\xf7\x64\x43\xab\xb6\x68\x12\x6a\x98\x84\x79\x06\xee\x0d\xcc\x6b\xb9\xee\x36\x48\xbe\x9e\xe2\x12\xf1\xca\xe0\xad\x79\xd8\xe0\xd2\x1c\x9e\xa7\x55\xb4\x69\x01\xe0\x16\xe0\x8f\xea\x55\x5a\x74\x35\x07\x4d\x65\xc4\x4d\x0f\xda\x40\xdd\x55\x11\x09\x80\x29\xa2\x06\xa8\x8c\xee\x66\x03\x90\x9f\x2a\x46\x34\x70\x9f\x76\x00\x07\xe4\x3d\xb6\xa0\xd7\x83\xd5\x9d\x85\x73\x16\xac\x6a\x4e\xae\xf4\xf0\xa3\x66\xc0\x72\x2f\xc3\x40\xf1\x2d\x80\xaa\xe4\x1d\xb7\x83\x5a\x0d\xc4\xd9\x7b\xd2\x04\x48\x01\xde\xf6\xc6\x00\x4c\x73\xba\xe9\x3f\xad\xcf\x1d\xdb\x70\x52\x9b\x02\xbe\x19\x05\xdd\xd2\xdf\x88\x74\x24\x66\xc2\xcf\x23\x4b\x02\xeb\x46\x4a\x0f\x6b\x32\x98\x5c\xf6\x89\x51\x55\xf9\x48\x78\xba\x99\xe8\x2d\xf8\x82\xd4\xde\x80\x43\x5b\xa6\xab\xbe\x2e\xab\x0e\x81\x2c\x2f\xb9\x48\x41\x87\x0b\x2b\x0f\xf0\xba\xb9\x26\x81\x8b\x69\x1f\xbe\xdc\xf6\xeb\x7a\x61\xb2\xe1\x03\x9a\xcd\xa6\x5f\xb3\x99\x34\x8b\x92\x67\xc3\x5e\x04\xe0\x15\x6b\x2d\xe1\x31\x43\x57\x29\x5e\xf3\x5a\x6c\x64\x4a\xaa\x14\xbf\xa4\x92\x24\x99\x92\x2a\xc5\x29\x89\xa4\xab\xb6\xae\x1d\x46\x03\xf4\x87\x89\xbe\x98\xb5\xb8\x0b\x2d\xec\x05\xbe\x3d\x5a\x0e\x33\x73\x66\x6a\x52\x00\xbd\x81\xde\x41\x98\xd5\x8b\x05\xca\xb9\x3c\x35\x1f\x63\x2f\xe6\x6f\x7f\xd7\x9a\x6c\x82\x14\x14\xe3\x18\x8a\xe5\x66\xdb\xf9\x87\xd7\x34\x4b\xee\x82\x13\x72\xbc\x4a\xe0\x6c\xd3\xf6\x46\x6a\x45\x81\x4f\xb8\x5a\xc1\x37\x7a\x36\x8f\x04\x05\x58\x99\x97\x0b\x1c\x55\xf4\x59\x15\x09\xdc\x8a\x5e\x6b\x6a\xd5\xb7\xb4\xf6\x41\x15\xb9\xbd\x35\x05\x17\x5b\x5a\xfb\xa8\x8a\x6c\x06\x21\x34\xd6\xc6\xa6\xf2\xf8\x06\xd0\x28\x8b\xbf\x51\x2c\x1b\xcb\xdf\xed\x7a\x87\x9c\x51\x16\xf2\x08\xd3\xa6\xd8\x87\x3a\xd0\xee\x7c\x2c\x77\x42\xe3\x8e\x5b\x27\x7e\xcb\xa4\xdf\x51\xb6\x74\x6e\xff\xcf\xe4\xa4\x31\x7a\x5d\x65\x19\x46\x3b\xd9\x61\x59\x25\x26\xd9\xd2\xc1\x73\x55\xc2\xed\x23\xaf\xa6\xc3\x0b\xd9\xcf\xb0\xc8\x9a\x1d\xfa\x62\xd9\x65\xf7\x4c\x30\xfb\xf6\x56\xf4\xed\xdf\xdd\xd2\x0b\x55\x04\x7d\x38\xb4\xdb\x5b\x75\x9d\x86\x05\xda\x19\xed\x76\x54\x00\xc5\xa9\x01\x10\xa6\x3b\x2f\x7f\x60\x6f\xd1\xa7\x4f\xbf\x05\xb7\xd4\x85\xbc\x1c\x40\xe8\x30\x5b\x2c\xf2\x55\x8d\x22\xe5\xb2\x60\xfc\x61\x43\x90\x42\x2a\x9b\x10\x28\xab\xb1\xf0\x00\x6a\x82\xb6\x48\xb0\x8b\x4e\x0d\x59\x78\x0a\xc2\xd7\x71\x07\xe7\x1c\x66\x91\xad\x17\x18\x79\x29\xd3\x4d\xbc\xf3\xf3\x54\x98\x6a\xf4\xdf\xaa\x98\x48\xcd\x8b\x0b\xd4\x52\xc9\x28\xfa\x2f\xd6\x48\xd7\x4d\x89\x11\xee\x6c\x39\xa9\xa4\x82\xff\x9c\x01\xe7\x51\x39\x0c\x91\x26\x28\x24\xfd\xfe\x5b\x5e\x64\x16\x5f\x14\x24\x45\xa7\xde\xdd\x6f\x24\x2b\x8b\xad\x77\xbf\x21\xd1\x43\x54\x6a\x2d\x22\xd9\x90\x4b\xa5\xae\x7f\x82\x4a\x55\x0d\xc5\x75\x17\x95\xba\xb6\x33\xe6\x59\x7e\x39\xd7\x9c\x0c\xc7\xac\xa3\xa4\xc3\xf1\x68\x74\x9b\x7d\xb5\xac\xe5\x47\x9d\xc6\xfd\xa9\xf3\x7f\x47\x3c\x64\x40\xf4\x23\x25\x75\x29\x80\xb5\x1b\xe5\x37\xef\x9f\x6e\x77\x35\xf3\x96\xc7\x22\xbd\x01\xb0\x58\x31\x0d\x17\xe2\xe5\xfb\xb7\x18\x45\xb0\x2f\xfd\x28\x23\x08\x7d\xa2\x50\xfe\x89\x15\xd3\xff\x80\x02\x06\xc0\x05\xcd\x6b\x43\x8e\x3a\x39\x93\x13\xdc\x75\x6a\x77\xae\xac\x1a\xd7\x94\x43\xaf\xa2\xca\xbe\xd0\x74\xb8\xcb\x18\xad\x31\xf9\x43\x50\x04\x06\x2f\x48\x8b\xba\x08\x74\x6d\x08\x8e\xed\x50\x00\x8b\x6b\xd5\xbe\xd3\xa2\x5a\xc1\x14\xe5\x0a\x52\x1b\xbc\xd6\xdf\xf1\xe7\x1e\x47\xfe\x36\x09\x49\x86\x8e\xd1\xad\xf7\x63\xd2\x95\xbb\x3b\x33\xa5\x19\xa7\x9b\x1b\xcd\x4c\xa1\xcf\x42\x41\x71\x21\xd6\xc9\xf5\x0a\x63\xc5\x17\x97\xbf\x65\x17\xf2\x36\x46\xfd\x47\x76\xef\x56\x34\x07\xd1\x0a\x50\xb4\x91\x48\xec\xef\xf3\xe3\x93\x4e\x38\x1d\x9d\xdd\xdc\x20\x4d\x4a\x00\x31\xb2\xec\x18\x93\xd1\x64\xfa\xd4\x1a\x96\x3a\x91\x8a\x7f\x9b\x1a\xbb\xe6\x40\xa9\xd3\xe9\x19\x86\x7c\x53\x88\x45\x5c\x24\x0b\x39\xfa\x83\xe6\x60\x3a\x59\xc8\x10\x87\xfd\xd5\x41\x12\x29\x59\xe7\x61\x74\xc0\xe9\x88\x3c\x58\xf5\xbf\x25\x82\xb8\xfe\x9a\x5d\xc5\x17\xfa\x2d\x62\xb1\xb1\xcc\xb0\x31\x22\xda\xfc\xe9\x02\xb6\xaf\x30\xc3\x9c\x63\x80\x82\x70\x6b\x78\x27\x72\x7b\x07\x11\xf4\x3d\xb7\xc8\x9d\x95\xa0\x40\xa2\xf1\x3a\x40\xce\x48\xce\x70\x86\xd2\xee\xaa\x5c\xd7\x8b\xab\x4f\x88\xce\x64\x98\xcc\xf8\xfa\xcb\x97\x79\xb3\x5c\x00\x17\x8d\x38\xbc\x2f\x87\x73\x3a\x3f\xc3\x7b\xc9\xf8\x42\x19\x93\x77\x6f\xe9\x26\xf7\x76\xb2\x4d\x4e\x18\x6f\x5c\x39\xb4\xba\x3d\xb4\x52\x12\x6f\x08\xbf\x11\x3a\xaa\x6e\xd2\x5c\x9f\x81\xd8\xda\x25\x3e\x28\x22\xe3\x7a\x32\xff\xe8\x01\xfa\x0a\xc3\x50\xa0\x7f\xc8\x60\x64\x35\x33\x20\x6a\xdd\xbd\x9b\x17\xde\xdd\xec\x49\xaf\x83\x57\x1b\xf0\xca\x8f\xb6\xf2\xd1\xc1\xdb\x32\x3e\x3a\x7a\x20\xcc\xc5\x1a\x1f\x05\xae\x78\xe1\x5f\xc8\xf1\x23\x9f\x15\xdf\x59\x03\xa3\x4b\x3a\x6a\xdf\xed\x86\x39\x47\x55\xc8\x00\x4b\xbe\xaa\xf2\x6f\x78\x13\xf3\xb3\x41\x1a\x94\x74\xd6\xbb\x5c\xd8\xbc\x10\x91\xe2\xdd\x08\x07\xb5\xb8\x37\x0b\x11\x31\x0a\x91\xab\x3e\xc9\x87\xa8\x34\x62\xcb\x72\xf0\x21\xc7\x7a\xe4\xf4\x73\x6e\x41\x73\x4e\xeb\x80\xe2\x88\xf4\xcc\x0d\xb2\x30\x0a\xc9\xd8\x1a\x62\xd5\x36\x7b\xd7\x16\xcf\x28\x24\x52\x53\xd7\x0a\x30\xaf\x97\xc0\x0d\xa3\x4d\xcc\x85\xbe\x17\x50\xbd\x91\x30\x32\x23\xc7\x20\x21\x6a\x56\x68\xa3\x26\x85\x36\x5a\x12\x69\xe5\x2e\xd2\xca\x24\xd2\x0a\xe2\x17\x33\xc2\xbc\x1b\x97\x04\xa6\x81\xa1\xf8\x71\x70\x43\xfc\x01\xa7\x76\x49\xd2\x8b\x9c\x84\x55\xcd\x4f\x23\xa5\xa8\x17\x1d\x54\x8c\x98\x32\x89\x98\x46\x8c\x98\xdc\x83\x59\x7b\x07\xd3\x86\x44\x38\x9c\x0f\x44\x87\x68\x57\x82\x32\xe0\x92\x91\x7b\xda\x3a\x85\x5b\x3b\xab\x18\xed\x20\x88\x25\x0e\xe1\xcf\x39\x7e\x5d\xdd\x2e\x8d\xed\x22\x81\x6b\x2f\xc7\x6b\xf5\x67\x1e\x1c\x6c\x19\x76\x88\x72\xf6\xe5\xb8\xc2\x11\xfd\xce\x75\xdf\xce\xb3\x15\xd7\x10\x11\x0c\xe0\x93\xac\xbc\x1b\x6d\xdd\x25\xeb\x15\xb2\x23\x57\x32\x2c\x19\xac\xe8\x36\x2a\xda\x90\x4f\xb4\x60\x1e\xfd\x54\x4e\xd7\x35\xba\x81\xb5\x06\x7b\xf7\xca\x7c\x38\xff\x92\xb9\x3e\x92\x81\x2a\x1d\xdf\x27\x9a\xe6\xfb\x3c\x9f\xce\x29\x90\x32\x8b\xc0\x68\xe8\xb6\xab\xc6\x36\x85\x35\x89\xee\x31\x3d\x64\x57\x81\x33\x71\x9c\x2a\x55\x94\xbe\x9b\x27\xb4\xf0\x10\x55\xf2\xf9\xa5\x26\x4e\xf9\xa9\xff\xf6\x92\xa2\xe6\x48\x4f\xee\x08\x45\xcd\xce\xc9\xdb\x14\xad\x5e\x7c\xa9\x04\x74\xff\xb1\x99\xe8\x71\xbf\x2d\x33\x15\xb8\x80\x52\xd9\xb2\x0f\x77\xf9\x83\x91\x55\x1e\x63\xce\xe8\xbc\x38\xfa\x53\x3a\xfd\x0a\x68\x63\x9a\xf1\x02\x00\x21\x74\x73\x13\xbd\xa4\x78\x64\x3a\xe5\x58\x8f\x2c\x8e\x3e\x17\x39\x92\x94\xf9\x45\x0e\x80\xa6\x0a\xec\xef\xeb\x12\x6a\x7f\x58\x0f\xa0\xfd\x6c\xea\xcf\xca\x5d\x84\xb0\x14\x70\xe7\x47\x02\x85\x36\x09\x7c\x0e\xbf\x03\xd1\x1d\x92\x70\x29\x11\x02\x11\x25\xf2\xa3\xab\x11\x57\xd4\xc2\x43\xb6\x49\x28\x3e\x2b\xec\xcc\x52\xa6\xf1\xb6\x97\x05\x40\xe8\xcb\xf2\x7b\x61\xdf\x28\x90\x84\x17\x0d\x2f\x8d\x95\xce\x29\x2d\xfc\xeb\xbf\x9e\x39\x38\x08\x70\xed\x91\xd8\x4a\x36\x05\x31\x73\x08\x49\x02\xc1\xf4\xe0\xe7\x1e\x25\x76\xd6\xd6\x54\x78\x7b\x1b\x7e\x84\xbb\xaa\x01\x1e\xa6\x8e\xfe\x90\x17\x4f\x4b\xe0\xa8\x1b\xf6\x17\x98\xf5\x4f\x6d\xd9\xce\xce\xca\x81\x9d\x17\x91\x16\xed\xe4\x8e\xde\xc2\x9b\x26\x5b\x3a\x8f\xdb\x81\x87\x43\x4f\x94\xe3\x12\x7e\x2d\x51\x8e\x7c\xc1\xf1\xa5\x38\x4a\x13\x62\xbb\x0c\x47\x8e\x2a\x74\x0d\x91\xa0\x06\x1b\x77\xe5\x37\x69\xc7\xeb\x63\x2d\x22\x6b\xa0\xf5\xae\x97\x0f\x75\xe0\x8a\x6f\xf4\x9b\x64\x6a\xa7\xda\x8d\x3b\x72\x20\x2d\x24\x90\x52\xbf\x16\x29\x3b\xb5\x74\x25\xb5\x4b\x13\xfd\x74\x21\x61\x62\x6b\xad\x5a\x03\xce\x76\x62\x96\x9e\x3b\xf1\x69\xc9\x42\x03\x6a\x36\xc6\xdb\xb0\xf6\x0f\x9f\xaa\xd2\x5e\x18\x8e\x0e\x20\xcf\xb5\xd2\x6b\x65\x29\xfb\x93\x30\xb6\xd9\xd8\xce\x41\x87\x19\xda\x61\x65\x72\x00\xf6\xc2\xa1\x93\x11\xb7\xaf\x34\xcc\x0d\x6f\xef\x0b\x0d\xb7\xd2\xe1\xba\xa8\xe7\xf9\x45\xb3\x53\x5d\x3e\x9a\x58\x9d\xb6\x5a\x86\x27\x40\xc9\x6e\xba\x19\xec\xfe\xfa\x8b\x71\x97\x98\x7b\x6c\x95\x3d\x5f\x37\x4d\xe9\x91\xcf\x9c\x76\xa8\x95\xb2\x03\xc4\xbd\x0d\x34\x1b\xfb\x4d\x22\x40\x56\xb7\x86\x53\xc3\x1d\x78\xc8\x9d\xd4\xc1\x1b\x26\x20\xf3\x9e\x96\x97\x61\x71\xb7\x0d\x88\x6d\xc1\xb5\xcf\x1c\x3b\x3a\x3e\xb7\x3e\x2f\xbb\x14\xfb\xfd\x5f\x45\x1b\x83\x40\xf2\x13\x11\xc0\x53\xc0\x2b\x3f\x0e\xb1\xc7\xde\x0d\xd0\xb2\x14\xfe\x1d\x94\xbb\x4b\xfd\xfa\x7c\x70\xb3\x83\xfe\x84\x35\x89\xa0\x06\xc5\x2e\xc8\xa9\x67\x13\xbe\x1a\xc7\xf8\x68\x22\x57\x6c\xaf\xc5\xcc\x4a\xfe\xd7\x4a\x51\xea\x0e\xdd\xe8\xc3\x04\x7f\x68\x57\x43\x61\x1f\x9d\x52\x84\xff\x43\x8d\xf1\x5b\x3d\x3a\x21\x37\xb5\x2e\x51\xbb\x3d\xb7\x9c\x16\x06\xaa\x4e\x6a\xcd\x3f\xdc\xc6\xc4\x66\x46\xc1\x35\x78\xb6\xf8\x50\x59\x03\x20\xfd\x8a\xed\x2f\x32\x21\x2a\x65\x77\x42\xe4\xf7\x6b\x25\xba\xf7\xb6\xff\x28\xa3\x5e\x60\x94\xba\x91\x75\x9d\xd7\x5d\xd7\xf9\x2d\x8f\x2f\xdb\xe0\x58\x75\xd3\xf1\xc0\x12\xbc\x88\x7f\xe6\x81\x45\x5f\xb9\xff\x5f\x7b\x60\xd9\xfa\xbc\x70\x87\xb7\x84\xee\x63\x2d\xba\x98\x4d\x61\x9b\xdb\x37\xbe\x4c\xbe\xb1\x64\xf2\xc7\x99\x24\x14\x6a\xa3\x4b\xd5\x68\x2c\xa3\x91\x4b\x30\xac\x5c\x58\x66\x9e\x91\x7e\x8c\x31\xdf\x41\x87\xd6\x12\xf0\x92\xa8\x80\x85\x8e\x04\x8a\xa4\xb3\xdd\x45\xd2\xd8\x14\x4b\x9a\x59\xd4\x56\xb5\xaf\x43\xa0\x0b\x7e\x46\x0a\x9d\xed\x24\x85\xde\xa1\x7f\x8b\x49\xc8\xba\x58\xac\xbb\xaa\x69\x85\x50\x01\x64\x8c\x7e\x4a\xa0\x7c\xff\xce\xea\xb6\x5b\x10\x8b\xaf\xea\xe5\x72\x11\x3f\x73\xa9\xda\x13\x8d\xba\xee\x43\x06\xfb\x8a\xb0\x05\x01\x28\x79\xc8\x62\x91\xb1\x7d\x13\xe0\x7e\x11\x10\x62\x18\x53\x25\x39\x0e\x17\xb8\x8b\x28\x00\xef\xa7\x9d\x6e\x22\x6a\x9e\xdb\x7d\x77\xfb\xa5\xb4\xbb\xc4\xf3\xd6\x1b\x8b\x36\x7a\xbc\xc5\x00\x4b\xfb\xe5\x68\x1c\x6e\x20\x3b\xe8\x37\xc7\x51\xaf\x4f\x6e\x4c\x06\x51\x1c\x01\x33\x62\xfc\x82\xe8\x5b\x4b\xda\x64\x59\x66\x90\xb6\xed\x56\x88\xb2\x0a\xea\xfc\x75\xd8\x6f\xd5\x1d\xf6\x5b\x6b\x37\x5d\xf2\x9e\x93\xb6\x51\xd7\x06\x23\xfb\x2b\x93\x6c\x47\x6e\x37\x94\x76\xe2\xc0\xb7\xe0\xde\x88\xb6\xb2\x28\x49\xa7\x81\xef\x90\x16\x2e\x5c\xee\x20\x22\xc7\x4d\xe8\x58\x0c\x6d\x2b\x94\x95\x47\x47\x6d\x0a\xac\x8b\x03\x60\x83\x6e\x77\x00\xc6\x22\x7d\xe7\x31\x34\x66\x14\x8b\xec\xa2\xf1\xc7\x00\x9b\x5e\x97\xc5\xe0\xd6\xd1\xb0\x41\xa6\x3d\x9a\x74\xa8\x8d\x91\xed\x4e\xb8\x60\xb0\x61\x2c\x31\x10\xf6\x2c\x9e\x53\x50\x56\x67\x22\xa6\x4b\xd6\x44\xea\xea\x32\x1b\x96\x8b\xd9\x41\xd4\x63\x7f\xc3\x33\x32\xe3\x41\xfb\x95\xe8\x20\x3b\x25\x7b\xcb\x33\xbb\x6b\x28\xcb\x3d\x2b\x0b\x7e\xae\x2f\x5a\x65\x4d\xf7\xe6\x29\xd8\x19\x01\x89\x43\xad\x5d\x5a\xde\x52\x60\x59\x36\x33\xb7\x48\xa1\x98\x5f\xbc\x6a\x00\x25\x08\xdb\xa3\x49\xea\x58\xb2\xe9\x19\x34\xa5\xf9\xad\xde\x92\x89\xa3\xd6\xfd\xac\xd9\x19\x81\x0b\x2f\xb5\xd1\x6b\xa6\xfc\xc0\x36\x9b\x16\xd8\xc6\xae\xdd\x02\x5b\xda\x61\x48\x64\xf8\xbb\xb5\x85\x25\xb9\x3e\x68\x35\x80\x1e\x11\xec\x25\x91\x36\xba\x6d\xe7\x28\x36\x3b\x33\xd1\x10\x7c\x4a\x4a\x67\x31\xee\x2c\xd3\x04\x5a\xbf\x91\xd3\x94\x42\xa4\xd0\xba\x85\x9c\xae\x94\x11\x45\xf4\xe7\xb2\x6e\x38\x6d\x0e\xbf\x50\xca\x46\xab\x4b\x29\xca\xce\x41\xa9\xa3\x71\xaa\x3a\x03\x67\x22\x40\xc5\xe8\x89\x28\xe1\x93\x33\x15\xc7\xe6\x02\x9d\xfd\xe1\x75\x9e\x90\xba\xc5\x3a\x24\xe6\x11\x35\x95\xb5\x17\xc8\x68\xcf\xb9\x6b\x69\xca\xd5\xda\xdc\x3b\x10\xac\x45\xaf\x9c\x92\x15\x00\xd3\x3e\x1c\x0e\x23\x19\x15\xe7\xf7\x98\x65\xb9\x76\x3b\x77\x31\xd6\xb2\xac\x9c\xc3\xc8\x9e\xee\x20\xdb\x7e\xeb\xfe\x2e\x7a\xe4\xb6\xaf\x2e\x75\x2b\x65\xb7\xc6\x86\x21\x56\x44\x47\xc5\xe6\xc8\xfc\x24\x0c\x27\xdb\x58\x15\x3d\x1b\xd2\x07\x9b\x50\xb4\xed\x3c\xab\x39\xda\x8d\xef\xd0\xcf\x0d\xd4\x5d\x60\x18\x74\xdb\xcb\x34\xa0\xc3\x8a\xd2\x30\x00\x62\x83\xc1\xa7\x45\xd5\x36\xbb\x0e\x45\x53\xde\xdf\x47\x28\xc2\x20\xf6\x96\xc7\xed\xff\x9b\xb4\x6b\xeb\x6d\x5b\x39\xc2\x7f\x45\x22\x50\x83\x0c\x29\x45\x4a\x4e\xdd\x03\xa9\x8c\x5a\x34\x0f\x6d\x81\xa4\x0f\x3e\x07\x7d\x30\x84\x80\x96\xe8\x13\x02\x32\x29\x90\x54\x62\xc3\xd6\x7f\xef\x5c\xf6\xbe\x4b\xda\x42\xf3\x10\x59\xe2\x5e\x66\x97\xb3\xbb\x33\xb3\x33\xdf\x18\xb9\x73\x6f\x4e\x40\xd7\x04\x64\x03\xf4\x02\xc5\x39\xa0\xe4\x42\x65\x45\x00\x63\x77\xe5\x04\x6b\x63\xc0\x9e\xce\x46\x95\x11\x8c\x2c\x1c\xd5\x32\x13\xfc\xba\x34\x32\x5c\x8b\x51\xb3\xe8\x12\x63\x0e\x3d\x63\x18\xcf\x46\x96\xec\x95\xbc\x1c\xc9\xca\xfa\xf4\x50\x72\x96\xf1\xe9\x72\x38\x03\xf9\x14\xb4\x2f\x18\x3c\xe5\x30\xf8\xf6\x8d\x1a\xfd\xf6\x2d\xc7\xf4\x55\x8d\x3f\x15\xd3\xb8\x9c\x48\x50\x45\x22\x32\x3c\x7a\x89\x93\x58\xc0\x20\x8b\x09\x89\xdc\x93\xa2\xb3\x92\x09\x9f\x59\x94\xa0\xdb\x27\xc4\x64\xb6\x40\xec\x8b\x71\x88\x7c\xb6\x9c\xae\x1b\x81\x02\x29\xcc\x1a\x3f\x19\xfd\xf4\xbf\xe5\xdd\x0d\xf1\x36\xec\x6b\x08\xb9\x1b\xa5\x6a\x03\xd8\x31\xbc\x39\xee\x39\x69\xf4\xfe\x67\x17\xa9\x9a\xb0\xca\x51\xde\x0c\x80\x73\x95\x9c\x2a\xcb\xb4\x02\xeb\x3a\x04\x82\x31\x52\xc9\x80\x8c\xb0\xea\x89\xd5\x1c\x80\x2e\xfe\xf7\xcd\x7f\xbe\x62\xf8\x76\x87\x8c\xba\x2f\xfa\x02\xd9\x80\x1a\xab\xe7\xcc\xb2\x78\x5b\x06\x7a\x6d\x87\xf2\xa7\x4c\x4c\x44\x09\xb6\x32\x64\xf7\x67\xbc\x47\x94\x3c\x60\xbf\x3e\xd9\x3d\xdd\x34\x52\x3f\x1d\x65\xd4\xaf\xee\x9f\x62\xf6\x89\x2d\x33\x44\x2c\x2e\x61\x6f\x26\x83\x2d\xf1\xc5\x39\xae\xac\x04\x82\x30\xc3\x85\x84\x14\xea\x56\x84\x17\xf4\x71\xdc\xab\x55\xbd\x3e\xf1\x10\x39\x68\x72\xdc\x10\x82\xdf\xf1\xb6\x44\xf7\x31\xfc\x40\xfc\xbc\x67\x3a\x14\x11\x6c\x2e\x59\xd1\x8f\xe8\xa2\x16\x78\xa8\x61\x58\x5b\x4b\xe0\xad\xe2\x67\x82\xce\x28\x33\x2d\xa6\xc3\x17\x3c\x06\x57\x08\xe6\x15\x99\x55\x1b\x03\x5e\x6d\x1d\xfd\x4d\x42\x2a\x6c\xea\x3c\x6a\x40\x56\x4e\xe5\x0f\xb0\x32\xe0\xa7\x1f\x68\xda\x22\x57\x12\x8d\xb7\x80\xc2\x14\xd9\xbf\x5a\xca\x2b\x68\x83\xeb\x1a\xcc\xa0\x89\xc9\x67\xac\x23\x23\x45\x3a\x8e\xa2\x89\x92\x0d\x10\x20\x8e\xd3\x55\xb0\xcc\x0f\x2c\x93\xaa\x32\xe2\xe4\x2d\x2d\x40\x5a\x1c\x8e\x98\x2d\x16\x2f\xe6\x1d\xbc\xb4\x38\x78\x53\x80\x21\x21\x9a\x2e\x1b\xf4\x00\xed\x0f\xc3\x0f\x79\xaa\x4a\x9a\x19\xf8\x7b\x2a\xa6\x6d\xb6\x5c\xe9\x49\x94\x4f\xe8\x26\x7c\x29\x26\x53\x54\x49\xad\x2a\xc6\x34\xf3\x13\x51\xa5\xff\x54\xe2\xf3\xf2\x53\x0f\x5f\xd0\x5e\xc2\xb8\xb7\xa6\xed\xed\x64\x69\x31\xee\x65\x96\x56\x4d\x0e\x43\x11\x4c\x47\x64\xaf\x7b\x84\x65\x6d\x15\x9a\x68\x18\x7b\xd6\xc6\x6f\xdc\x59\x39\x31\x7e\x6b\xe2\x83\x3c\xfd\x09\x16\xe8\xc6\xb2\xb6\x1a\x85\xf4\x76\x20\xb1\xac\x06\x8b\xa2\x64\xc1\x60\x32\x37\xf2\x42\x0d\x56\x02\x68\x20\xce\xa2\x3e\x09\xd9\xd5\x12\x4c\xf6\x74\x07\x0f\x8b\xab\xdf\x02\x37\x9c\x45\xeb\x02\x23\x37\x3e\x62\x32\x5d\x56\x9c\xec\x14\xc4\x0d\x65\x73\x87\x8f\x8c\x6a\x36\x92\x89\x04\x8b\xa3\xe3\x50\xc1\xcf\xbd\xf6\xb4\x06\xb1\x72\x61\x6e\xa8\xad\x1a\x57\xd1\x49\x28\x1a\xb1\xf8\x49\x88\xc0\x62\xc9\xfa\x64\x5a\xed\x5a\x09\x6f\xcd\xa1\x63\x63\x96\xc4\xae\xba\xe9\xdd\x0e\x42\x33\xa1\x35\x10\x8f\x72\xd5\x41\x6d\x74\xd0\xe2\x34\x31\x2f\x9e\xe6\xf7\x88\xb5\xd8\xba\xdd\xac\x39\x4a\xab\x26\xc8\xf9\x0c\xf3\x98\xc3\xbc\x61\x56\xc8\x20\x01\x52\x25\xf0\xd2\x41\xf3\xad\x9f\xc8\xcd\x45\x53\xd6\x6e\xd7\x15\x77\x86\x46\xc2\xe0\xab\x6f\xe2\x4a\x6a\x16\x74\xe3\x26\x44\x9b\x40\xa7\xa4\x45\x0c\xbd\x2d\xd6\x2d\xf2\x32\x58\x13\xd5\x87\x40\x2a\x53\x31\x1d\xb0\x01\x09\x09\x1d\x98\x4f\x8a\xe8\xce\xbb\xa6\x6f\x68\x3d\x21\xae\x10\xda\x17\xbf\x35\x6b\x34\x3d\x6d\x82\x39\x7f\x40\x01\x8a\x57\x01\x52\xd1\x90\x91\xa8\x09\x40\x0d\x2d\x50\x2d\xcd\x91\xa7\x2a\xcc\x8c\x59\x84\xe2\x48\x03\xec\x86\xeb\xcd\x1a\x59\x70\x8e\x2d\x4f\x46\xba\x9e\x10\x91\x86\xf6\xd0\xf1\xc9\x76\xdd\xeb\x17\xd6\xcb\x59\x15\x9a\x9b\xa2\x9f\xe7\xc6\x7e\x8d\xbd\xfd\x1a\xdd\x1e\x07\x16\xb5\x50\xa4\xac\xb8\x48\x3a\x67\xc5\x21\x8b\x1b\xde\xd0\x2a\x0b\xd4\x55\x1b\x49\xb9\xf5\xbb\x33\x36\xa7\xd7\xe7\xac\x94\xd1\x97\x06\x35\xf2\x27\xa4\x2a\x38\x20\x50\x3e\x95\x16\x18\x30\x54\x23\x59\x54\xc8\x5f\x3f\x56\x99\xab\x2b\x71\x28\x6e\xac\xc3\x91\x30\x6d\xff\x08\x2d\x84\x57\x6a\xd3\xdb\xe3\xd0\x5d\xba\xa4\xa6\x56\x86\x6e\x04\x8f\xb6\x95\xf0\xfe\xff\x0c\x26\xb2\x6c\xbf\x97\xc3\xb9\x05\xc0\xee\xc2\x5e\x8a\x68\x05\x5c\x7e\xf8\x15\x84\xf4\x5b\xcc\x31\x32\x5b\x66\x5d\x8e\x02\xf4\x01\x0f\x49\x10\x5d\xe7\x66\x71\xda\xf0\x2a\x53\x76\xed\x44\x86\xc3\x53\x5e\x5f\x7a\xb8\xb6\xcc\xc9\x4e\x6c\x2f\x47\x9f\x82\xae\x06\x12\x42\xc5\x42\x59\xa5\xbc\x09\x4a\x34\x25\x89\x70\xd3\x06\xc3\x4d\x05\xa4\xfa\x10\xbd\xb9\x23\xfd\x56\xbc\x08\x60\x6b\x33\x49\x23\x31\xac\x80\x8e\x68\xf8\x16\x73\x56\xb7\x05\x66\x2f\xcc\x94\xab\x9c\x59\xaf\x40\x12\x05\x39\x33\x44\xd8\x2d\xd2\x34\x5c\x5d\x79\xd3\x85\xbb\x9d\xcd\xc2\xd5\x86\xb9\x8d\xeb\x6e\xb0\x20\x73\xa6\xc5\x7b\xa7\x57\x7d\xc2\x86\x18\x6d\xdc\xc7\xd6\x15\xf0\x11\x88\x94\x3c\x8d\x49\x5b\xf8\x0c\x94\x66\xec\x45\x28\xd4\x1e\x2d\xd4\x0a\xe0\xa9\x28\x51\x70\xd5\xe4\x2a\xbd\xe6\x0f\xf6\xeb\x66\xe7\xe8\x5c\xe7\xb1\x93\xcd\xe4\x75\xaa\x9b\x64\x91\xfc\x2f\xc9\x59\x6e\x94\xb8\xcf\x1c\x58\xc9\x38\xe8\x6d\x79\x63\xfc\x8d\x4b\x99\xd1\xa2\x93\x95\xfd\x73\x0e\x0b\x7d\x15\x1b\xbf\xe1\xb6\xe9\x17\x61\x99\xf4\x0d\x7e\x5c\x2e\x66\x99\xef\xb6\xe5\x9b\xcd\x5d\x2f\xe1\x41\xa7\x2d\x53\xce\x45\x6d\x29\x6f\x2f\x5d\x71\x9d\x2b\x7e\x9e\x2c\x49\xd5\x54\x62\x9d\x82\x3b\x42\x1a\x13\x30\xae\x24\x1c\xd4\xfb\x80\x1c\xa3\x7d\x7b\xf0\xb5\xb2\xcb\x30\xe1\xa6\xa1\x68\x62\x43\x5b\x2a\x6d\x5e\x32\xfd\x21\xb0\x1d\xa8\xb8\xfe\x06\xdd\x1c\x0c\x8e\xb9\xba\x12\xba\x13\x7e\xb1\xe2\xd4\x49\x73\x53\x36\xe5\x8c\x39\xd5\xef\x49\x99\xb3\xbd\x51\x08\x0f\x29\xf2\x2f\x93\x87\x12\x8a\x16\xaa\x5c\x95\x15\xc9\x73\x3c\x6d\x5f\x5e\x5a\x44\x56\x23\x59\xa8\xb2\xc4\x1e\x90\x78\x80\x0e\x3d\x1d\x3d\x0e\xbe\xd0\x83\x17\xfe\xa2\x68\x2b\x8c\xce\x98\x08\x35\x40\x20\x1b\x12\x03\xd4\x21\xe0\x30\xa5\x7d\x49\x36\x4d\x58\x68\xb1\xba\x6d\x87\xba\x05\xfa\x31\x6b\xf4\xea\xa2\xf2\x3e\x9d\x9a\x69\x42\x02\xc5\xc1\x13\x28\x0e\x61\xf5\x26\x38\x14\xd5\x48\x50\xbd\x39\xf0\x0e\xf9\x45\xc6\x7f\x06\x0f\xf6\x03\x1d\xec\x07\x71\xb0\x8b\x4f\x29\x10\x0c\x1d\xe5\xce\x76\x7a\x7c\xeb\x51\x3e\xe8\x5d\xeb\x98\x69\x9d\x1b\x64\xcb\xcb\x6a\x68\x67\x1e\xf7\xa2\x35\x76\xe6\xe4\x79\x97\xd3\xc2\x93\x13\x13\xcb\x78\xba\xec\xa0\x9d\x86\x0e\x6a\x85\x34\x73\xf4\x81\x56\x85\x41\x5a\xcd\x54\xdc\x4b\x66\x21\xfd\x84\xb7\xc1\x80\xa4\xc1\x41\x4a\x3a\x8f\xa6\xda\xeb\x0a\xb9\x4d\x9a\x37\x8d\x63\x5b\xa3\xe9\x54\xc1\x81\x94\x6e\x68\x4e\xde\x88\xf3\x9d\x43\x27\xa3\x49\x94\x45\xcb\xeb\xe3\xe3\xe4\x73\x8b\x88\xf9\x37\x45\xdd\x4d\xbe\x34\x35\xe6\x90\x0b\xa1\x17\xe5\xd7\xef\x54\x53\x24\xc8\xec\x28\x41\x8b\x71\x1b\x52\x0b\x7c\x91\xcb\xf6\xdb\xb8\xb3\x42\x3a\x1d\x80\x60\x77\x7b\xad\x74\x3c\x34\xbb\x79\xef\xbd\x22\x85\xe5\xb9\xa3\x4a\x91\x9e\xa6\x1a\xb6\xc5\x73\xd0\xea\x2e\x78\xb9\xf6\xe2\xda\x41\xcb\x0e\x49\xe6\x58\xeb\x38\x50\xde\xa7\xcf\xa2\xe7\x00\xf4\x04\xeb\x8d\xac\xc4\xdd\xf8\x4a\xf4\x16\x9c\x8e\x29\x32\xf8\x0e\xd6\xd5\x9f\x33\x87\xed\xac\x3b\x0f\x77\xad\x8d\x3b\x78\xbb\x52\x90\xb4\xb3\x51\x7e\x4d\x16\x44\x30\xc1\xd4\x66\xba\x5c\xc5\x9d\x34\x69\x9e\xb3\xe9\x22\xe1\xef\xf8\xc5\xfe\x7d\x48\xbc\x78\xb3\x87\x86\xbb\xc2\x02\xd2\x84\x08\x02\xbe\x58\x66\x68\x3c\x5e\x25\x2d\x5c\xf2\xeb\xdf\xf7\xfb\x10\xb3\x0e\xca\x15\xe7\x0c\xcd\xef\xce\x5e\xcd\x1f\xc2\x1b\x51\x72\x46\x87\x9e\x5d\x68\x76\x77\x0a\x4b\x55\x55\x4f\x08\xcf\x65\xe6\xd5\x36\x49\x74\xb5\x0c\x10\x28\x86\x24\x08\x11\xa8\x11\x8c\x64\x7c\xed\xbc\xeb\xbc\xf3\xae\x1b\x67\xf0\x6e\x5c\x72\x1f\x3c\x51\x46\x9d\x4e\xcc\xe3\xc6\x61\xed\x37\xbb\xe2\x9a\xc0\xc6\x0e\x44\xd4\x30\x32\x54\x1f\x0c\x98\x1b\x96\x82\x1d\x1f\x91\x10\x54\x23\x0a\xe4\x97\xeb\x96\x95\xcf\x91\xa6\x00\x9b\xb9\x7b\xf5\x1b\xc5\xe0\x42\x3a\xa2\x64\x74\xeb\x3f\xc4\xfc\xda\xa6\xfb\x0f\xed\x84\xe9\x76\x19\x30\xfc\x7a\xd2\x79\x08\x6f\x52\xee\xb3\x01\x41\x59\xe5\x88\xd1\x49\x46\x96\xdb\x0d\x99\x2f\xcc\x5f\xd6\x3b\xe9\x13\x8c\xc8\x03\xd2\xef\xb7\xcf\x76\x64\x71\xca\xfb\x4d\xcf\x71\x7d\xe4\x88\x5f\x06\x36\xec\x80\xfc\x86\x10\x11\x3b\xe5\x56\x2c\x96\x96\x5c\x55\xaa\x13\x94\xce\x55\xe7\xa4\xf4\xe9\xfe\xc5\x57\x22\x81\xfe\x76\xba\x1d\x5e\x7b\xa5\xd5\x77\xbc\xf3\x6c\x5f\x54\x59\xbd\x30\xcf\x14\xba\xd3\xfe\x95\xf6\x30\xb0\xe1\x46\xe9\x30\xb8\x43\xd1\xc0\x6a\xfb\x9e\xc4\x1f\xa6\xfd\x9c\x07\xad\x86\xa9\xc6\x18\xa0\xd1\x64\x99\xc0\xfb\xa5\xcb\xd0\x36\x6c\x75\x53\x5e\xde\x06\xf9\xd4\xd1\x14\x7f\x52\x03\x14\x6f\x86\x80\xc1\x06\x5e\x8f\xa4\x94\x4b\x49\x72\xc5\xb7\xde\x22\x78\xc4\x38\xc8\x14\xb7\xac\x1e\x95\xd9\xb3\x30\x01\xae\x24\x79\xb8\xed\x6d\x76\x5a\x20\x8d\x25\xf7\x89\x7e\x9c\xb9\x59\x0d\xbd\xd6\x20\xf8\x2a\x65\xf5\x2c\x5d\xbd\x70\x94\xf3\xfc\x96\x95\x97\x62\x48\x2e\x91\xa3\x30\x4c\x97\xc1\x62\xa2\x8f\xd7\x85\x9c\x43\xc8\x9f\xc4\x32\x6c\x19\xe2\x8b\x6b\xd7\x62\x33\xf1\x60\x3c\xc8\xa0\xc2\xe2\x04\x8a\x84\xd5\x95\x01\xb7\x92\x37\xe8\x2c\x6f\x76\xb8\x1f\x39\x6c\xde\x80\x47\x28\x4f\x1d\x94\xab\x2e\x3f\x2a\x1a\xf2\x20\x77\x77\x15\x33\xad\x94\xc1\x48\xab\x28\x59\xb7\x88\x74\x17\x97\x0a\x5b\x7e\x81\x68\x15\x59\x41\x92\x9d\xe4\x72\x95\xd9\xc1\xc9\xc4\x60\xb3\x59\x61\xfa\xb7\xbe\x2a\x5b\x14\x9e\x6c\x51\xb0\xf8\xff\xd5\x72\xb3\xe5\xc8\x2d\xb4\x79\xd1\xbd\x54\xe9\x57\xf1\x2e\x3f\x82\x5b\x4a\x61\xda\xed\xbd\x4b\xbb\x82\x17\x88\xd3\xb5\x62\x69\xa4\x75\x83\xff\xf1\x25\xb6\x32\x9e\xd3\x3d\xfd\x78\x79\x9a\xb0\xd7\x8c\xed\xc5\x38\x08\xc1\xab\x0c\x3c\xc0\xb1\xbf\x04\x52\x8b\x79\x3c\x6b\x71\xe9\xba\x9e\xff\xfe\xfb\xbf\x3e\xfb\xae\x21\xd1\xa3\xf8\x37\xa3\xff\x7e\xc1\xff\x9e\xe4\x57\xf9\x2f\x52\x57\x5d\xef\x6f\x1f\x9f\xb6\xef\xff\x08\xb8\xe6\x2d\xaf\xdf\x7d\x29\xfa\xef\xf3\xb6\x00\xed\xf5\x21\x4e\x5e\x16\x59\x9d\x47\x8f\x11\x6c\x70\x70\x50\x7f\xbc\xea\x5f\x7e\xd5\x31\x72\x7d\x73\x43\x9b\x42\xbc\xbc\xa6\xdd\xb9\xd6\xa0\x10\xb9\x7d\x64\x02\x3b\x4a\xa3\xed\x5a\xee\xd5\xc7\x62\x8f\xf0\x17\x20\xf5\xc2\xd4\xff\xb3\x39\xb5\x1d\xa8\x6b\x1f\xb2\x68\x81\x2e\x11\xee\xf3\x2f\x55\x0d\x9b\x87\x2e\xa1\xa2\x15\x52\xf4\xa9\xa0\x9c\x5b\xa6\xee\xe9\x65\x45\x51\xa9\xce\x43\x62\xcb\xc7\xed\x66\xb1\x32\xbf\xc2\x6e\xb0\xc0\x85\xef\x65\x54\xe3\x58\xc9\xf2\xb6\x41\x9c\xa3\xf8\x3a\x05\xf1\x0b\x25\xf5\x0d\x7f\x88\xe2\xe9\x72\xb5\x48\x92\x77\x35\xa6\x36\xee\xd2\x42\x19\x93\xf9\xe9\xbb\xfa\xaf\x7d\x52\x30\xc8\x45\x7e\xab\x9e\x6e\xd7\x18\x48\xff\xcc\xb7\x1b\xba\x8e\x91\x47\x62\x97\x47\x11\x48\xa7\x98\x4b\x11\xa8\xbb\xcf\xa7\xcb\xf5\xc9\x40\xc3\x2c\x84\xa9\xb2\x4b\x4f\x98\x6e\x42\x76\xf6\x09\x13\xcc\xc5\x07\x36\x49\xef\x50\x28\x5e\x98\xc8\x44\x8b\x6c\x9f\xcb\x56\xd6\xfb\x4f\x8c\x4b\x44\x54\x3c\xe4\xa7\xdb\xef\xdb\xf5\x3d\xd4\xc6\xbe\xb2\x2e\xcd\x11\x27\x20\xcd\x1f\x54\xdb\xd9\x31\x4d\xb3\x0e\x7a\xd8\xc4\x78\xd0\x1f\x37\x46\x3f\x88\x3c\xb5\x9f\x2d\x37\x70\x92\x3e\xa4\x68\x27\x81\xf9\xd2\x13\x94\x60\xe5\x7c\x99\xac\x44\x85\x07\x3c\x73\xd5\xdf\x48\x24\x0e\x32\xc1\x51\x82\x22\xab\xdb\x4a\x65\x63\x69\x5e\xe3\x29\x0d\xdf\x33\xd5\x67\x72\x96\xd3\x8a\xd9\x2c\x45\x56\xfc\x7d\xb3\xa3\xd7\xea\xba\xe7\xef\x8a\xfa\x47\xd1\x45\x0c\xf6\x8e\xc7\x2a\x3a\xe9\x3e\xc2\x83\x0f\x7b\x5a\x67\x86\x99\xc7\xcd\xfe\x22\x9c\x82\xe6\xf7\x50\x05\x6f\xe2\xe1\x65\x15\xdd\xa9\x2d\x7f\xc3\xfa\x65\xc2\x38\x5b\x94\x9d\x96\x00\xc4\xee\xa4\xed\xc8\x58\xb5\xec\x6e\x36\x44\x1b\x46\x87\x10\x18\x19\xc6\x8f\xcc\x7f\x54\x5d\x75\x57\x01\x1b\x3c\xe5\xd1\xf7\x0a\x64\x4a\xba\xad\xe0\x67\x0c\xe9\x15\x2d\x17\x8b\xe3\x63\x94\xa9\xf6\xee\x9a\xfd\x13\xe6\x4a\x2c\xeb\x3d\x81\x83\xc5\xa5\x46\xad\x35\x71\xc2\x64\x33\x0d\xec\x5f\xf7\x87\xe6\x67\x1e\x31\xc9\xf2\xb8\x1c\x27\xb0\xf6\x88\xf8\x13\x52\x66\xf6\x5b\x27\x6b\x99\x2c\xd1\xec\x57\xb9\x30\x81\x6c\x0f\x0d\x7e\xe5\x6b\x78\xbc\x2d\x96\xe4\x66\xfd\x8c\xf2\x31\x6a\x47\x51\xf8\x72\xce\x30\x67\xc9\xfa\x7f\x01\x00\x00\xff\xff\xd2\xf5\x8e\xf2\x15\x51\x04\x00" +var _dist_bundle_js = "\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\xfd\x79\x77\x1b\xc9\xb2\x20\x86\xff\xfd\x9b\xdf\x97\x20\xf0\x74\xa1\xaa\x46\x12\x24\xa5\xdb\xfd\xba\x0b\x4a\xe2\x69\xa3\xc4\x6e\x89\xd4\xbe\x91\xbc\x7c\x45\xa0\x00\x94\x58\xa8\x82\xaa\xb2\xb8\x88\x85\x39\x3d\xfb\x62\x7b\xbc\xfb\xd8\xe3\x65\xc6\xfb\xee\xf1\x7e\x6c\x8f\xed\x39\xc7\xf7\x93\x4c\xfb\x03\xf8\x2b\x38\x22\x72\xa9\xac\x42\x81\x52\xdf\x77\xe7\xf8\x1c\x89\xc8\xca\x7d\x89\x8c\x8c\x88\x8c\x88\x6c\x8d\xf3\x78\x28\xc2\x24\x5e\x0b\x1c\xc1\x62\x96\xba\x57\x26\x26\x71\x7c\x96\xb9\x57\xe1\xd8\x69\xc5\x07\xfe\x91\x0c\x09\x0a\x9d\xf9\xe9\x5a\xce\xdb\x3a\x6b\x9b\x73\x71\x39\x0f\x92\xf1\x5a\x1a\x7c\xca\xc3\x34\xe8\x74\x54\xa0\x8f\x65\xb2\x4e\x27\x77\xd3\x40\xe4\x69\xbc\x96\x43\xa5\xad\x4d\x17\xe3\x43\x1d\x17\xaa\x38\xac\x75\xc8\xe3\xe0\x7c\xed\x61\x9a\x26\xa9\xd3\xbe\xef\xc7\x71\x22\xd6\xc6\x61\x3c\x5a\x9b\x25\xa3\x3c\x0a\xd6\x6e\xb6\xbb\x7e\xb7\x7d\xb3\xed\xf6\xc5\x34\x4d\xce\xd7\x86\xbd\x61\x32\x0a\x78\xfb\xe9\xfe\x83\xd7\x4f\x1e\x1e\xef\xed\xbf\x3a\xde\xd9\x7f\xbd\xf7\xa0\xcd\x86\x0b\xac\x2f\xe2\xd8\x77\x7e\x15\x5c\xcc\x93\x54\x64\xde\xd5\x62\xd1\xc7\x31\x1c\x6c\x1e\xf5\x86\x7e\x14\x39\x51\x4f\x25\x31\x3d\x1a\x27\x90\x03\x8c\x39\x65\xdc\x3a\x3a\x08\x8e\xfa\xaa\xab\x89\x13\x0f\x62\x2f\x70\x17\x2c\x62\x65\xc9\x80\xc9\xb9\x5b\xa8\x5c\xd8\xa4\x4e\x5c\x8c\x61\x24\x58\x5d\xf8\x35\xf3\xc5\x7c\xbe\xd9\xf7\xef\xa4\xbd\x28\x88\x27\x62\xda\xf7\xbb\x5d\x37\x71\x52\x9c\x74\xd3\x85\x85\x73\xb5\xe5\x1d\xd8\xbd\x6d\xe7\x59\xb0\x96\x89\x34\x1c\x8a\x36\xcd\xa2\xe0\x81\xd3\x4e\x03\x1f\xbe\x5d\x16\x9b\x8f\xf5\x34\xc9\x45\x90\x42\x5c\xca\xe3\xde\x0b\xfc\x60\x09\x84\x1e\x04\x63\x3f\x8f\x04\x45\xf4\x21\x73\x6f\x23\x4c\x87\x90\x8b\x82\xc3\x64\x36\xf3\xe3\x51\x5b\xae\x4f\xc8\x29\x32\x4b\x86\xa7\x01\x56\xee\xcb\xef\x5c\x84\x11\x7c\x65\x5c\x17\x99\x27\x71\x10\x8b\x6c\xe3\xee\x7c\xde\xfb\x98\x5d\x40\x5a\xbe\x94\x76\x3f\x89\xe3\x60\x28\x54\xfa\x70\x39\x7d\xea\xeb\xc4\x68\x29\xf1\x65\x20\x44\x18\x4f\x32\x95\x61\x2e\x33\xf8\x34\x27\xd9\x06\x0d\x14\xa2\xc7\x3c\x4a\x60\x99\x5f\x8a\x24\xf5\x27\x41\x2f\xcf\xc3\x51\x7f\x5c\x14\xce\xbc\x17\xfb\x67\xe1\xc4\x17\x50\x6a\x28\xbb\x81\xad\xd4\xf3\xf2\x31\xf7\x7b\xaf\x5f\xef\x3e\x70\x5c\x97\x85\x3d\x98\x6d\x93\xbb\x04\x17\xf7\x4a\xc3\x71\x2f\x0b\xe2\x91\xd3\xc6\x92\x90\xee\x2e\x74\x99\x00\xc1\xb9\x5d\x01\x30\x55\x04\x6a\xcb\x92\x28\xe8\x45\xc9\xc4\x09\xa0\x78\x7a\x16\xa4\xdd\xb6\xb7\xd6\xee\x06\xbd\x59\x90\x65\xd0\x11\xa8\x86\x66\x7e\xca\x45\x6f\x08\xcb\x28\x82\x87\x51\x30\x83\x39\x70\x52\x76\x15\xfb\xb3\xc0\x6b\xfb\xf3\x79\x9b\xcd\x7d\x31\xf5\xda\x1b\x6d\x36\x85\xd5\x8a\x82\xd4\xcb\x16\x6c\x65\x09\x33\x0a\x9d\x39\x87\xce\xae\xcc\x9d\xa9\xb9\x2e\xb3\x47\xd7\x66\x17\xbe\xc8\x33\xd3\x23\x4f\x0e\xab\x2c\x3c\xbc\xae\xf0\x10\x16\xbd\x5e\x74\xc3\x83\x58\xe8\x70\x74\x7d\x1d\x09\xbb\xb2\xfa\xe7\xf6\xe3\x5e\x9a\xc7\xce\x94\xc5\xbd\xc7\x61\x06\xab\x7a\xf9\x04\xd6\x17\x17\xa0\xb2\x12\xa2\x97\xc2\xaa\x05\xa9\x53\xaf\x2e\x60\x71\x1e\x45\x2e\x1b\x25\xc3\x1c\x23\x7a\x27\xc9\xe8\x12\x56\x63\xc1\xae\x96\x20\xcd\xbb\xb5\xf5\x2d\xb3\x36\x0b\x7c\x7f\xcf\x9a\x77\x02\x24\xfd\xc0\x56\x00\xba\x77\xeb\xd6\x66\x3d\xcd\xda\x24\x90\x7c\x8b\x5d\xb3\x0d\x20\xfd\x3b\xa6\x76\xaf\x77\xeb\xf6\x16\x2b\x77\x2a\x7c\x52\x51\xda\xa8\xde\xad\xdf\x6e\x32\xc2\x08\xde\xd6\x0f\xd0\x60\x05\x39\x78\xb7\x37\x17\x47\xec\x96\x8d\x61\x10\xbd\xb9\x57\x2d\x2b\x02\xce\x89\x06\x6c\x36\x0a\x00\x55\x03\x32\x93\xbf\x3d\x7f\x36\x1a\xc8\xa0\x73\x70\xd4\xb0\x5f\x82\xde\xdd\x5c\x24\x51\x18\x9f\x06\x29\x4f\x1d\x98\x5a\xaf\x9d\x9c\x7c\x44\xb8\x34\x55\xc6\x03\xa1\x31\x29\x66\xf1\x96\xca\x38\x62\x1a\x66\x76\xe5\xb8\x57\x02\x6e\x22\x84\x7b\x15\xf4\x5e\xc3\xa8\x7b\x7e\x96\x85\x93\x58\xe6\x17\xee\xa2\x6f\x7a\x31\x4f\x13\x91\x60\x7b\xfc\x0a\xf7\xa3\x48\xf3\x21\x40\x8b\x17\xb0\x3c\x8d\x32\xaf\xb5\xc9\x82\x99\x1f\x46\x18\x10\xe7\xa1\x80\x39\xc2\x20\x1c\x53\x6f\xe1\x5c\x4a\xce\xf1\x03\x71\xef\xfc\x59\x0a\x63\xbd\xa0\x6c\x00\x77\x00\x69\x81\x77\x96\x84\xa3\xb5\x4d\x36\x8c\xa0\xed\x3d\x02\x6f\x80\x60\x31\x8b\x9e\xf9\x29\x40\xb6\x4e\x9e\xf9\x62\x38\xad\x46\x09\x7f\x72\x2f\x0f\xa3\x51\x19\x83\x43\xf6\x6c\xb8\xd5\xe7\x8a\xe0\x38\xa2\xde\x24\x10\x8f\x4d\xcd\x0e\x62\x7d\xd1\x9b\xe3\x07\xe4\x05\x74\xbf\x09\x88\x1e\x16\x21\x84\x80\x0f\x18\x5f\x1f\x2f\xdb\x61\x3f\x84\x23\x86\x26\x2d\x83\xa3\x32\x3c\x02\x3c\x4d\x95\xbd\x82\xf9\x70\x10\x2b\xcb\xaf\xe0\x42\x38\x74\x6a\xb7\x03\xb9\x3d\x60\x89\x78\xee\xb6\x7d\xfc\x95\x59\xfc\x09\x0e\xd1\x71\x3b\x1d\x27\xeb\x85\xd9\xfd\x28\xc9\x00\x32\x1d\x77\x90\xf2\xa7\xb0\x9d\x7b\x33\xff\xc2\x49\xd7\xb7\xd8\xa6\xeb\xa5\xd0\x26\x4b\x7a\xf3\x3c\x9b\x3a\x43\xb7\x1f\x44\x70\x7e\x51\xdd\xb1\x08\xc5\xa5\xac\x7a\x39\x79\x13\xe2\x53\xd9\xd7\x48\x0e\x1a\x27\x25\x1c\x5f\xbe\x14\x29\xe6\x53\x25\x22\x77\x41\x25\x4c\x05\xfa\x58\x4e\x7a\x1f\x93\x10\xd0\x71\x1b\x8f\x6f\x53\xd2\x6b\x40\xcb\x7a\x46\x9f\x96\x2b\xe3\xb8\x80\x27\xe6\x91\x3f\x0c\x70\x3f\x60\xba\xc4\x16\x94\xe5\x05\x15\x7b\xe3\x47\x94\x02\xd5\x37\xa5\x79\x36\x4c\x12\x81\x81\xf3\x49\x55\xa9\x9a\x77\x62\x98\xbb\x98\x57\xa3\x24\x99\x22\xa1\x56\x82\xae\xcb\xda\x08\x70\xf1\xc4\xda\x26\x9a\x96\xa2\x3a\x63\x98\xa8\xd6\x96\x8e\x12\x66\x24\xc1\xa8\x5c\x47\x38\xae\x00\xd4\xfd\x78\x88\xc5\x83\x1e\xc2\x0e\xac\xa0\xa9\xa6\x27\x92\x97\xd4\x86\x23\x4f\x9f\xd4\x40\xd9\x2b\x03\x9a\x00\x1e\x09\x4f\x7b\x27\xf8\x05\x63\x32\x04\x8a\x55\x76\xc1\x2a\x70\xe9\xd5\xf6\xa9\x82\xdd\x72\x4b\xe8\x3a\x04\x9c\xd1\x4b\x89\x44\x1a\x06\x56\x44\xaf\xac\x19\x4e\x03\x6a\xcb\x5a\xb1\x15\x8d\x59\xbb\xad\xa1\x35\x2b\x55\x35\x67\xc5\xf4\x6c\x78\xb8\x22\xec\x40\x85\x30\xa4\x90\x04\x7d\x53\xd0\x20\x0b\x8a\x52\x1f\x15\x4c\x41\x09\x56\x04\x9c\x59\x6a\x14\xe5\x1c\xaf\x18\x44\x89\x1f\x1a\xc6\x50\x26\xaa\x21\xdc\x8d\x87\xd3\x24\xb5\x16\xee\xaa\xc4\x5e\x54\xc2\x7c\x96\xa8\x4b\xd6\xa4\xbe\x2c\x0c\x26\x41\x5f\x7f\xca\x2e\x2f\x58\x40\x5b\xd1\xc2\xba\x78\x60\x48\xb8\xa1\x2e\x38\xb1\x01\x8f\x94\xb2\x02\xbc\x60\x29\x9a\x5c\x7e\x85\x41\x6b\x9d\xaf\x4c\x92\x1d\x81\x48\x9c\x5f\xf9\x27\x30\x63\x70\x5c\x3d\x0d\xc4\x34\x19\xd9\xd3\x43\x0c\x41\x5b\xa7\xb7\x17\x4c\x22\x7c\xcf\x3e\xc7\x4a\xb4\x89\xf0\xbf\x26\x5c\xd1\x9b\xfa\xd9\xfe\x79\xfc\x2c\x4d\xe6\x41\x2a\x2e\xa1\xa3\xb0\x07\x83\x83\xf8\x08\xa8\xff\xb8\xa4\xba\x03\xe8\xc1\x85\x00\x42\xc1\x6b\x1a\xa3\x28\xcf\x10\xd8\x12\x56\x9f\x16\x88\x94\xcc\xf1\x92\x4a\x12\xba\x1f\x02\x06\xae\x35\xdb\xb6\x4e\x9e\xb6\x3b\x80\x5d\x6f\x9d\x44\xf6\xd1\x69\x27\xf4\x80\xf0\x8b\x2e\x25\x6e\xf0\xd3\x09\x51\x29\x80\x7d\xa8\x15\x9f\x87\x56\xcb\xb8\x08\x89\x1e\x8b\x6f\xd7\xc1\x43\xe6\xf7\xb2\x1c\x7a\x41\x8b\xca\x53\x36\x02\x0c\x2f\x82\xb5\x4a\x17\x58\xf5\x0c\xf5\x61\xe8\x2c\x84\x29\x89\xa2\x70\x9e\x85\x99\x57\xa7\x15\xcc\xd9\x2a\x0f\x9a\x6d\x41\x88\x0d\xe9\x29\xce\xe3\x41\xbb\xd7\x6b\x7b\x31\x0b\x38\x90\xbc\xf9\x89\xc4\x65\x0e\x1c\x7a\xeb\xfa\x60\x72\xbb\x50\x3f\x4c\x39\xc0\x64\x70\xb1\x3f\xae\x2d\x21\x60\xaf\xbb\x69\xea\x5f\x96\xe3\xeb\xa9\x8c\xae\x69\x57\x45\x20\x5a\x32\x2b\x0e\x67\x5f\xca\x75\x97\xfa\xe9\x76\xdc\x8f\xe1\x1c\x82\xda\x68\xb9\x01\x97\x96\x48\x54\x06\xd6\xb7\x16\x2c\x9b\x47\xa1\xb8\x1b\x8f\xee\xfb\x73\x88\x0a\x96\xbb\xd2\x02\xfc\x1a\x25\x27\x7e\xe4\x4a\x8e\xd4\xe2\x5f\xff\x9c\x0a\xbf\x08\x26\xc1\xc5\x9f\xaf\xcd\xf2\x4c\xac\x4d\xfd\xb3\x00\x4e\x17\xe0\x63\x27\x37\xd7\xc6\x91\x3f\x59\xcb\x90\x8d\x2a\xfb\x08\x3d\x84\x63\x3a\x01\x2e\x10\x0f\xf0\xe0\x22\x18\xc2\xb1\xd4\x77\x53\x79\x96\xd9\xf3\x95\x00\x5d\x4b\xa3\x84\x2d\xa8\x92\x63\xe0\x6a\x5d\xe2\xe8\x28\xa1\x8b\xdf\x66\xb8\x7a\xf7\x2d\x57\x84\x15\xd0\x1e\x56\x87\x00\x57\x8b\x2d\x01\xde\xd9\x27\x92\x8c\x5d\x9d\x4f\x43\x11\x64\x73\x38\x94\x68\x44\xde\xc6\x61\xd6\xdd\x60\x8d\x70\xba\x8a\xe8\x92\x07\x67\x08\x14\x6d\x8a\x6d\xf1\xea\x67\x51\x58\xdf\xaf\x9e\x3e\x81\xc9\x37\x64\xc5\xca\x53\x5a\xc8\x74\x2e\x0f\x65\x8d\x3d\xab\x45\x1a\x4b\x14\x45\xbb\x4d\x2d\xdc\x15\x15\x22\x80\x09\xc3\xfe\xab\x13\x0f\x33\x64\x8e\x41\x05\xf1\x41\x00\xc8\xa1\x6c\xae\x56\x7e\x89\x88\x50\xc5\xa1\x94\x69\x2e\x5b\xa6\x05\x56\xb5\x56\x9d\xc7\x58\x4f\xa2\x69\x39\x5b\x35\x4c\x1f\x13\xf1\x50\x30\x1f\x80\x46\x5d\xea\xc2\x7d\xdc\xe9\x2b\xbb\xac\xfa\x08\x28\x09\xb3\xb5\x19\x4a\x3b\xfc\xd1\xa8\x56\xc8\x46\xa5\xac\xa4\x0e\x28\x17\x11\x06\x14\x53\x83\x19\xa0\x3f\xd5\x78\xd4\xfe\x04\x62\x34\x1d\xa4\x3d\xda\x27\x00\x88\x1e\xc0\x7e\x06\x70\xaf\xbf\x61\x13\x40\x7f\xa6\xe1\x18\x89\x16\x77\x7d\x0b\x36\x69\x48\xc8\xa7\xd3\xf1\x15\xc8\x9b\x89\xaa\x4f\xb7\xea\xfe\x11\x70\xf0\x92\xec\x5b\x6b\xeb\xa9\x4b\x83\x59\x72\x16\xfc\x7f\x32\x20\x5f\xed\x47\xc2\x87\x66\x6c\x30\x38\x25\x53\x93\xc3\xeb\xaf\x6f\xb5\x80\x06\xc6\x51\x62\x49\xa0\x39\x73\xb6\x65\xe8\xd8\x5f\x31\xd2\xc9\xd2\x62\xaf\x04\x4f\x5d\x8b\xdc\x17\x70\x3c\xad\x82\x12\xea\x1b\x36\xd2\xad\xcd\x51\x17\x1b\x36\x98\x17\x33\x04\x14\x45\x30\xb7\xab\x77\xf9\x4a\xb8\x2b\xd1\x82\xb5\x97\x1b\x8a\xad\x28\x25\xfb\xad\x49\xcf\x3a\xdd\x14\xd8\xf4\xab\xe4\x53\x98\x22\x97\x88\x7e\xa5\x59\x40\x3e\xa2\x84\x27\x2e\x06\x34\x48\x64\xda\x0e\xda\x77\xda\x24\xe6\x6b\x6f\xb7\x99\xae\xc9\xf4\x0d\xea\x6a\xdf\xd9\xc0\x0c\x90\x7c\x64\x71\x19\x95\xaa\xed\x2e\xd1\xb9\x61\x36\xa6\x3a\x77\xda\x52\x78\x17\xd4\x51\x01\x74\xf4\xe0\xa8\x5f\x21\x5c\x02\x37\x68\x22\x5c\x84\xda\x14\xdd\x9b\xbc\x7d\xb3\x8b\xc7\x5a\xf7\x66\xfb\x66\x39\xa4\x12\x3e\x16\x0b\x38\x60\x97\x08\xc3\x15\x98\xff\x57\xe1\x78\x35\xea\x06\x0c\x27\x89\x51\x75\xc8\x38\x57\x0a\x0f\x7b\xc0\x43\x32\x9a\x06\xcf\x62\xab\xe4\xd0\x85\xc5\x89\x52\x58\x76\xf8\x31\x90\xcb\x24\x91\x33\xc0\x41\x25\x81\x1c\x18\x06\x59\xa6\x06\x85\x9c\x8e\x55\x46\x72\x3e\x28\x4c\xd3\x68\x5c\x73\x69\x35\x2c\x6a\x1d\x00\x57\x53\x68\xc8\x03\x92\x5c\xa1\x03\x99\xff\x7e\x26\xb7\x06\x1e\xcc\xfa\x54\xc5\xed\x5c\xee\xc3\x54\x1d\x74\x86\xac\xc6\x64\x38\x77\x52\xe8\x0d\x6f\x1f\x9f\x44\x7e\x7c\x8a\x82\x59\xdd\x03\x5d\xa3\x57\x17\x41\x2b\x08\x35\xe4\xb6\x59\xc8\x81\xe8\x12\x6c\x76\xdb\xeb\xb0\xcb\x3c\x84\xfc\xa5\xd1\x37\x6d\x34\x05\x5b\xa3\xe4\x95\xa2\xec\x1d\xc4\xee\xe5\x67\x65\xd5\xaa\x27\x90\xa6\xf5\x1c\x79\xf4\x19\xde\xa0\x28\xf6\xf2\xd9\x09\x30\x47\xcf\xf6\x5f\xee\xbe\xda\x7d\xf3\xf0\x78\x77\x6f\x67\x77\x6f\xf7\xd5\x7b\x05\x64\x8d\xfc\xda\x0a\x48\xc3\xbc\x92\xba\x58\xda\xbf\x1b\x07\x9b\xeb\x3f\xf8\xeb\x9f\xef\xae\x7f\x38\x2a\x83\xde\xd1\x37\x1b\xb0\x3f\x36\x0e\x7e\x77\x98\x1d\x6e\xb6\x6f\x6e\x1f\x6e\xf0\xc3\x8b\xcd\xad\xf5\xc3\x8b\xad\x9d\xc3\x8b\x3f\xdd\x39\x02\x1a\x25\xe6\x1b\xce\xc0\x6b\x1f\xfc\xae\x7d\xf4\xcd\xa0\x5d\xdc\x3c\xf8\xdd\x4d\x08\xdc\x2c\xe0\xb7\xcd\xef\x6c\xff\xf9\x61\x76\xd4\x75\x37\x70\x95\x7b\x59\x92\xa7\x43\x40\x5b\x90\xff\xf0\x30\xfb\x86\xe3\x9f\x76\x37\x36\xf1\xee\xa0\x6d\x00\x08\xc0\x19\xfa\xfa\xf0\x62\xee\x1c\x60\xfe\x36\x20\x01\xa7\xf5\x60\xff\xfe\xab\xf7\xcf\x1e\xba\xf0\x25\xe3\xa0\x86\xae\xfe\x48\x59\xbb\x68\x33\xab\x36\x48\x70\xbf\x69\x13\x56\xa1\x8f\xc2\x14\xbb\xe3\x6c\x40\x5b\xf0\x85\xa2\x60\x3b\xbf\x5d\x6b\xaa\x8a\x63\x2f\x37\x06\xa6\x9e\x12\x05\xb1\xf6\x24\x84\xcd\x0e\xdb\x07\x67\xf6\xfe\xd4\x47\xd6\x28\x48\x1f\xa2\x9c\x25\x0c\x32\x45\xc8\x39\x9d\xf8\x24\x9b\xf7\x8b\xce\x9f\x6c\x7d\xb7\x09\x3f\x91\xc0\x30\x05\x27\x32\x78\x0b\xfe\x7e\xca\x13\xfa\xb8\xfd\x5b\xfa\xfb\x43\xdf\xdd\x98\x84\x8c\x64\x4c\xcd\x82\x29\x66\xce\x51\xb3\xac\x48\xd9\xc2\x99\x09\xe8\x0c\x79\x01\x3c\x47\x04\x4f\x35\x99\xab\x4f\x41\x1f\x58\xaf\x4d\x3a\x37\x0f\xb6\xe0\x38\x12\x07\xb7\x51\x2a\xd5\x6a\x89\x83\x5b\x47\x78\x4d\x50\x21\x82\x85\x22\x82\xfb\xc3\x52\x76\x42\x7d\xc2\x2d\x00\x74\x3b\x0d\xf5\x72\x2f\x19\x05\x99\x33\x44\x81\x3c\x62\x48\xc5\x38\x85\x70\xd4\xea\x28\xc7\xda\xe1\x4a\x02\x8c\x85\xf0\x0e\x8c\xe5\x2e\x9d\xff\x8a\xaa\xd6\x47\xf8\x02\x90\x78\x72\x47\xf3\x13\x5a\x2e\x55\xa5\xac\xfb\xd1\x97\x7b\x15\x35\xf5\x4a\x9f\xf5\xc0\x64\xad\x28\xd7\x4c\xb9\x20\xf7\x60\x36\x57\x8d\x77\xd1\x3b\x77\x35\x28\xb8\x6a\x7d\xcc\xfd\x53\xb8\x9d\xf4\x93\x2e\xbf\xa5\x17\x26\x3d\x48\x70\x61\xe0\xa7\xbb\x75\xd4\xf7\x3b\x9d\x78\x69\xf2\xb0\xa7\x72\xe6\x60\xd6\xb2\xa6\x1c\xe5\x20\x9c\xac\x1c\xa9\xc1\x86\xd6\xec\x57\x98\x6d\x14\x3a\x5b\x5b\xaf\x82\x58\xec\x15\xbb\x12\x88\xfc\x04\xd3\xe7\x0b\xca\xb2\x9e\x24\xe7\x41\x7a\xdf\xcf\x48\xa4\x29\x05\x93\x5e\xba\x30\x82\xba\xb2\x47\x4d\x08\x70\xb9\xb5\x72\x00\xaa\xb1\xb2\x2a\x3d\xfc\xaf\xaa\xc8\xcc\x55\x59\x4d\x13\xca\xc4\x2c\x2b\x10\x26\x95\x03\x02\xe5\x57\x1e\xd1\xea\x58\xf5\x74\x72\x45\xa8\xc2\x94\xc0\x77\x25\x03\x05\x69\x4b\xfd\xb4\x56\xa0\xd6\xd5\xc6\xe1\xb0\xf2\xf8\x6f\x9b\x15\x69\x6d\x99\x8e\x2d\x35\x6d\xe4\xce\xbf\x82\xc5\x5b\x30\x23\x86\x5e\x95\x53\x35\xbd\x3c\x1c\xb3\xc4\x5f\x37\x9a\x6b\xfa\x2d\x65\xda\x4b\x2d\xe8\xb5\xff\x8b\xd6\x8f\xab\xa1\x6a\x5f\x21\xaa\x5c\x01\x3a\xd7\xdd\x6e\xd4\x2e\x34\xa8\xe2\x20\x5d\x75\x32\x3b\xbf\x83\xa3\xf4\xf0\xfc\xc8\xfd\x33\xe7\xf0\xfc\x6a\x8b\x6d\x7d\xbb\x70\xe9\x54\x86\xb3\xea\xe0\x70\xbd\xef\x75\xf8\x61\xf7\xf0\x06\x3b\x3c\x3f\xec\x1d\x75\xff\xcc\xd5\x27\xf2\x01\x1c\xe0\x70\x8c\x1f\x1d\xac\xf7\xba\x32\x08\xe7\xfa\x51\xd7\x73\x06\xad\x55\x49\x87\x1b\x87\x1b\x2e\xa4\x1f\x8e\xba\x87\x1b\x03\x17\x8f\x69\x8c\x19\xd0\xf1\x8d\x75\x9e\x9f\x43\x23\xf0\x95\x00\x4d\x60\x0a\x1e\xf6\x0e\xd7\x8f\xbe\xb1\xbe\xd7\x8f\x36\x00\xcd\x6d\x1c\xf6\xa0\x44\x18\xc3\xa0\x63\xba\x18\xf4\xa3\xc2\x6c\x24\xf8\xc4\x0f\xda\x17\x09\x70\xd2\x01\x66\x9b\xa7\x61\x16\x64\xc5\x7c\x9a\x88\x64\x92\xfa\xf3\xe9\x65\x01\x74\xd7\x48\x66\xcf\x8a\x71\x92\xc7\x23\xaa\xa9\x08\x67\xb3\xe4\x24\x8c\xc2\x00\x82\xf1\x28\xc7\x09\x85\x82\x33\x3f\xf6\x27\x04\xc7\x58\x0e\x09\x77\x8c\x15\xc1\x70\x1a\x27\x51\x32\xb9\x2c\x86\x53\x68\x41\xcc\xfc\xac\xc0\xab\xc4\x3c\x06\xd0\x29\x46\x61\x1a\x60\x1f\x2e\x8b\x00\x5a\x92\xd5\xa3\xba\xc0\x9c\xea\x41\x31\x7e\x28\x72\x20\xc4\x66\x7e\x7a\x1a\xe0\x6d\x60\x91\x25\x51\x2e\x7b\x74\xe6\xcb\x02\x59\x71\x02\xe4\xa7\x1f\x62\x20\x81\xb4\x4f\x79\x50\x9c\x48\xa2\x1f\x9a\x02\xbc\x85\x07\x56\x31\x8c\x02\x3f\x96\x81\x04\xb6\x07\x06\x92\xd9\x1c\xaf\x05\x8b\x11\xf0\xcc\xc3\xd4\x17\xd0\x1b\x7f\x96\xc4\xa3\xac\xa0\xf1\x87\xc3\xac\x98\x26\xd1\x08\xef\x20\x8b\x28\x9c\x4c\xa9\x7d\x38\xb2\x44\x8c\x35\xcf\x23\xa0\x0d\xa9\x47\x39\x9c\x6d\x34\xd6\x14\x3a\x81\x31\x67\xd0\x79\x38\x94\xb2\x02\x7a\x08\x95\xc3\xd0\xfd\x34\xa0\xde\x40\x93\x7e\x0c\xdf\x69\x4e\x93\x3d\x4a\x66\xd4\x6f\xbc\x06\xcc\x82\x51\x31\xa6\x66\x60\xb2\xa3\x04\xe7\xaa\x98\xf8\x51\x14\xc0\xe4\x4c\xf2\x10\x48\x6c\xea\x4e\x38\xf2\x2f\x8b\xd3\x10\x81\x36\x2e\xe2\x00\x66\xdf\x4f\x8b\xe4\x34\x8c\xfd\x73\xbf\x80\xc9\x0c\xe7\x50\x6f\x0a\x1d\xf0\x23\xfc\x3d\x0b\x83\xf3\xac\x00\x5e\xfc\x34\x9b\xfa\x05\xe2\x83\x08\xd2\xb1\xcb\x49\x2a\x8a\xec\x32\x13\xc1\x0c\xfa\x39\x09\xe2\xe1\x65\x01\xa4\x6e\x14\x02\x68\x00\x7e\x49\xfd\x62\x48\x60\x01\x7d\x1e\x8f\x83\x00\xe1\x65\x94\x40\x8f\x7d\x9a\x85\x00\x2f\xc2\x83\x22\xc0\x91\x52\xf7\x61\xb9\x8b\x71\x2e\x4e\x92\xa8\x38\xf5\xf3\x31\xf4\x2d\xca\x2f\x72\xe8\x3a\x0c\x30\x83\x45\x85\x79\xf5\xb3\x69\x31\xcb\xb3\x20\x9f\x15\x00\x29\xc9\xa5\x2f\x61\x0d\x7b\x39\xf7\xc3\x14\x7f\xa8\x4f\xc9\x30\x04\x60\xa5\x59\xbd\x2c\xa0\x19\x91\x24\x05\xc0\x12\x40\x1f\xce\xf0\x59\x10\x15\x67\xa1\xff\x11\x46\x71\x16\x46\xc0\x3d\xc0\x4f\x86\x60\x73\x96\x50\xcf\xce\xa0\xe2\x49\x50\x10\x64\x4b\x30\xc0\xd9\x87\x35\x85\x09\xf3\xe7\x05\xaa\xd4\xe0\x28\xe2\x21\xf4\x1e\xb1\x43\x31\x41\x0e\x04\x66\x16\x7a\x86\x30\x3c\x49\x0a\x58\xc3\x8f\x3e\x2d\xb4\xda\x0e\x30\x7f\x09\xce\x5a\x12\xc1\x5c\x8b\x04\x57\x40\x24\xa7\x97\xd0\xad\x24\x81\x59\x3e\x47\x14\x52\x9c\x27\xe9\x29\xcc\x64\x90\x26\x85\x9f\xce\xfd\xc2\xcf\x42\x1f\x66\x14\x56\xf1\x24\x3c\x05\x88\x8c\x08\x2c\x3f\x7f\xc6\xe9\x85\x7e\x44\xf9\x09\x74\x26\xc1\x5d\x99\xcc\x8b\xb1\x9f\xce\x8a\x71\x08\x33\x34\x09\xc7\xb0\xee\x79\x9a\x03\xf4\x8f\x93\xe2\x63\x72\x92\xc1\x72\x9f\x87\xc5\x69\x0a\x00\x02\xec\x15\xfc\x09\x67\x49\x81\x37\x0d\x05\xec\x92\xbc\xc0\xcd\x08\x7f\x60\x7a\x50\xcd\xa0\x98\x23\xdc\xce\x31\x15\x60\x4a\x14\x9f\xe6\x30\x37\x69\x08\x1d\x4c\xf3\x69\x5a\x64\xc1\x05\x74\x1e\xb8\x1d\x9c\xaf\x00\xff\x24\xd0\x7f\x98\xb7\x73\xdc\xce\xe7\xe1\x69\x58\x7c\x4e\xe2\x00\xb7\x14\xf4\x7b\x04\xff\xb1\xc3\x27\xb8\x8f\x00\x20\x12\x84\x60\xdc\xaa\xc5\x24\x39\x83\x0e\x0a\xe8\xda\xac\x98\xc1\x2c\xc6\x81\x28\x92\x38\x2a\x92\x74\x82\xdb\xbf\x98\xc3\xf0\xb0\xc3\x02\x96\x2b\x8f\xa1\x0d\x08\x5f\x5c\x5c\x14\x17\x97\x9f\x61\x6d\x0a\x7f\x04\x33\x55\xf8\x63\x80\xbc\xc2\x0f\x0b\x58\x6f\x7f\x56\xf8\x71\xe1\xc3\xe4\x7d\x82\xf9\x83\xd9\x2b\xa0\x45\x3f\x2f\xfc\xf3\xc2\xbf\x28\xfc\xcf\xd0\xa3\xe2\xe4\xa4\x38\x81\x2e\x41\xef\xc6\xc5\xc9\xa4\x38\x99\x42\xf7\x8a\x93\x8f\xc5\xc9\xac\x38\x89\x61\xf3\x17\x27\xd0\x69\xc0\x02\x30\xe5\x67\xc5\xc9\x79\x71\x02\x20\x8d\xdd\x2f\x86\xc3\x62\x08\x70\x30\x2e\x86\xb0\xed\xa7\xc5\x30\x2c\x86\xa7\xb0\x04\xc5\x70\x56\x0c\x11\x15\xc2\x86\x2c\x86\x79\x31\x3c\x2b\x86\xe7\xc5\xf0\xa2\x80\xbd\x30\xfc\x0c\x78\xa1\x18\x7d\x2c\x46\xa7\xc5\x68\x06\x3b\xb5\x18\x7d\x2e\x82\x61\x01\x5b\x21\x00\xf8\x4f\x61\x0b\x14\x30\xe6\x20\x87\x65\x2b\xc6\x1f\x8b\xf1\x69\x31\x86\x25\x4c\x8a\x71\x0a\xdb\xb6\x98\x9c\x14\x93\x51\x01\x80\x38\x19\x17\x93\x49\x31\xc1\x85\x05\x50\x2b\x26\xb3\x62\x12\x17\x93\x79\x31\xf9\x04\x58\xa6\x00\xcc\x32\xc1\xe5\x2e\x26\xe7\x05\xa0\xc8\xe9\x69\x31\x9d\x15\xd3\xb8\x80\x95\x9a\x8a\x62\x0a\x40\x30\x2a\xc2\xa0\x80\x09\x86\x79\x86\xad\x19\x26\x45\xf8\xa9\x80\xcd\x12\x66\x45\x28\x8a\x8f\x41\xf1\x71\x06\x30\x52\x7c\x9c\x17\x00\x63\xa7\x93\xe2\x74\x0a\x4b\x52\x9c\xce\x8a\xd3\xb8\x38\x85\xc8\xb4\x38\x3d\x2f\x4e\x01\x63\x7c\x06\xd8\x29\xa2\x93\x22\x1a\x02\xe8\x14\xd1\x69\x11\xa5\x05\xc0\x6e\x24\x60\xa3\x16\xd1\x59\x11\xe1\x56\x2d\x66\xc3\x62\x36\x02\xb0\x2a\x66\x93\x62\x06\xdb\x15\x40\x2c\x2a\x66\xb0\xc4\xb8\x83\x0b\x80\xdb\xd9\xa7\x62\x96\x16\x80\x32\x66\x02\x36\x73\x31\x3b\x2b\x66\xe7\xc5\xec\xa2\x00\x24\x37\xfb\x0c\x00\x58\xc4\x43\x80\x85\x22\x1e\x17\x00\x53\x71\x58\x00\x48\xc0\xea\xc7\xf3\x22\x4e\x0b\x80\xd5\xf8\x73\x01\x00\x04\xbb\x63\x0e\x80\x3a\x2e\xe6\x00\x2c\xd3\x62\x0e\xa0\x1a\x15\x73\x88\x8f\x01\x76\x0a\x80\xcd\x39\x9c\x21\xe7\xc5\xfc\xb2\xf8\x84\x38\xad\x00\x78\x02\xe4\x07\x5b\x22\x3d\x2f\x32\xc0\x62\x27\x45\x36\x2c\xb2\x11\x00\x73\x91\x01\xfe\x9d\x02\x5e\x2b\xb2\x8f\x45\x76\x5a\x64\x80\x38\x66\x45\x16\xc3\x5e\x2d\x32\x80\x76\x40\x27\x79\x91\x9d\x15\xd9\x05\xe0\xba\x22\xfb\x5c\x88\x61\x21\x00\x2a\xc7\x85\x98\x14\x62\x5a\x88\x8f\x85\x38\x2d\x44\x54\x88\x59\x21\x62\xd8\xcf\x85\x98\x03\x96\x29\x84\x28\xc4\x59\x21\xce\x0b\xf1\xb9\xc8\xfd\x22\x9f\x14\xf9\x69\x91\x67\x45\x7e\x59\xe4\x9f\xe1\xe4\x29\xce\x86\x80\xe5\x8b\x33\xc0\x37\x61\x71\x06\xc8\x27\x2f\xce\xc7\x05\x60\xda\xcb\xa0\xb8\x14\xc5\x67\xbf\xf8\x3c\x2b\x3e\x9f\xbb\x87\x27\x1b\xcc\x87\xe3\xfa\x70\xdd\x1c\xd0\xdd\xce\x9f\xfd\xc9\xe1\xc6\x6f\xf8\x5f\x3e\x76\xdc\xe2\xe6\x8d\x6f\x0e\x0f\x0e\x8f\x06\x2d\x8f\xf5\xfa\x70\x8c\x7f\x21\xdf\xd1\x46\x33\x87\xde\x66\x9a\x91\xb6\x78\xed\x36\xd3\x3c\x3f\x4b\x74\x20\x6c\xca\xa6\xf8\x6e\xa7\x64\xdf\xcb\x02\x35\xd6\xdd\xe9\x0d\x36\x88\x79\x4f\xbf\x3a\xe7\x8a\xb6\x35\xbf\x0f\x3c\xa7\x25\x80\x58\xc5\xe2\x0f\x81\xa7\xbb\x17\x00\x2b\x18\x3c\xc3\x8b\xb1\x61\x02\x3c\x77\xa4\x74\x10\x88\xcf\xff\x9d\xd3\x73\x07\x48\x2f\xfd\x41\xd7\x36\x44\x04\xbe\xf1\xf1\x70\xc5\x7b\x43\xc9\xcc\x3c\xad\x44\xa2\x68\x9d\xd4\x16\x96\x2e\x04\x4b\x1d\x82\xf2\x62\x43\xeb\x53\x94\xb5\x2b\x12\xd3\xd2\xcf\x62\x09\x0b\x19\xf1\xe0\x6c\xc8\x22\x36\x97\x35\x8d\x81\x43\x55\xf2\xae\xfb\x80\xec\xb1\x71\xa9\x6c\xd1\x50\x00\x95\x1d\xc6\xb2\x18\xa9\xd0\xa1\x36\x45\xcc\xc6\xb2\x41\x23\xc1\x1b\x43\x7d\x48\xed\xbe\x14\x69\x77\xda\x1d\x03\x13\x3f\x96\x5f\x0b\x73\x01\xec\x1a\x19\x5b\xb5\xcd\x1a\x93\x6a\x77\x40\x09\x05\xd8\x9c\xe7\x45\x31\x64\x63\x8e\xfa\x3f\xf0\x87\x14\x30\x3a\x9d\x96\xad\x1a\x50\x14\xa1\x8e\x91\x67\x6e\xe1\xeb\x6f\xa4\xd4\x8b\xa2\xd5\xb0\x0a\xbd\x30\xa3\xb0\x1c\x3c\xb6\x3a\x77\xcd\x2d\x66\x1e\x45\x46\xc3\x84\x8a\x3d\xf6\xb3\xd7\xf1\x89\x1f\xe1\xc1\x3e\x52\x8c\x11\xb0\x08\x01\xae\x7c\xa7\x83\xea\x03\x4a\x78\x81\x97\xb1\x4a\x04\xb0\xbe\xe5\x62\x97\x5d\x00\xb4\xd0\x8d\x6c\x9d\x88\xde\x43\xec\xa6\x73\x35\x2b\x55\x4b\x80\xeb\x96\xdc\x44\xb8\x28\xd5\x76\x62\x17\xc5\xa3\xb0\x64\x8c\x1a\xa0\xeb\x8c\x2d\x17\x75\x3a\xed\xca\x5e\xc9\x59\xa8\x57\xa7\x26\xe7\x31\xe9\xf5\x79\x89\xaa\x16\xe5\xe7\x0a\x14\x46\x7c\x2e\x6b\x50\x12\x86\xeb\xf7\x80\x4b\x12\x25\x58\x80\x11\x75\x69\x54\xed\xd2\xa2\xda\xa5\xd7\xe9\xd2\xe8\x60\x25\xe0\xef\x5c\x55\x0d\x19\x24\x04\xb4\x5a\x99\x89\x84\xf6\x80\xfc\x3b\x0b\x74\xca\xfc\x0b\x3a\x1f\x0a\xc0\xae\x0c\xfc\x79\x63\x66\xa0\xcf\x9b\x4a\xde\xcb\x8b\x16\x0b\x76\xfd\x1a\x36\x08\x8f\x03\x9a\x8e\xbb\xc2\x09\xca\xc5\x24\x1d\x2e\xb7\x4d\xd7\xdd\x4a\xcc\xad\xc6\xeb\x6c\x1c\x3a\x1b\x13\x97\xc4\x47\x3a\xc2\xc5\x88\x84\xc7\x28\xc6\x91\x55\x14\x05\x09\x88\x3a\x9d\xb4\x8c\x20\x6d\xee\xed\x44\x01\x5e\x6b\x53\x0d\xa9\xb5\x25\xd9\xd2\x2a\x8e\x58\xc1\x8d\x86\xf1\x19\xe6\x58\x85\xb9\x0e\x80\xbd\x94\x98\x6b\xea\x67\x3b\x00\xd9\x65\x46\x95\xe1\x1a\x86\x71\x03\xd6\x2d\x7c\x09\xcb\x38\x0b\xbe\x94\x9d\xea\x7f\x9b\xa4\x23\x14\x90\xdd\x1d\x03\xe8\xd5\x1a\xf2\x50\xd2\x7c\xf4\xcd\x40\x57\x00\x7c\xa4\xb5\x05\x57\x29\x42\x08\xbd\x95\x55\xe6\xd7\xba\x3f\xb0\xf3\xd4\xb5\x77\xae\x80\xe9\x01\x50\xd1\x7b\x89\x78\x0c\x44\xbc\x6e\x7a\x3f\x7d\x90\x08\xba\x98\x58\x9d\xf7\xae\x78\x12\xf8\x99\xd8\x8f\x03\xdd\x7b\xbb\x40\x98\xed\x2e\xcd\x6f\x09\xa5\xb0\x45\x07\xad\x2d\x60\xf4\x17\xac\xde\xbf\x46\xa8\xb2\xf6\x5b\x75\x62\x5d\x54\x38\xa8\x48\xdb\x14\x7e\x6d\x7f\xf4\xcf\xfc\x6c\x08\x60\x2f\xbc\x76\x0b\x60\xaf\xd3\x69\x9f\x9d\xd8\x11\x0b\xf6\xa5\x09\xa8\x5d\xd1\x28\x18\x73\x5a\x01\x8c\xb1\xd3\x91\x92\xcd\x06\xd8\xe8\x09\x60\x2f\x68\x9a\xe9\xe2\xb2\x54\x0d\x69\xf7\xda\xb0\xe5\x9b\x9a\x5d\x9e\xcb\xc6\xb6\xd7\x02\x68\x76\xd0\xd2\x2d\xaf\x86\x1a\xd9\x85\xc0\xf5\x60\x47\xb0\xeb\x97\xa2\xe1\xd2\xa6\xd5\x0a\xd4\xf0\xae\xdb\x23\xba\x0d\x4b\x12\x24\x37\xde\x1f\xe7\x4e\xef\x8b\x02\x43\x4b\xc1\x70\x95\xac\xcd\x42\xa5\x52\x7d\xc1\x5c\xe6\xad\xae\xd6\xba\xce\x6a\xcc\x63\x8d\x96\x8e\xa3\x25\x69\x9a\x35\x13\xd7\x4a\xe9\xb0\xb0\x94\x2d\x52\x3d\xab\xc6\x40\xf9\xea\xbd\x5f\xae\x0e\x73\x89\xc4\x53\x57\xe4\xf5\x42\xd7\x4d\x92\xcc\x6b\x0d\x4b\x1d\x8c\x7f\xe8\xc0\xd4\x01\xaa\xc4\xa6\x95\xd3\x74\x95\xf0\xd4\xce\xf4\xe5\xa1\x4e\x85\x98\x67\xde\xc6\x86\x2a\xd6\x03\xe6\x77\x43\x8d\x7b\x55\x4d\xcd\xe3\x6f\xff\x59\x63\x31\x6b\x2a\xe0\xbc\xbd\x7e\x1a\x60\x2f\xcb\x63\xd5\x10\xbc\xd4\x3b\x2d\x24\x74\xa4\x70\x70\xb0\x11\x2e\x9d\xd6\xba\x80\x3c\x2e\x74\x2a\x54\x36\x47\xe3\x80\xd1\xf5\xa2\x69\x68\x56\xce\x2f\x74\x70\x85\xe2\x01\x64\xa9\x28\xaa\x34\x52\x0b\x0a\x59\xd7\xc9\x8b\x5a\xb4\xe9\x54\x51\x38\x65\xed\x9c\x16\x02\xd6\xa1\xdd\x55\xfa\xc9\x4b\xf9\x79\x6b\x93\xb4\xea\x56\xae\x68\x55\xfb\x00\xc9\x1f\x77\x99\x5a\xdf\xe8\xf8\xb3\x79\x7f\x63\xc2\xda\x9d\xb6\x7b\xcd\xa2\x5e\x53\xd9\xea\x19\x40\xdd\x4b\x6e\xd3\x48\xd5\x3c\x72\x71\xf1\xaa\x90\xd5\x09\xa9\x5a\xc9\xd7\x1a\x12\x28\x73\xa0\x75\xaa\x51\xef\xe7\x55\x0a\x3b\x0c\xa8\xa6\x97\x91\x8f\x9a\x70\xa8\x9e\x52\x29\xd1\x78\x6f\x5e\x65\x56\xaa\x70\xc6\x48\xd7\xe3\x9a\x0e\x7f\x45\x8d\x8d\xf0\x28\x2b\x6e\xe8\x75\x43\x85\xed\x0d\xa4\xe9\x9a\x28\x3e\x9a\x99\x40\x51\xb9\x9b\x6c\x1d\x69\x6f\xb9\xad\xc8\x96\x65\x71\xc4\x6e\x57\x8d\x3d\x2c\x1b\x40\xa9\x57\x0b\xfd\x3b\x96\x52\x4c\x6e\x7f\x14\xc5\xd5\x42\xae\xc3\xf1\xcc\xbf\x78\x12\x66\xb0\x25\x83\x54\xe7\xb1\xa3\x8a\x42\x5a\x31\x2c\x4c\xc5\xa9\xd5\xf3\x65\x43\x92\x60\x61\x59\x21\x96\x19\x63\x52\x34\x68\xcc\x16\x5a\xd9\xea\x36\x24\x70\x7c\xaa\xdb\x66\xab\x80\x6f\xad\x85\xec\x1c\x4e\xdf\xa2\xb4\x36\x89\x81\xd1\x7f\x88\xe3\x7c\x38\x93\x08\x18\x23\x4a\x8d\x53\x3d\x21\xca\x3c\xa3\x92\x54\x99\x0d\x93\x61\x24\xad\xec\x9e\xda\x89\x5b\xd5\x92\x59\x50\x4d\xb6\x97\x19\x55\x86\x70\x32\x80\xde\xde\x06\x92\x27\xcc\xf6\xfc\x3d\x04\x6e\xa9\x75\x8a\x98\x49\x69\x9d\xc6\x52\xd5\xf4\x24\x58\xf3\xd7\xe6\xc0\x1f\x20\x38\xad\xa9\xa9\xab\x6e\xc1\x6a\x47\xb5\xd6\x95\xdd\xa1\x00\xc6\xce\x97\x48\x40\x60\x73\x13\xc9\xe0\x1a\xfe\xd2\x80\x44\xe5\x13\x35\x0e\x99\x32\x7f\xc3\xe9\x05\x50\x6c\xd9\xe9\x3d\x4a\x82\xc1\x38\xcb\xb1\xae\x26\x99\x2b\xb1\xfa\xb6\x9d\xe6\x43\x70\xa3\xf5\x0c\x7c\x1d\x13\xb6\x49\x03\x4d\x86\x9a\x1c\xd1\xaf\x4f\xd2\xcd\xd7\xf1\xd0\xcf\x27\x53\xc1\xd6\xf2\x38\x9b\x07\xc3\x70\x1c\x06\xa3\x35\xd5\xd5\x35\x6a\xb1\x77\xd3\x5d\x90\x31\x85\xdd\x8b\x83\xe0\x88\xf9\x40\x2f\x6b\x5e\x67\x0b\x67\x20\xc5\x88\xec\x3c\x24\x1e\x5c\xf7\xc8\xe8\x05\x0c\x81\x10\x5e\xdb\xf2\x2c\x43\x0e\xb7\x7f\x92\x06\xfe\x69\x9f\x52\x6e\xd9\x29\xcc\x1e\x50\x25\xdb\xed\x95\xd9\xac\x8f\x5b\xa6\x8c\x02\x36\x0f\x15\x03\x12\x5e\xef\x14\xcb\x88\xd1\x25\x2d\x6a\x27\x41\x16\x3f\xe7\x5b\xfd\x64\x3b\xef\xe7\xdd\xae\x9b\x1d\xe4\xeb\x5b\x47\xd6\xdc\xe6\x47\xfd\xd8\xd6\x35\xcf\x94\x85\x0d\xb2\x7d\x38\xf4\xab\x3f\x56\x2b\x58\xcf\x90\xc7\x0a\x57\x21\xe7\x39\xd4\x75\xe5\x7c\xd3\x14\x1d\x42\xde\x5a\x7f\x0c\xeb\x59\x01\x5f\x7f\x34\xd2\xf0\xcd\x97\x15\xbc\x12\xb2\x4e\x4e\x81\xea\x5d\xde\x44\x91\x2a\x66\xed\x25\x83\xa6\xdc\xaf\x81\xfa\x0a\xe8\xc2\x34\xe8\x7e\x28\x52\x1e\x37\x16\x6c\xd5\x32\x1e\xb5\x07\xd1\x06\x51\x37\xec\x0e\xca\xb0\x27\xaa\xf5\x01\x10\x0e\xaa\x5b\x06\x62\xa0\x40\x35\x42\xe9\x5d\xb8\x5e\x2d\x9e\x1f\xd4\x01\x5a\x1c\x2d\xe5\x11\x6c\xb9\x81\xda\x86\xc4\x26\xce\xfd\x34\x0e\x46\x7a\x3a\x01\x04\x9c\x65\xc4\x82\xd6\x0c\x0d\xb8\xcf\x5b\xce\xc9\x92\x4e\x27\xd9\xde\x54\x53\x64\x35\xa3\xac\x08\x12\x14\x52\x35\xf6\x00\x48\x1b\xa6\x6d\x69\x03\xb9\x82\x4e\x9c\x8c\x02\x77\x0d\xd3\xf1\xfe\x1f\x51\x61\x16\x9e\x44\xc1\x9a\x8d\xd4\xd7\x66\x70\xb8\xa6\x97\x6b\x11\xec\x99\xb5\x51\x20\xe0\xdc\x08\x46\xbd\xb5\xdf\x8c\xd6\xf4\xdc\x67\x6b\x00\x44\x18\xf7\x1a\x00\x3e\x90\xa5\xea\x78\xda\x71\xd7\x44\x02\xc8\x07\x35\x40\x20\x57\x14\x42\xb6\x5e\xbb\xbe\x64\x1a\x21\xb0\x86\x03\x4f\xf7\x1d\x39\x1b\xc0\x92\x95\x4f\xc7\xad\x68\xfe\x56\x21\x3c\x89\xf9\x0a\x80\xaf\x65\x1b\x06\xfc\x4b\x67\xbc\x24\x34\x74\x79\xb4\x7f\x85\x1d\x08\xb0\x9d\xe0\xec\x8a\x66\x63\x13\x42\x91\x7f\xd0\x1e\x22\x90\xe1\x80\x40\x8d\xc9\x99\xce\xaf\x94\xeb\x7b\xd4\xd3\xd8\x6d\x38\x96\xaa\x3d\x6d\xd8\xda\x78\x40\xf9\x2c\xfb\x8b\x6c\xf0\x56\x75\x87\xd7\x41\xdf\xb5\x96\xa4\xdf\x7c\x4c\x18\x3b\x4b\xc0\x63\xeb\x5b\x0c\xad\xf2\x44\x51\xc0\x61\x51\x6e\x72\x92\xab\xe9\x61\xa0\x48\x4e\x19\xdf\x2c\xed\x50\x1b\x9b\x54\x47\x5f\x41\x28\xd5\x24\x52\x59\x2e\x05\xb1\x25\xae\xce\xb8\xdf\xcf\xd6\xd7\xb7\x37\xfb\x68\xfe\x12\x1f\x64\x47\xb2\x6f\x18\x32\xfd\x81\xbe\xd9\x9f\x52\x62\x98\xf0\x4c\x9e\x30\xb8\xee\x9b\x46\xe6\x27\xa7\x01\xf5\xf3\xf5\x98\x07\x8e\x0e\xf1\x4d\xd6\x3c\x2a\x17\x8e\x34\xa5\xde\x9e\xb0\x2d\xf7\x2f\x34\xc8\xd5\x3b\x44\xe6\xbe\x1b\x45\xcd\x64\x95\x22\x68\x96\x56\xbc\xbe\xbe\xad\x6b\x7a\xa7\xf3\x22\x09\x59\x3f\x04\x07\xb5\x93\xa1\x8e\x69\xd1\x5a\x7a\xe5\x92\xf7\x95\xd5\xeb\x32\x51\x81\xab\x28\xc8\x84\xcd\xee\x73\x7d\x6a\xa4\xa4\xcd\xda\xdc\xf6\x34\x58\x26\x9b\xab\x72\xd4\xeb\xab\xae\x11\x57\xe4\x7f\x33\x95\x44\x44\xd1\x2a\xbc\x22\x61\x12\x07\xd1\x37\xc6\xc8\xab\x32\x1f\xc4\x86\x97\x29\xed\xf1\xae\x99\xb4\xea\xf2\x47\xab\x57\xdd\xd2\xf4\xb7\xaa\x59\x3a\x7d\x06\xe9\xf2\x51\x5b\x3f\x42\x97\x0e\x50\x4d\xc2\x78\x07\x47\xd8\x1f\xdd\x8b\xfb\x49\x1e\x8b\x26\x7c\x65\xb0\x20\x0f\xca\x8e\x98\xe0\x81\xc0\x5e\xd8\x9f\xee\x60\xcb\xb3\xbf\xd5\x14\x79\x9b\x0b\xc9\xd2\xfd\xf6\x5a\x96\x6e\xa1\xcd\x16\x35\xb3\x73\xb5\xe8\xa7\x40\xa5\x5c\x88\x57\xe1\xf0\x94\x2f\x71\xf1\xed\x3c\x96\x86\xfc\x23\x00\x29\x75\x64\x9d\x2b\xcd\x76\xf9\x8b\x47\xe2\xee\x6c\x16\x8c\x42\x34\x17\x15\x5f\x53\xe2\x69\x2e\x48\x35\x69\xff\x44\x7a\x79\x00\x04\xf9\x15\xa5\x50\x5f\xe3\xa9\xf4\x8c\x61\xe2\xe0\xd4\xa3\x43\x5d\x43\x0d\x6e\x9b\x40\x6f\xca\x06\xde\xbb\xa1\xcb\x28\x07\x50\x86\xce\x07\x47\x44\xdf\x29\xa2\x86\x1b\xf7\x0f\x55\xef\x10\xed\x51\x78\x86\x77\x62\x44\xe2\xd6\x87\xe2\x2c\xcd\x60\xaa\x01\xa2\x9f\x96\x68\x31\xe8\xc1\x0e\x78\xe8\x03\xd7\x60\x77\x32\x40\x4f\x08\xa5\x9d\x42\xd8\x4b\x64\xad\xe8\xdf\x02\xed\x24\xc2\x93\x5c\x04\xa8\xb9\x07\x54\x66\x65\x70\xe6\x42\x26\xd1\x36\x5c\x94\xd5\x69\x5f\x06\x59\x9b\xb5\xe3\xa4\x6d\x2c\x05\x51\x4e\xac\x21\x6e\xe0\xac\x98\x46\xa7\xad\x5c\x90\xb4\x97\x7c\xe3\xe0\x2d\x80\xbc\x91\xc6\xb9\x02\x46\x8c\x73\x59\x09\x9c\x21\x64\xe4\xc9\xf1\x46\xb1\xad\xee\x4b\xd7\x05\x40\x95\x14\x4f\x8c\x7c\xe1\xa3\x40\xa2\x97\x89\x04\xa5\x25\x73\x7f\xe2\xcb\x89\x62\xba\xff\xdb\x9b\xae\xbe\x99\x4a\x8d\xf1\x17\x64\x00\xc8\x46\x01\x56\x75\xc8\x6a\x34\x6c\x19\x3a\x9c\x6a\xeb\xac\xfd\x4d\x1b\x3d\x4c\xd8\xc5\xd1\xbc\x30\x9c\x05\x49\x8e\x97\x2b\x9b\xd0\x00\xf5\x42\x84\x22\x02\x90\x3f\x01\x82\x21\xc3\xe3\x25\xed\xa9\x20\x92\x41\x69\x2f\x88\xcf\x10\xf1\xa5\x3d\x40\xca\x67\xa4\x6e\x4d\x44\x18\x46\x58\xdc\x46\x4c\xd1\x40\x74\x51\x60\x3c\xa6\xdf\x1a\xd9\x52\x46\x55\x4e\x27\x8c\x26\xbe\x1b\x03\x27\x30\x2e\x20\x5f\x79\xdd\xce\xd9\x36\x33\x55\xe3\xd4\x79\xd7\xc2\x6c\x0d\xdd\x26\x29\xfd\x35\xd8\x4b\x28\x44\xea\x0d\xcf\x47\x7c\x59\x74\xb9\xd1\xa6\xb4\xe9\x28\x4c\xbf\xaa\x0d\xca\xd9\xd4\x82\x44\x3b\xdf\x2e\xbb\x0d\xa9\xc0\xb6\xbd\x31\x6c\x59\x90\xb2\xa5\x0d\x5a\xf6\xb5\x24\x02\x0c\x5a\x10\x20\x34\xd1\x96\xde\x06\x12\xa5\x15\x17\x85\x85\x26\x6c\x21\x8f\x39\x87\x89\x29\x17\x28\x25\x69\xa5\xcd\xb9\xe1\x54\xd4\x2e\x13\xd6\xb7\xf4\x4e\xd8\xac\x48\x9d\x64\xef\xb1\xa2\x96\x65\x1a\x3c\x93\xc7\x97\xd6\xb7\x4f\xb9\x03\xfd\xd9\x74\x81\xbc\x4b\x4a\xd3\xe2\x6e\x37\xbd\x93\xf4\xa5\x65\x71\x5a\xb1\x2c\x4e\x4b\xcb\x62\x5b\x74\xc5\xac\xbb\x58\x55\x07\xb6\x80\x7b\x2c\xc5\xbb\xab\x7e\xbc\xbe\xde\x77\xc9\x4c\x19\xff\xf4\xce\xfc\x28\x0f\x4a\xd3\xf4\x26\xa1\xd6\x92\x8b\x88\x60\x10\x78\x72\x6f\x06\x83\x76\xdb\x0b\xba\xed\x76\x59\x30\xab\x48\x26\x51\x86\x78\x1f\xb8\xa7\xbb\xc2\x81\x5d\x61\x32\xe5\x35\x0b\x7a\x24\x6a\x53\x7b\xd4\xf1\x1d\x24\xd4\xcc\x05\x9b\x11\x46\x02\x21\xb0\xbd\xbe\xd5\xb7\x4c\xaf\x4c\x9d\xc3\x7a\x9d\xa6\x3a\x18\xf2\xaf\xad\x2c\xaa\xdc\xce\xe1\xfc\x0d\xd3\x10\x55\x5b\x7d\xf2\x15\x24\x83\x6e\x51\xa8\x3b\xc0\x75\x55\x7b\x59\xc1\xbc\x61\x84\xb8\xae\xa6\x9a\x90\x97\x15\x01\x81\x9f\xd8\x63\xf7\xfb\xda\x8f\x4a\xea\x24\xb0\x4a\x2c\x24\x07\x02\x00\x05\x86\x98\xcc\x16\x55\x03\xf5\xe5\x1e\x8c\xad\x85\x78\x2c\xd0\x66\xd8\x24\x4d\xad\xa4\x37\xd5\xa4\x91\xb5\xee\x87\x87\xed\xee\xa7\x6a\xf2\x4c\x43\x73\x09\xb6\x41\xc9\x9a\xc4\x03\xe4\x4a\x3c\x47\x48\x40\xee\xc7\x83\x64\x7d\xdd\xeb\x76\x93\x3b\xa9\x1a\x51\x08\x50\x97\xd0\xa9\x18\xc2\x5e\x30\x7e\xdb\x92\xc5\x32\x30\x9f\xd9\x80\x04\x27\xc0\x92\x2c\x16\xf6\xa4\x95\x7d\x62\x65\xdf\xfa\x6e\x73\x1b\x45\x84\xc1\x36\xff\xa1\xd3\xd9\xba\x0d\x1f\x45\x71\xfb\x16\xc7\x1f\x48\xa3\xdf\x6f\xff\x54\x05\xbe\xdb\xfa\xf6\x7b\x0a\x40\xee\xef\xb7\x7e\xb8\x05\x67\xca\xf7\xb7\x36\x6f\x51\x99\xef\x6f\xa9\x52\x10\xb8\xad\x03\x3f\xa8\xc0\xf7\x7f\x2a\x2b\xbc\x75\xeb\x7b\x59\xc1\x77\xdf\xde\xfa\x53\x4c\xb4\x00\xfd\xf2\x5a\x40\x97\xdc\x1c\x19\x31\x11\xc8\xab\x8d\x49\xa4\xb6\x74\x25\xf0\x16\x96\x1e\xe6\xef\x88\x97\xd6\xc9\x61\x59\xfb\xc3\x5a\xed\x50\x75\x05\x7d\x40\xd5\xf0\xed\xcb\xfa\x09\x91\x28\xb0\x42\x64\xc2\x72\x2e\x06\xc2\xc9\x58\xca\x02\xd7\xcb\xfa\xc8\xa5\xa1\xbb\x1c\x60\xd3\x63\x9e\x33\x1f\xda\x0d\x8f\xb8\x11\x88\xad\xf9\x65\xbb\xf7\xab\x5e\x83\x88\x23\xb5\x36\xaf\xb8\x13\x77\x3a\x13\xa7\xb2\xfb\x05\xda\x64\x19\x32\xb9\xac\xea\xa4\x5a\x95\xa9\x45\xe0\x9e\xfd\xca\x3a\x2e\xac\xa5\x7f\x5b\x85\xd7\x17\x54\xbd\xfe\x12\x4a\xfa\x8d\xa0\xd5\xe9\xb4\x6e\x64\xf2\xd7\x09\x6c\x71\xef\x44\x4a\x84\x2b\x71\xc6\x29\x0e\x11\x29\x41\x26\xe5\xa7\x01\x6b\x1f\x1f\x43\xff\xc2\xf8\xf8\xb8\x0d\x15\x55\xe2\xcf\x53\x7f\x3e\x0f\x46\x98\xa2\x0b\xdf\xc5\xab\x8a\x85\xa5\x51\x88\x07\xd9\xc2\x22\xa7\xd5\xde\x92\x0c\x40\x59\x83\x92\xa7\x43\x94\x72\x15\x06\x51\x70\x56\x1c\x68\x66\x5e\xf7\x01\x0d\xdb\x6a\x1b\xe2\xab\xaa\x02\x54\xae\x63\xe1\x48\x86\x98\x2d\xf3\x09\x64\x15\x31\x1a\x10\xb9\xa9\x23\xc7\x61\x04\x58\x8b\x6a\x6b\x99\x9c\x88\xc8\x80\xa6\x0d\xea\x15\x0a\xff\x34\xd0\x35\xbc\xcc\x74\x2c\xa9\xc9\xab\x9c\x65\x8f\x6f\x54\xef\xfa\xac\x3e\x6a\x03\xeb\x4a\x3b\x4c\x73\x8a\xba\x3a\x26\x55\x09\x27\x4e\x7d\xd4\x96\xc7\x18\x7b\xe0\xc1\xe0\x06\xe9\x52\x50\x7f\x53\x33\x7a\x7b\x2a\x64\xb4\x35\x0b\xcb\x13\x43\x59\xac\x39\x59\x9a\x25\xca\x60\xcf\x8f\xc0\x76\x85\xd5\xae\x3d\x49\xcb\xf3\x46\x59\xcc\x8c\x61\xd9\x58\x97\x2d\xe7\x2e\x10\xd2\x16\x7c\xa9\x75\x3d\xa5\xe5\xcc\x00\xcb\x6c\xc6\x0a\x5b\x37\xa8\x2d\xe9\xa6\x94\xc8\x07\xda\x60\x38\x89\x51\x7e\x6e\x8a\x7c\x03\x65\x1a\xe8\x85\x58\xd4\x17\xcf\xcc\xbe\xa4\x31\xa4\xaf\x28\xb9\xe7\xf4\x86\x78\x1e\x3b\xcb\xf0\xe8\xf6\x2d\x7b\x65\xbd\x0c\x31\xdf\xdc\x16\xb0\xbe\x97\xa8\x50\x68\xd0\x5b\x75\xf9\xa5\x0f\x29\x34\xd0\x10\x64\x78\x18\xc4\x23\xc0\x7d\xe1\x7a\xc2\xb2\xa6\x65\xcb\xf9\x71\xe6\xf8\x0d\x70\x8a\xae\xca\xe2\x41\xe8\x25\x30\x39\x51\x13\xdc\xcd\x79\x34\x88\x0c\x9b\xcc\xc6\xb0\x35\xa6\x88\x63\x03\xba\x23\xe9\xfb\x88\xba\xf2\xed\x31\x60\xdb\x61\x17\xe8\x4d\x8d\xdd\x46\x38\xdb\x33\xc0\xbd\x43\x44\xc7\xa3\x3b\x73\x85\x8e\xcf\x78\x74\x30\x3a\x62\x13\x7e\xd6\xd3\xad\xb0\x4b\x3e\x71\x66\x6c\x08\x98\x99\x3d\x84\x78\x3c\xf2\x70\xfa\x1e\x72\x7e\xcf\x9d\xf1\x4b\x23\x88\x6b\x5d\xd2\xaa\x43\xfc\x8e\x8b\x26\x46\x61\x9c\xc3\xd2\x49\xb9\x1a\x2c\xcf\x22\x1b\x64\x70\x02\x4f\x0f\xc6\xdd\xee\x11\x9f\x69\xdc\x33\x2d\xd7\xed\xb1\x30\xf7\xb2\xc7\xc8\x51\x01\x04\x5c\x2d\xca\xe4\x37\xa2\xee\x5b\x61\xea\x4b\xac\x59\x11\x9b\xa8\xa2\x15\xd4\xfb\xd6\x2a\x0a\xf8\x90\xe4\x28\x80\x0d\x91\x68\x3c\xf6\x56\x17\xfb\xdc\x5c\xac\x45\xe7\x79\x56\x5e\x5c\x99\xd2\xcc\xc6\xa1\x9f\x84\x4d\xb8\xd5\xcb\x3b\xf5\x66\xb9\xf6\x81\x62\x2a\x78\x2f\x2c\xc6\x74\x10\x98\x55\xa6\x55\xa4\xe2\x58\x98\x5f\x4d\xf1\xee\xfc\x7e\xe6\x48\xc7\x8e\xc0\xfe\x79\xb8\xc1\xa6\xd9\x02\x4f\x2e\x25\x80\x92\x1c\x25\x8a\x58\xca\xfa\x1f\x89\x2a\x8d\x8e\xb5\x01\x5c\x2f\xd1\xd8\x40\x42\xed\x87\x80\x24\x06\x31\x72\xe0\x34\xeb\x88\x31\x30\x30\x85\x1a\x0d\x42\x1b\x6c\x7a\x36\xd1\xf4\x5c\xd4\x0c\xfe\xb1\xfe\xfe\x32\x05\x4f\xb5\x07\x78\x33\x84\xb5\x03\xbb\x89\x78\x50\xc8\xda\x61\x5a\x5a\x16\x03\x73\xa3\xd2\xe3\x2a\xa1\x4e\x93\x42\xee\xc2\x76\x7c\x27\x85\xe3\x59\x91\x31\x42\xf3\x17\x0d\xa7\xf5\x07\xf1\x75\xc4\x3f\x11\x40\x2c\x86\xe5\x6d\xa1\x0f\xba\xbe\xdb\x80\x75\x7e\x5c\xaa\xab\x46\xf4\x7f\x4d\x25\x41\xdd\x9f\x57\x53\x87\x88\x07\x6b\x59\xf5\x95\xd7\xb6\xe6\xc2\xb0\xa4\x33\xae\xaf\x71\x99\xec\x53\x36\xd1\x34\x63\x02\xfd\xb6\x30\xdc\x62\x8e\xa2\xfd\x7c\xcb\x86\xbb\x44\xb8\x5f\x6c\x83\x96\x44\xb7\x90\x90\x1f\xb2\xb2\xfb\xa5\x0f\xe0\x92\x79\x8e\xaf\x21\xeb\xa0\xea\x67\x99\xa4\xed\xfa\x5a\x9e\x85\xa0\xdd\x4f\xb6\x51\x27\x3b\xe5\x89\xe9\xa4\x75\x2a\xd5\xfd\x4b\xd6\xab\x7c\xd9\x58\x65\x4a\xd7\x73\x2b\xaa\xf4\x15\x99\xc4\x52\x5d\x86\xe6\xb2\x02\x92\xd0\xa3\x90\xac\xe5\x03\x9a\x40\x9c\x84\xe4\x4e\xd8\x77\x81\x60\x70\x60\xf0\x68\x79\x9e\x58\x73\x60\xf1\x7d\xd9\x52\xed\xf5\x8a\x13\x55\xf1\xfa\x3a\x56\x9c\xe0\x66\xff\x72\xb5\xf9\x57\x83\x58\x03\x84\x6d\xf6\x8d\x12\x74\xc9\xec\x56\xd4\x47\x1b\xa5\x18\x03\xe1\x59\x40\x1e\x59\x03\x5b\x2a\xd4\xb2\x44\x1f\x1a\xc7\xa6\x40\x89\x02\x9f\x6f\x6d\xdc\x79\xcd\x04\x23\xc8\x51\x9e\x40\x4e\xbd\xf5\x81\x3e\x45\xcb\x05\xf4\xe9\x6a\x0e\x3d\xb5\x3c\x69\x39\x52\x5a\x89\xaa\x13\x80\xe0\xc0\x47\x76\x24\x06\x66\x04\x1d\x65\x33\x5f\xde\x36\x39\x39\xf2\x23\x03\xfc\x9b\x79\x19\x6c\xe0\x0c\x37\x45\x53\xbf\xb3\xa2\xf0\xa5\x33\x1b\xd4\x64\x43\x37\xdd\xb9\xbb\x58\xde\xe9\xe3\x2f\xee\x99\x73\x58\x63\x97\x78\x73\x15\xe5\xe3\x36\x0a\xe5\x36\x0a\x0d\xff\x84\xf8\xad\x9f\x0c\x9c\x8c\x93\x4b\x85\x9d\x28\xf1\x81\x93\x72\x81\x69\x82\x5d\xf6\x22\x45\xa6\x0a\x26\xef\x20\x3b\xf2\x8e\x5d\xcf\x97\xc8\x30\x3b\x6a\xe0\xa4\xa6\x66\x4e\x63\xe2\xbb\x04\x50\xba\x57\x0b\x5b\x2a\x44\x0c\x5d\x5c\x93\x07\x29\x5e\x3a\x06\x36\xae\x2f\x0e\x42\xac\x3e\x34\xd5\x5b\x4b\x36\x6a\x1e\xb0\xa8\xc1\x9d\x02\x75\x1a\x15\x82\x31\x9f\x03\xa7\x82\x4b\xf3\x94\x05\x4d\xf3\x38\xab\x1b\xe3\x28\xe8\xe9\x2f\xab\x61\xa5\x83\xa6\xf5\x02\xfe\xf6\x02\x99\xa1\xc1\x07\x5d\x93\x57\x8a\x94\xf6\x7d\xcb\x79\x6f\x3a\x78\x8d\x38\xc4\x6b\x14\xbd\x0d\x1e\x43\x5a\xb7\xdd\x76\xbd\x8f\x32\x80\xd7\x77\xa5\x00\xc1\x80\xbc\x34\xa4\x51\x8b\xa7\x2c\x66\x60\xed\x92\x01\x39\x20\x66\x09\x1c\xac\xa4\xdc\xd7\x08\x5a\x46\xe2\x42\xa0\x4e\xc7\x66\xc9\x0d\x4a\x57\x5b\x44\xd4\x62\x72\x4e\xd4\x58\xc6\x1f\xe2\xe0\x58\xcb\x08\xeb\xe8\x0c\x55\xba\x2e\x57\xca\x39\xbd\x66\x16\xd1\x7c\x65\xc8\xf9\x73\x2c\x3f\x6c\xf1\x0f\x9d\x0e\xfc\xfd\x8c\xfa\x4d\x51\x51\x24\xa6\xad\x1d\x01\x74\xe3\xe0\x04\x25\x9c\x43\x18\xa6\x97\xc0\xe6\xbc\x5a\x90\x4c\x88\xdf\x4f\x9d\x68\x70\xb5\xf0\x2a\x6d\x12\x68\x65\x0c\x76\x69\x80\x77\xeb\x00\x5e\x78\xe2\x00\x8c\x42\x08\x45\x02\x25\x90\xcd\x79\xa8\x01\x62\x8e\xf8\x0c\xa5\x33\x07\xf3\x23\x94\x64\x68\x88\x85\xcf\xf2\x16\x41\x4b\xca\x95\xe3\x34\x80\x7b\x27\x1f\x7c\x10\xde\xb3\xd8\x85\x26\x8d\x5c\x16\x27\xf6\x2a\x43\x70\x3a\xc3\x0f\xa9\xeb\x15\xd0\x4a\x2c\x80\x64\xb2\x38\x55\x0b\x37\xa1\x4d\x89\x01\x9f\x12\x2f\x59\x1e\x11\x1f\xf9\xce\x9b\xf2\xf2\x2e\xb3\xe5\xc0\x81\xd2\x2c\x38\x66\x9f\xd0\xc1\x5d\x8a\x4a\xf9\x36\x44\x5c\x56\x7c\x32\xd9\xe4\x1d\xd3\x97\x35\x25\x2e\x53\x2e\x36\xa5\x04\x65\x82\x2e\x6a\x33\xee\x73\x9e\xa0\x5b\x63\x14\x27\xaa\x2b\x06\x7e\x6b\x73\xb3\xd3\xb9\x87\xe4\x19\xf0\x0d\x66\x67\xe5\xb0\x80\x3e\x7f\x24\xa0\x10\x32\xc9\x80\x8f\x34\x7b\xd0\xed\x86\xe6\xc0\x8b\x68\xe3\xd2\x22\x76\x3a\x78\xd7\x11\x95\x7b\x75\xce\x87\x66\x39\x04\x2d\x07\xa4\x5a\x34\x7e\x5a\xf5\x51\xec\x03\xe6\x8d\xdc\x3b\x9b\x68\x4e\xa3\x13\x96\x4f\xcf\x87\x2b\x67\x80\x06\x7f\x9e\x96\x0a\x69\x6b\xcf\x64\xde\x3a\x2e\x3a\x45\xd8\x26\x44\x14\x23\x81\x95\xa0\x28\x09\x97\x7a\x35\x81\x75\xff\x57\x34\xfa\x72\xa9\x51\xd9\x9e\x22\xe7\x52\x79\x38\xa6\xd7\xb4\x76\x52\x69\xcd\x9c\x9e\x72\xe8\xd6\x95\x02\x81\xa7\xb9\x2b\x6d\x21\x6d\x47\x71\x0b\x74\xa7\x55\xca\x96\xae\x27\x08\x4a\x4f\xa4\x9b\x5e\x17\xe5\xf7\x6c\x73\x5b\xba\x5e\x5e\x8f\xb7\x13\x88\x4c\xd0\xff\x68\xca\x9b\xd0\x57\x5a\x14\x40\xe9\x0c\x12\xaf\x9b\xca\x82\x44\x48\x75\x81\xec\x41\x8c\xbf\x8d\xa4\x7d\xba\xbd\xbd\xbd\xc9\x62\xf8\x4b\x3a\x6b\x31\x09\x08\x91\x95\x13\x0d\x03\x7f\x51\x19\xf8\xc1\xd1\xb5\x03\xd7\xa3\x35\x5e\x75\x82\xda\xc0\x8f\xeb\x03\x37\x64\x4d\xb5\xb6\x98\x85\x25\x83\xa8\xbe\x07\x0e\x70\xe2\xf8\xba\x05\x6b\x6d\xb9\xca\xed\x38\xd4\x6e\xd1\x9a\xe7\x56\xed\x25\xa9\xe0\xa4\xea\x06\xa4\xa4\xe7\x60\xef\xc1\x77\x26\x69\xe5\x92\x74\xc8\x8d\x1c\xf9\x0c\x90\x6e\xa7\x03\x30\x94\x6b\x8d\x06\x98\x45\x40\xc8\x39\x90\x02\xf7\x43\xf8\x71\x61\xb0\x10\x95\x73\x68\x33\xa7\xb3\x46\xbf\x0f\x42\xfc\x7d\x6e\x2f\xa7\xd6\x8a\xe8\xf2\x08\x9a\x1b\xde\x89\xfa\x6e\x06\x24\x24\xd2\x13\x80\x7d\xe5\x46\xc3\x83\x5a\x47\x9a\x2d\x66\x61\xb3\xa7\xf1\xb2\x8c\xbc\xdc\x38\x78\xcd\x4b\xb8\xb3\xc4\xb9\xb8\x95\x4a\x89\x7f\x88\x67\x3a\x11\x82\x09\x90\x0c\x80\xc0\x13\x57\xfa\xe0\x96\xba\x32\xcb\xcb\xfe\xaa\xa1\x3d\xd9\x54\x22\x9b\x0a\xcb\xcb\x85\x10\xf1\x89\xa2\xbd\x12\x85\x79\x04\x3d\x0a\x02\x34\x57\xfa\x85\x86\xf6\xab\x26\x4b\x6a\x9c\xef\x42\x0b\xc1\x3e\x6b\xcc\x12\xe4\x56\x96\x97\xd5\x2c\xaf\x1a\xb2\xec\x5d\x4f\xb5\xac\x64\x9f\x88\x7e\x79\x15\x12\x01\xf8\x25\xf6\xe9\x41\x8d\x84\xa1\x15\x6a\x50\xa7\x43\x51\x52\xe5\xa0\xf0\x91\x46\x04\x10\x27\xb2\xd0\x5b\xb9\xcb\x34\x89\x96\x00\x19\x2e\x55\xc6\x91\xb6\x46\xee\x06\x05\xeb\xe9\x11\x0f\x07\xa1\x3a\xad\xf0\x1a\xd0\x3b\x86\xfd\x61\xd1\x85\xbb\x15\xda\x45\x0a\xa4\xed\xdb\xbf\xcd\x96\xbc\x7b\xd8\x80\xd8\xad\x0d\xa1\xfc\x34\xeb\xd3\x12\x05\x5e\xaa\xfb\x4b\x24\x59\x8b\xfb\xe5\x65\x8a\xfc\xb0\xd2\x32\x3b\x2d\xd3\x57\xf0\x81\x0e\x88\x01\xde\xab\xa2\x11\x19\xde\x64\x7a\xa7\xb2\x97\xbb\xb1\xe9\x68\x39\x82\xd3\x66\xea\x4b\xd2\x4a\x8c\x68\x26\x3a\x31\x3f\xc1\x1e\xfc\xd4\x47\xc5\xd7\x0a\x4d\x04\x14\xd1\xe7\xc1\x90\x7f\xf0\x24\x49\x04\x44\xce\x13\xa2\xbc\xa0\x28\x64\x8d\x4c\x56\x81\xe4\x13\x64\x8d\x20\x6b\x24\xb3\xe6\x98\x55\xb8\x6a\x9b\xcf\x91\xb8\xfa\x80\xcf\xb7\xe0\xcf\x14\xbf\xc8\x96\x79\xda\xe9\xe0\x73\x42\xad\xb9\xa1\x97\xe8\xf2\x98\x0d\x65\xb1\x11\x9f\xaf\x16\xe8\xb3\x19\x1f\x5b\xd2\xa8\x5a\x2a\xd6\x3e\x2a\x8a\x99\xb1\x9e\x76\x46\x00\x40\x4a\x08\x0a\x38\x71\x36\x10\xe6\x4b\x98\xe9\xa1\xa3\x70\x6a\x29\x83\x5f\x43\xb0\x9d\x95\xc8\xe3\xcc\x10\x6c\x67\x55\x82\x0d\x3f\x45\x7f\x89\x58\x13\x72\x78\x13\xee\x64\x83\x71\xea\x8d\x52\xb7\xb6\x4c\x16\x99\x97\xcc\x1d\x2a\x47\xbf\x93\x72\x69\xef\x5a\x4b\xab\xe1\xdc\x10\x3e\x48\x5d\x4b\xa0\xd1\x63\x09\x4d\xbf\x15\x2e\x6f\x25\xb0\x71\x7d\xc4\xe5\x92\xf0\x41\xfc\x33\xc0\x97\x8e\x10\xb6\x0e\x90\x03\x3c\xf2\x5a\xe5\xdc\xd3\x43\x51\xe5\xc4\x60\x65\x58\x91\xae\x43\x9d\x07\x98\xab\x5f\xd6\xe7\x4a\x14\x5f\xd6\x92\x2b\x7b\x6f\x4d\x76\xe5\x47\x6c\x4e\x2f\x3a\xf5\x87\xb0\x49\x13\x27\x62\x73\xc8\xe3\x1d\xb3\xa6\xa3\x1a\x3d\x02\x0e\x39\x6c\xca\x39\x8b\x60\x9e\x5a\x9b\x4a\x5b\x75\x68\xba\xb5\x58\x96\x02\x3d\xf9\x35\xe7\xb1\xf6\x6d\xa7\xbe\x6b\x87\xf1\x6b\x5b\x5d\x06\x09\x7a\x7a\x94\xa3\x9c\xf1\x2d\xa0\x40\x0c\x33\x86\x1e\x0f\x13\xba\xe2\xc3\xa4\xa7\xa9\x53\x32\x11\x0d\x1a\x4c\x06\x39\x25\xa8\x24\x01\x85\x6c\xb0\x4f\xdd\x85\xf5\xea\xd4\x0e\x9a\x2b\x48\x8e\x38\x56\x8a\x04\x24\xb1\x01\xb4\x2b\xaf\xa8\x81\x38\x26\x66\x97\xda\xec\xaf\x6e\x53\x01\x10\x71\x02\xe5\x20\x3f\xd6\x0e\x0f\xd4\xb6\x1d\x98\xd2\x71\xad\xc7\x68\x48\x8e\xa2\x4a\x34\xf8\xf5\xae\xcb\xb5\x4b\xde\x14\x50\xa5\x8f\xee\x4c\x5a\x9b\x76\x9b\x3b\x0d\xa0\x7c\x4e\xca\xf3\x36\x2d\x81\x26\xbf\x12\xa7\xa8\x41\x39\xa1\xe6\x77\x44\xb9\x92\x82\xe9\x57\xce\xce\x30\xab\x26\xbe\x61\xf7\xa6\xb4\x8f\xa5\x02\x34\x86\xee\x49\xd6\xcc\x67\x3b\x0a\x73\xba\x7d\x4d\xd4\xf8\x47\x74\xfb\x20\x49\x15\x94\x83\x64\x08\x93\x51\x23\x01\x39\x24\x9f\x90\x43\x14\x62\xb7\x42\x40\xdc\x4d\x59\x8a\xa2\x25\x33\x71\x3e\x1c\xe0\xdf\xdc\xcb\xd1\x21\xb4\x11\x94\x0c\x5d\xb2\xdf\x32\x33\x72\x6f\x09\x6f\x6b\x00\xc8\x0c\xd6\xc1\xab\x63\x3c\x6b\x33\x83\x7c\x50\xed\xd7\xbc\xcc\x86\x04\x9f\xbc\xbe\xf6\x21\x41\x53\x5b\x24\xd7\x8a\x68\xaf\x0d\x59\x8e\x12\x2e\x64\x63\xf1\x36\xa5\xa9\xe3\x51\x1f\xf0\x2f\xe0\xf9\x9c\x35\x93\x76\x4f\x88\xb4\x03\xb4\x7f\x03\x9d\x71\x0e\x86\xde\x10\x2f\xc6\x86\x78\x22\x7b\x1f\x2c\xea\x0f\x72\xc0\x2f\xe4\xd8\xc1\xbf\x98\x44\xb9\x81\x59\x9e\x23\xad\xa3\x5d\x76\xe6\x06\x41\x46\x2e\x9b\x0f\xa8\xf3\xc0\x54\x43\x3f\xe5\x24\x78\x0e\x71\x67\x03\x34\xfd\x82\xb6\x70\x36\xcd\xeb\x0e\x91\x75\xea\x3d\xb6\xc1\xbc\x84\x8c\x0a\x54\xe2\x31\x7a\xec\xd1\x3d\xb5\x75\xd1\x52\xf5\x17\x5f\x92\x3a\x63\x8b\x21\x12\x52\x8b\x27\x55\x9b\x4f\xc1\xab\x25\x82\x12\x5a\x4f\x24\xa4\x93\xfd\x05\x52\x2a\x9a\x3a\x0a\xfb\x33\xb3\xaf\x43\xf4\x01\xbe\x58\x16\x01\xbf\xad\x59\xa5\x77\x87\x99\xb3\x9f\x39\xee\x37\x8e\x58\x0f\xba\xe8\xd7\xa2\xbc\xa7\xa9\xec\x1c\x5d\x55\x15\xb3\x11\xe9\x12\x03\x2b\x00\x3b\x00\xb8\x60\xbc\x62\x40\x41\xa9\xa4\x14\x2a\x08\xee\x53\x13\x39\x56\x2a\x03\x70\x3d\x6f\xc0\x65\x09\xc9\x2c\x09\x72\x33\xb2\x2e\x14\x97\x25\xdc\xaa\xd2\x67\xf9\x9e\x0d\xd0\x2e\x92\xcb\xb2\xd9\x33\xc5\x65\x89\x6d\x64\xdc\x62\xa8\x05\xf9\x2c\x21\xf9\xac\x0a\xc2\x4b\x5c\xa3\x83\x85\x0a\x58\x80\x20\xbb\xe5\xed\x8b\x45\x4f\xfe\xd4\xa4\x82\x7b\x3d\xcb\xa9\x71\x3d\x6b\xc5\x30\x19\xad\x96\x35\x1d\xef\xe3\xa5\x3b\x17\x92\x40\x54\xf8\xa2\x14\x85\x11\x19\xae\x73\x48\x52\x08\x29\x98\xb8\x97\xd1\x5b\x4b\x70\xdc\xe4\x38\xed\x8f\x00\x8b\x20\xa0\x7b\x0e\x09\x22\x50\xe7\x03\x76\xc8\xd0\x92\x46\x94\x72\xcd\x48\xee\xd1\x39\xe9\x85\x44\x24\x83\xf6\x88\x56\xf2\x97\x84\x13\x63\x8b\x6f\x52\x48\x20\x3f\x18\x23\x36\x9e\xdb\x32\x0a\x58\xa4\x5c\x6e\xab\x39\x74\xaa\x2a\xb0\x80\x6d\xcd\xe6\x24\xb0\x70\xf0\x0e\x09\x65\xbb\x0d\x79\x0d\xed\x3e\xb4\xee\xd0\xbe\xc8\x1f\x2c\x5f\x7d\xa8\x63\xaa\xe1\xda\xe3\x79\x55\x3a\xd1\xaf\x3c\x67\x34\x91\xaf\x8d\x68\x7a\x6d\x49\x18\x22\x9a\x05\xb3\x38\x8d\xc8\x8f\xc0\x11\x3c\xcf\x8c\x33\x5e\x1f\x15\x3d\x33\x04\x54\xbf\x87\xcd\xab\x04\xbf\x87\x37\x75\x77\xd3\x09\xee\x8a\xe5\xbb\x83\x1b\xb5\xad\x81\xef\x6f\x59\x1c\x09\xa9\x28\x2f\xd9\xb3\xa2\xae\xbe\xd4\x23\xda\xcd\xb6\x01\xd6\x69\xae\xf0\xae\xc6\x74\x31\xed\x26\x00\xee\x28\xdb\x22\x11\x94\x13\x0f\xc4\x36\xf7\x3d\xb1\xed\xe3\x33\x5b\x61\x77\xcb\x4b\x78\xb8\xa8\xe9\x67\xad\xbd\x93\x9d\xd9\xc7\xa7\x05\xca\x2e\xbe\xb3\xb8\x79\xd8\xab\xf6\x53\x29\xd2\x0b\x70\x8d\x83\x22\xee\x01\x40\xb7\x51\xa8\x4b\x9e\x82\x35\x55\x07\xf8\xc7\x49\xba\xa1\xbb\x71\x8b\x6e\xe5\x1d\xa4\xdb\x94\xc0\x94\x93\xc9\xa8\xef\x4a\x22\x3f\x2a\x8a\x54\xde\x8a\xcf\x79\x36\xc0\x23\xaf\xaa\xaf\x69\x44\x89\x70\x08\xa4\x38\xd4\x21\x0c\x75\xd8\x9f\x0f\x12\x9e\xc3\x58\x43\x9e\xeb\x21\x1e\x67\xb0\x54\x0f\x32\x6b\x78\x46\x48\xbd\x52\x3a\xa9\x8a\xee\xfb\xb4\x18\x4d\xa3\x2a\x45\xc6\xca\xba\x33\x36\xe6\x9c\xf5\xd3\xc2\x7e\xf4\x46\x31\x18\x30\xd9\xda\x76\x73\x29\x77\x05\xab\x94\x25\xa4\x2c\x4b\x96\xfa\x6d\x73\x29\x4b\x72\x53\x2d\x87\x80\x28\x4b\x7e\xbb\xaa\x24\x12\x06\x2b\xca\x12\x55\x57\x2f\x66\xe5\x56\xd6\x5f\xf6\x3b\x43\xd6\x8d\xae\x7d\x80\xfa\xe6\xc0\xb2\x95\x47\x83\x74\x59\xe0\x11\xd7\x64\x03\x2f\xb2\xd2\x6e\x3d\x85\xd2\x5a\x8c\x24\x4a\x0a\x06\x19\xf8\x6e\xe6\x12\x1b\x91\xf5\xdd\x1c\x89\x21\x62\x22\x14\x5e\x24\xa5\xc5\xfc\x20\x3e\x48\x8e\x8e\xa4\xb4\x89\x12\x48\x84\x02\x99\x51\x0a\x07\xb1\xf0\xa3\x71\x4a\x6e\x5d\x00\x37\x74\xb1\x72\x91\xa3\x35\xf3\xec\x7e\x26\xd8\xcf\x0c\xe3\xf3\xb2\x9f\x43\xec\xa7\xdf\xcd\x5d\x92\x1b\xfb\x7d\x77\xa8\xaf\x7b\xcc\x16\x8b\xe0\x68\xef\x76\xb3\x3b\x39\x26\x46\xdd\x0c\x87\x91\x99\x61\x10\x5a\xc2\x78\xbc\x2c\xa2\x92\x56\x97\x2d\xa4\x1a\xa7\x95\xa3\xbf\x0e\x5f\x8a\xcb\x83\x83\xc1\x55\xd7\x0e\x29\x3f\x4b\x51\xc6\xcf\x6e\xbb\x0c\x88\xb0\xd8\x75\x6b\x6c\x9e\x75\x69\x45\x33\xac\xb6\x34\xf1\x5c\x01\xec\xb1\x9c\xe1\x11\x40\x0f\x40\xc5\xea\x4c\x78\x88\xed\x59\x04\x75\x8c\x4d\x63\x5e\x81\x16\xad\xf4\x49\x12\xda\xf2\x00\xb6\xae\xaf\xd3\x26\xd2\x4b\x73\x4d\x4b\x16\xc5\xb1\x65\x2f\xbc\x49\x9c\xd2\x2d\x54\x0a\x57\xe2\xdc\xca\x23\x78\x62\xfb\x76\xa7\x73\x9c\x3a\x2b\x4d\xa5\xad\x8f\xdb\x47\xd2\xff\x19\xe0\x2b\x2a\xd6\x20\x52\x2a\x33\x8b\xf5\x5b\x92\x51\x4d\x39\xe0\x98\x32\x7e\x7d\x5d\xac\x57\x9a\x10\xeb\xeb\x47\xec\x5b\x65\xeb\x24\xb6\x6f\x7d\xb1\xde\xad\x23\xba\x41\xaf\x54\x79\x54\xc1\xca\x04\xe1\xc2\x1c\x07\x65\x4e\x14\xab\x02\x0f\x08\x0b\x11\xda\x0f\x11\x5b\x33\x9d\xa4\x0d\x86\x40\x8a\x31\xc2\xa3\xac\xa2\x39\x39\x48\xbd\xc0\x6d\xda\xf3\x72\xdc\x7e\xea\x34\xde\x98\x87\x8d\xab\xb9\x7c\xe8\x1f\xfb\x4e\xee\x23\xbb\x45\xca\x5f\x66\x73\xb5\xdb\x74\xfa\x23\xd9\xc6\x11\x7e\xe4\xbd\x41\x23\xdc\xf8\xd7\xc2\xcd\x47\xdc\xa0\xc6\x06\x8c\x9e\x40\x6e\x18\x8c\xae\x77\x1f\x0d\x23\x07\xb1\x27\xac\xfa\xb3\xeb\x37\x56\x42\xa0\x15\x2b\x61\x3c\xac\x19\x69\x14\xa9\xbb\xa7\x33\x24\xfa\x7c\x45\xfd\xd2\x49\x1f\xc2\xc1\x37\x03\x12\x56\x0a\x85\x5a\x38\x05\xa1\xda\x85\xae\x16\xb2\x91\x70\x2d\x96\x17\x92\xc0\xff\xdd\x0d\xad\xfb\x95\xc0\xc9\xa1\x7f\xbb\x74\xe5\xd2\x4f\xb9\x51\x23\x9f\xc9\x3e\x08\x1b\x17\xe7\x69\x95\x15\xd4\x9e\x08\x4b\xa5\x02\xa7\x5c\x8f\xfb\xcb\x5b\xec\x84\xdf\x67\x17\x88\xbf\xee\xbb\xfd\x13\x44\x9b\x17\x07\x27\xb6\x99\xfe\x09\x6d\x3b\xbc\xf5\xb8\xe0\x80\xd4\x2f\xa4\xe4\x83\x85\x14\x21\x30\x02\xcf\x12\x97\x8d\x8a\xe2\x4c\x8e\xec\x05\x8f\x7a\xe4\xea\x04\x1d\x45\x07\x29\x3b\xe6\x97\x90\xeb\x05\x0d\xf5\xfe\x3a\x3f\x36\x58\x73\xfb\xbe\x2c\x70\x0e\xc4\xc0\x0d\xbc\x9a\x97\x0a\x93\xfb\x88\x70\x87\xeb\xf7\x11\xd3\x3e\xe3\x23\x60\xc3\x28\xfa\x25\x04\x31\x00\xdc\xe8\x2e\x04\x2f\x64\xec\xa9\x8e\xbd\xe8\x8b\x02\xc2\x7b\xde\x03\x26\x3a\xfc\x2f\x3b\xa3\xc1\x03\x6f\xcf\x65\x33\x54\x7c\xc2\xef\xa7\xc5\x2b\x98\xcc\xbf\x84\xed\xdd\xe5\x66\xd2\x76\xd9\x33\x76\xca\x5e\xb2\x73\x98\xb4\x7d\x03\x21\x77\xed\xfe\xf3\x17\xec\xee\x82\x36\xc2\x13\x3e\x46\xb0\x99\x96\x4e\x2d\xa5\x03\x9b\x27\x07\x0f\x8f\xe8\xed\x03\x98\x91\x97\x38\x23\x19\xcc\x07\x70\xc6\xf9\x9d\x8b\xf2\xf9\x27\x1d\x04\x0e\x9c\x2d\x6d\xc0\x68\x30\x29\x0a\x82\xf1\x72\x1f\x3e\x61\x17\x72\xff\x01\xa9\xdf\x39\x65\x63\xf8\xfb\x94\x4d\xe1\xef\x2b\x36\x82\xbf\xcf\xd8\x0c\xfe\xee\xb3\x33\xf8\xfb\x92\x4d\x78\x0b\x1a\xa1\x1a\xd8\x43\x6e\x6c\x45\x2c\xbd\xdd\x61\x5a\x53\x0c\xb1\x24\x53\x82\x77\x01\x77\x6f\xa3\x49\x70\xeb\x24\x2b\xe5\x22\xea\x85\x22\xa0\xa0\xd7\xd3\xd2\x62\xd1\x3c\xeb\xb7\xd6\xf6\x62\xbc\xcf\x3f\xf3\x01\x2c\xb3\xcc\x49\x36\xcc\x83\x7e\xae\xf1\x3f\x93\x58\x44\x41\x94\x5a\x17\x4a\x06\x51\x39\x35\xe5\xa3\x6c\x19\x48\x73\x8c\x1f\x96\xb8\x23\x42\x80\xcd\xba\x43\x3c\x70\xf3\x3b\xc3\xbe\x1b\x01\xc9\xc9\x53\xed\x53\x42\xca\x3c\x20\x0e\xcf\xff\x12\x94\xbb\x25\x57\xb8\xb4\x02\xc9\xc0\x2f\xa7\x3e\x54\xcb\xcc\x22\xb9\x02\x21\xcd\xbd\x5f\xc5\x83\x16\x77\x32\x5f\xda\x83\x46\xe0\xd9\x79\x45\x32\xe3\xbc\x2a\xc1\x5f\x79\x63\x2e\xa5\x30\xf8\xa4\x98\x7d\xfb\x3a\xd4\x40\xbc\x57\x3c\xc0\x8b\xca\x44\xe2\x1f\x36\x5c\x47\x49\x4d\x49\xb4\x8b\xce\x03\xcd\x24\xa6\xc0\x21\x26\x7d\x9d\x75\x21\xd9\x41\xec\xc6\x63\x12\xed\x4f\xf9\x41\xd9\x63\x94\xaa\x52\xaf\x69\xab\x8f\x3b\x9d\x31\x5e\xdc\x22\xcf\xf7\x2a\x75\xa6\x6c\x8c\x2f\x52\x4d\xf1\x38\xcd\xe0\xe7\x07\x00\x75\xfc\xab\xc0\x20\x1b\xe4\xc0\x9c\x1b\xc6\x01\x76\x6e\xb6\x3e\x84\x9d\x8b\x6c\x3c\x30\x37\x4f\x5d\x29\xa7\x87\x45\x99\xa2\xc8\x73\x4a\x3e\x4b\xe8\x84\x1c\x21\x87\xb1\x47\xb7\x14\xb0\x39\xf7\xa0\xc4\xf4\xe0\xb7\xda\xb0\x75\x90\xa7\x46\x4d\x60\x0a\x0c\xae\xfd\x45\x93\x34\x83\xbd\xb8\x93\x79\x6f\xcc\x56\x9c\x39\x23\x48\xb3\xd4\x88\xd2\xe6\xab\x0d\xa2\xdc\x82\x92\x72\x13\x25\x4c\xb5\x68\xb2\xf3\x16\x1f\xa2\xbd\x01\xe0\xfc\xe1\x76\x5e\x93\x69\xa3\x30\x4f\x91\x71\x57\x72\x6f\xa2\xce\x10\x6e\xce\x03\x39\x7b\x11\x3f\x66\x29\x09\xc5\x92\x41\xea\x8c\x61\x66\x01\xad\xa5\xce\x9c\x8d\x09\x2b\x34\x4a\xd1\x90\x31\x4f\x0c\x61\x36\x05\x9e\x69\x8a\x17\xe9\x0e\xd6\x3a\x3d\x62\x2d\xa8\x0c\xb0\xc9\x1c\x0e\x95\x31\xd0\x3e\x54\x97\x1e\x14\x19\x5b\xd0\x74\xae\xce\xa3\xa5\xde\x2d\x0b\x1b\x4c\x0d\x36\xa8\x71\x3a\x3f\x79\xf4\xf3\x5e\xb1\x14\xdd\x80\x03\x6e\x90\x6c\xc6\x23\xcf\x70\x07\xe8\x54\x1d\xfa\x4f\xbf\x68\xb7\xac\x0c\x47\x31\x4a\x05\x65\x91\x77\xa6\x48\x8b\x77\x83\x01\x2c\x75\x57\x78\x68\xd1\x33\xd0\x97\x62\x9e\xd5\xc0\x8f\xb2\x6d\x21\x4c\x29\xa8\x10\xed\xd6\x96\x55\xeb\x46\x2b\x56\x57\xca\xdd\xf1\x4d\x6b\xb3\xc0\xa4\x01\x87\xdc\xa8\x85\xf0\x60\x8d\x61\x21\x5b\x49\x75\x71\x69\x41\x61\x2d\xe9\xda\x62\x6c\xd6\x78\xca\xb3\x83\xf1\x11\x20\xdd\xf2\x2e\x69\x2a\xef\x8f\x64\x3a\x6a\x8b\xc3\x32\x9d\xd1\x6a\xf5\x47\x0a\x00\x46\x04\x00\x67\x6c\x86\xf0\x9b\x3a\x33\x76\x06\x81\x66\x00\x18\x51\xf6\x59\xa7\x33\x83\xe5\x3b\xc3\xe5\xc3\xdc\x66\x89\xe9\x12\x63\x54\x76\x75\x0e\xd8\x60\xce\x2b\x2f\xc8\x72\x3e\x95\xd9\x94\x97\x5c\x7c\xd3\xd3\x7e\xce\xf5\x12\xed\xd8\xca\x6f\xec\xfc\xa4\xc5\x2f\x01\x29\xd9\xb5\x84\xd2\x86\xab\x16\x85\xbe\x4c\x9d\x06\x4a\x76\xd2\xe9\x4c\x6a\x52\x98\x86\x5c\xd0\xc6\xa5\x9d\xeb\xd2\xbd\xee\x36\x66\x56\x3b\xa4\xe2\xc1\xcb\xcc\x7b\x96\x21\xd9\x88\x37\xe4\xab\x44\x76\x36\xc2\x55\x9f\x7d\xc7\x89\x07\xc9\x76\xee\xe5\xdb\x09\xa0\x16\x54\x4f\x84\x55\xc1\x9f\x10\x29\xb8\x84\xe7\x28\xf1\x40\x01\xa7\x25\x1f\x3c\x23\x07\x04\xa5\x16\x89\x74\x1f\x7d\xe2\x0f\x4f\x8b\xe2\xa9\x6f\x10\x3f\xc7\x5b\x98\xa7\xfe\x60\x16\x7b\x09\x4b\x07\x89\x2a\xe4\x59\x27\xc2\xa4\x52\x53\xc8\x8d\x61\x63\x51\x3c\x37\x47\x69\xc8\x91\x50\x7c\x0e\x35\x78\x21\x0b\x06\xa1\xae\xc7\xea\xd1\xe5\x4a\x1e\x75\x10\x97\x47\xc4\xb2\xc2\x21\xa9\x2e\x64\xe1\x67\x23\xc9\x08\xc9\x3c\x41\x6e\xf2\x36\x5a\x58\xa0\x49\x28\xf7\x2d\x97\x53\x14\xfb\x02\xdf\xda\x68\x7b\x62\xbd\x9a\x84\x86\x17\x10\x8b\xc6\x18\x82\x05\x5d\xdf\xad\x27\xaa\x72\x01\xf1\xca\x4c\xac\x97\xd2\x85\x2b\xb2\xf5\xf0\x02\x86\x8f\x29\xdb\x24\x37\xa9\xdf\x19\xeb\x72\xc3\xf0\x49\x8f\xcc\x16\x0c\xda\x7e\x2b\x00\xc4\x96\xb4\xe4\xe1\x58\xa9\x5c\x02\xd3\x44\xa3\xa5\x97\xa3\xde\xc5\xd5\x3e\x60\xe9\x01\xdd\x79\x2e\xe8\x1b\x7e\x2b\xb2\xed\xfb\x95\xde\xd8\x7b\x65\x59\x5d\xd2\x12\xdf\xd9\xa0\x2d\x75\xec\x3f\xf9\x50\x2f\x8c\xc1\x36\x9f\x5b\x22\xbd\xec\xfa\xd5\x02\x09\x85\x80\x53\x83\xfd\x48\xca\xd2\x6f\xc2\xca\x44\x30\xa4\x4e\x57\x27\x27\x42\xa6\x87\xea\xd7\x57\xbf\x99\xfa\xcd\xd5\xef\x50\xfd\x46\xea\x77\xae\x7e\xc7\xc2\xd3\x6a\x53\x27\xf9\x78\x5c\xbe\x32\x2e\xdb\x89\x07\xd0\x95\x04\xe0\x9b\x41\xfa\xa5\x08\xf6\xc7\xe3\x2c\x10\xc6\xc2\xc7\xd5\xb8\xbe\x86\xbd\x65\x61\xdd\xc7\x1f\x3d\x05\x9d\x32\x56\xfb\xbd\x3f\x16\xe5\x73\x70\x61\x2f\xf2\x33\xb1\xab\xd6\xcc\x84\x1b\x14\x43\x2e\xcc\x6a\xc5\xe4\xc4\x9c\xec\xd2\x81\x30\x6a\xc1\x9a\x63\x26\x7c\x0d\x2a\x1b\xc8\x73\xca\x93\x51\x0f\x02\x7c\x68\x46\xde\xe0\x9b\x0d\xfe\xc1\xd7\xba\x0c\x7d\xab\x20\x5d\x06\xb6\xce\x85\xf4\xb1\x4b\xef\x25\x53\xd4\x03\x13\x53\x14\x7b\xa8\xe8\xc0\x76\x32\xba\x7f\x6d\x52\xe2\x7b\x51\xe5\x28\x03\x8e\x7e\x3a\xcd\x15\xc9\xdd\x0c\x7d\xa7\x6f\xaf\x6f\x01\xe8\xfe\x66\x8b\x73\x74\x82\xb5\x6d\x5d\xf0\x1d\xa7\x96\x34\xb3\xb5\x1f\x56\x5c\xd0\x55\xf4\x79\x45\x55\xb4\x9c\xba\x72\x64\x96\x0c\xeb\x1c\x2f\x7a\xe9\x9e\x49\xe0\x25\xa6\xb4\x4a\xb2\x8c\x59\x52\x09\xc7\xe5\x8d\x48\x88\xb7\xb6\xe2\x88\x57\x1c\x28\x9e\xa7\xd7\x79\x66\x44\x33\x5e\x7b\x30\x77\xb3\x6d\xbb\xf0\xd3\xb4\xf2\x28\xa5\x74\x0d\x48\x1e\x18\x91\x10\xd8\xde\xf4\x94\xca\xae\xa5\x30\x95\x56\x04\xfe\x48\x7d\xa6\xf4\x40\x20\xe2\xbe\x02\x4f\x83\xd3\x62\x17\xb0\x1c\xb0\x75\x40\x96\x86\x85\x5f\xec\x17\x2f\x51\x3d\xbd\x73\x8a\xe7\x55\xda\x39\x25\x59\x74\x67\x57\x7e\xed\x22\x05\xe0\x0c\x51\x57\xde\x3d\xf8\x53\xbc\x3e\x01\x16\x9b\x3e\xbe\x47\xea\x0d\xe0\x66\x9b\x43\xd6\x74\xdb\xc7\x9b\x28\x1f\x43\x7c\x17\xc9\xe4\x64\x9b\xc3\x74\xa0\x78\x1e\x7a\xbc\xbb\x8d\x7a\x65\x40\x8d\xa3\x36\x9b\x36\x2e\xbb\xc3\x15\x54\x01\xe1\x6c\x74\x43\x50\xf5\xb3\xf3\x94\x2e\x1f\x6f\xa1\xa8\xef\x16\xf4\xbb\x80\xee\x3c\x05\x62\x79\x5f\x2b\xaf\xe0\x4b\x87\x35\x3a\xe2\x36\xea\x76\xdf\x3e\xe2\xb3\x41\x80\x34\xc3\x88\x09\xa0\x89\x5d\x0f\xb8\xe3\x91\xcb\x02\x08\x43\xca\xa5\x83\x59\xd8\x5b\x8a\xa6\x74\x0d\x7e\x58\xe5\xb7\x40\xa9\x40\xbb\x58\x19\x04\xf1\x0f\x14\x11\xba\xb2\xef\xac\xca\xbe\xd3\x95\x7d\x5b\x56\x06\xe9\x2e\xb2\x97\x38\x47\x23\xea\xfe\x9f\x1e\x71\x2a\x00\x9b\x00\xa7\x16\x62\xbe\xd7\xb4\x3f\x06\x07\x02\xfe\x78\x70\x2e\xe0\x07\xc3\x0f\xc8\xa9\x93\x7f\x38\xa2\x02\x3f\xe0\x0c\x20\xdf\x80\xb8\x5a\xaa\x3e\xe0\x82\xf2\xc4\xbe\xd2\xde\x57\x0b\x1e\x28\x5d\xd2\xd5\xf7\x46\x57\x8b\x8a\x4a\x59\x28\xaf\xb9\xc3\x35\x49\xbe\x38\x89\x96\xbd\xba\x0d\x77\xa7\xcf\x2a\x60\x85\x6e\x70\x94\x4c\xe8\x7a\xf5\x4b\x27\xa6\x7b\xc5\xda\x7d\xe8\xcb\x74\x95\x61\x13\xca\xbc\x32\xa3\xa0\x40\x8e\xd5\x38\x99\xb1\xf6\x53\xeb\x4e\x98\xae\x9e\xc8\x65\x04\xde\x01\xa3\x29\x07\xf6\xdd\x3b\x6e\x50\xeb\xdb\xa3\x0d\xa4\x2e\x2e\x0d\xc6\x23\x92\xef\x8c\x9c\x84\x96\x5a\x59\x2d\xfe\x01\xd8\x78\xeb\x40\xb4\xe9\x39\x57\x1a\xc6\x54\x88\xc3\x86\xa3\x0d\x1f\xab\x70\xe2\xaa\x71\x75\x1d\x01\xad\x9a\x3a\xc4\x79\x5c\x2c\x9a\x49\x5d\x40\xa4\x15\xc5\x95\x52\xd5\x2f\xb5\x8d\x90\x62\xfe\x8e\xf0\x6b\xe5\xce\x20\x45\x4e\xc3\x60\xb5\x12\xed\xfb\xb8\x37\x15\x92\x73\x48\x73\xad\x28\xc2\x5e\x9c\xc4\x0f\x01\x4d\xdd\x4d\x27\x59\xa7\x73\x9f\xb0\x8b\x96\xdb\x93\x4e\x62\x66\x00\x08\xd0\x04\x32\x6f\x8e\xbc\x8b\x1f\x32\x44\xef\x65\x27\x87\x6e\x79\xe7\x39\x34\x20\x65\x5d\x23\xec\xa6\x35\x45\x1d\xc4\x6a\x07\x47\x1e\x22\x4c\x7d\x42\x0e\xa4\x21\x5f\xe0\x7d\x42\x97\x1d\x5e\xe2\x57\x6c\xca\x4f\xed\x1a\x2a\x39\x2d\x75\xae\x0a\x06\xad\xd0\xdd\x70\xce\x29\x03\x60\x4f\xd9\xab\xdb\x86\xbd\x64\x14\xac\x6c\xcf\x19\xc2\x60\xc5\x8c\xd7\x6a\xe1\x89\x39\x72\x04\x87\x23\xdf\x9c\x40\xca\xe4\x43\xa0\x0b\x2a\xa0\xee\xf0\x6a\x7f\x8b\x6d\xd9\x97\xac\xb5\xcb\xce\x4d\x7d\x6f\x82\x32\x1a\x94\x0a\xa1\x4a\x0e\xdd\x6a\x2a\x77\x05\x9f\xe4\x0e\x4b\xbb\xbc\x24\xed\x2c\xb5\xca\xd7\x69\x93\x3d\x5a\xd5\x0e\x80\x68\x60\x5a\xc7\xd2\x30\x2d\x94\x86\x69\x21\xe1\x00\xa9\xbe\xd9\x84\x02\x3e\xa6\x96\xc0\x29\xc0\x9a\x96\x2f\x1e\xa0\xde\xc0\xc8\xdd\xed\x4b\x88\x80\x10\x36\x49\x6e\x49\x77\x05\xb6\x45\x45\x13\xf7\x12\x45\xc6\xe7\xd6\x35\x01\x6b\x6d\xb1\xd6\x26\x83\xfa\xec\xb9\xde\xa9\x53\x84\xb6\xba\xbd\xa6\x25\x06\x4e\xe3\x32\xd0\xcd\xc5\x96\xcb\x68\x16\x37\xb7\x51\xdd\x02\x26\x18\x1d\x8f\x95\xea\x41\x7f\x84\xea\x05\x4f\xd7\x69\xb1\x37\x75\x53\x2b\x1a\x7b\x7c\x5d\x63\x92\xda\x92\x4d\xaa\x47\xcd\x05\x0a\xcc\x91\x75\xbf\x4d\xd8\x50\xda\x7f\x92\x79\x42\x60\x79\x8e\x50\x4d\xa6\xdd\x2d\x6b\xda\xde\xfc\x8a\xa6\x24\x19\xb4\xbe\xb5\xd4\x26\x5d\x1a\xca\x56\xb5\x2d\x60\xb5\x55\x5b\x62\xf9\x36\x5d\xb2\x2c\x68\x98\xcb\x64\x80\xc6\x4a\x9a\x2a\x6a\x59\x58\xd4\xcc\x2f\xe1\x5d\x84\xdc\xc4\x65\x96\xb9\x42\x75\x2a\x3f\xa7\x4d\x0a\x36\x4b\x06\xce\x95\xc1\x68\xd7\x43\xd6\x2c\x5e\xe7\x7d\xe8\xd3\x75\x53\xd8\xb0\x3c\xbf\xa6\xee\x9f\x2a\x38\x6a\x80\xa7\x3d\x1c\x66\xa5\xbe\xcc\x57\x40\x65\x6d\xca\x04\xa9\x7f\xa5\x03\x69\x89\x50\x9d\xac\x47\xe9\x0a\x23\x70\xcd\x2c\xca\x52\xad\xcd\x6a\xb1\xe7\x5f\x0b\x43\xeb\x5b\x8d\x4a\x1b\xb1\x8b\x6e\x0e\xe2\x01\xa0\xc2\xb4\x1b\x33\xa8\x1d\x55\x96\xac\xd7\x8f\x14\x2e\x92\x1a\x21\xae\x56\xdd\xd0\x62\x67\xd4\xf7\x18\xe0\x5f\xdf\xf3\x5b\xf0\xd7\x1d\x84\x5e\xe9\x92\x4a\xfb\xa1\xb2\x14\x4b\xec\x39\xa5\x7d\x6d\x6f\x88\x77\x55\x5c\x86\xce\x46\x24\xba\x5c\x92\xa0\xa3\x76\x23\xe0\xe5\x89\xbc\xab\x0a\x39\x4f\x2a\xb8\xd3\x92\xb9\x23\x0e\x45\x0c\x97\x49\x0c\x97\xb9\xa4\x43\x67\xac\xc8\x94\xe1\x12\x1c\x96\x99\xb1\xae\xda\xba\xa5\xac\xab\x20\x12\xe8\x84\x85\x65\xe1\xad\x55\x26\x37\x51\x65\x52\xda\x72\x0c\xf2\x12\x93\xcf\xb1\x5b\x63\x9e\xe2\xed\xae\x51\x76\x22\x93\x0e\xb2\x99\x43\x83\x0e\xe6\x8c\x07\x8f\x84\x83\xf2\x53\x2f\x74\x50\x9e\xea\xde\xd9\x54\x1e\x31\x79\xdc\x5f\x5f\x17\x46\x4e\x97\x12\xfe\x1f\x3b\xce\x14\x4b\x4c\x65\x09\x3c\x14\x54\xa1\x52\xe9\x69\x81\x52\x6e\x33\xa6\xb9\x0e\xe9\x75\x98\x5b\x7a\x25\x5f\x04\xb3\x80\xae\x72\x6d\x48\xff\xf1\x57\xc0\x98\xc4\x2a\xcd\x0a\x42\xb1\x9b\x70\xa7\x0a\x6c\x40\x56\x92\x8a\x5c\x8a\x7e\xfd\xbb\x5b\x36\xdc\x25\x0a\xe6\x10\xe4\x55\xc5\xca\x93\xd3\x12\xf0\x85\x9e\xf4\xec\x34\x48\x10\xf8\x9a\x9c\x9e\x91\xfe\xb4\x14\x79\x27\x0a\x0b\x90\xd1\xa9\x95\x2d\x69\x40\x01\x41\x62\x3c\x8c\xd4\x6f\xee\xf1\xe1\x9e\x96\xa1\x88\x0c\x9b\x54\x9e\xf3\x9b\x00\xb7\x04\x9f\x69\xd3\x79\x2c\x90\x5e\xab\x2a\x2c\x55\x41\x96\x0c\x69\x58\x88\xb7\x93\xe4\x30\xac\x54\xa4\x44\x6f\xb3\x0d\xa6\x58\x22\xb1\x3d\x6c\x41\x61\xf2\xd6\xb3\x74\x78\x23\xb1\x63\x3b\x00\x4a\xbe\x80\xa3\xa5\xd1\xcb\x0a\x44\x6d\x7c\x08\xa4\xd2\x87\x40\xaa\x7c\x08\xa8\x4d\xe5\xb2\xb2\xd7\x80\x7c\xd1\x4b\x2e\xcc\x7e\x93\x69\x4c\x6a\x77\x7e\xa7\x8e\x17\x92\xe4\xab\x08\x80\xaf\x38\xb4\xe4\xb2\xa4\x8a\x06\x20\xc3\xac\x0a\x3a\x0d\x93\xfa\x01\x79\x86\xd7\xd6\xa5\xac\x54\xde\x84\xeb\x3b\x43\x85\x15\x3d\xa5\x8c\x96\xd0\x7d\x76\x65\x7e\xfd\x3f\xa4\x42\xc2\xf2\xb5\x3a\x49\x89\xbc\xbc\xe0\xff\xba\x19\xf9\x0a\x8a\x6b\x05\x19\x94\xff\x11\x1a\x58\xa6\xb9\x1a\x9b\x1a\x5e\xd7\xd4\x5f\x8c\xe2\xaa\xd2\x5b\xd1\xaf\x68\xe8\x0f\xa7\xb7\xaa\x77\xc4\xf3\xa4\x54\x43\x7b\x1f\x3b\xcb\xb4\xb4\x0d\x2c\xe3\x1a\xb0\x84\xcb\x5d\x0c\xcb\x2e\xb6\x4f\x92\x04\x5f\xbc\xae\x98\xb8\x4b\x13\x04\x21\xb5\x3a\x00\xd4\xd5\xea\xa4\xae\x54\x2b\x40\x5b\x7f\xa0\x41\x94\xed\x16\xaa\x7a\x68\x6c\x8a\xc7\xf7\x2c\x96\xca\x48\x2d\xae\x28\x3c\x9f\x80\x0f\xd5\x3c\xa0\x46\x44\x66\x70\xd0\x0e\xd0\x03\x1c\xac\x36\xe9\x0b\xdb\x67\xfb\x34\x69\x60\x74\x9c\xa0\x64\x73\x3b\x1d\x68\x87\x7c\x88\xfc\x88\x57\x7d\xa4\xff\x9c\x2a\xcb\x0e\x75\x7a\xe3\x91\xc7\x29\xcb\xe3\xd8\xb2\x7d\xb0\x25\x91\x33\x1b\x55\x90\x75\xf5\x27\x7b\x52\x2b\xbb\xef\x2c\xf9\xe3\x32\x47\x12\x6e\xd2\xc1\x65\x4c\xbe\x2a\x50\xee\x30\xf4\x85\x73\xa9\x2c\xbf\xbd\xd8\x48\x4e\x07\x30\x3d\x69\x15\xce\x27\xd5\xce\x2c\xd1\x34\xe4\xd0\x06\xc0\x29\x20\x67\x3e\x68\x67\x52\xe9\x8b\xd6\xd1\x48\x9c\x8a\x79\x79\xb2\xa4\xb5\x5d\xc1\xde\x24\x5f\xc2\x46\xd1\x97\x28\x6c\x45\x14\x28\xc0\x09\xe6\x92\x70\xff\xe0\xc8\xad\xc9\x9e\xa4\x37\x18\x12\xdc\x90\x1c\xca\x93\xec\x67\x08\x45\x80\xff\xc4\x57\x3d\x1a\x58\xd0\x87\x89\x25\xbe\xb6\x55\xab\x6c\x37\x71\x9b\x95\xeb\x09\xb3\x13\x35\xd9\xa1\x5f\x36\x0d\x2a\x86\x21\x27\xd7\xe4\xb3\xc4\xe7\xd6\x1e\x83\xbe\x90\xbf\x31\x4b\x72\x6d\xa5\x4a\x81\x02\x39\x29\x52\xda\xd5\x35\x77\x76\x56\xb9\xe3\x2a\x38\x33\xfd\xfe\x6b\x45\x8c\x64\xfc\x58\xdc\x45\x27\x1e\x30\x73\x61\xc5\xf3\x5d\xe2\x09\xa0\x4c\xe5\xd4\xa2\xfa\x42\x6a\xa7\x9a\x63\xb0\xee\x2c\xcf\x92\x52\x27\x2b\x3d\x9c\xf5\x9b\x85\x27\x4e\xdd\xb5\x59\xa9\xb2\x53\xf1\xc7\x26\x6f\x75\x50\xb8\x92\x06\x67\x41\x9a\x35\x4c\x85\x7a\x7a\x43\x4c\xd3\xbc\xe2\x05\xd7\x5c\x9b\x9b\x92\x0b\x6b\xda\x9e\x26\xb5\x07\xd9\xd4\x44\x57\x1c\xb6\xbe\xb2\x32\x3d\x8f\x97\x7c\xe7\x2d\xfb\x67\xb3\x04\xab\xc9\xf5\x04\x2c\x5a\x52\xc9\x47\xa3\x48\x92\xe5\x32\x32\x66\xf9\x12\x19\xf4\xec\x2b\x8e\x3b\xf2\xd3\x42\xaf\x96\x91\xc0\xcb\x72\xe2\x82\x3c\x1d\x60\xcb\x65\x82\x77\xb0\xcc\x5a\xc1\x9e\x6c\x72\x8d\xa5\x1d\x43\xde\x25\x79\x59\x8a\x16\x23\xe5\x5b\x8f\xd8\x31\x20\x02\xbd\x89\x3e\x6a\xe1\x83\x9e\x63\x2c\x65\xb7\xb5\xfe\x53\x6d\x83\x20\xf6\x4e\xf4\x35\x48\x93\x12\xb9\x68\x56\x57\x57\x94\x92\x39\xf3\x60\x78\x84\x64\x2c\xf9\x6d\x63\x73\x22\xf6\x5e\x98\x5b\x17\xab\xfc\x52\xf1\x07\xb6\x83\x62\xe9\x9d\x4f\x55\x64\x44\x06\x06\xf1\xc3\x50\x07\x78\xbc\x97\x72\x64\xbb\x66\xe5\x31\xe0\xa1\x7d\x0e\xed\x2e\x21\x8d\xe5\x02\xf7\xed\x02\xa7\x49\xe5\x6e\x8b\x7a\xf7\x9a\x8e\x1f\x4b\x60\x59\xab\xb4\xf9\x02\xb5\xd1\x18\xa8\xd3\x91\xd3\xa3\x9c\x90\x79\x74\xdd\xff\x21\xd6\x93\x6b\x89\x2c\xff\xe2\x6d\x28\xe7\x64\xde\xfd\x55\x6d\xbc\xae\x8d\x55\x4e\x47\xe5\x04\xbd\x65\xe7\xff\xd8\xb8\xd2\x71\xec\x3d\xf9\xaa\x95\xde\xa9\x36\x47\xb5\x3d\xae\x4d\xed\xbd\x25\x12\x59\x36\xe2\xc7\xde\x67\xd3\x08\xe6\xa1\x66\x52\xf6\x5b\xc0\x5d\xac\x7e\x7a\xde\xb9\x5d\x05\x82\xc7\x2b\x2a\xcd\x7e\x65\xa5\x15\x40\x79\xf3\xeb\xc1\xde\xba\x49\xb0\xfc\x60\xb5\x84\xfa\xb6\x31\xe7\x5b\x7b\x57\x34\xd1\xd5\x57\x0a\xa7\xf5\x6b\x2a\x8f\x66\xab\x6c\xc2\x4e\x79\x1b\x3b\x92\x9d\xc6\x1d\x23\x47\xfe\x39\xb1\xf5\xfc\xb4\xe2\x26\xb0\xde\x92\x1e\x97\xd6\x6d\x89\xc1\x65\xd6\xc9\x4e\x25\x4d\xb3\xab\x7d\xaa\x55\x68\x38\x35\xdf\xd4\x11\x01\x67\x62\x8b\x2e\x1b\x89\xb2\x43\xdf\x5b\x30\x2f\xc8\x79\xa3\x1c\xa3\xe1\x9e\xf9\xd3\xd7\xa0\x77\x74\x33\x86\x9a\x51\x2a\xd5\x12\xd9\x35\x2e\x50\x1e\x7b\x3f\xfd\x33\x41\x83\xef\xbf\xc8\x3c\xfb\xf2\xba\x7a\x40\x56\x7d\x96\xe7\x86\x25\xb6\x54\x6a\x40\xda\xd0\x53\xd7\x0a\x22\xbb\x04\xe5\xc8\xe1\x4a\x7b\xf1\xf6\x84\x4a\x61\x74\x56\x78\x29\xa3\xe3\xd6\xa3\x17\x12\x43\xe0\xc8\x6d\x43\xd1\x47\xd6\xdc\x1a\x50\xef\x1b\xaf\x42\xd2\xe0\x80\x2e\xa5\xe9\x86\x57\x18\xc3\x02\x54\xae\x84\x68\x65\x56\xdb\x4c\x66\x9e\x23\xb2\xd1\x27\xab\x1c\x77\x4a\xe3\x4e\xaf\xf5\x58\x51\xc2\x54\x52\x01\x27\x04\x1c\xa4\x83\x25\x43\xa0\xae\xa1\x8e\x3d\x60\xba\x20\x42\x3a\xb4\x88\xed\x79\x48\xd5\x04\xc4\xf5\x09\x98\x5b\x13\xf0\xbc\x8a\x8d\xf6\x9a\x10\xfd\x0d\x95\xa7\xd9\xec\x6a\x65\x42\xb3\xee\x2b\xda\xf6\x05\xe4\x60\xcd\x70\x06\x01\x3f\x01\xa0\xe4\x5d\xba\x15\xdb\x64\x96\xf2\xbf\x12\x3f\xad\x07\x77\xb6\x06\x2b\xde\xab\xd2\x7e\x6d\x2c\x91\x69\xfd\xb0\x5b\x09\x59\x81\x96\x32\x88\x81\xad\xdf\xaa\x6c\x5b\x5d\x46\x5a\xbf\xa7\xd2\x60\xbd\xf6\xc7\x86\xf9\x0f\x36\xc3\xd1\xff\xa3\xcc\x52\x6a\x66\x29\x5d\x69\xc3\x05\xd3\x02\xe8\x0d\xd5\x63\x9a\x27\x46\x8e\x93\xd9\x26\x23\x3f\x56\x58\xa3\xa7\x64\xb9\x57\x43\xf0\xdb\xb7\xf4\xd6\xad\x9d\x80\x00\xd0\x97\xc0\xe2\xfd\x98\xd8\xaa\xf3\x6e\x3f\x2e\xf8\x9e\x11\xaa\x4a\x9d\x38\x21\x8d\xde\x4a\x91\xa1\xf5\x96\xa7\xf4\x85\xb7\xd4\xe8\xd6\xa0\x91\x1c\xf5\x1e\xd5\x94\x46\x44\xe5\x6d\x85\xa7\xc5\xab\x3f\x64\x08\x22\xbc\x76\x08\x82\x8c\xe2\xab\x43\x88\x43\x0d\x53\xcd\xc0\xa4\x16\x8d\x26\xe0\x59\x23\xc0\x28\xa8\x31\x27\x53\xc5\x00\x21\xae\xf4\xc8\x76\x28\x9d\xfe\x8a\x86\x5f\xfe\xfa\x86\xd3\x95\x0d\x27\xa6\xe1\xb2\x2f\xc8\xac\x77\x3a\x79\xe6\x8c\x5d\x96\x53\x20\x47\x55\xdc\x31\x87\xa3\x73\x51\x51\xf7\x57\x9c\xef\xba\xf3\x3c\x73\xdc\xf5\x88\xd4\x67\x36\xb7\x39\x59\x81\xc3\xf2\xe9\xc2\xaa\xf7\xd3\xbe\xaa\x44\xe9\xd5\x3e\x97\xc6\xd3\xda\xc4\x07\x6f\x04\xd8\xb8\x28\xd0\xe5\x4c\xc6\xe7\x72\xe0\xca\x54\x6d\xcc\x47\x99\x93\x54\x84\x2e\x61\xa5\x9b\xaa\x62\xe7\xac\x28\x66\x2d\x25\x8a\xfb\xda\x16\x4a\x91\xa5\xa3\x3c\x0a\x96\xd0\x14\xc9\x3a\xe6\xc4\x85\xb2\x29\x3f\x43\x75\x6e\x60\x5a\x26\xe8\x96\x86\x1c\x38\xc9\x39\x98\x74\x3a\xad\xb1\xf4\x79\x02\xb5\x4f\xa0\x81\x11\x37\xcb\x36\x5b\x77\xa2\xf5\x11\x9e\x0d\x30\x39\xe4\x88\x6c\xd6\xf7\x07\x4e\x4e\xee\x73\x68\x86\x50\x57\x27\xaa\xf5\xd4\xf5\xb0\x9f\x39\x8e\x3c\xb4\x75\xd3\xfc\x4e\x67\x3c\x18\x73\x1a\xb8\x07\x7d\xc1\x7b\x00\xb4\x8e\x51\x73\x84\xd6\x59\x31\xf9\xc3\xc3\xb7\x15\xab\x35\xb2\x96\x5f\x14\xf5\x09\x60\x43\xa2\x96\xc8\xdc\x88\x4c\x08\xc6\x6c\x0a\xdd\xd9\x84\x01\xc2\xee\x3c\x53\xda\xf4\x5f\x85\xd3\xc8\x04\x45\xc9\x3a\xe9\xdd\xbc\xd6\xa6\xd6\x63\x86\x5a\xa0\xaa\x2d\xb9\x9c\xa4\x07\x07\x7d\x9c\x90\x5a\x88\x8f\xaf\xdf\x40\x6b\xed\x99\x7f\xf1\xd6\x0f\x05\x2a\x2b\xc3\x08\x10\x45\xc7\x3d\x15\x47\x66\x08\x2e\xf4\xa6\x2d\xd4\x83\xca\x94\x6b\x10\xf7\xf4\xb7\x77\x56\xea\x20\xf4\x86\x28\x16\x40\xe3\x09\x4b\x1d\x21\xb4\xf1\x13\x79\x41\xdc\x62\xb6\xf4\xcc\x82\x83\xb0\x72\x5a\x2a\x8f\x89\x36\x8a\xb1\xe4\xd1\xe1\xf2\x45\x09\x13\x15\xab\x9c\xd2\x4b\xe4\x12\x72\x5f\xb3\x2f\x57\x16\xf2\x76\x05\x5b\x7b\x15\xba\xab\x9c\x30\x5a\x75\x94\x5a\x36\x28\x4e\xa4\x17\x66\x1a\xcf\x08\x12\x75\x09\x20\x29\x64\x9e\xf2\x39\xda\xd4\x12\x33\x5a\x12\xf0\xeb\x87\x24\xef\x53\x61\x95\xff\x99\x8f\x4a\x5c\x3f\x2a\x72\xcb\xf1\x95\x63\x1a\x86\xd7\x11\x37\x01\xec\xa2\x46\xc3\x1e\xb1\x82\xb8\xb1\xba\xab\x14\xdc\xa1\x07\xc3\x69\x80\x4e\x0a\x56\x92\x30\xf5\x8b\xb4\x94\x1c\x8d\x97\xfe\x82\x52\x7c\x70\xdd\x49\xb4\x39\x62\xb0\x62\xd8\x26\x77\x86\xb9\x59\x88\x9a\xef\xa5\xe0\x91\xba\x41\xf2\xae\x61\xd8\xbb\x4f\x7d\xb2\x5f\xda\x09\xd5\xa3\x1c\xbf\xc6\xed\xe7\xd2\xfa\xb6\x56\x74\xcd\x9a\xef\xb9\xbd\xd9\x88\x72\xb2\x37\xcd\x38\x2c\xe9\xf1\x9a\x0c\x1b\xd0\x06\x5a\x7b\x8e\x6b\x87\xb7\x4d\x7a\xec\xa9\xc3\xae\x2a\x83\xff\x62\x95\xd3\x6b\xaa\x7c\xd0\x54\xe5\xc8\xaa\xb2\x91\x6e\xa9\x54\xb1\x7b\x1d\xed\x38\xfb\x0b\xcd\xbb\x58\xb6\xe7\xc7\x89\xaf\x98\x8f\x9e\x85\x55\x8e\xac\x85\xac\xc9\xaf\x40\xdd\x1a\x80\xe8\x50\x1b\xa0\x07\x19\x4f\x63\xe9\x94\xb7\x15\x92\x96\x38\xb7\xd5\x32\x58\x1b\xb8\x8f\xa4\x8e\x92\x31\xd9\x20\x65\xe0\xcf\xee\x09\x9d\x1b\xf0\x31\x7c\x28\x8c\x8e\xa6\x8a\xf0\xa5\x73\xf2\x84\x29\x5a\xe4\x9e\x3d\x71\x93\x2a\x2a\x2e\x15\xaf\xf7\x81\x03\x64\x44\xc6\x29\x70\x40\x9f\x53\x07\xb6\xf3\xff\xcb\xb0\x14\x84\x28\xb1\xd2\x1f\x7e\x6f\x84\xfe\x6e\x1a\xd5\x2b\x3f\xc4\xfa\x9a\x52\x7b\x40\xb6\xba\xf0\x30\x5c\x12\xc8\x35\x8b\xb6\x94\xc0\x4a\xd7\x82\xef\xf6\x5a\xd5\xdc\xb7\x00\xf1\x8c\xc4\x9b\x9a\x8d\x39\xae\x09\x7f\x4b\xed\x51\xce\x3f\x57\x9f\x6c\x3a\x09\x6b\xaa\xdb\xad\xcd\xa2\xa0\xdf\xad\xa2\x90\x6f\xf4\xd8\xa5\x7f\xaa\x96\xbe\xb0\x4b\x2f\xe7\x7e\x5f\xcd\xfd\xa2\xd2\x56\xa7\xb3\x45\x6f\x08\xe2\xc3\xce\xf8\x92\x6f\xa7\x53\xaf\xc0\xc8\x7b\xdb\xea\x99\xc6\x36\x0a\x7a\xab\x75\x1e\xeb\x2d\x54\x73\x78\xb7\xd9\xaf\x9a\x9e\xd4\xc5\xe1\x4a\x91\x94\xc4\xcb\x74\x9b\x85\x3f\xb2\x03\xe8\xbd\x52\xbd\x64\xeb\xba\x83\x96\xf0\x5a\xcd\xc2\x95\x73\x0b\x92\xe8\xcd\xd4\x6b\x41\xe1\x36\xfa\x18\xea\x74\x48\x55\x9e\x7e\x4a\xf7\x64\xe4\x55\x52\xdd\xb0\xc6\x03\x75\x85\xae\xd7\xb0\x49\xbc\x99\x0c\x76\x8d\xcf\xee\x56\xcb\x92\x4f\x3d\x5d\x5e\x8f\x65\xe1\xba\xb6\xe1\xab\xae\xd5\xa3\xea\xbc\xbe\xb2\x6a\x6a\x18\x57\xed\xe1\xaf\x7d\x0b\x14\xaf\x71\x44\x0e\xf4\x5a\xf5\x15\xb1\x6a\x2d\xcf\xc2\xba\x8c\x52\x1a\xf7\xd9\xce\x53\xbf\x76\x9e\xb7\x50\xff\x45\xa9\x63\x24\xa8\x9e\x94\x19\xef\x84\x30\xf7\x99\x99\x7b\xe3\x7a\x2f\x23\xd7\x7b\x7e\xc5\xd8\xc8\x77\x8d\xe7\x3d\xe9\xab\xc4\x95\xbe\x40\x42\x57\xba\x20\x41\x0d\x26\xba\x18\xc4\xfb\xc1\x23\x46\x6e\x41\xa8\x76\x63\x69\x2e\x3d\x70\x21\x09\x6d\x23\x80\x97\xf6\x32\xed\x86\xb4\x4e\x64\x42\x69\xdd\x28\x84\x0d\x6a\xc7\x80\x7d\xed\x25\x7b\x3e\x48\x32\x69\xb2\x52\x1a\xba\xb8\x9e\x02\x62\x65\xcc\x82\x60\x6d\xcf\xf1\x83\xe5\x7a\x6d\x4b\x8e\xdd\xf0\x3a\x33\x90\x26\x8c\xf0\xae\x5a\xff\xe9\xf5\x18\xe1\xc7\x6a\xee\xbb\x76\x73\x0d\xb7\x40\xcb\x15\x88\x1a\xcc\x3c\x59\x6e\xcf\xd6\xcc\xee\x74\x3e\x8a\x83\xb2\xfc\x51\xb5\xf0\x6b\xbb\xf9\xa6\xf7\x1b\x2c\xb9\x7f\xf8\x55\x72\x58\xf5\x9a\xd5\xc1\x51\x5d\x09\x7c\xc7\xee\x27\xb9\x85\x7f\x57\x93\x6e\xdc\xab\x1d\xd5\x1f\x33\xfb\xea\x78\x85\x14\x6b\x40\xaf\x3d\xa4\x8c\x36\x8a\xeb\x59\x2c\xfc\xe3\x66\xc4\xa8\xfc\xe5\x0b\xb4\x57\x58\xa6\x1e\x85\x52\x84\x8f\x5d\xf6\x63\x66\x6c\xb2\xed\x43\xe7\xcd\xf2\xd9\xb5\x74\x99\xf4\x2c\xae\x2a\xe7\xbc\xfd\x8a\x32\x2f\x6b\x65\x3e\xd7\xca\xfc\x7a\x39\x75\x79\xdb\xc3\x9a\xdc\x24\x7f\x5a\xee\x94\x29\xc1\x5e\x35\x14\xf8\xe9\x8f\xd9\x23\xe5\xa4\xd9\x12\x9d\x7f\x45\x77\x2a\x0e\x9a\x1f\xd9\x00\xb5\xd7\x04\x50\xcf\xab\x44\x12\x40\x6d\xe9\xce\xb5\x7a\x5b\x7a\xe3\x4b\x72\xa6\x9a\x75\xaa\x34\xc3\x2e\xd1\x32\xf3\xa5\xd5\x4e\x6a\x3d\xcf\x91\xc8\xe7\x0d\xd1\x7e\xbe\x2f\x4c\xd3\x3e\xcb\xdd\x81\x7f\x90\x1f\x69\x95\x4c\x0f\x3f\x38\xbe\xd2\x41\x81\xac\xe1\x7d\x8e\x77\xcd\x90\x7c\x70\xd4\xdf\x97\xc7\xb6\x13\x70\x32\xa7\x70\xeb\x67\xbe\x40\x02\xae\x76\xe2\xbf\xce\x9a\x6c\x47\x3a\x1d\x94\x25\xf4\x6d\x53\x1f\xdb\x86\x66\xb5\x6f\xea\x98\x9c\xb7\x6b\xdf\x34\xf4\xc6\x6d\x28\xe5\xf5\xe8\x63\x6d\x5b\x1a\xef\x0a\xe5\xb9\x30\xed\xb6\xdb\xa6\x8d\x4c\x3e\x96\x22\xcd\x52\x90\x6c\x07\xd8\xa9\x1a\x7d\xa3\xcb\x91\xa4\x62\xec\x03\xe7\x16\x1a\xbf\xa8\xb9\xeb\x2f\xeb\x0d\x7e\xa8\x21\x91\xd2\x04\xca\xde\x73\xcf\x9a\xae\x52\x52\xf5\x3a\x11\x7d\x2d\x5c\x5b\x1c\xf8\x63\x68\xdf\xc4\x55\x56\x41\xfa\xa1\x6a\x96\x79\x2b\x1e\xb8\x41\xcb\x8b\xee\x44\xde\x97\x8e\x8e\xc9\x3a\xec\x32\x76\x94\x59\x50\x29\xd5\xb2\x77\xc1\xb3\x5f\x79\x7f\x18\xf8\x4d\x86\x26\xf9\x92\xe1\x91\x76\x54\x28\x2c\xbd\x9f\x98\x9e\x55\xc2\xbb\x96\x83\x90\xa1\x86\xf7\x51\x83\x9e\x8f\xf0\xeb\x77\x0d\xea\x9c\xbe\x5a\x78\x4d\x04\xfd\x80\x46\x50\x62\x01\x8f\x86\xfd\x45\x8d\x54\xbf\xba\xa4\xf6\xe5\x8f\x71\x78\xd2\x68\x8c\x25\x99\x17\x40\x1f\x21\x5e\x3d\xa5\xfa\x10\xb4\x4f\x89\xd4\x6f\xbc\x16\x26\xdf\xae\x81\x92\xdc\x59\x37\xc2\xca\x31\x17\x3a\xb4\x50\xaf\x97\x19\x45\xa9\x8a\xd1\x73\xcc\x93\x81\xba\x19\x07\x56\x32\xc4\xf3\x10\x8e\x33\xe8\x07\x5a\xe7\x87\x96\x2f\x27\xe5\xce\xbf\x84\x53\x27\x69\x78\xc5\xa4\xea\xb5\x53\xfa\x2f\x5d\x7e\x26\x22\xb1\xde\x4b\x96\xfe\x29\xd5\xbb\x2b\xa5\xac\x6f\x29\x47\x1d\x67\xfa\xfe\x6a\x4c\x58\x91\xb9\xab\x55\x60\x89\x66\x3d\x4b\xa7\xdb\x28\x66\x4d\x80\xcc\xd5\x6c\xa5\xf5\x1c\x14\x1a\xe7\xb1\x80\x6f\xb9\xde\x72\xaa\x20\x0d\x43\x41\xfc\x39\x99\x63\xd2\x33\x57\x82\x23\xe2\x41\x56\x13\xef\xc8\xe8\x62\x7a\x00\x91\x58\xcb\x26\xde\xf2\xc8\xeb\xaa\x18\x08\xeb\xdf\x00\x67\x24\x7e\xb3\xa5\x17\x04\x5d\xc6\xea\xed\x85\xf6\x9b\xdd\x50\x3a\x90\xb5\x3c\xd5\xb6\xb7\x82\xf5\x76\xd7\x71\x42\x7c\xbe\xc7\x88\xf1\xd0\xbf\xbb\x30\x1b\xf0\x6d\xfd\xa0\xca\xfc\x0a\xc3\x48\x9a\x3f\xa4\xd3\xa8\x1e\x74\xde\x74\x7b\x22\x79\x3d\x9f\x07\xe9\x7d\x1f\x75\xa1\xba\x81\xf2\x15\x64\x8b\x52\xf3\x55\x95\xa4\x01\x09\x63\x9c\x7d\xc1\xc6\x56\xfe\xa1\x59\x16\x95\x59\x74\xb9\xf2\x5e\xb4\x7c\xef\x1f\xf3\x46\xf7\x8f\xe8\x05\x8d\xee\xf8\xcb\x77\x42\x00\xd1\xac\x97\x56\x9c\xdb\x68\xd9\x5c\x55\x32\x82\xc5\xb4\xa4\x64\xcd\x9d\x7e\x68\x28\xed\x41\xd9\xff\x09\x3a\x11\xb1\xdf\xfe\x9a\x37\x17\xde\x6b\x2a\xfc\x52\xb0\xf6\xe1\xe1\x8d\x4e\xbb\x52\xc3\x78\x69\x0e\xd0\xb3\x4a\x6d\x0a\x50\x7e\xb8\xec\xe8\x49\x11\x7d\x09\x07\x08\x48\xdd\x8d\x5b\x70\x44\x0d\x51\xc4\x08\x4c\x11\x5a\xf0\x59\x62\x9e\x61\xea\xb4\xdb\x2c\x23\x7f\x80\xc6\xc7\x53\x08\x8b\xd8\xb5\x26\x62\x5a\xc7\x7b\xe5\x78\x8c\x1b\x2a\x9b\x97\x19\xad\xce\x1f\x74\x4d\x09\x4b\x2c\xb6\x84\x57\x97\x94\xd6\x01\xa9\x65\x35\xc0\x3c\xf3\xed\xdb\x41\x80\x0e\x7a\xaf\xc1\xcc\x14\xdb\xa2\xf7\xe6\x83\xfa\xd4\xc4\xfd\x51\xb2\x26\x7e\x73\x4b\x7a\x24\xa6\xcc\x30\x37\x02\x9d\x9d\x06\xf0\xdd\x3f\x9f\x86\x51\x60\x39\xa9\xb0\xe6\x61\xb2\x62\x5c\xf6\x83\x34\x35\x88\x2b\x35\xe4\x2c\x0f\x08\x4d\xc0\x76\xe9\x3b\x35\x5f\x25\x22\x98\x01\x78\x88\xe0\x65\x20\x04\xf0\x49\xf4\x58\xf4\xb1\xf6\x43\x42\xb8\x43\xf9\xad\x63\xa6\x1b\xf3\xd8\x81\x7f\x57\x0b\x74\x70\x80\x46\xca\x2c\x8a\x95\x18\x19\xdd\xc8\x95\xc9\x71\x2f\x9c\xa1\xad\x6d\x06\x79\x74\x10\xf3\x4a\xf7\x3a\x39\x1a\xd7\x3f\x42\x6f\xe8\x43\xbc\xf2\xc2\xc7\x56\xd1\xd5\x86\x08\xd2\x79\x82\x1d\x2a\x8a\x67\x00\xed\x1c\x1f\xfa\x5c\xeb\xf2\xb5\x9b\x6d\x36\xe3\x3f\xf9\x8e\x13\xf7\x82\x6c\xe8\xcf\x29\xdd\x55\x0e\x21\xba\xed\xa2\xdd\x1d\xdb\x1f\xce\x18\x88\xa6\x0b\x31\x78\x01\x58\xbf\x9a\x0d\x2b\x40\xe5\x05\xd5\x84\x95\x76\xa3\xcd\xda\x93\x36\xdd\xfb\x6c\x6c\xfc\xc9\x9a\x8c\x7f\xfd\xe2\x09\x87\x42\x6d\xf3\xa5\xaf\x82\x4c\x84\xd7\x8e\x92\x91\x9f\x4d\xcb\xa9\xa4\x94\xec\xa0\xdd\x5d\xeb\x76\x5f\x8b\x6e\xfb\xa8\xed\x76\xdb\x87\x71\xbb\x5f\x6e\xc6\x59\xd5\x17\x26\xba\xed\x41\x22\x56\x2f\xb9\x74\x1d\x01\x5b\x69\x0a\xc0\xa2\x76\x0c\x3e\x62\x60\xca\xef\x0a\x36\x92\x57\x6f\x21\x4a\x5f\x21\x5b\xfb\xe6\x5a\xf7\x30\x3e\x3e\x0e\x9c\x76\x37\xee\xb6\x5d\xfc\xba\x09\xa3\xf1\xe9\x89\x0d\x9d\xa7\x0f\xdd\xe8\xfa\xdd\x76\x1f\xb3\xaa\x89\xa5\x53\xc1\x31\x55\x38\xce\xf1\xb1\x58\xe3\x6b\x50\x0f\x50\x96\xae\xbb\xc6\x39\x91\x20\x6b\x83\xb5\x9b\x37\xd7\xbc\x35\x48\x35\x95\xcf\x79\xde\x35\xa8\x0e\xcd\xb7\x4d\x23\x7d\x79\x13\x87\xfe\x95\xd3\xd0\x3f\x89\x82\x3e\xde\x53\xc2\x7a\x9e\x87\x62\xba\xe6\x24\x27\x1f\xdd\xb5\x2b\xec\xcc\x14\xa7\x66\x01\x21\x74\x9c\xe0\x64\x83\xa9\x19\xe3\x14\x10\x16\x20\xab\x69\x39\xea\x11\xc4\xdc\xd8\x6a\x97\x11\x33\x8a\xe8\x53\x59\x43\x1b\x41\xc7\x1d\x68\x0c\x05\x42\x38\xf1\xaa\x1d\x67\x32\x68\xb7\xe9\xf9\xb9\xb5\xa2\xa0\x0e\xc0\x18\xf1\x41\x3e\x6c\xba\xdb\xc6\xee\xc2\xc8\xd8\x1a\x4e\x0b\xcc\xca\x4d\x28\x11\x0e\xda\xf8\x1d\xc0\xf7\xb1\x82\x3a\xa8\x01\x72\x43\x37\x29\x05\xab\xb8\x9b\xa6\xfe\x65\x49\x7b\xf4\x3e\x26\x61\x0c\x75\x96\x28\x3a\x0d\xf1\x05\xe5\xb5\xab\x35\x35\xe1\x50\x4c\x71\x2d\x86\x3e\x83\xe6\xdc\x35\x9c\x03\xaf\x2d\xbb\x03\x93\xa2\x0f\xd9\xe3\x39\x4c\x8f\x9c\xce\x4b\x7e\xee\x3b\xcb\x17\x60\x6f\x7c\x67\xc8\xce\x4c\x09\x98\x52\xd7\x30\xd9\x11\xba\x54\x05\x94\x75\xa9\xe0\x95\x4f\xd9\xd3\xd0\xb9\xd4\x57\x63\x97\x1a\xff\x5c\x5a\x72\xe4\x1a\x65\xa8\x45\x6e\x0a\xed\xb9\x03\xa9\x35\x97\xd6\xec\xbc\x35\x98\xe2\x0b\xf2\x0c\xdf\x7e\xef\xa2\x6b\x72\x3a\x51\x99\x4e\xcb\x09\x97\xb2\x21\xfd\xa0\xd3\x79\xfb\x24\xba\xbf\xa2\x5d\x83\xd7\x4d\x13\xcd\x1d\xc0\x86\x3d\x6a\x01\x09\x8f\x4a\xd5\x27\x5f\xac\xfa\xfa\x31\x6d\x9a\x01\x95\x31\x43\xdd\x12\x45\x5b\xc2\xeb\x6b\x68\x3d\x8b\xd2\xbb\x0b\xf4\xd7\x13\x4d\xdd\x01\x7b\x83\xd4\x2f\x3d\x0b\xac\x29\xad\x76\x16\x00\x51\xe5\x6b\x7f\x5a\xf4\x9e\xaf\x8a\xf0\xc2\x3e\x5d\x93\xe0\xae\x93\x89\x66\x13\xa2\xea\x33\x5d\x93\x24\xb3\x30\xcb\x90\x51\xa0\x74\xe0\x1c\x7b\x3a\x06\x5d\x4e\x49\x37\xed\x92\xcc\xb3\x4e\x34\x38\xe4\x97\x6d\xed\x24\xe3\x9d\xae\xdb\xd2\xd2\xad\xed\xac\x34\xe8\x53\xd6\x9a\x66\x66\x32\xb7\xa4\x5a\xb5\x21\xcd\x5a\xde\x4d\x30\xf6\x34\xa4\x77\x0b\xb0\x49\x95\x3f\x03\x0c\x1c\xf8\x29\x7a\x9b\x52\x63\x27\xc5\x80\x6a\x7d\xc8\x6e\x85\xbd\x49\x94\x9c\xf8\x11\xbd\x9e\x03\x27\x41\xa8\xbd\x01\x39\xda\x1d\x50\x88\xcc\x2e\x6e\x66\xc0\xe2\xf8\xfe\x43\xe9\x18\x68\xb3\x3f\xe4\xa1\xcc\x34\x77\xfb\x2e\xfa\x75\x23\x82\xac\x9f\xf3\xdc\xb4\x23\x7b\x1c\x0d\x32\x0f\x76\xcd\x42\xdb\x48\x96\xa4\x1b\x1c\x6f\x6e\x8b\x2b\xa7\x61\xe4\x26\xdf\x3a\x6a\x43\xe8\x24\x39\xb3\x71\xec\x2a\xc7\x25\xcf\x09\x13\x60\xdd\x59\x34\xd3\x6d\x97\x4d\x74\xdb\x99\x60\x17\x15\x08\x3b\xfe\x22\x21\x53\x39\xb0\x83\xde\xcc\x27\x5f\x51\x45\x71\x8a\xe2\x00\xdb\x58\xe6\x9c\xfa\x21\xd2\xcb\xfa\x9d\xdf\xf1\xb2\xb9\xcf\xd0\x57\x1e\xa7\x54\xd6\xa7\xa1\xd4\x11\x45\x5e\xec\x31\x8a\x26\xac\x0b\xc2\xa7\x5f\xd9\x45\xba\x60\x7a\x46\xee\x2d\x66\x75\x96\xe0\x95\x3d\x47\xcb\x58\x2f\xb0\x9a\xdb\xaf\x4c\xa7\x25\xfa\xb7\xe3\x5f\xc7\x8e\xba\xef\xb2\x59\xb3\x97\x7e\x45\x9c\xa5\x5f\x1b\x3d\x23\x3d\xcb\x4a\xce\x3d\x7f\x49\x5c\x61\x10\x0a\xed\x5c\xe5\x6d\x44\x5f\x2e\x00\xa7\x65\xac\x42\xf6\x62\xe9\x46\xc9\xc1\xb7\xc1\xb4\x7b\x7f\x97\x20\xb9\x85\xf2\x03\xbc\xf8\x43\xe6\x4b\x1a\xd5\xc8\x07\xa2\xa8\x8c\x94\xc0\x6a\x4b\x32\x38\xc5\x95\x37\x12\xba\x48\x61\xc3\xf2\xb5\x28\x75\x97\xea\x5b\x77\xa9\x6d\x32\x31\x51\x0a\x2e\x8e\x8f\x6a\x03\x18\xe1\x6a\xff\xe1\x19\xfa\x40\xa5\x01\x44\x1c\xdf\x79\x41\xc5\xa3\x83\x08\x9d\xcb\x44\x47\x7c\x8e\xda\x58\xb6\x83\x64\x8c\x6c\xb8\x24\xae\x29\x27\xc4\xbc\x6a\xde\x42\xba\x74\x48\x26\x6a\xcc\xbb\x64\x85\x62\x4c\xe3\x52\xdb\x14\x05\x05\xc9\x4b\xe6\x29\xae\x14\x51\x91\xf6\x98\x47\x3a\x32\x99\x67\x29\x8d\xc8\xa7\x16\x60\xa7\xa0\xbd\x79\x69\x13\x05\xd4\x95\xd2\xd0\x3e\xb0\x2d\x65\x8c\xb2\xac\x79\xc6\x21\xb1\xb4\x0b\x98\x30\x4f\xb8\x25\x00\xd8\x80\x35\x9a\x5e\xcb\x7d\xe0\xdb\xde\xef\x8f\x79\x9a\xd5\xde\x9c\xdf\xc5\x0c\xd6\x35\x86\x0d\x8f\xfa\x85\x5b\xeb\xde\xa2\x11\xe2\xeb\x4f\xcc\x68\x19\x8d\x05\xff\x4f\xbe\x28\x5f\x30\x7c\x7e\xc9\x45\x6c\x29\xe6\x41\x5f\x72\x2f\xf1\xff\x75\xf9\x2c\xba\x69\xcd\x1c\x64\xf7\xdd\x0d\xb4\x27\x07\xa4\x80\x1a\xad\x8d\x8f\xa9\x20\x97\x13\x37\x48\x12\x5f\xdb\x9b\x88\xdc\x9b\x6d\x6d\x2b\xe6\xc9\xb8\x89\x50\x76\xa1\xaa\x55\xa8\x1c\x05\x0d\x6c\x2f\x53\x6f\x74\x18\xe1\xdd\x96\x6c\x33\xe8\xbb\x7b\xd9\x76\x3a\x40\xd1\x30\xc7\x27\x74\x3c\x7a\x47\x67\x59\xb0\xf6\xd1\x2f\x2f\x5b\xba\x5d\x61\x9c\xc0\x62\x74\x57\x2c\x02\x98\xd9\x77\xa2\x07\x1c\xbe\x9f\x47\x22\x73\x7e\x12\xbd\x7d\xba\x52\x74\x60\xf6\x18\xa4\xcc\xc3\xe1\x29\xc4\xb2\x27\x78\x27\xf2\x93\x64\x92\x77\x7c\x38\xa8\x88\x04\x64\xf7\x30\xf8\x00\xe8\x7f\xf6\x18\x43\x0f\xd3\x34\x49\xd9\x1b\x0c\xee\xa8\x1e\xb0\xb7\xf8\xf5\xd4\x07\x5a\xf9\x33\x86\xf6\xe8\x26\x8c\x7d\xc2\xb0\x6c\x8a\xfd\x84\xe1\x17\xc1\xe4\xe1\xc5\x9c\xbd\xc7\xf0\x4b\xba\xbe\x62\x8f\x30\x8c\xf7\xd9\xb2\xda\xe7\xe8\x27\xa7\xdc\x9b\xec\x86\xcf\x3f\xd9\xdf\xef\x7c\xee\xbc\xc3\x22\xe7\x70\x78\x25\xe7\x00\x0a\xef\xfc\xde\x28\x19\x12\x74\xb3\x0f\x3e\x7f\x63\xe5\xee\x89\x44\xb5\xf2\xa3\xcf\x01\x2a\x35\x65\x01\xc3\xce\xf8\x0d\x1f\x15\x87\xf6\xcf\xe3\x67\x69\x32\x0f\x52\x71\xc9\x44\x86\xd6\xdd\x94\x62\x0a\xa6\x19\xb4\x75\xcc\x92\x0c\x0f\xe6\xf6\xef\xda\xdd\xb9\xef\xc4\x59\x49\xa7\x6f\xe8\x9c\x85\xa1\x5f\xdd\xde\x37\x03\x67\xc0\x0f\x0f\x0f\x1d\xb7\x58\x83\x85\x5d\xeb\x75\x55\xc4\x91\xbb\x31\x41\xba\x1e\x72\xe0\x69\x7e\x03\x7a\x12\x66\x7c\x0f\x48\x87\x4c\xcf\xf6\x3d\xf2\x38\x88\x62\xbf\x8c\xf9\x94\x06\x7f\xc3\xac\xd3\x21\xc9\x60\x86\xf2\x22\x3a\x83\x21\x87\x9f\xb1\x2c\xe3\x6f\xfd\xde\x30\x08\x23\x96\x63\x15\xc3\x08\x28\x8e\x57\xe1\x2c\x48\x72\xc1\x86\x94\x38\x8e\x12\x98\xd7\x88\xaa\x82\xbf\x30\x9b\x93\x40\x3c\xd3\x53\xb4\x3f\x46\xdf\x6d\x19\x9b\x67\xfc\xb9\x7c\x4d\x8a\x8d\x69\x06\xe6\x6a\x56\x76\x33\x94\xfd\x07\x29\x72\x3a\x6c\x4a\xb5\x4c\xb1\x25\x60\xab\xa1\xe4\x34\x63\x23\xfc\xca\x02\xa1\x5b\x9d\x51\x4d\x52\x1f\x80\x9d\x51\x81\x33\xcc\xf2\x1a\xb8\x85\xef\x69\x88\x50\xee\x2c\x63\x13\x4a\x9a\x60\xd2\xdb\xc0\x3f\x7d\xea\xcf\x21\x7e\x92\xb1\xcb\xcc\xd6\x0b\xc3\x13\x5c\x02\x36\x64\xc6\xab\x0a\x12\xc5\x7d\xf7\x5b\x5d\x91\x50\x3e\x32\x85\xa3\xe6\x67\x0b\x36\xee\x26\xec\x20\x48\x52\x07\x7b\x0a\x88\xca\x08\x23\x00\xe4\x1f\x52\xc3\xf0\x17\x00\x0d\x11\xab\xac\xe8\x61\xc6\xee\x53\xc2\x7d\x9a\xa3\x61\x1a\x00\xc0\x43\xfc\xfd\x8c\x9d\x60\x1f\xc3\x6c\x27\x8c\x43\xd8\x03\x17\x94\xeb\x82\x72\x9d\x06\x97\xf8\x06\xd0\x45\xc6\x5e\xd0\x5c\xcf\xfc\x0b\x76\x2c\x43\x61\xcc\xce\x29\x27\xfc\xbd\xe7\xf7\x62\x82\xd5\xf3\x8c\x3d\xa5\x48\xf8\xfb\xd9\x37\x75\xa2\x82\x43\xc6\x5e\x61\x33\x24\x6e\xdc\x05\x50\xde\xa7\x6a\x52\x1f\xa0\x7c\xc6\x9e\x51\xf6\xbd\x87\x8f\xee\xbe\xda\x7d\xf3\xf0\x78\x77\x6f\x67\x77\x6f\xf7\xd5\x7b\xf6\x92\xe2\x9f\xed\xbf\xdc\xad\xc6\xef\x51\xe1\x79\x72\xee\xdc\x62\xb7\x6f\xe1\xeb\xb4\x0f\xa0\xd9\x0c\x7e\x77\xf1\x97\x1e\xd1\x39\xcd\xf8\x65\x36\xb8\xcc\x7a\xf7\xde\xbf\x7a\xf8\xf2\xf8\xd9\xc3\x17\xc7\x0f\x9f\x3c\x7c\xfa\x70\xef\x95\xb7\xc9\xee\x5a\x15\x7c\x7b\x1b\x2b\x78\x92\xf1\x89\x82\x42\x58\xa4\xd7\x59\xe9\x71\x0c\x85\xd1\x2d\x6b\xc9\x5e\x67\x96\x87\x49\xde\xc2\x9b\xf9\xde\xdb\x30\x7e\xf1\x8a\x76\x38\x8c\x55\x3b\x8e\x7c\xe1\x32\x95\x97\xfc\x4c\xf2\xa5\x1b\x6d\xd8\xcb\xe8\xb2\xb2\x8f\x40\x00\x39\x61\x26\xf8\x16\x2a\xc1\xbc\xd3\xeb\xf3\x40\x6d\xfc\x9d\xd4\x9f\xe0\xaf\xe3\x1a\xf5\x98\x92\xaa\x53\x25\x5b\x5b\x0b\x55\x8f\x75\x9f\xc5\x5b\xe3\xac\xce\xb3\x6e\xb9\x95\xb2\x95\xdc\x9b\x70\x62\x92\xb5\xc3\xb2\x7c\x89\x5f\x49\x46\xda\xbb\x0f\xc4\x8d\x92\xc3\x78\x27\x82\x59\x92\x1f\xef\x42\x30\x2d\x35\x00\x76\x9b\x29\xd1\x91\x77\x75\x8c\xae\x60\x09\xed\x7e\xac\x40\x7f\x79\x75\xe2\x94\x40\x6c\xd2\xe5\x59\x23\xbd\x61\x5e\x09\xeb\x56\x2d\xd6\x42\x77\xdc\x18\xfd\x4a\x0a\x7a\x3f\x2f\x45\x31\x81\x39\x08\x16\xb8\x33\x76\x32\xfe\x24\x1b\x58\xd7\x08\xe5\x09\xfd\x24\x23\x45\x49\xe2\x72\x83\x85\xb7\xef\xf7\x7d\x74\x0c\xfa\x63\x4c\xb8\xe9\xcc\x2e\x55\xfa\x8d\x45\xef\xa8\x4f\xb4\x27\x5b\x00\x36\x12\x14\x9e\x66\x2e\xf9\x2c\x8b\xbf\x39\x45\x4f\xc6\x6a\xdb\x0a\xc9\x5a\x99\xfb\x24\x88\xbd\x44\x3d\xec\x4d\xb4\xe5\x0c\xa9\x6d\x15\x17\x50\x5c\x79\xe3\xd5\x42\xda\xd4\x91\x45\xce\xb0\x48\x8a\x1c\x92\x2e\x70\xa6\x5c\x92\xa2\x59\x9a\x07\x84\xb7\x54\x56\xa7\xf9\xb9\x97\xf1\xfb\x19\xa2\xb0\x4a\xdf\x35\xa6\x80\xb2\xef\x91\x5f\x29\x4b\xb1\xc7\xb5\xe9\xb1\x27\x07\x75\x4e\x31\xf3\xae\xcf\xde\x64\x75\xc5\x56\xa0\x3d\x80\x0c\xde\x5c\xd2\x48\xb4\xe4\x95\xa4\x1f\x1f\xf2\x8f\xeb\x4e\xb2\x2e\xd4\x45\x52\xc2\xc2\xed\x4d\x5a\xe3\x6e\x37\xd8\xe6\xaf\x8d\x08\x56\xb2\x70\x41\x59\xe3\x4e\x46\x75\xd1\x22\xbe\xcd\x78\x9c\x3a\xf6\x22\x92\x0c\xdc\xdc\x89\xc6\xee\x00\xaa\x43\xdb\x7c\x7a\x09\x70\x0b\x88\xca\xcf\x5f\x2e\x42\xea\xc1\xea\x35\x56\x59\x10\x09\x35\x97\x7d\x6a\x2e\x4a\x77\xa3\x90\xfc\x53\xc6\xb3\xd4\x49\x63\x97\xbd\xa7\x50\x42\x6a\x0b\xec\xd1\xaa\x52\x83\x4d\x6f\xcb\xb4\xb3\x58\xb6\x6e\x3a\x38\x40\xf5\x44\x6c\xf8\x79\xc6\xcf\x01\x02\x97\x72\xd0\xaa\xdf\xf3\x5d\x5c\x11\x3c\x92\x00\xb4\xd9\x8d\x8c\x3f\xb4\xf3\x5e\xaf\x01\x63\xab\xcf\x7c\x22\x05\x98\xbe\x44\x21\x00\xef\x2f\x42\xde\x50\xcb\x4a\xdd\xbc\xd6\x87\x4c\x6b\x14\x49\x98\x7b\x97\xf1\xa7\x8d\x3d\x69\xf2\x21\x4b\xa4\xe3\xa2\x8f\xf7\x80\x1b\x17\x1b\xa8\x6f\x87\x8f\xff\xbe\xc2\xf3\x94\xbc\x50\xbd\x6a\xec\x4c\x45\xe3\x49\x35\xfb\x21\xe3\x51\x15\x72\x95\x07\xa2\x8a\x9f\xcc\xaa\x47\x4b\xdc\xc0\xc4\x51\xec\x8f\x61\xf7\xe2\xe9\x2b\xa5\xe6\x11\xdd\x06\x20\xd1\x60\xf9\xa1\x89\x07\x01\x47\x83\x95\x28\xa3\x76\x63\x8f\x3c\x74\x2e\xe0\x87\xfd\x98\xf1\x34\x75\xe6\x00\x02\x41\xce\x2f\x96\x7a\x11\xb8\xba\x31\x5b\x81\x20\xae\xdf\x52\xad\x70\x38\x5d\x55\x25\x28\x8a\x26\x25\x5d\x58\x51\x5a\x62\x80\x62\x72\xab\xe9\x49\x9f\x92\x17\x99\xd4\x3c\x5a\x78\x0f\x52\x26\x72\xec\xe4\x0e\x5e\xe3\xe4\x3c\x5c\x06\x4d\x73\xbd\x0e\x78\x3f\x79\x92\x9c\xeb\xdb\x3a\xe0\x06\xf0\x15\xba\x95\x97\x79\xc2\x5c\xe6\x79\x82\x94\x04\xae\xab\x9d\xea\x6a\xaf\x4b\x49\x6c\xad\x21\x58\xc8\xef\x5b\xfc\x55\xe6\xdc\x15\xdd\xf6\xe6\xf7\xe4\xb9\x74\xe6\xf3\xe6\x9a\x9a\xfd\x55\x02\x06\xf2\xe4\x0b\x94\xf8\xf2\x64\xc0\x1f\x92\x10\x45\xde\x0b\x01\x68\x3f\x2d\x45\x34\x5b\xdf\x79\x5b\x28\x21\x90\xc0\x93\x7c\xb9\xcf\xc7\x2b\xfa\xcc\xc2\x2f\x97\x5d\x53\x92\xe7\xaf\x99\x44\xeb\x19\x2d\x5b\x8b\xe4\x23\x3a\x97\xb5\x1e\x3c\x9a\x54\xd3\xe2\x15\x69\x36\xc4\xf1\x09\x7b\x6c\xd5\x71\xd0\x1e\x05\x51\x20\x82\xf6\x11\x7f\x23\x2a\x29\x88\x57\xf8\xdb\x5a\x1c\x30\x12\xfc\x73\x2d\x0e\x4e\x20\xfe\x49\xb0\xf7\x76\x1c\x22\x36\xfe\x1c\x28\x73\x65\x54\xc0\x1f\x0b\xe4\xc7\xc7\x40\x21\xf0\x1b\x09\x06\xd3\x4b\xfe\x8e\x02\x59\x16\x4e\x62\xfe\x63\x86\x61\xc1\xf7\x31\xee\x24\x00\x66\x22\xe0\x1f\x28\x0c\xec\x0f\xff\x51\x87\xee\xc2\x12\x07\xa1\xfa\xf8\x29\xb8\xe4\x02\x3f\xb4\xb7\x7e\xfe\xd4\x67\x42\x8a\x48\xf8\xc3\x84\x82\x79\x7c\xca\x9f\xa4\x18\x04\x1a\xcd\x1f\x0a\xfe\x5a\x7e\x90\x2b\x10\xc1\x5f\x51\x81\x24\x8f\xc5\xbd\x4b\xfe\x16\xfb\x20\xe9\x2d\x7e\x8f\xea\xcd\x53\xe8\x66\x6c\x82\xe4\xed\x9e\xa7\xf8\x3d\x0a\x4e\xa0\xd4\x30\xe0\x89\xfc\x92\x1c\x27\x7f\xac\xbe\x60\x98\xa1\x0c\x46\xfe\x25\xf7\x29\x18\x22\xbf\x13\x60\x99\x8f\xd8\x07\x74\xbb\xcf\x77\x74\x48\x56\x7d\xaf\xf2\xf9\x16\x6f\x18\xf9\x63\x1d\x27\x3f\xdf\xe0\xe7\x38\x84\x79\x78\xab\x42\x38\xa7\x7b\x38\xda\x31\x90\x5e\x22\x88\xf9\xfb\xb4\xfc\x78\x10\x04\x73\xfe\x48\x46\x24\xe7\x3c\x0b\x55\x48\xb6\x97\xd3\x67\x92\x3e\x84\x35\xe2\x77\x93\xf2\x43\x26\x3f\x51\x31\xbb\x31\xff\x1c\xea\xa0\x4c\xfa\xa4\xbe\x81\xad\xe4\x3f\x95\x61\x99\xf8\x9e\x22\xd4\x5e\xc8\xf8\x23\xfc\x9c\xa4\x49\x3e\x87\x49\xfe\x8c\x93\x4c\xf2\x58\xf8\xf8\x24\x3f\x42\x11\xfa\x11\xbf\x91\xd2\x87\x40\x57\x29\x54\x92\xbf\x93\x31\x67\xc0\x9e\xf1\x1b\xa1\x0c\x27\xa7\x01\x7f\x8d\xfd\x42\x96\x84\x07\xb9\x0a\xed\xa2\xeb\x60\x86\xd6\x02\x73\xfe\x31\x91\x81\x37\x88\xd4\x33\xfe\x41\xc6\x03\xa1\x0b\x1f\xcf\xfc\xf2\x43\xf3\xc3\xfc\x25\x45\x06\xb3\x24\xfc\x1c\xf0\x21\x65\x0f\xd2\x49\xc0\x05\xd6\x3e\x0b\x2f\x00\x9c\xf6\x30\x4b\x1c\x4c\x10\x36\x22\xcc\x91\xcc\x42\xc1\x7f\xa4\x10\x2e\xe9\x1c\x43\x73\x3f\x44\x36\xda\xa7\x60\x4a\x83\x1a\x87\xe5\x87\x9c\x9c\xa9\x89\xa1\x31\x3e\xc2\x29\x40\xb9\x04\x17\x54\x2e\xca\x21\xb8\x83\x23\xd0\x8c\x29\x3f\xf5\xad\xaf\xfd\x31\xbf\x4b\xdf\x88\xed\x82\x44\x85\xee\x02\xc2\xc6\x30\xb0\x51\xd0\xef\x27\x98\x01\xe0\x38\x9d\xf0\x51\x48\x41\xa4\x7d\xf9\x1b\xca\x01\xc3\x3c\x03\xfa\x58\x86\x33\x00\x67\x0c\x65\x53\xe0\xc6\x01\xba\x3e\xd3\x07\x22\x21\x9e\x50\x10\xc8\x76\x58\xa7\xf7\x65\x18\x77\xe0\x23\xfa\x9c\x43\x0b\x23\x3e\xc3\x06\xf0\x29\x08\x9e\x25\x2a\xa4\x60\xab\xf2\x29\x81\x77\xa8\xe3\xe4\x67\x24\x3f\xe7\xfc\x3e\x05\xa6\x80\x3e\x04\x44\x9f\x85\xf2\x2b\xe7\x27\x14\x1f\x22\xcf\xf4\x1a\xc7\x24\x12\xe2\x62\xf9\x47\xca\x91\x3c\x8b\x60\xa7\x4b\xc2\x9e\xef\x50\x14\x8c\x3f\x03\x48\x9c\xf1\x14\xb3\xe7\x31\xce\xf0\x3c\x91\xc1\x4f\x7c\x2c\x43\x9f\xc3\x39\x9f\x62\xf0\x4c\x02\x48\xe2\x9b\x30\x80\x51\x88\x5f\xe7\x53\xd8\xaa\xfc\x39\x66\xc2\xdb\x4e\x60\xf7\xf9\x8c\x3e\x52\xe8\xed\x04\x9b\xba\x00\x54\x7a\x86\x51\x58\xdb\x44\x05\x54\x5f\x2e\x09\x5d\x01\x42\xa2\x3d\x47\x9b\x6c\x98\x44\x11\x26\x11\x6c\x22\x2e\x4a\xb2\x40\xa6\x04\x66\xef\x05\xd5\x8d\x17\x5c\xc0\xfe\x1d\x49\xcc\x88\xc6\xfb\x00\x7a\x81\xc4\x70\xb3\x00\xba\x34\x52\x1b\x2b\xb1\xda\xcc\x02\x6a\x64\x4f\xce\x6b\x18\xc9\xc5\xc5\xb1\xe7\x01\x8e\x7e\xcf\x77\x04\x32\x36\x88\x6a\x91\xad\x13\xfc\x9c\x10\x20\xf0\x9e\x11\x9e\x41\xc0\x36\xd1\xe7\x3c\x14\x7e\x84\x9b\x21\xa3\x64\xf4\x32\xcd\x2f\x43\x1d\x24\x9c\xf2\x50\x61\x41\xc0\x8b\x3c\xc7\x5c\xd0\xd7\xec\x2d\xcc\x15\x1f\xd2\x17\xb1\x88\x3c\x2a\xc3\x52\x24\xc6\xe7\x14\x03\x5b\x1a\xb6\x1d\xa1\x17\xc4\xef\x0f\x74\x48\xde\xf5\x7c\x4e\xd5\x27\x62\xf8\x37\xa1\xfa\x78\xe2\x03\xb4\xee\x26\xd6\x97\xcc\xfd\x29\xb5\xa2\xb0\xc4\x5b\x5d\xe2\x2d\xad\xe2\xa9\x2c\x92\x42\xe9\x9f\x30\x2b\x9e\x61\xcf\x09\x9b\x8c\x80\x0d\x0e\x61\x83\xed\xfb\x84\x5b\x86\x51\x3e\x42\x14\x91\x30\xf3\x6c\x0b\x7f\x4e\x28\x08\xa5\xd2\x92\x69\xe6\xf7\x43\x15\x81\x70\x78\x83\xd6\x26\xbb\x27\x55\xb6\xf8\x89\x4c\x43\x09\x22\xbf\x90\x61\x65\xa0\xc2\x5f\xa8\x4f\x98\xf3\x4b\x7e\xac\x3e\x3e\xe5\x80\x21\xce\xd5\x07\xca\x0c\xf8\x53\xf9\x21\xa5\x25\xfc\x9d\xac\x5e\x0b\x1f\xf9\x2b\x99\xfa\x14\xd1\x17\x7f\x26\x3f\xf6\xfc\x3d\xfe\x52\x07\x45\x08\x5b\x7b\x4f\x7d\x21\x82\x78\xa0\xc3\x48\x73\xf3\x5d\xf9\xa5\xa0\x74\x5f\x7e\xd9\x9b\xe8\x83\x6c\x50\x2d\xd5\xa9\xcc\x20\xc5\x7e\xfc\xae\xfc\x42\xaa\x7f\x24\x47\xff\x44\xc6\xbc\xd6\x2a\x55\xfc\x75\x48\xd8\xf8\xc4\x3f\x21\x60\x4a\x11\x98\xf0\x86\x8d\x7f\x48\x55\x48\xdd\xb5\xf1\x1f\x53\x42\xc3\x17\xfc\xa7\x8c\x50\x2c\x1c\x5a\x18\x88\x93\xfb\x49\x3c\x06\xf4\x23\xf8\x03\x42\xb8\x09\x9c\x91\xbb\x32\x74\x0e\xac\x23\x61\xce\x11\x1f\x4b\x0c\x3b\x7a\x12\x8c\x01\x9f\xaa\x0f\xb9\x73\x46\x0a\xf9\x92\x6c\x89\xcf\x7c\x89\x13\x51\x2c\xe2\x4b\xa4\x38\xca\x01\xb7\xdd\x4b\x4c\x58\x16\x7b\x2c\x23\xe6\x70\xf6\xf3\x33\x99\x31\x83\x03\x9d\xc7\x14\xce\xe3\xdd\x18\x3a\x26\x60\x47\xf2\x17\xb8\xcd\x70\x6b\x7c\xa2\x0d\x17\x03\x32\xa3\xc1\x26\x39\xa1\xc8\x59\xc0\x7f\xd2\xc8\x32\x50\xe0\x1c\x96\x11\x25\xd4\xfa\x14\x89\x6f\xe4\x50\xf1\x30\xd7\x9f\x72\x13\x4d\x08\xdd\x29\xc9\x0b\xbf\xa4\xaf\x34\x9c\x01\x2d\xab\x42\x34\xf6\xfb\xfa\x4b\x8e\xe2\x44\x7e\x02\xb8\xf0\x0b\x89\xff\xd4\x36\x7c\xe1\x1b\x34\xb0\x3b\xe2\x1f\x09\xc3\x25\x29\x60\x90\x63\x0c\x02\xf5\x24\xf7\xa2\x1f\x5f\xca\xde\xa3\xc3\x5c\x80\x0a\xb5\x17\x46\x40\x1f\xe2\x8a\x48\x6a\x20\x1a\x45\x72\xfe\x30\x98\xca\x99\x9b\xe2\x49\xf0\x53\x5a\xee\x22\xbd\x89\x08\xaa\xee\x29\xc4\xb3\x24\x2c\x28\x95\x90\x9f\xc5\x76\xba\x7c\xab\xda\x22\x52\xd3\x23\x54\xe6\xc6\xdb\x81\x18\x89\xed\x00\xd9\x7f\x54\x7d\x84\x29\xf3\x61\x8a\x02\xfe\x56\x1d\x98\x9a\x24\x95\xb1\x0d\x4c\x63\xf5\x6e\x4b\x7b\x71\x0c\x06\x0d\x1e\xdc\x4a\x99\xd0\xdb\x04\xef\xf1\xa0\x65\xef\x6d\x52\x71\x8a\x07\x2c\xb7\xe8\xbd\x79\xf8\xe2\xe5\xee\xfe\x1e\x3f\x67\x1f\x84\x73\xd0\x46\xca\xb4\xcd\xda\x8a\x40\x85\x10\x91\x8e\xfa\x57\x3e\x98\xc4\xda\x8a\x24\x28\x43\x32\xe1\xa8\xe2\xf3\x05\x7d\x1b\x56\x1c\x33\xa0\xa4\x81\x1a\x91\x64\x1f\x94\x06\x32\x07\xfe\x9a\x23\xb5\x52\x41\xa9\xf4\x26\x38\xdf\x41\xbf\x7c\x9c\x3f\xee\x5b\x7c\x01\xba\x4e\xb4\xb2\x97\x2f\x09\xe3\x10\xd5\xdb\x02\xf4\xa2\xd4\xf1\xb1\x6c\x90\x7c\xce\x65\x14\xa1\x4f\xa4\x0c\x67\xd1\xa9\xc5\x90\xc3\x44\x7d\x75\x54\x29\xcd\xf1\x2a\xb1\x28\x52\xd4\xf6\x3d\x3e\x1e\x85\xe9\xf1\xf1\x9d\x4d\x96\xa9\x6b\x41\x5d\x85\x47\x2f\x72\xd1\xeb\xc5\xd8\x4f\x4f\xd0\x7b\x5d\x7a\xf0\xf4\x8c\x95\x1c\xf4\x8a\xf1\xb6\x8f\x8f\xdb\xdd\xa0\xdb\xbe\x8f\x94\x3d\x84\xd1\x30\xbc\xdb\x96\x33\xb4\x72\x02\x50\x69\x5c\xbf\xe6\x2a\xdf\x3c\x18\x66\xe4\xc8\x0e\xe5\xa0\x4a\x4f\xd2\x9e\x19\x94\x5d\x25\x95\xc1\xe9\xf9\xc3\x47\xed\xfb\xf4\xb2\xbd\x18\x1c\x4b\x77\x0c\x5e\xd8\x4d\x49\x9a\xa5\x4d\xcf\xa0\xe0\x59\x18\x9c\xcb\xe9\xb3\xbe\x68\xea\x7c\x35\x1f\x88\x68\xbc\x54\xce\x01\x30\x91\x49\x39\x65\x83\xb6\x7a\x7a\x0b\xaf\x1f\x2d\x5f\x93\xac\x32\xba\xae\xca\xd5\x78\xef\x4b\x63\x31\xae\x09\x61\x2a\x20\xcd\x72\x55\xd8\x58\x93\x02\x32\xde\x28\x3a\xad\x55\x98\x1e\x51\xaa\x55\x65\x09\xbd\x70\x18\xc3\x0a\xe2\x89\xb0\x6a\x05\x69\x75\x81\x59\xb6\x07\xba\x72\xe9\x2a\x5d\x80\x79\x07\x0e\x5a\x6f\x51\x74\x29\xa0\xdb\x55\x9c\x06\xb4\x8c\x94\xef\xaa\x96\x09\xbc\xa8\x65\x68\x54\x36\xfe\xab\x5a\x36\xcd\x11\x2d\x0f\x8d\x11\x31\xb9\x6a\x67\x0e\xf4\x5e\xf6\xe4\x5e\x86\x5d\x3a\x78\x1d\x7b\x8f\xe3\xd5\x1b\x75\xa9\x4d\xf2\xdf\x88\xcd\x56\x79\x7e\xc9\xf0\x36\x77\x55\x31\x8e\xce\xbe\x5f\x5d\x69\x8b\xd3\x6c\xe8\x6e\xa9\x74\x75\x26\xc5\x2e\xb7\x95\x33\x4c\x55\x9b\xa5\x11\x69\x2b\xe6\xe3\xeb\x49\x31\x6f\x05\x2a\x1a\x01\xb6\xd2\xa6\xe2\x4f\x1a\x81\xea\x2b\x9a\xb2\xed\x3d\x02\xf5\x5d\x6f\x42\xf2\x34\xd5\x16\x02\x63\x32\xb1\xe9\xd1\xd5\xba\xf2\xd6\xb0\xb9\xad\xcf\x03\xcd\xbd\x38\xeb\x81\x72\xf2\x89\xd3\x53\x9a\xdf\x35\xd9\x74\x69\xc9\x93\xbc\xaa\x47\xef\x26\x71\xc9\xd2\x3b\xeb\xc2\xf5\x62\xaa\x98\x6e\xe1\xd1\x4e\xa1\xd2\x4f\xcd\xe1\xac\x58\x35\x6a\x7e\x13\xc6\x06\x07\xa6\x55\xac\x62\x11\x61\x34\x83\xd1\xd0\x2a\xe4\x1b\xbf\x73\x06\x1e\xed\xb8\x02\xf7\x9b\x7b\x63\x43\x8a\xbf\xd0\x0b\x6b\xe5\x88\x5d\xf6\x52\xb1\xe4\x6e\xd4\xb7\x3c\x7c\x64\x35\x3d\x11\x96\xf3\x56\x6b\x85\x53\x55\x7c\xc3\xb7\xe2\x7e\x15\xdf\xe5\xec\x74\x5a\x39\xbd\x9a\x0d\x01\xa3\x8b\x16\xe1\xab\x36\x28\xa8\xc5\x77\x15\xf5\xb3\x9b\x95\x23\x97\x16\x69\xce\xeb\xd7\x30\x31\xb7\x7c\xff\x1a\x85\x90\x98\xf9\xa8\xba\xac\x1f\x05\x07\xea\x41\xbd\xab\x7b\x03\x51\xbb\xd6\x03\x8b\x06\xa9\x67\xb9\x7c\x65\x53\xe3\x4c\x63\x0c\xe5\xa5\x3b\x69\x54\x0b\x2b\x8a\x69\x55\x9b\x85\xca\x8f\x78\x25\x16\x75\x64\x2b\x7a\x30\x88\xd0\x47\xb6\xde\xcb\x49\x22\x15\x5f\x0e\xe6\x47\x46\xe5\x45\x94\x48\x5c\xfa\x9b\xc5\x57\x0c\x16\xf6\xd2\x13\x71\x32\x2f\xb1\x8b\x74\xa9\x0c\xe8\x05\xd5\x55\x91\x8e\xa0\x43\x11\x9b\x81\x9f\x6c\x1a\x8e\x31\x0d\xa9\x4e\xfc\xa1\x4b\xea\x36\x3e\xcd\x24\x53\xaa\x74\x86\x9c\xbf\xe7\x3e\xfa\x44\x48\x25\xc0\x60\x3d\x05\x96\x2e\x54\x11\x03\x37\x81\x3b\x00\xe4\x3c\x07\x7c\x85\x3d\x6a\xb3\x44\x16\xc0\x5e\x14\xd0\x87\xa2\x9e\xbb\x02\x65\xc1\x12\x94\x59\x4e\x63\x8c\xc2\x07\x00\x44\x15\xb6\x60\x0b\x95\x8e\x2c\x8c\x47\x62\xb5\x27\xf1\xa0\x69\x52\xb5\x31\xab\x8e\x94\xdb\x12\x76\x24\x9e\xf6\x46\x0d\x0d\xd1\x41\xc5\x03\x51\x89\xa6\xe6\x78\x2c\x2a\x14\xa6\x14\x32\x5e\x54\xc9\x4e\x40\xb9\x28\x15\x7a\x51\x8d\x05\x02\x0e\x58\x91\xe3\x6a\xa4\x6e\xeb\xbc\x1a\xad\x95\x2c\xf8\xd3\x5a\xf6\x1c\x3d\xba\xd9\xf9\x7e\x7c\x09\x24\xa7\xa8\x77\x13\x58\xab\xa5\x38\xfe\xaa\xde\x4b\x29\x8a\xb0\xe3\xe0\xe8\xa9\xe4\x21\x82\xde\x8e\x20\x04\x52\xa5\xb1\x83\xa5\x5a\x24\x6a\xae\x0e\x08\xa5\x10\xd5\x81\x63\x3d\x7f\x89\xf4\xb9\x8e\xd9\x39\x6f\xdf\xee\xdd\xea\x6d\xb6\xd9\x53\xbe\xc5\x5e\xf1\x5b\x6c\x9f\xff\x96\x3d\xe3\xdf\xb3\x97\x7c\xeb\x3b\xb6\xc7\x6f\xdf\x62\x0f\xf8\x77\xbf\x65\xbb\x7c\xeb\xd6\xf7\xec\x94\xdf\xfa\xf6\x3b\x76\x97\xdf\xde\x64\x4f\x78\xbb\xd7\xeb\xb5\xd9\x6b\xbe\xf5\xed\x26\xfb\x88\xb9\x77\xf8\x26\xbb\x07\xd5\x3c\x86\x6a\xde\xf0\x36\xb0\xb0\xd0\xc1\x60\xb4\xe6\x9b\x8b\xc8\x36\x7b\x8b\xb4\xa1\xd4\xf6\x3f\xb6\x28\x6b\xa4\x11\x3f\xf3\xf6\x81\x14\xa6\xac\x19\x76\xff\xa8\xcd\x3e\xd9\xd1\x80\x9a\x21\xea\xa7\x32\x4a\xb1\xfe\x10\xf9\xbe\x8c\x44\x01\x00\xc4\x3c\x2a\x63\x88\xbb\x87\xa8\xe7\x65\x94\xe6\xea\x21\xf6\x46\x19\xfb\xd4\x9f\x43\xc4\xbb\x32\x42\xb2\xee\x10\xf7\xa1\x8c\x93\xdc\x3a\xc4\xfd\x58\xc6\x49\x9e\x1d\xe2\x02\x51\x46\xbe\x0c\x30\x97\xb0\x63\x08\xbc\x20\x32\xb6\x22\x95\x5a\x0a\xc4\xa6\xa2\x36\x5a\xa9\xa5\x03\x29\x89\x95\x42\xaa\x29\xb7\x6f\xe9\xe9\x08\xeb\x49\x4a\x6b\x05\x92\x7c\x2b\x69\x57\xab\xc5\x40\x7c\x56\x8d\xdf\xfa\x4e\x27\xe4\xd5\x84\xb2\x91\xa1\x95\x50\x6a\xd8\x40\x42\x54\x4f\xb8\x1f\x01\xf7\xa7\x64\x14\x90\x3e\xaf\xa5\x97\x6d\x8d\x6b\x29\x65\x63\xc0\x4b\x6f\x1c\x9e\xa0\xb6\xff\x21\xda\x57\xdc\xec\x6f\x4c\xd8\x88\xe2\x1c\x15\xe9\xa2\x25\xc5\x61\x17\xe2\x67\x10\x0f\xb1\xc1\xa1\xd3\xfb\x66\x70\xe8\x16\x58\x4e\x1c\xba\x2e\xa4\x1e\xc6\xb2\xe8\x19\x64\xe9\x00\x8e\x84\x7e\x15\x91\x28\x26\xa2\xf8\x94\x27\xa2\xf8\x93\xdb\x3f\x14\x7f\xf2\xc3\x77\x2e\x66\x99\x40\x96\x83\xce\x9d\xed\xf6\xcd\x3f\x3f\x82\xcf\x4b\xc0\x22\xb4\xa0\xce\x99\x50\x4a\xd2\x2e\x7b\x68\x22\x27\x65\xe4\x7d\x28\x78\xe7\x37\xeb\xce\xc1\x61\x76\xf8\xf2\xa8\x3b\x70\x7f\xb3\x0d\xe5\x4f\x28\xb6\x16\x79\x41\x91\xbc\x16\xfb\x02\xc7\x75\xe3\xf0\xca\x39\xf8\xdd\xe1\xe1\xe2\xe8\x1b\xe8\xe7\xe1\x61\x4f\x7d\xb8\xdf\xb8\x87\x0b\xc8\x74\x8c\x99\xce\xbf\xb9\xb1\xc1\xce\x21\xf4\xbb\xc3\xec\x1b\xbd\xa5\x0e\xd6\x0e\xe3\xc3\xf4\x50\x1c\x75\x0f\xcf\x37\xd8\x53\x4c\xdd\x3c\xb8\x78\x77\xb4\xc1\x5e\x51\x4e\x3d\xc1\xbd\xee\xe0\x7e\x79\x0b\x75\x78\x04\x55\xed\xe3\x98\x0f\x2f\x86\x9b\xeb\x87\x17\xa3\xef\xe0\xff\xf7\x18\x08\xe0\xff\x18\x02\x63\x88\x19\x63\xcc\x78\x8c\x33\xf2\x0c\xa7\xf9\xc6\xef\xdc\x0d\xf6\x12\x8b\xf5\xbe\xe9\x0e\x7e\x77\xe3\x6a\xe1\xb8\xc5\xc1\xe1\xd1\xe1\xc6\xe1\x21\x66\xda\x33\x33\xf4\xb2\x9c\xa1\x07\xb4\x70\x78\x52\x1c\x9e\x6c\xb0\x5d\x2c\x7d\x93\xfa\x9c\xdf\xda\xbc\xf5\x3d\xfd\xfd\x41\x16\x3f\x15\xcb\xa7\x53\xfb\xe0\xee\xfa\x87\x43\xd9\x4b\xea\xa6\xec\x27\x76\x14\xb7\x16\xa4\xfb\xeb\x9f\x0f\x65\x9f\xa9\xd3\xb2\xd7\xd4\xed\x6e\x5b\x1f\x69\xaa\x57\xc0\x46\x5d\xdd\x62\x0b\x67\xc0\x91\x3d\x15\xdd\xb6\x5b\x10\x9f\x3a\x68\xe3\x87\x0c\x77\x8b\x83\xcd\xf5\x1f\xa0\x2c\x99\x32\xa1\xa4\xe3\x2e\xb4\xb2\xf6\xff\xfb\xff\x1f\x8e\xff\xaf\x7f\xf8\xff\xfc\xe3\x7f\x52\xef\xfa\x3f\xfd\xfb\x3f\xff\xd3\x7f\xf8\xf7\x7e\xf9\xf9\xe7\x5f\x7e\xfe\x2b\xbf\xfc\xfc\x57\x7f\xf9\xf9\xaf\xfd\xf2\xf3\x5f\xff\xe5\xe7\xbf\xf1\xcb\xcf\x7f\xf3\x97\x9f\xff\xd6\x2f\x3f\xff\xed\x5f\x7e\xfe\x3b\xbf\xfc\xfc\x77\x7f\xf9\xf9\x1f\xfd\xf2\x57\xfe\xc1\xff\xfd\xf3\xcf\x6d\xf6\x44\xf0\x83\x36\x81\x3a\xb4\x61\xed\x72\xf8\x42\xcc\x05\x3f\x84\xae\xe0\xd7\xde\xe8\xfa\x53\x6d\x6e\xfc\x34\x58\xb5\x6d\xf6\xb6\x0c\xab\x3d\x26\x3f\xca\xf2\xa8\x37\x09\x3f\x12\xa5\x41\x40\xe2\x31\x08\xc8\xe9\x81\x00\x20\x2c\xfc\x2b\xd5\xa3\x58\xfb\x18\xc5\x26\x96\xa6\x1f\x7c\x6a\x15\x48\x08\x6a\x39\xa9\x14\xa2\x90\xc4\x0f\x69\x1d\xa3\xa1\x07\x1f\x46\xdf\x12\xc2\x25\xd6\xd0\x1f\x36\xa6\x50\x71\x65\xcf\x2d\x8c\x00\x5f\x0a\x45\x22\x37\x47\xfa\x98\x18\x65\x54\xbd\x80\x9c\x7a\x4d\x66\xe4\x1f\x49\x47\xec\xa3\x38\x48\xc4\x11\x87\x9f\x50\xfe\xf8\xf2\x27\x93\x3f\xb9\xfc\x19\xca\x9f\x48\xfe\xcc\xe5\xcf\x18\x7e\x5a\x70\x9c\x89\x83\xcf\xf4\xfd\x89\xfe\xa6\x32\xf1\x27\xfa\xfb\x9e\xfe\x3e\xa2\xbf\xcf\xe9\xef\x0d\xfa\xfb\x8e\xfe\x7e\xa0\xbf\x3f\xd2\xdf\x40\x16\x13\xf2\x27\xc6\xaa\xa5\xc6\xc3\x0e\x75\x73\x87\x1a\xd9\xa1\x46\x76\x64\x23\x3b\xd4\xc8\x0e\x35\xb2\x23\x47\xb1\x23\x47\xb1\x23\x47\xb1\x23\x47\xb1\x23\x47\xb1\x43\xad\xee\x50\xab\x3b\xd4\xea\x8e\x6c\x6e\x47\x0e\x6f\x47\x0e\x6f\x47\x0e\x6f\xc7\x0c\x6f\x87\xfa\xbf\x43\xfd\xdf\xa1\xfe\xef\xc8\xde\xee\x54\xba\x79\x0f\xba\xa9\x1d\x87\xb5\xb6\x98\x72\x04\xe6\x6d\x32\xe3\x2e\xac\xb5\xb5\x60\x8f\x21\x57\xfb\xf7\x3f\x03\x3d\x7a\x17\x16\xe5\xf7\x7f\x45\x07\xfe\xaa\x0e\xfc\x35\x1d\xf8\xeb\x3a\xf0\x37\x74\xe0\x1f\x42\xc0\xc7\xc0\xbf\xaf\x03\xff\x81\x0e\xfc\x87\x3a\xf0\x1f\xe9\xc0\x7f\xac\x03\x7f\x0b\x02\xf7\x31\xf0\x9f\x42\x60\x88\x81\x7f\x09\x02\x0f\x30\xf0\xdf\x42\x00\xa5\x7f\xbf\xff\xdb\x10\x78\x88\x81\xbf\xa3\x03\x7f\x57\x07\xfe\x39\x1d\xf8\xcf\x20\x80\xc0\xfb\xfb\xff\x5c\x07\xfe\x0b\x1d\xf8\x2f\x75\xe0\x9f\x87\xc0\x2e\x06\xfe\x05\x1d\xf8\x7b\x3a\xf0\x2f\xea\xc0\x7f\x05\x81\x10\x03\xff\xb5\x0e\xfc\x37\x3a\xf0\x8f\x74\xe0\x5f\x86\xc0\x1e\x06\xfe\x3b\x08\xe0\x8e\xfd\xfd\xbf\x02\x81\x7d\x0c\xfc\xab\x3a\xf0\xaf\xe9\xc0\xbf\xae\x03\xff\x86\x0e\xfc\x9b\x3a\xf0\xdf\xa3\x01\x1e\x06\xfe\x07\x1d\xf8\x1f\x75\xe0\x7f\xd2\x81\xff\x59\x07\xfe\x17\x1d\xf8\xb7\x20\xf0\x1a\x03\x7f\x5f\x07\xfe\x6d\x1d\xf8\x77\x74\xe0\x7f\x85\x40\x8e\x81\xff\x4d\x07\xfe\xb1\x0e\xfc\xef\x3a\xf0\xef\x42\xe0\x3d\x06\xfe\x0f\x08\xe0\xb6\xfc\xfd\x3f\xd1\x81\xbf\x89\x6b\x4a\x53\xf6\x9f\xe0\x3a\x51\xe8\xdf\x83\xd0\x2b\xc4\x38\xbf\xff\x3f\x89\x5d\xc1\xd0\x3f\x80\x50\x96\xb5\x17\xec\x0d\xc2\x4d\x07\xbe\x3a\x80\x04\xfa\x90\x74\x07\xc3\x91\xc0\xe0\x36\x06\x27\x18\xbc\xd9\xbe\x09\x41\x3c\xae\x31\xfe\x26\xc6\xc3\xb1\x8d\xe1\x3f\xa7\xf0\x0f\xdf\xf5\xa1\xae\xb7\x54\x17\xd5\x03\x91\x90\x48\xf5\x78\x50\x25\x93\xf5\x78\x50\x25\xd3\xf5\x78\x50\x29\x53\xf5\x78\x50\x27\x53\xf5\x78\x50\xe7\x82\x7d\xc6\xba\x0c\xc1\xea\xa1\x63\x3e\x42\x93\x10\x5a\xb0\x4f\x98\x78\x78\x08\x59\xe1\x8f\xec\x0f\x96\x27\xbb\x43\x5c\xd5\x43\x94\x23\x21\xb2\x93\x27\x04\xce\x1b\xfd\xaa\x88\x1f\x54\xc4\x0f\xd0\xce\x4f\x82\x7f\x86\xdd\x2a\x85\x16\x12\xa9\x1d\x75\x3a\x32\xd0\xe2\x9c\x58\xad\x4e\x87\x18\x2e\xa5\x82\x3e\x90\xbf\xc4\x74\xb1\xf7\x76\xf1\xf8\x88\x74\x8f\x5a\xb1\xa5\x18\x16\xb3\x47\x76\x16\x01\x59\x04\x32\x76\x56\x16\xc1\x9e\x0b\xfe\x1e\x62\x1f\x89\x8a\xf7\xaf\xf2\x71\xf1\x7e\xeb\xb9\x28\x8a\xe7\x42\x19\x8e\x41\xbf\x9e\x43\xd6\xe7\xa2\x67\xfa\xa9\xbe\x81\x1b\x19\xd3\x17\xb0\xdf\x30\xb2\xe7\x42\xca\x09\x6e\x08\xfe\x88\xea\xef\x05\x17\xa4\x82\xca\x39\x35\xf8\x5e\xb0\x77\x40\x2b\x38\x6e\xbf\x41\xdf\x4a\x8a\x74\x1a\x7a\x24\x13\x7a\xfe\x6c\xd4\xe9\x94\xe1\x01\xda\x19\x1c\xf3\x77\x82\xc9\xb8\x06\xfb\xce\x77\xc0\xde\xbb\x9e\x1c\xe9\xe0\x86\x18\x38\x56\x87\xde\x09\x97\x4a\x43\xb2\xfc\x55\xb5\x2d\xdc\xd2\x4b\xa9\x6b\x7f\xb0\x26\xa9\x93\x9c\x9f\x81\xfc\xf1\x9a\x72\xe0\x0c\x0d\xf0\x4f\x63\xaa\x9c\x4f\xbd\xc2\x57\x28\x3e\xbb\x5a\x1c\xb1\xef\xbc\x83\xba\x4e\x53\xa9\x01\x4d\x22\xbe\x6b\xe6\xcf\x9a\x22\x35\x33\x07\xed\x34\xf0\x87\x28\x7e\x48\x5c\x6f\x69\x7a\x51\xbf\x4c\xcf\x4a\xe2\x04\x8e\xca\x8c\xee\xab\x7a\xbb\xf1\x58\xde\x89\x26\x4e\xda\x7b\x81\xf1\x40\x1a\xd1\x6c\x34\xe9\xe3\x4a\x25\x1e\x38\xde\xb3\xcc\xb9\x1a\x85\x19\x70\x7a\x97\xa8\x7a\x0d\x08\x53\xd5\x03\x7c\x41\x9a\xcc\x11\x0c\x33\xef\x6a\xea\xc7\xa3\x28\x78\x39\x4c\x81\x33\xf6\x82\xde\x33\x9d\x42\x3a\x2c\x90\x31\x00\xba\x67\x74\x0f\x6f\x5d\x5f\xa2\x40\xde\xce\x21\xb5\x19\x75\x9e\xbb\xa3\x11\x69\x75\xf8\xd1\xe3\x00\xc5\x7d\x4d\x59\x03\x79\x23\xbc\x32\x03\xdd\xbf\x7e\xca\xc3\x34\x18\x31\x75\x0f\x17\xa4\x5f\x95\x3b\x54\x63\x7b\x82\xbd\x0d\x26\x61\x7c\x2f\x11\x22\x99\xed\x8f\xc7\x40\x13\x35\x75\x25\x89\x77\xad\x22\xcb\x23\xc7\x21\xc1\x31\xfb\x72\x1e\xc6\xd0\x87\xff\x97\xbc\x77\xed\x8a\x1b\xc9\x12\x45\xbf\x9f\x5f\x01\x9a\x39\x94\xd4\xa8\xd2\xa4\xed\xb2\xab\x94\x25\xb3\x30\x50\x5d\xdc\xb1\x8d\xc7\xe0\xae\xe9\x43\xd1\x94\xc8\x54\x82\x8e\x33\xa5\x6c\x49\x09\xc5\x01\xfe\xfb\xdd\x8f\x88\x50\xbc\x94\xa4\xab\x7b\xce\x9d\x59\x77\x79\x99\x94\xe2\xa5\x88\x1d\x11\x3b\x76\xec\xe7\x01\xf4\x1c\xf5\x5f\xcc\x96\x60\x33\xc7\x45\xa3\xb7\x83\x07\xb3\x5e\x04\x1d\x9a\xc4\xa8\xc4\xc1\x00\x3e\x69\xa1\x0d\x94\x83\x36\x3f\x55\xf5\x1e\x6a\x84\x7d\x6e\xf2\x9a\xf3\x1a\x5f\x2f\xc7\x38\x8d\x34\x7b\x7a\x26\xab\xd0\x3f\xc6\x57\x79\x7b\xc0\xda\x57\x98\xd7\x24\xce\xe6\x33\x67\x57\xcb\x7e\xec\x1f\xdf\xc1\xf1\xfb\xc1\xa4\xb8\x11\xea\xd0\x16\x98\x8c\x26\xdc\xa1\x03\xa5\xb2\xee\x60\x87\xdf\xed\x3c\xd2\x08\x8e\x58\x30\x41\xa5\x13\xe7\x0a\x42\x38\x18\x97\x2b\xfe\x35\xd7\xe2\xee\x8a\xbc\x44\xcb\xb3\x16\xd2\xb3\xe7\x70\x73\x71\xab\xda\xcb\xd7\xd3\xba\xb3\xc2\xfb\x3f\x12\x97\x29\x12\xfc\x28\xdd\x0f\xf5\x52\xd7\xc5\x6c\x52\xe7\xca\xcf\x12\x95\x41\xc3\x9e\x10\xae\x47\x6d\xf4\x4c\x2b\x6a\x6c\x15\x15\xe3\xee\x9e\xd7\xc5\xf1\x74\x5f\xb4\x94\xac\x68\xbd\x21\x50\xa3\x1d\x82\xe8\x2f\x07\x86\x88\x05\x52\x20\x59\xfc\x09\x8a\xdd\x13\x33\xed\xb0\x9c\x24\xa5\x7f\x76\x51\x8e\x0b\xbd\xe2\x49\x3c\xad\x16\xb2\x49\x80\xd0\x4d\x51\x2d\x1b\x5f\x86\x85\x40\x7a\xf1\x45\x2b\x3a\x2c\x6e\x30\xb2\x85\x42\x34\x2a\x68\xde\xc7\x98\x34\x88\x4a\xe8\xc5\x2f\xc5\x6c\xf6\x29\x07\xf0\xdd\xe4\xd6\xfa\xef\xfc\x6e\x22\x96\x24\x4f\x4a\xdc\xda\x66\x4a\x56\x3e\xd6\xc8\x50\xe5\xd9\x4d\xf5\x95\xec\xc2\xea\xd8\x03\x1b\x95\x4e\x52\x5a\xef\xd6\x49\xee\xae\x3f\x21\x4f\xcd\xfb\xd6\x55\xd7\x94\x9d\x93\x56\xbb\x95\xdb\x22\xcb\x08\x00\xcf\xd1\x1e\x0a\x4b\x5d\xd9\xa0\x55\xe9\x3f\xd5\xd5\x5c\x4d\x4f\xd8\xa2\x8a\x6b\xf7\xca\x72\x29\x05\xd9\x83\x62\xf2\x79\x31\x31\x36\x24\x8a\xe4\x7b\x97\x1a\x81\xd5\x4a\x13\xf4\x53\xcf\xe7\x31\xcb\xee\x81\x39\xb3\xef\x51\x7e\xad\x23\x04\x34\xdc\x27\x05\x7c\xb9\xf6\x59\x79\xd5\xb7\xbf\x74\xdf\xe9\x74\x4b\x0d\xd5\xe1\xb7\x31\xa9\xf2\x66\xa3\xac\x5a\x78\xd8\xc8\xca\x3b\xa8\x5d\x5e\x6d\x90\x5b\x8f\xaa\x9c\xdd\xc1\x9f\x7c\x83\x9a\x19\x04\x16\x44\x9c\x0e\x99\x60\xbf\x77\xb6\x9b\x90\x09\x4f\xa1\x90\xca\xc2\x41\x03\x86\xfd\x00\x47\x47\x08\x74\xcd\xac\x50\x7b\xdc\xdd\x5b\x1e\x20\x79\x36\x9a\xa7\x94\x9c\xcb\x65\x9b\x9f\x56\x2d\xe0\x56\xbb\x67\x3d\x12\x36\x0f\xe6\xf9\x53\xff\xa4\x13\xf6\xee\xfa\xd1\xd3\xe6\xca\xf1\x37\xb2\xf6\xa3\xbe\xcd\x0f\xaa\xdb\xb2\xaf\xb9\x06\x61\x3d\x70\xa0\xf0\xa3\x96\x69\xc3\xf1\x31\xf6\xae\x41\x0f\xb6\x20\x74\x4c\xa6\x94\x61\xfe\xcc\xfc\x9c\xb1\xb1\xd1\x8d\xd0\x8a\xec\x3f\xa1\x33\xfe\x72\x7b\x45\x89\xb8\x12\xc7\x43\xf6\x3b\x7a\x6e\xf8\xd6\x2d\x6a\xef\x7c\xb4\x1b\x32\x4f\x94\x55\x13\x8c\x01\xa5\x3d\xdf\x77\x1b\xcd\xf4\x31\x57\xfd\xe7\x4f\xdc\xa4\xdd\x59\x55\xf4\x97\x1b\x59\x7b\xc2\x3d\x6a\x32\xe7\xa8\x69\xdc\x95\x9f\xf7\xad\xf3\x9e\x19\x86\xf5\x2e\x09\xc0\x9f\xbd\x14\x8f\x89\xbd\x74\xaa\x28\x7c\x72\x95\x0a\xd9\xbb\x51\x09\x85\x3b\x35\x14\xea\x56\x30\x74\x61\x9e\x95\xd9\x95\x28\x21\x0e\xb1\xc6\xc5\x17\x34\x02\xe3\xa4\xdb\xda\xd2\xf9\x7c\x61\x5f\x31\x3e\x7b\x98\x24\x02\x12\xa6\xe3\xf5\xe9\x97\xae\x5c\x03\xbe\x79\x72\x7a\x4f\x57\x84\x9c\x06\x98\x35\x89\x37\x67\x9a\x8d\x2f\xed\x58\x5f\x42\xf1\x6e\xec\x27\x44\xe5\xb4\xf8\x20\x27\x63\x8d\xfa\x0f\x90\x5c\xf9\x35\x7d\xb3\xc6\x6e\xf8\xb6\x9f\x52\xd3\xb3\x56\x5e\x22\x46\xad\x14\xcd\xf2\xdc\xf8\xa8\x08\x07\x2c\x0e\x09\x05\x10\xd7\x01\x6e\x92\xd7\x74\x08\x5e\x2e\x01\xcb\x76\x43\x38\x69\xef\x66\xb9\x8f\xb2\x7f\x92\x04\xad\x6e\xf2\x1a\x95\xb0\xff\x23\x09\xae\x8b\xc9\x24\x2f\x03\x95\xf4\xd7\x24\xe0\x39\x0a\x1e\xc5\x07\xb9\x8e\xf5\x31\xa5\x6d\x73\x7f\x5b\x4c\xda\xeb\x24\x18\xee\xec\xfc\xcf\x20\x16\x9f\xee\x10\x42\x1e\x6d\x07\x8b\xdf\xb1\x2d\xeb\x56\xc1\x3b\xdd\xd3\x7b\x81\x03\x92\x55\xf0\xdc\x0d\x2e\x67\xd5\xf8\x0b\x72\x77\xe0\x08\xc6\xd6\x61\xd3\x4f\xf2\xda\xbe\x24\xb4\x3a\x2e\x76\x10\xce\x9f\xfa\x70\x15\xc6\x9d\xee\x3f\xdc\xbe\xed\x69\x13\x10\x56\xd4\xdf\x64\x9d\xfa\x5a\x64\xc3\xa6\x55\x9d\x8c\x57\x7c\x8d\xa3\x33\xbb\x67\xa0\xb6\xe7\xd0\xb7\xe6\x60\x51\x91\xfd\xc8\xe1\x0d\xa9\x6a\x33\xcc\xd0\x7d\x8e\xbc\xcf\xdd\x77\x77\x49\xbd\x93\x32\x71\xd7\x97\x88\xf6\xcb\x80\x1a\xe5\x6a\xc1\xf5\x88\xf2\x4b\x5c\x24\x54\xdc\xb7\x56\x43\xbc\x34\x8a\x8d\x4e\x85\x7c\x98\xf9\x51\xef\x18\x7f\x61\x5e\x55\xed\xb5\x1a\xd2\x2f\xa4\x77\x53\xcb\xaf\x55\x6e\x85\xb6\x5a\x9c\x2c\xb2\x71\x57\xa6\xeb\x91\xb6\x98\x43\xb6\xc8\x73\x6a\x5f\xd2\xce\x5e\xa7\x01\xd6\xba\xb5\xaa\x9b\xeb\x3c\x78\x8c\x57\x2e\x64\x0d\xb4\x3d\xd7\x6e\xb6\x58\x46\x4d\x0d\x35\xd3\xc4\x86\x22\x2e\x50\x32\xfc\x61\xe7\xf1\x3c\x7e\x6d\xf2\xa3\x34\xc3\x71\xba\x8e\x77\xfc\xa3\x92\xf9\x57\xdf\xaf\x28\x2f\x03\x99\x09\x17\x29\x15\xba\x5d\x26\x27\x5e\xad\xe5\x2f\x03\x63\xee\x48\xcd\xd8\xb3\xea\x1c\x2e\x17\x14\xcd\xbe\xd0\x35\x9a\x88\xc2\xde\xda\xaa\x43\x38\x64\x0a\x19\x48\x01\xc6\x22\x7d\xe6\x30\x2f\xeb\xd9\xac\xb8\x7c\x76\x9b\xd5\x25\x8a\xb7\x70\x55\x1b\x19\x45\x49\x36\xf3\x18\xce\x02\x28\x9d\x7b\x84\x64\x31\x6e\x12\xf8\xf4\xac\xc0\x8b\x88\x7b\xc1\x13\x64\x90\xc6\xe1\xea\x10\x2b\xb1\x49\x50\xf7\xc5\x87\x33\x2a\xec\x67\xf0\x3f\x9b\x0d\xb1\x77\x9b\x8d\xac\xce\xc9\x85\x47\x0d\xe7\x4e\x5e\x6f\x00\x22\x9d\x16\x57\xcb\x3a\x23\x60\xd1\xad\x00\x96\xee\x46\x73\x5d\x2d\x67\x13\xba\x3a\x5c\xe6\x1b\xdc\x6e\x3e\x09\x62\x71\xfe\x28\xf9\xae\xde\x25\xe8\xc1\xa8\x9b\x98\x02\x26\xc6\x3b\xe6\x64\xf8\x7a\x27\xf6\x80\x29\x19\x7e\xff\x03\xcc\xe4\x0f\xf6\x4c\x0a\x77\xdc\x7d\x00\xb4\x80\x7e\xf8\x7b\x3e\x5e\x62\xe5\xc3\xf2\xa6\xa8\xab\x92\xa3\x86\x60\xe0\x2f\x38\xd3\x61\x5d\x23\x86\x11\x5e\x9d\x86\x31\x9a\xee\xe8\xd0\x42\x56\x67\xb0\x9f\x95\x38\xec\x65\x93\x6f\xfc\x5c\x34\x30\xc6\x3b\x32\xf1\xd9\x10\xf6\x41\x1b\xd9\x06\x34\x83\x93\x2a\xb1\x67\x3a\x8c\x99\x9d\x3a\xb8\xd6\xca\x87\x26\x38\x2a\x13\x1c\xde\x6e\x26\xaf\x5e\xc6\xbd\x20\x03\xd0\x0c\x77\x7a\x61\x33\x78\xa6\x38\x66\x04\x93\xfb\x31\x9b\x31\x08\xc6\xe7\x3c\xfb\x92\x7f\x84\x23\x2c\x29\x89\xe1\xa7\x33\x13\x31\xeb\x67\xdc\xe7\x6e\x16\x59\x59\x11\x11\x7d\x5a\x79\xb2\x85\xc7\x18\x34\x63\xf0\xe4\x5e\x55\x6f\x11\xba\x4e\xc6\x63\xac\x3a\xd3\x67\x93\x2c\xd6\x18\xf6\x7f\x20\x0b\x4b\x1f\xb1\x5d\x7f\xd7\xad\x8d\x85\x55\x6d\x63\x48\x76\x0b\x46\x55\xbd\xa4\xaa\xae\x0f\x79\x65\x6d\xad\xa0\xaa\x2c\x20\x62\x13\xc9\xb2\x0a\x67\x5b\xcb\xa6\xc6\x65\xa3\x4f\x6e\x32\x7c\x8e\x2b\x61\xf8\x15\x2b\x01\x8f\xe6\xfd\xff\xba\xcb\x01\x6e\x16\xfb\x5a\x17\x3d\x04\x94\xea\xae\x83\x7d\x64\x0e\x99\x09\x87\x76\x76\xd4\x8d\xc6\x5b\x13\x73\xfa\x6a\x1a\x83\x75\x6a\xeb\xb9\x7d\x2d\xe8\xf0\x70\x1a\xd0\x32\xfb\xea\x0b\x88\x39\x55\x39\xbd\xa7\xd6\xe3\x5a\xab\xe7\xf9\x1a\x38\x96\x75\x36\x84\xd9\xb6\x81\x67\x01\x9d\xaa\x16\xd1\xdf\x49\x78\x3f\xcd\x66\xcd\x5d\xdf\x86\x44\x07\x68\xbb\x1a\x73\xea\x47\x74\x7a\xfb\xcd\x9b\x8d\x79\x76\x47\xe7\xcb\x75\x76\x93\x03\x52\x0d\xbe\xd9\x6e\xb7\xbf\x09\x36\xf0\x48\xfb\xa6\x8b\xeb\x1b\x93\xfa\xb2\x8e\x45\x15\x99\x10\xf7\xf6\x36\x79\x85\x27\xc9\xf0\xc5\xd3\x44\x01\x6b\xdc\xc2\xf9\x2c\xce\xd3\xac\xce\xe6\x4d\x2a\x68\xd4\xbf\x2f\xd1\x7a\xb1\x74\xa9\x8d\xe1\xcb\xd5\x00\x74\x8f\x25\x1b\x9a\x95\xbb\x55\x0b\xd4\x58\xa4\x53\x99\x89\x47\xd2\x55\xcc\x6c\x4c\x0e\xbb\xe5\x13\x96\xd9\x6b\x0f\xf2\x05\xac\xac\xca\xd9\x69\x8d\x28\xb1\x2f\xd9\x79\xfd\x45\xf5\xaf\x35\x90\x9f\x91\x83\x5c\x7d\x73\x7a\x90\xc7\xd3\x95\x9e\xde\xd1\x66\x1b\x26\xe6\xd4\xb3\x06\xac\xfc\x1c\x92\x3b\xc0\xf3\xe8\x71\x1d\x26\xe5\xc5\x92\xb8\xb9\x26\x0c\xc2\x27\x38\xbe\x6b\xd7\x45\x6e\xed\xe7\x72\xee\xfd\xb2\x1c\x42\xdf\x0c\x28\x4e\x30\xe5\x72\x12\xc7\x54\x80\x2f\x78\x3f\xfd\x4f\xfa\x84\x62\xfb\x9c\x15\xe7\x11\xcd\x4f\x97\xdd\xc7\x7c\xf4\xcf\x87\xe4\x86\x0a\xc1\x2b\xce\xf2\x27\xad\x40\x8f\x54\xa2\x3b\xe3\xcc\xd5\xeb\xed\x6d\x77\x2b\xd8\x2d\x85\x80\x57\x18\xd7\x12\xc1\x4e\xdf\x89\x6b\xf4\x5a\x8e\xe1\x39\xd5\x6d\x23\xa6\xcb\x4a\x81\xf2\x77\xf2\x09\xa5\xe3\xc1\xcc\x83\x07\xe3\xf5\xf1\xc8\x77\x4f\xe3\x11\xdb\x11\x12\x7a\x09\x2f\x20\x19\x8d\x4f\x61\x53\x8c\x5b\xf6\x49\x52\x61\xa0\x86\x42\x77\xbf\x2a\xa3\x0a\x0a\x73\xb1\x7c\xc0\x66\x1e\x24\x30\x81\x51\x8d\xb2\x81\x71\x2b\xd8\xda\xb2\x12\xc2\x29\x33\x87\xae\xd3\x7b\xf4\x2c\x96\x4c\xc9\xc1\x58\x0c\xbd\xaf\x6a\x71\xff\x7c\x9b\x03\x8a\x2d\xaa\x3a\xd9\xdc\x9c\x0e\x7c\x19\x8f\xa3\x2c\x4d\xd3\x19\x7d\x7a\x37\xbc\x1e\xdc\xc2\x1a\x3f\xd5\x4e\x38\x40\xf1\x53\x40\x92\xf1\x54\xe0\x47\x78\x20\xd4\x18\x51\x4a\x7b\x9d\xf2\xcf\xc3\xc3\x74\x30\xad\xd1\xab\x50\xf0\xa7\x20\x4a\xa0\x21\x31\x5b\x90\x2f\xe7\xcd\xd3\xb8\xca\xdc\xda\x52\x8f\x4e\x29\xa7\x22\x72\xc8\xd6\xa9\x8a\xe5\x18\x42\x93\x94\xfd\xeb\x50\x4f\x83\x67\x14\x1e\x20\xec\x7a\x8e\x60\x43\x17\x84\x9b\x69\xba\x24\x48\xf0\xf3\x98\x9e\x79\x7a\xe6\xa9\x59\x7c\xb4\x40\x03\xf1\xcb\xa6\x9a\xc1\xea\x0d\xe7\xe8\x24\x76\x9e\x2e\xc8\xad\x78\x08\x94\x54\x14\x41\xaf\x09\x3e\x8b\x01\x00\x7d\x4e\x96\xf6\x50\x8c\x9d\x5d\x89\xac\x49\x8c\xb0\x1f\x8b\x2f\x86\x9c\xba\x9d\x22\x04\x47\xd7\x0c\x6f\xf6\x25\xb7\x40\x3f\x01\x35\xac\xd3\x8f\x2a\x4d\x94\x86\xfd\xbd\xb5\xb5\x27\xb0\x30\xfd\x86\xad\x56\x33\xe2\x51\xcb\x57\xe9\xf9\x23\xd4\xb7\x6a\x13\x7e\x3b\x84\xc1\xea\x1f\x54\xbe\x94\xf3\x28\xfe\xe6\xf4\x3a\xdf\x28\xf3\x06\x95\xec\x09\x1f\x6c\xe0\x77\x37\xe0\x5e\x19\x6c\x14\xcd\x06\x79\xab\x2e\xaf\x00\x6f\xe4\x9c\x46\xad\xe4\x78\xbd\x84\x1b\x73\x01\x97\x4e\x48\x80\xfd\xdb\xd5\xfa\x46\x40\x26\xce\x63\x9e\x11\xe9\x9a\xe7\x86\xdd\xa7\x85\xd7\x5d\xb4\x53\x02\x35\x7a\xc6\x17\x9e\x7c\xeb\x33\x4e\x3a\x8f\xbf\xf9\x6b\xb5\xdc\x18\x77\xd7\x35\xfc\x3e\xe6\x70\x27\xf0\x92\x3b\x87\xb5\x0e\xc9\x59\x49\xa2\x2e\xea\xfa\x37\xb1\x98\xeb\x58\x35\x94\xde\x44\xda\x2c\xec\xc2\x97\xda\x38\xf8\xf1\x43\xd5\xfe\x04\x68\x9e\xf1\x1b\x90\x2b\xcb\x46\xd1\x2a\x62\x38\x3f\x72\x16\x9c\xdd\xb2\x6f\xa8\xf4\xa4\xd5\x8a\x03\xec\xa1\x41\xe8\x98\x3d\xb2\x3f\xb2\x00\x90\xb9\xad\x4e\x15\x7b\xad\xa7\x5b\xaa\x75\x59\x2e\x88\x62\xab\x2b\xe9\x0d\x1f\x34\x09\x0e\x74\x69\x0c\x54\xa8\x55\x7c\xdd\x38\x27\x5a\xa5\xa7\x87\x69\x7e\x62\x8d\x51\x7a\xfa\xe4\x1f\xa4\xde\x0f\x35\xc6\xf0\x86\x8f\x2d\x54\x2f\xd2\x9a\xbd\x41\x4f\x7a\x37\x91\x1e\xab\x5e\xf3\x35\x5f\xa5\x67\xca\xae\x2c\xeb\xe4\xae\x72\xbb\xe4\x86\x02\x12\xba\xba\xfc\x0b\xe2\x61\x79\x34\x21\xee\x08\xf3\x54\x3a\xa9\x8a\xd0\xa5\x34\x99\x82\xa1\x51\x52\x5c\xe9\xf1\xe9\x73\xb4\x48\x84\xb3\xeb\x5e\x70\xd2\x70\x0d\xa2\xab\xb5\x8e\xab\x83\x88\x21\xef\x30\x95\x46\x9b\x32\x2e\xc8\xb5\x97\x87\x07\x1f\x66\x50\xed\x88\xc3\xdf\x87\xf6\xd3\xcd\xcd\xdc\x9b\x11\x0b\x65\x40\x0b\x51\xe7\x2e\x56\xf6\x14\x24\xc4\x6c\x17\xc5\x44\x5d\xb2\x84\x4a\x05\xe2\xe9\x51\x1c\x7c\x1d\xe9\xdc\xf4\x33\x7b\x96\x4c\x36\x2b\x6a\xac\x79\xa6\x2f\x94\x80\xe2\x95\x58\x05\x8c\xfd\x12\x60\x24\x13\xbb\xc4\x27\x71\x44\x53\x90\x0c\xca\x5c\xb6\xc5\xac\x79\x86\x17\xcb\x40\xbf\x7d\xdc\x33\x35\x42\x2d\x35\x38\x24\xd2\x4f\x53\xda\x29\x55\x4c\x39\x40\x83\x30\xb9\xd1\xd7\xcb\xe4\xf9\x8b\x78\x55\x1f\x93\xe7\xdf\xc5\x3d\x3d\x4c\x9e\xbf\x8a\xcd\xfe\x25\x2f\x5e\xf9\x29\x19\x97\x7b\xf4\x6a\x35\x19\xc3\x2e\xf4\xda\x2e\x7e\x2e\x79\xd4\xc7\x35\x44\x0b\x14\x37\xbd\x7c\x31\xfd\xea\xa1\x6b\x3b\xde\x6e\x28\x13\x90\x8f\x40\x35\x38\x26\xbc\x4a\xc6\x42\xa7\x4d\xad\x1d\x31\x8a\x17\xbc\x59\x91\x73\x0d\x4f\x9d\x0d\xff\x62\x7d\x8c\x7c\xbc\x57\x7d\xd1\x54\x5f\xc9\x21\x2c\xf4\x45\x00\xc4\xe9\x2f\xc4\xdc\xe3\xaf\x7e\xac\x78\x41\x63\xb4\x16\x8d\x73\x0b\x93\x53\xd5\x13\xb3\x88\x2b\xf9\x63\xc1\x82\x60\x2a\x02\xb1\xe0\x26\xa6\xf7\x52\x64\x66\x24\xa3\x39\x65\x11\x46\x9a\x12\x82\xf7\x23\x86\xdc\xe4\x1f\xf8\x16\x7b\xcb\xb0\xb5\x8f\x9c\xdb\x56\x2d\x0f\x03\x43\x29\x43\xce\x4b\x18\x21\xb9\xab\x73\x53\xf9\x33\x1b\x97\xa2\x80\xcd\x50\xfd\x8a\xbb\x9d\x10\x4c\x3f\xa5\xc5\x83\x6b\xda\x53\xad\xed\x6e\x5b\x1e\x19\x2d\x3a\x6d\xd5\xe4\x57\xb1\x8c\x70\xd7\xf6\x8e\x73\x44\x74\xa5\xde\xa0\x9c\x1d\x87\x3f\x33\x70\x26\x50\x17\x95\x69\xf8\x9a\x13\xd8\xb6\xd8\x62\xea\x88\xcb\xcc\xea\xe5\x99\xbc\x78\x1d\xff\xc3\xec\x66\x47\x08\xb3\x2e\xbb\x19\x19\x00\xac\xb6\xd0\xc3\x65\xec\x0a\x30\x32\x5d\x59\xe4\xa3\xc0\x3a\x4f\x14\xc2\x9b\xc9\xca\x22\xff\x8e\x77\x16\x4f\x09\x20\x9a\xc7\xe8\x50\xa9\x87\x39\x69\xb2\xaa\xfd\x97\x64\xb3\xb3\xa1\x76\xc7\xf6\x28\xaa\xf6\x55\xe5\xf2\xa2\xb2\x1a\xf4\x57\x7d\x19\x6b\xa8\x06\x08\x20\x5f\x51\x1d\xcb\x8b\xca\x0c\xaa\xb5\xeb\x52\x71\xac\xaa\x40\xb9\x0e\x73\x5e\x16\x96\x0c\xf2\x75\x38\x97\x4f\xc8\xf9\xb4\xb3\xa2\xff\x14\x91\xc7\x99\x1e\x2a\xb4\x16\xad\xc9\xf0\xaf\x4a\x46\xc8\x26\x6a\x21\xfa\xff\x8d\xe0\xcc\x12\xaf\x2d\xbe\x76\xa7\xa0\x3c\x32\x2d\xca\xf2\x1f\x6f\x4f\x84\xd6\x5c\xc5\x49\xcc\xdc\xfd\xd8\xb8\x54\x0c\x50\x4e\xf6\xae\x5c\xad\x74\x96\x09\x9d\x37\x73\x9b\xae\xac\xc3\x07\xbf\x0c\xa8\x13\x3d\xfa\xb6\xf0\x93\x1f\xc5\x52\x8f\xee\xbe\x76\xeb\x15\xe1\xbd\x21\x89\x66\xd6\x84\xf1\xd5\xbe\x55\x6c\x57\x65\x66\x46\xdf\xea\x2d\x54\xbd\x46\xbf\xee\x63\xe0\x9f\x34\x4d\xad\xee\x27\x06\x42\x17\xa4\x10\xde\x0d\xea\xd0\xe9\x6b\xcc\xfe\x87\x39\xf8\x12\x1c\x96\xa1\xdd\x25\xf8\x74\xe4\x65\xc1\x5a\x33\x99\x3d\x8d\x5f\x57\x15\x51\x93\xb3\xba\x10\xcd\xc3\xaa\x22\x0c\x6e\xb7\x84\x02\xab\x93\xb5\x0e\xab\xd8\x1a\xab\x3c\x84\xb5\x34\x77\xb4\x56\x21\x4e\xf5\x8d\xd8\xd3\x1a\x5d\xc3\x9c\x71\x3b\x05\x69\x02\xed\xb1\x5b\xa5\xfe\x9d\x27\x51\x0e\x9f\x2f\x62\xe2\xcd\x3c\xd3\x97\x3e\x06\xa5\x4b\xe8\x3f\xc5\xa8\x74\x64\xe7\x36\x76\xd4\xae\x97\xbc\x01\xb2\x4b\xf8\x3e\x5c\x63\x9a\x8a\xa3\xcd\x48\x56\x71\x0b\xf4\x61\xdb\xc9\x98\xbc\x34\x76\x8f\x4c\xa3\xbb\x4e\x8d\x6a\xdd\x53\x71\x7c\x4f\x1f\x33\xf5\x1a\x3a\x02\x52\xeb\x89\x54\x2e\xd3\x3b\x87\xae\xb0\xf7\xde\x1e\x7f\x3a\x0d\x48\x0c\xcb\x9f\xf0\xcb\x60\xa9\x1a\x79\x4d\x97\xf7\x7b\x74\xbc\x0e\xd7\x35\xa7\x78\xe7\xfd\x06\x3b\x2f\x1c\x05\xea\xce\x9d\x4b\xcd\xb9\x91\x4a\x2e\x88\x48\x84\x1d\x5b\xeb\x3d\x8c\x72\x0c\x2c\x26\x43\x91\x95\x3e\x36\x24\x46\x6b\xf0\x65\x60\x30\xbb\xb3\xea\x3c\x46\x5d\x5b\x4f\xb6\x60\xba\xff\xf8\x62\x6b\x0b\x0f\x77\x0e\xe5\x90\x45\xf7\x39\xfc\x11\x8e\xf3\x51\x6a\x8c\x71\x05\x2a\x3c\x84\x5b\x5b\xb2\xad\xb9\x0a\xc2\xa1\x16\x6a\xa8\xec\xaa\x48\x2b\x5c\xaf\x18\x6d\xd5\x3f\x5a\x97\x5f\x4b\x63\x75\x93\xc3\x8a\xfa\x83\xcc\x37\x27\x4f\x0e\xf3\xe5\x13\xc3\xac\xa3\x51\xc1\x3e\xc6\x4c\xb9\x9c\xbe\xf4\x92\xe1\x8b\xa7\x36\xcb\xf3\x1e\x65\x8a\xfb\x8f\x9f\x4f\x7e\x4e\x84\x7f\x9d\x4f\x87\x1f\xdf\xed\xed\x1f\x26\x81\x90\xd7\x06\xf1\xc7\xe3\x8f\x09\xb9\xe0\xd1\xb7\xaf\x10\x0b\x3e\x5f\x21\x95\x1f\x3c\x13\x8e\x82\x9e\xbd\xab\xc6\xa4\x6c\xb3\xc7\xef\x4c\x3f\xfb\x6e\x0f\xd6\x4d\xa6\x81\xfb\x12\xc7\xf0\x18\x67\x18\x32\x7b\x40\x1d\x15\xcf\xb2\xa3\x42\x11\x45\x6a\xea\x52\x68\x8f\xd1\x25\x40\xe2\xcb\x48\xd6\x82\x01\xe4\xbb\x76\xb9\x7c\xf0\x7b\x9c\x0f\xee\x22\x6f\x03\x3e\xa1\x72\xff\x78\x92\xe7\x78\x79\x78\xde\x23\x63\x7e\x62\xa4\xd1\xbd\xbf\x03\x1e\x60\x3b\xd2\x5d\xbf\x0c\x16\x7a\xba\xaf\xeb\x38\x29\x44\x65\x4b\x5f\xcb\x15\xd6\x84\x06\xff\x26\x26\x4f\xd1\x4d\x82\x6e\xb7\x34\xe3\x42\x3a\x50\x2a\x61\xaf\x16\x13\x31\x50\x0d\x48\x32\x1e\x8f\x15\x8b\x48\x24\x08\xde\x97\x2b\x92\x45\xa5\x38\x4b\x87\xca\x19\x40\xf2\x7d\x6c\xf6\xde\x90\x66\x21\x68\x1c\xf1\xb4\x7e\x0e\xa8\x2d\xbe\x43\x06\x26\x97\xcb\xb6\xad\x4a\x83\x12\x56\x4e\xd6\x36\x61\x5d\xcc\xf3\x36\xfb\xb7\xfc\x0e\x43\xab\x64\xb3\x56\x3c\x8d\xdb\x7a\x26\x1e\xc9\x0d\x14\x3c\x47\x22\x72\x9b\x06\x7f\x8b\x72\x1d\xff\x2e\xc9\xd5\xfe\x33\xa4\x11\x53\xf3\x01\xee\xd6\x57\x72\xbe\x96\x22\x91\x34\x8d\x15\x93\xcf\x9c\xbf\x59\x5a\xad\x98\xbf\x77\x45\xf9\xa5\x9b\xb7\x26\x5e\x1a\x33\x97\xd1\x89\xbc\xaf\x14\x41\xc7\x62\x12\x0d\xe5\x97\xca\x9b\xcc\x94\x1c\x64\xb1\x8d\x6b\x4c\x74\x5b\xf7\x5a\x95\xfb\x40\x0d\x7f\x81\x04\x84\xef\x3a\x46\x8c\x76\x5f\x02\x4e\x40\x8d\x60\x5e\x34\xdc\xa0\x23\x67\xa5\xa8\xf1\x23\x43\xdb\x9a\x4a\x92\x93\x3a\x37\x19\x1d\x09\xc6\x9b\x35\xb1\xad\x4b\x66\x5e\x43\x39\x8c\x4b\x88\x73\x3a\x91\x7d\xcc\x51\xc1\x36\x9f\x60\xc6\x0e\x96\x11\x81\xe8\xc9\x26\x05\x99\x2e\x5c\x0e\xb5\x60\x85\x05\x94\xa1\x35\xa5\x2b\xdb\x57\xba\x26\xb8\xa4\x7f\xbb\x14\x26\xc1\x99\x7a\x37\xb5\xbb\xcc\x8b\x82\x52\xe8\xfa\xea\xb6\x99\xd6\x54\x70\xb5\xf4\xaa\x73\x5b\xef\xd8\x52\x0e\x46\xe6\xfe\x99\x2f\x03\xfd\x5c\x48\x1e\xbb\xbc\xcf\x7e\x75\xdf\xec\xd6\xad\x45\xc0\xdf\x40\xc1\x41\x9f\x5a\x38\xc6\x0f\xbd\xd7\xad\x1b\xe2\xfb\x6b\xa5\xf6\x24\x40\x0a\xb3\x64\x69\x45\xeb\x00\x21\x4d\x66\x5e\x5b\x1a\x9f\x9e\x12\x3a\x3d\xdd\x8a\x34\x83\x29\x2e\xa0\xab\xfa\x1d\x99\xb8\x6b\x26\x70\x97\xb6\x93\x93\xe1\x8e\x07\x73\x75\x3b\x3b\x19\xbe\x5e\x53\x2a\x1f\x9b\x68\x25\x19\xbe\xfc\x1e\xf1\x9e\x23\xa8\xff\x4f\x3c\x12\x4c\x9e\xfd\x7f\xfd\x33\xc1\xe1\xfe\xff\x27\xc2\x46\xd1\x61\x3d\x60\x11\x80\x10\x60\x21\xd2\x5c\xbd\x01\xa2\x55\xcf\x1a\x48\x10\x44\xff\x1c\x40\xf4\x73\x35\xff\x18\x20\xf8\xd2\xa3\x29\xc1\xd0\x29\xb7\x12\x3c\x5f\xbd\x64\x5c\x78\xc0\x08\xfc\x4a\x1e\x15\xd9\xe1\xaf\x6f\x2f\x5f\xa3\xbc\xca\x00\x6c\xb6\x3e\x60\xed\x91\x27\xcf\xbf\x37\x81\xed\xf0\xeb\x7a\x81\xad\xb7\xf3\x1e\x21\x43\x00\x7f\x12\x8c\xf2\xcb\x3a\x34\x5d\x1c\x69\xb0\x1f\xfd\xaa\x4b\xa1\x85\xbf\x2a\x01\x05\xb7\x5f\x80\x6d\xcc\x41\x3a\xd7\xee\xee\x4a\x55\x6a\xb4\x57\xdd\xdd\xc6\x74\x35\x38\xe8\x73\x7e\x2e\x09\x89\x36\x5e\x28\x6e\xb7\x20\x26\xea\x47\x47\x60\x1d\x17\x71\xd6\x31\x17\x81\x9c\x89\xc7\x40\x00\xed\x50\x28\x6e\x11\x64\x6a\xf1\x66\x36\xda\xde\x9e\xd1\xe5\x0d\x88\xaa\xb3\xd9\x39\x90\x51\x55\xd8\x48\x9e\x54\x63\x4a\xf0\x1b\x4b\x71\x01\x3f\x10\xb3\xcf\xf4\xa5\x8a\x0b\x2e\x39\x7c\xc2\x53\x68\xd8\x00\x69\x46\x6e\x56\xd3\x63\x43\x04\xdd\x84\xcc\x64\x40\xfe\x95\x0c\xcd\x17\x36\xd0\x47\x6c\x55\xf9\x3a\x85\x43\xcf\xad\xd8\xaa\x8a\xbb\x75\xd8\x8a\x2a\x49\xe9\x2d\x5b\xea\x65\x4b\x55\x16\x45\x57\xba\xb4\xdd\xcf\x87\x75\x6c\x3f\x30\x08\x2f\x72\x65\x37\xd3\x94\xb8\xb1\x2b\x98\xbb\x99\x9c\xc8\xb8\xc2\x79\xe8\x67\x39\xa3\x04\x15\xdb\xeb\x1a\xd3\xe6\x2c\xd5\xb5\x72\x80\xa6\xdd\x81\x29\x5c\xca\xe9\x9b\xbd\x19\xc3\xf4\x8d\x23\x9a\xbd\xe5\xd9\x18\x16\xf5\x59\x83\x7d\x2b\xe1\xc7\xee\x1b\x8c\x12\x3b\xb2\xb5\x55\x84\x19\xc6\x40\xd6\xf8\xda\x8d\xae\x6d\x70\x29\xb5\x14\xe4\xc2\xcb\x1f\xa5\x65\xe1\x19\x3a\x84\x85\xc5\x23\xee\x72\x0f\x0f\x1f\x89\x4d\xd0\x18\xb8\xe5\xe1\xe1\x04\x08\x74\x68\xe8\x1a\xff\x7c\x60\x86\xd1\x01\xfd\x8c\x9c\x50\x97\xf5\xee\x38\xdc\x5c\x3c\x3c\x04\xe8\x1e\x16\x92\x61\x2b\xe7\xe5\xcd\xe0\xc3\xf1\xc1\xe1\xc5\xe1\x87\xbf\xb0\xce\x88\x66\x66\x82\x12\xc2\x6c\x83\x25\xaa\x1b\xb2\x1f\x38\x5d\x24\x1e\xdc\xc8\x3b\xc1\xd5\xc6\x65\x3e\xce\xa4\xbe\x8f\x30\x63\x41\x66\x82\xb4\x56\xf9\x92\x2f\x5a\xac\xd8\xdc\x95\x63\x36\x76\xc7\x82\xc2\x8e\x76\xe3\xf3\xa7\x77\x41\x94\xcc\xc2\x05\xf2\x6f\xca\x3c\x9f\x34\xd0\x3c\x51\xbe\xdc\x25\x4d\x9f\xe8\x7f\x36\x96\x8c\x12\xf5\x47\x6a\x98\x84\xf9\xc3\xc3\x29\xca\x37\xc3\x3a\xbd\x61\x08\x1e\xc1\xd4\x3d\x81\xa9\xc8\xf4\x4a\xc8\x8b\xe1\x70\x5f\x96\xa5\xf4\x33\x81\xa6\x45\xb3\x8f\x80\xb4\x20\xa1\xe3\x88\xe8\xf8\xeb\x03\x4c\xdb\x07\x8d\xb1\xf5\x3e\x12\xe0\x47\xfe\x30\xda\xd3\xee\xcd\x66\x2e\x8b\x9e\xd1\x9d\xbf\x75\xa9\x15\x6a\xe8\xcf\x74\x1c\x40\x53\x77\x48\x4b\x87\xf1\x70\x22\x2d\x04\xe6\x16\xf2\xeb\xd9\xf9\x63\x9c\x4d\x26\x76\x37\x60\xfd\xa9\x75\xb7\x2f\x28\x47\xa7\x2d\x69\x77\x2c\x10\x0c\x32\x5f\x74\x47\xc0\x8a\x8f\xae\x2c\x30\x3c\x5f\xe1\xd1\x1a\xc0\x90\x83\x54\xdd\x42\x65\x36\xa9\x0c\x5b\xe7\x0d\x49\xea\x28\x48\x94\x4f\x8e\x5e\x19\x1f\x77\xa0\xe5\x01\x54\x7c\x2c\xa3\x08\xb1\x44\x0c\xbe\xa6\x90\x96\x4c\x89\x56\x18\xc0\x10\x3f\x12\x31\xea\xb1\x29\x69\x88\x6a\x40\x7e\x9d\x0a\x61\xce\x9c\x37\x8d\xa7\xa7\xc3\x12\xdd\x63\xcf\x00\x21\x7c\xf3\xb9\x44\x3b\xc5\x8d\xb6\xda\xc0\x18\x39\x42\xe3\x8a\x14\xe4\x52\x54\x90\x7b\xf3\x0d\xf1\xe1\xe0\xde\x4c\xc2\x1e\x31\x68\x1e\x01\x77\xf6\x58\x04\xf6\x10\xf8\xb6\xc6\x88\x42\x2b\x4d\x70\xb4\x0e\x59\x76\x3b\x12\x53\xd5\xb0\xd3\x26\xbb\xc1\xbf\x04\xdb\x15\xda\x39\xae\x34\xc7\x99\x85\x12\xa9\x28\xef\x55\xb5\xb3\x47\xf5\x16\x78\xb3\x3b\x48\x24\x30\x82\x3a\xd8\x1d\xfb\xb0\xab\xac\x31\xc2\x0a\x3d\x50\x91\xd6\x56\xf5\x84\xb1\xcf\x5a\x7d\xd3\x1a\xe8\xed\x5a\xdc\x7d\xdd\xd7\x3d\xaf\xd9\x90\x74\xa1\xbe\x4e\x1f\xb8\x76\xff\xe7\x6f\xc5\x89\xf3\x06\x2e\xfe\x38\x39\x37\xbb\x21\x80\x80\xdc\x6f\xc0\xa5\x33\x09\xc7\x64\x40\x28\x6d\x93\x36\x6e\xb3\x66\x83\xc9\xce\x89\x8e\x86\xeb\x1c\xf5\x40\xcb\x4a\xa2\xe3\x6b\xd6\x25\x09\x28\x7a\x8b\xe4\x5c\xec\x11\xfb\x3f\x1f\x54\x25\x3d\x99\x41\x43\x61\xd1\xbb\x47\x88\xeb\xd9\xe4\x73\xc9\x6d\x4d\x36\x08\x19\xc2\x6f\xb7\x00\x36\x37\x98\x37\x9d\x6c\x04\xdb\xb8\x45\x74\xb3\xcd\xf7\x18\x57\x46\x4f\xb8\xd8\xed\x05\x3c\x5e\xda\x95\x8c\x4e\x4a\x07\x69\x65\x08\xd7\x2d\xdc\x05\xea\x11\x0d\x87\x9e\xcc\xe1\x70\xc7\x73\x59\x56\xf2\x48\xf7\xaf\x31\x6e\x9b\x8b\xb6\xf0\xb4\x20\x7e\x77\x2e\xd4\x62\x59\xeb\xf8\x31\x96\x19\xfa\x02\x2c\x9f\xc2\xec\xc2\x6f\x8f\x20\xc2\x2a\x11\xfd\xa0\x44\xc4\x82\xa7\x17\x10\x03\x28\xd5\xd8\xda\x2a\x53\xd4\xba\x44\x36\xb2\xe0\xde\xf8\xd4\x98\x30\x7e\x80\x16\x2d\x66\xce\xdd\x8c\x46\xe3\x90\xc9\xc3\x22\xfe\xe6\x83\x98\xf7\x0d\x11\x6f\xaf\xd3\xf3\x1d\x6c\xbc\x07\xb0\x6e\x34\x4b\x58\x20\x77\xb0\x30\x49\x7f\x53\x20\x22\x12\x43\x11\x22\xda\x40\xc2\xe9\x96\x57\x51\x89\xe5\x84\x75\x6a\x03\x18\x8a\x84\x22\x2c\x22\xa5\xa0\xc8\xf7\x82\x64\x59\xc6\x33\x20\x77\x25\x76\x7e\x78\x00\x02\xe6\x3a\x95\x1c\x16\xa2\x76\x26\xa9\x60\xaf\xd0\xdb\x3c\x2d\xf4\xb2\x37\xf0\xaa\x95\xbd\x82\x57\x55\x76\xb4\x10\x7b\x62\x37\x5c\xa6\x8b\x7e\x25\xb6\xcd\x2c\x9c\x43\x07\xaf\xe3\x9b\x78\x12\x5f\xa1\x9a\xe7\x2c\x9d\xaf\x2c\xbe\x30\x8a\xc3\xee\x5a\x22\xe1\x05\xb5\x78\x4c\x77\xa4\xfc\xfc\xbb\x64\xaf\x78\x6d\xc4\x50\x1f\x69\xf4\x21\xbd\xa3\x0a\x87\xa9\x8c\x24\x2a\xbb\xfc\xad\xa4\x20\xa3\xd1\x1d\x29\xe3\x87\xcb\xf8\xb0\xd3\x5c\xd5\x62\xb8\x3c\x3c\xdc\xe9\x02\x9d\xdd\x03\x76\x3c\x78\x04\x68\xe7\x4e\x98\x5f\xdd\xc1\x4e\x08\x67\xd0\xdf\x2b\xa3\x05\xbd\x64\xcc\x77\xf9\x3c\x66\x69\x00\x5c\x5a\xd4\xfd\xa5\x50\xf2\xfc\x58\x90\x9b\x73\x79\xcb\xb9\x11\x57\x9b\xab\xc7\x88\xfe\x01\xae\x5d\x9a\xaa\x6c\xb3\x70\x53\xf0\xd4\x04\xa1\x14\x0b\x22\x0a\xf1\x4c\x36\xc3\x88\x84\x77\x1b\x35\x67\x01\x96\x39\xd0\xe2\xde\xf0\x0d\x0b\xae\x17\x47\x03\x6d\xa3\x42\xc7\x81\x64\x82\x5d\x80\x94\x14\x13\x34\xa5\x31\x7e\x59\x7a\x8f\x89\x2c\x43\xd8\x95\xe4\x9a\x57\x46\xfa\x73\x9d\xd6\x88\x09\x3c\x54\xef\x51\xb7\x99\x6b\xa9\x8e\x5c\x23\x05\xc2\x7b\xff\x1d\x60\xc6\xbc\x44\x8b\x05\x4f\x62\x28\x3b\x61\xe2\x0b\xc5\x5f\x14\xb0\x40\xd7\xba\x26\x15\x43\xa7\x15\x3d\xeb\xe7\x84\xde\x15\x47\x45\x49\xda\x1d\x01\xa2\x5e\x7c\x05\xd1\x58\x8b\xc0\x92\xee\x68\x7c\xe9\x6b\x0f\x08\x7d\x9d\xc9\x1b\xfc\x15\x2c\xab\x43\x83\x27\xa2\x78\x65\x9f\x04\x23\xa8\x47\x29\xc2\xb0\x8c\x5b\x5a\x5e\x0e\xd7\xb2\x91\x5b\x55\xc9\x34\x5a\xd3\x4b\xfe\x11\x13\x38\xbb\xbb\x86\x29\x94\x48\xec\xef\x27\xab\x8a\xf4\xe4\x5a\x3d\x65\xe3\xb9\xd5\x0e\x08\xa5\x86\x4b\x7a\xbd\x96\xcf\x39\xdb\x1f\x18\xd4\x5b\xc3\x48\xee\x68\x80\x8b\x4d\xa8\x98\xc9\x15\xe1\xe9\x45\xad\x29\xba\x2a\xbe\x96\x47\x8d\xa7\xd3\xb2\x93\x60\xe9\x31\x3f\xd3\xb5\x71\x46\x1d\xff\x01\xc3\xae\x3d\xf6\xc3\xd8\x3a\x72\x51\x09\xb7\xec\x67\xc0\xfb\xe6\x2f\xdc\x51\x84\x6f\xbe\xbb\xb4\x8c\xd9\x94\x06\xbc\xc6\x4c\x97\xb6\x6b\xaa\xda\x91\x7b\xa3\x91\x03\x41\x04\xa7\x5d\x6c\x44\x6a\x14\x1f\x91\x20\x6e\xa9\xf3\xd8\xc6\x7d\x8e\x29\x66\xfd\x5a\xd3\x8b\xaf\xd4\x9a\x9e\x32\x23\xb4\x5f\xca\x7d\xcd\x05\xa4\xfa\x6f\xf3\xec\x68\x5e\xe0\xbc\xbc\x05\x4a\xa9\xc9\x6b\x39\xd1\x50\x72\xc2\x25\x25\x95\xda\x3c\xfb\x39\x6b\xae\xdf\x75\x34\xeb\xdc\xc9\x67\x72\x53\x2b\x72\x63\x17\xf9\xc4\xe8\x51\x2b\x72\xc5\x45\x3a\xf9\x84\xd8\xab\x90\x75\xc7\x59\xb4\xb6\xbb\xd4\x43\x91\x2a\xdd\xb6\x40\xd2\x7e\xc7\xfd\xa5\x84\xc1\x4a\x0b\x81\xf8\x92\x8b\x23\xa2\xd0\x92\xa1\x9d\xdf\x39\xa3\xc3\xb4\x90\xf6\xc9\x55\xec\xbb\xb0\x35\x6c\xe2\x5b\x4e\xf9\x59\xd1\xdb\xef\x39\x61\x9f\x10\xf8\x4c\x8e\xf5\x54\xd7\x08\x6c\x96\x0b\x62\x71\x76\x95\x8e\x3d\x0a\x83\x1f\xd3\xc5\xee\x24\x41\xeb\x93\x13\x78\xba\xa6\x85\xa9\xb1\x47\x1b\xc3\x53\x31\x54\xbf\x80\x05\x3c\xce\x1b\xe8\x66\xc4\xca\x18\x46\x17\x92\xd7\xb1\xd6\xcd\xe4\x87\xd8\x0b\xf9\x64\x38\x8c\x7d\x6a\x50\xa6\x5e\x47\x07\xef\x64\x48\x96\x12\xdd\x8c\x24\x43\xb2\x8f\x30\x26\x2e\x19\x22\xe7\x5a\x87\x6d\x32\xa4\xef\xaf\x50\x60\x88\xd7\x59\xa8\xc9\x73\xea\xad\x3d\x9b\xc9\x0b\x4a\xee\x59\xbd\xc9\x8b\xe7\xf1\xca\xb5\x9b\xbc\x78\x11\xaf\x5c\xb9\xc9\x8b\x97\x3e\xd5\xb0\xbe\xd9\x4d\x5e\x7c\x1f\xcb\xb9\x49\x5e\xfa\xe5\x6b\x5f\xaf\x1e\xbe\xc2\x81\xcb\x8b\x1d\xd7\x97\x74\x39\xd0\x35\x28\x9e\x32\xe2\x29\x07\x28\xaf\x77\x4a\x91\x10\x1f\x73\x0d\xd1\xdb\x93\x06\x3f\xe5\x40\x2e\x9f\x55\x96\x3f\x50\xca\xdb\x9a\xd6\x8a\x76\xa8\xfa\x8b\x75\xf2\x9f\x72\xa0\x4f\xfa\x13\xe8\x0c\x0a\x9b\x6b\xe0\x69\xf4\x86\x63\x32\x56\xc5\xd3\xe8\xae\x1c\xf8\x97\xf1\xda\x58\xb9\x1c\x48\x8f\x74\xa7\xd5\xa2\xaf\xb6\xa7\x88\x3e\x42\x1b\x5b\xc1\x5c\x2a\x24\x60\xa3\x63\x07\xe8\x24\x7d\x71\xc5\x6d\x52\x58\x04\xfd\xc3\x8e\x6b\xa8\x9b\x12\x45\x9c\x7f\x9e\xb0\x0e\x3b\x73\xb7\x30\xdc\x16\xe5\xc0\x83\x4c\x66\xec\xd5\x87\xaa\x84\x10\xbb\x47\x2c\x14\xe8\xa2\xec\xaf\xc0\x21\xab\x01\x98\x3c\x7f\x1e\x7f\x95\x3d\x19\xed\x94\xe4\xf9\xcb\x7f\xd0\xcc\xcc\xd9\x06\xc9\xf3\xd7\xbe\x74\x5d\xfa\x67\x43\x39\x79\xfe\xc3\xff\x0d\x6c\xd8\xcd\x5f\xf2\xe2\x3b\x44\x42\x8e\x2a\x9e\x57\x05\x4a\xc4\x85\x44\xe5\x46\xc7\x9e\xd3\xab\x12\x45\xb5\x1f\x1e\x4c\x6b\x6b\xe4\x6e\xe7\x1c\xeb\x1c\x3d\xa8\xd9\x7a\x50\x96\xee\x9c\x2e\x3a\x7c\xe1\x68\xc9\x69\xdd\x54\xdf\x9c\xe4\xe3\x6a\x92\x7f\xfe\x74\x14\x0a\xe5\x38\x09\x8e\x01\x2a\x79\x0c\x30\xe8\x5f\x1b\x06\xff\x12\x44\x67\xc3\xf3\x87\x07\x0c\x14\xab\x75\x5d\xd2\xa7\xc8\x17\x12\xc1\x2c\x9f\x05\x29\xfb\x30\x06\xc2\xb2\x05\x1a\x75\x77\x73\x27\x09\x17\x8a\x1d\x06\xf9\xdb\x39\x73\xee\x74\xc1\x23\xca\x91\xd2\xb4\x11\xfc\xa2\x50\x32\x1a\xb6\xd3\xa1\x14\x22\xdd\x0b\x0d\x78\x11\xcc\x37\x7f\x1c\x8d\xbd\xd6\xe6\xec\xa8\x4e\x17\xd2\xa1\x31\x19\xe9\x17\x85\xd9\xc3\x43\x83\x3a\x8a\x24\x43\xa7\x1b\x2a\xd9\x87\x2a\xc5\xb0\x7e\xfa\x52\x6a\x89\x75\xd8\x65\xcc\xdc\x95\xcd\x21\x10\xb3\xf7\xce\x65\xdb\xb8\x2c\x8c\xa5\xb1\x6e\x0c\x1d\x89\x67\x0f\x0f\x12\xd4\x50\x8d\xbc\x0c\xca\x5a\xbb\x3d\xe9\x61\x70\x0d\x0b\x7b\x4c\x5f\x08\xe2\x02\xa1\x27\x75\x29\xb3\xb6\x05\x08\x50\xe9\x30\xa8\x4a\xa3\x1c\x92\xe0\x9b\x3b\x74\x7d\x77\x6f\xcf\x66\x0f\xd3\xb1\x1b\x12\xb5\x63\xe7\x20\x5f\xef\x31\x8a\x77\xc8\x8c\x5d\x3a\xa5\x96\x83\xe0\xc6\xbd\xe3\xf0\x64\xad\x18\x8a\x56\xda\x3f\x14\xe4\xf6\x22\x24\x8d\xae\x67\x62\xd5\xc4\xce\xf2\x85\xfa\x69\x5e\xca\xd5\xad\xc9\x77\x9c\xfa\x42\xc1\xd5\x69\x42\x2e\x5a\x3b\x5d\xf2\x9e\xb6\xed\x8c\x06\xae\x53\xe3\xeb\x6d\x14\x41\xe8\x5f\xc6\x7e\x9b\x8c\x10\xea\xf5\xf1\xc7\x78\x29\xdd\xb9\xc5\xb6\x59\x5b\x2c\xa3\x38\xba\x97\xd3\xe0\x47\x1d\xcf\xbd\x09\x0c\x0d\xd6\x85\x50\x2d\x30\xce\x98\xa7\x14\x6a\x5f\xac\xf2\x66\xb4\x06\xaa\x78\x02\x20\x36\xba\xeb\xdb\xd1\x7e\xff\x11\xf6\x8e\xae\x68\x47\x17\xb4\x91\x3b\x23\xa6\x95\xdb\x37\x73\xb6\x2f\x8a\x14\x31\xd8\xec\x10\x36\xf2\x13\xdb\xb7\x51\xdb\x77\xf9\x47\xb6\x2e\xcc\x3c\xb1\x08\x82\xb8\xea\xdd\xb8\x5a\x19\xc4\x35\xeb\x6d\x5a\xb8\x27\xad\xb9\x69\x1b\x67\xd3\xf6\x75\xdf\xbb\x63\xf5\xde\x79\x37\xab\xdd\x7d\xef\x46\xb5\xdc\x18\x62\xbe\xf0\xee\xcb\x5c\xde\xc7\x38\x08\x62\x63\xd7\xc4\x59\x77\x0c\xc4\x34\xe3\xb0\xcf\x7b\xb6\xb1\xd5\xba\x28\xf2\xd4\x07\xb0\x51\xb1\xf9\xc5\x1e\xcd\x68\x43\x7e\xe5\x6e\x34\xe9\x0a\x6b\x43\x8e\xff\xd0\x86\xec\x77\x02\x36\xf0\x90\xec\xb5\xb3\xbe\x2b\xd8\x5e\x3d\x33\x30\x53\x64\xfd\x93\xc8\xb1\x0f\x21\x7a\x90\x5b\xed\x07\x9c\x6d\x4e\xb5\x0a\x8e\x16\xf9\x65\xc1\xb1\xf2\xc1\xd1\x47\xd3\x21\xf8\xd6\xf0\xaa\xe4\x89\x39\x84\x6a\x43\x25\x3a\x68\x63\xea\x40\x48\x76\xeb\x50\xa9\xb4\xc4\x12\x12\xe8\x8b\xbb\x53\x5c\x05\x02\x11\x68\xb3\xb8\xea\x0c\x99\xec\xeb\xc0\xc8\x31\x27\xb1\x09\x59\xec\xf5\x4a\x27\x0a\xec\x42\x81\x04\x8d\x1b\x33\x65\x37\x0e\x58\x8c\x5c\x24\x88\x89\xc9\x62\x93\xb1\x28\x09\xcb\x5d\x54\x7e\x42\x2c\x06\xdd\x0c\xc2\xb3\xbf\x3d\xdb\xfd\x97\xf3\xed\x28\x88\x92\xe0\x4f\x44\xaf\xa9\x7c\x8c\xf2\x9c\xe1\x9d\x35\xc0\x48\xa4\x54\xe2\xd7\x5f\xe1\x34\x83\xe1\xce\x90\x49\x79\xcf\x62\x38\x0e\x75\x2d\x02\x52\x06\x7f\x43\xaf\x7b\xc1\xbf\x62\x34\x45\x64\xee\x29\xc5\x23\x80\x92\x14\xfd\x63\xe5\xb5\x7c\x29\xfc\xbd\xa1\x74\xe2\x37\x04\xd1\x60\x9e\xd7\x57\x39\x2b\x42\xfe\x9d\x31\xf9\xb3\x24\xc4\x68\x99\x7b\xdf\xfe\xaf\x8b\x7f\x3d\x17\x4f\x3b\xdf\xfe\x00\x2f\x7f\x8a\x1e\xce\xfe\x34\x08\xa3\x5f\x31\x98\xe7\xaf\xdb\x0f\xf7\x8f\x7f\xfb\x57\x8c\xc8\xd9\xf4\xd7\xd9\x3d\xff\xd3\xd9\xee\xf9\x2e\x56\xc4\x92\xcb\xf4\xd9\xaf\xf8\x6f\xf7\x01\xff\xfc\xfa\x8c\x7e\x20\x7d\x0c\xe9\xbb\xe1\x60\x3b\x7a\x06\x74\xc8\xfd\x23\x92\x7c\x8e\x5b\x14\x9f\x96\x07\x3e\x6b\x8a\x58\x8f\xb1\xa1\x64\x96\xb8\x3b\xbc\x4e\xb1\x0a\x40\xa2\x15\xc2\xd0\x7a\x20\x00\xce\x11\xc4\xab\x48\xbb\x5c\x08\xd1\x69\xa7\x5c\x5e\xaf\x76\xc5\x44\x6e\x38\x70\x12\xab\xb3\x76\x7b\x78\x0e\x87\x43\x81\xee\xfe\x3b\x2d\x0c\xdb\xbd\x41\xda\x92\xc8\x52\x04\xb4\x57\xdc\x66\xb5\xda\xb4\xb8\x59\xe4\x91\x0c\x6d\xb9\xd0\xda\x54\x2c\xa2\x38\xd8\x0d\xe0\x14\x2a\x84\x18\xf1\xdb\x61\x14\xd5\x42\xb0\xdb\x9e\x15\xe7\xf1\x37\xef\x85\x6f\xa7\xe0\x9b\xed\x82\xdc\x33\x2a\xd7\x4e\xe8\x5f\x89\x05\xbd\xdf\x6c\xe7\x90\xf5\x4d\x67\x0f\x56\xa8\x06\x77\x62\x68\x52\x08\x70\xb1\x41\x01\x9b\x20\xa0\x1e\x67\xf2\x46\xc2\x9d\x49\x49\xc8\x6b\x79\xb2\xc2\x4a\xbb\x61\x46\xb5\xcf\xca\xed\xed\xf3\x58\x76\x30\x8b\x03\xd9\x3b\xaa\xbf\xf1\x2f\x1b\xe4\x5a\xd2\xd3\x33\x74\x7b\x44\xe3\xc9\x1e\x23\x05\x9a\x65\x0c\x37\x9d\x48\x4d\xb8\x65\x2d\xac\x45\x19\xe3\x69\x1e\x47\x9a\xe8\x80\xa4\xc7\x0d\x90\x3d\x70\xe5\x82\x26\x74\xad\x1f\xdf\x22\xeb\xe6\x63\x1c\xe3\xfd\x2c\x56\x4a\x36\x9e\x05\x56\x76\xbe\xbe\xa4\xd2\xd0\xa8\x64\x3b\x8e\xdd\x2a\x84\x73\x2e\x4a\x4a\x29\xe3\x2f\x84\x6a\x70\x31\xc5\x00\xe8\xf7\x70\x16\x00\xd4\x1b\x8c\x1d\xd4\xa9\xdc\xec\x2e\x6c\xad\x24\x0a\x44\xab\x48\xc5\xce\xd1\x61\x1d\xe1\x11\xdc\xa9\x1e\x79\x86\xe2\x5c\x1e\x1f\x63\xa5\x98\xb4\x7a\xe4\xcf\xfe\xf6\xeb\xb3\x3f\x3d\x13\x30\x47\x1f\x69\xd6\xd0\xdd\x0a\x50\xfe\x5f\xb9\xc2\x76\xeb\x10\xd0\x7f\x6f\x92\x17\x70\xbc\x18\xb8\x28\x79\xf9\x62\xa5\x47\x8b\x17\xab\xdd\x8a\x2b\x5d\xd5\xce\x6f\x09\x1c\x8d\x4a\x73\x50\xf8\x2f\x59\x08\xc5\x08\xc7\x21\xf4\xfd\xef\x92\xf2\x5a\x64\x57\xf9\x7f\x70\x24\x85\x87\x07\x19\xc8\x76\x20\x1f\x04\x8b\x41\x28\x57\xbe\xcb\xa7\x6d\x7c\xa7\xd7\xfc\xeb\x9a\x35\x31\x18\xc8\x3f\xd9\xf7\xcd\xe8\x7f\x58\x87\xe0\x3f\xe8\x42\xe4\xc5\x2a\x7f\x0d\x8a\x33\xc1\xcc\xb5\xaa\x1e\x2c\x9b\xbc\xde\xbb\x82\x86\x47\xd2\x4d\x10\xad\x35\xe9\x26\x28\xd8\x2b\x27\x35\x2a\x26\x3c\x1f\x04\xd1\xd6\x56\x5f\xee\xcb\xc1\x4e\x10\x3d\x3c\xd8\xd9\xef\xab\xcb\x62\x96\x6f\x9c\x64\x53\xe8\x23\x17\xd8\x34\x0a\xec\x5f\xd7\xd5\x3c\xf7\xe5\xb0\x8b\x95\x66\xe3\xe3\x35\x05\x1a\xd8\x35\x29\xd9\xad\xad\x40\x51\xca\x41\x51\x6e\x98\xb9\xb8\x17\x1d\xe3\xc5\x17\x8e\xca\x78\x57\x84\x39\xb9\x00\x4d\xc9\x8a\xa4\xe7\xe4\x25\xc2\xf3\xe5\x2a\x0f\xe0\x0a\x13\x28\x6a\xf3\x19\x21\x29\xd3\x87\x95\x2a\x45\xba\x1a\x90\x8d\x0a\xe6\xf4\x1d\x2e\x9c\xbc\x24\x8e\x64\xd7\x58\xf2\x12\x3d\x6f\xbc\x5c\xe5\x71\x5a\x50\x02\x68\xc8\x3a\xc9\x67\xc5\xbc\x80\xf3\x81\xe2\xa3\x4e\x48\x90\xfa\x5d\x4c\x02\xf2\x77\x98\x81\xc2\x15\x75\x86\x70\xca\x30\x7f\x01\xc7\x23\x23\xd4\xbf\x64\xb3\x65\xde\xa4\xd6\x9a\x11\x4a\xd3\x35\x9e\xeb\x68\xa8\xcd\x1c\x2f\x74\xfe\x26\x3e\x16\x0f\x9f\xed\x08\x0f\x55\x7a\xd3\xbb\xec\x45\x38\xb1\xd3\xd1\x6c\x63\x07\xe8\x14\x69\x73\x3c\xca\xde\x14\xa3\xed\xed\x82\x07\x05\x74\x2c\x1e\x15\xcb\x94\x56\x50\xe7\x08\x31\x38\x4f\x61\xee\xb5\x77\x78\x4d\xac\xec\xed\x21\xd2\x00\x54\x71\x19\xd5\x67\xe5\x80\xb1\x6c\xd8\x44\x90\x1b\x74\x6a\x9b\xe3\xb4\xcb\x52\x47\xe5\x32\x42\x1e\x8a\x93\xb1\xdc\x1e\xa2\x53\xd4\xb3\xf1\x79\x5a\xdb\x5a\xeb\xe3\x68\xf7\xec\x5c\x7a\xc9\xc5\x22\x91\x7c\x99\x45\xc9\x4c\x91\x76\x35\xdc\x1d\x18\xc0\x6c\x4a\x95\xda\x02\x1a\x24\x5c\xa4\xed\x80\xa4\x5f\x5a\x15\xbb\x8d\xd5\xfd\x29\x58\xc1\x23\x8e\x2f\x38\x3b\xc7\x53\xa0\x8a\x0a\x24\x6e\xf1\xb4\x97\x3d\xd0\x3f\x22\x55\x18\xbb\x51\x67\x69\x70\x46\x15\xcf\x76\xce\x61\xd7\x70\x23\x67\xca\x91\xfe\xf0\x7c\xb7\x12\x63\x1e\x76\xee\xf5\xe1\x3e\x5e\x01\x7d\x28\x23\x7f\x03\xfd\x3c\xdc\xc1\x2b\x6c\x10\x6c\x37\xa3\xcd\xa2\xf9\x90\x7d\x08\xd1\xc9\x65\x05\x7b\x36\xdb\xda\x5a\xa6\xf4\xd3\xbc\x49\x77\xe0\xef\x8f\x00\xce\x6e\xf1\xed\x86\xdc\xe1\xb3\x06\x41\xe9\xe9\x6a\x52\x9c\x65\xfe\xac\xc7\x4e\xe9\x40\x64\xff\x5b\x7e\xd7\xf8\xe0\x98\x4b\x3d\xd8\x67\x7f\xc3\x50\xfb\x40\xe8\x02\xd5\xfb\x0c\xa0\xf4\x2c\xfc\xf5\x4c\x26\xfc\x7a\x1e\x01\xcd\x8a\x2b\x30\x07\xbc\x8a\x27\x3c\xce\x80\xb0\x73\x53\x2e\x13\xec\xd9\xce\x90\xda\x90\x8b\xf4\xec\x7c\x84\xef\x30\x48\xbe\x16\x50\xa6\x32\x30\x58\x02\x31\xc8\x64\x52\x0a\xc4\x53\x21\x3f\x03\x70\x5a\xfe\x88\x2b\x0c\xf6\xe5\x28\xda\xde\x5e\xc6\xeb\x7c\x53\x3b\x92\xcf\x1e\x28\x82\x3e\x10\x31\x11\x72\x6a\xb5\x2f\x4b\xd7\x89\xaa\x43\x30\xd7\xdb\xb9\x98\xcf\x8c\xb7\x09\x50\x1e\xe7\xa4\xf3\xaa\x03\xb8\x11\xee\x7f\x1e\x35\x83\x7e\x8b\x22\x86\x25\x47\x64\x07\x7b\x26\xe3\x27\x2d\xba\x6d\x17\x4a\x58\xac\x5d\x58\xa6\x82\x32\x8e\x35\x2c\x91\x3a\xea\x5a\x5a\x26\x34\x4d\x1a\x3c\x74\x5d\xd2\xd2\xa3\x5d\xed\x05\xae\xd0\x1d\xce\x69\x19\x8c\x69\xc0\x71\x2a\xcd\x56\x21\x63\x57\xfc\x52\x25\x54\xcb\x69\xb5\xa5\xe8\xab\xa5\x2d\x54\xfd\x05\xea\x77\x2f\xb1\x8d\xcb\x7c\x0d\x59\x58\xd0\x4e\x48\x6a\x2b\x41\xad\x9a\xca\x05\x51\xbe\x6b\xa0\x66\x9a\x90\x24\x27\x54\x00\xeb\x57\xac\x9e\x2f\xb0\x17\xc2\x0a\x59\x76\x80\xc5\x52\xc9\x13\x1a\x2d\xdf\x34\x80\x56\x9b\x48\xa0\xbc\x0c\xf6\x1d\x20\x38\x6d\xff\x00\x39\x5c\xa1\x71\x4b\x0b\xeb\x1f\x76\x2a\xdd\x24\xc3\x22\x9e\xa9\xed\x56\x52\xb0\x2b\xa0\x2f\x42\xf4\x9a\xdc\x39\x3e\x43\x52\x0f\x4f\xa5\x7e\x4f\xf6\x2b\x4e\x25\x45\x25\xef\xe0\xb9\xa3\x4e\x3a\x73\x33\x57\xec\x0a\x0e\xd6\xc4\xdb\xe5\x74\x9a\xd7\xec\xf0\x07\x95\x83\x85\xcf\x26\x80\x82\xae\x50\x7c\x00\xa7\xbf\x28\x70\x74\x72\xac\xca\xc8\xf5\x4a\xf6\x0f\x01\x5e\xda\x1d\x00\xc3\x52\xb6\xa7\x10\xd3\xd0\x8c\x2f\xcf\x4a\x77\x71\x9f\x29\xd6\x4e\x47\xb9\xb7\xb0\xb3\x52\x8d\xa3\xdd\xe5\xe4\xd1\xb9\xb8\x84\x02\xc2\xc0\x8d\xb4\x62\xdb\x6c\x14\x6a\x25\x98\x53\x9b\xaf\x33\xb5\x23\xed\x20\xd8\xac\x06\x02\xca\xf6\x85\x0e\xc0\xa8\xc1\x3c\xcc\x69\xfa\x63\xd2\xbc\xb7\x53\xb7\x11\x83\x8c\x11\x65\x40\xbe\x8e\x81\xfb\xf0\x84\x79\x1b\xf6\x8d\x54\xdb\xcb\xbb\xda\x5e\x4e\xb4\x74\x20\x96\x44\xd7\x53\x77\x0e\x54\xde\xae\x7a\x4a\x6a\xf9\x34\x52\x6e\x64\x11\xce\x22\xea\xf5\xa6\x36\xa7\x72\x31\x74\xb7\x60\x09\xee\xc2\x06\x77\x06\xe0\x6e\x00\x9e\x02\xdc\xcd\x9b\x0c\xc0\x9d\x31\xb8\x97\x29\x1e\x53\xa3\x0a\x5d\x1e\xc8\x73\x57\x87\xdd\x12\x88\x17\x00\x87\x82\x58\xc5\x2e\xa9\x4b\xef\x0e\x7a\xe1\xd3\xd6\x20\x7c\x73\x5a\x39\xc4\x42\x47\x8b\xb5\xb8\xff\x4b\xe8\x64\xdd\xd9\x1c\xd6\x6f\x4a\xe8\x64\x19\xf9\xe2\x8e\xa3\x69\x1d\xde\x61\xe1\x27\x25\xe7\x67\x5d\xec\xa7\x58\x6c\x7c\x17\xe9\x2b\x6f\xa4\x1b\xb9\x17\xa4\x2a\xdb\x59\x62\x39\x1f\x41\x88\xaa\xce\x5a\xb4\x9f\x8f\xfd\x2d\xa8\x95\x9f\xa7\x67\xb9\x22\xa4\x00\x1d\xb9\x12\xde\x4d\x8b\x31\xc1\x26\x4d\x16\xac\xf0\x88\x1d\x75\xf4\xaa\x3e\xa9\x2d\xde\xc6\x76\x00\x71\xd6\x12\x5e\xc5\x9b\x0a\xe0\x55\x49\xdf\xef\x35\xfa\x00\x6a\xd2\x16\xe7\x36\x47\x3a\x04\xff\xec\x4a\xac\x88\x2f\x71\x03\x04\xa7\x9c\xd5\x1c\x01\xc7\xa4\xa2\x31\x43\xe4\x79\xc7\x92\x06\x69\xe8\x40\x3b\xcb\xb7\xf1\x20\xdf\x40\x85\x2d\x76\xb6\xa3\x5d\xc2\xd1\x9d\x90\x44\xbd\x9e\xc3\xf8\xe9\xb5\x0d\x33\x46\xbb\xf1\xec\x5c\x70\x2a\x5a\xcd\xdb\x2b\xd3\xc8\xe8\x02\x56\xd1\x9a\x67\x35\xed\x9a\x56\x09\x72\xec\x09\xd0\x02\x78\x31\xd1\x89\x04\x7c\x6e\x13\xf0\xfe\xa5\x57\x9c\x77\xee\x98\x91\x9f\xa4\xd8\xc2\x8f\x4c\x4a\x99\x7b\x8f\xe6\x8f\xdb\x6f\xbc\x17\x84\x65\x8a\x81\x14\x46\xb8\xd1\xd2\xee\x80\xa2\x7d\xd7\x46\xc6\xf4\x48\x82\x22\xf5\x30\x52\xce\x18\x88\x82\x43\x4b\xb4\xb0\x43\x8b\xc9\xc3\x86\x55\xed\x50\x04\xd0\x1d\x48\x9e\x36\x37\x9e\xa0\x8e\x76\x37\x87\x09\x39\x75\xd1\x5c\x92\xa2\xea\x82\xee\xa1\x54\x36\xdf\x97\x4e\xe2\x04\xbe\xc5\xbe\x74\x24\x20\x01\xf9\x79\x85\x2e\xc3\xe2\x18\x69\x47\xf1\xb4\x1a\x2f\x1b\x8c\x30\x2a\xbd\x85\x3e\xe5\xe8\x55\xf8\xc1\x58\xb6\xd5\x4f\x58\x15\x9d\x94\x48\x05\xdb\x2e\x56\xa9\xcf\x63\x64\xf7\xa5\x64\xf8\x1d\x6a\x82\xbc\x74\xe4\x0c\x46\x27\x3d\xfc\x08\x71\x7f\x47\xfa\x57\x31\x28\xc5\x82\xef\x40\x09\xd7\x17\x57\x38\x91\x0f\x6e\xf2\xba\x29\xd0\x83\x99\xba\xae\xa8\x34\xb8\x3f\xc1\xc5\xe5\xc7\x74\xf8\xdc\xab\x59\x12\x1a\x5e\x75\x3a\x57\x3b\xc2\xff\x0e\x22\xa0\xae\x08\x4e\x0e\x17\xd1\xd4\x4d\x06\xcf\x48\xd6\xb7\x5f\x11\x51\xd2\x6a\xde\x09\x28\x1d\x29\xfa\x8c\xf8\x2c\x9d\xb8\xb5\x87\x21\x24\x3d\x48\x9e\xdc\x95\xed\x75\xde\x16\xe3\xa3\x72\xb1\x6c\xa9\x95\xce\x09\x37\xec\x96\xe3\x29\x69\x59\x64\x1d\x03\x09\xc0\x72\x9a\xff\x2e\x8a\x2a\x5e\x08\xf6\x3d\x90\x4c\xac\xf7\x38\x39\x90\x25\xdf\x01\x75\x84\x74\xf1\x7d\xf1\x3c\x5e\x08\x87\x98\x64\xba\xb2\x7f\x9d\xd5\xfb\x38\xd3\xb3\x28\x9e\xc2\x59\xd7\x56\x8b\x77\xf9\x4d\x3e\xe3\xc0\x43\xd7\xe9\xfd\x65\x0e\x3b\x35\xa7\xbe\x25\xf7\x0b\xb8\xb7\xe4\x13\xd8\x4c\x05\x4c\x2d\x09\x80\x98\xe5\x7f\x7f\xb9\xbc\xbc\x9c\xe5\x93\x64\x19\xde\x57\xe5\x5b\xad\x0a\xa9\x5a\x43\xff\xb3\x05\xc0\xdf\x53\x60\x9f\x33\x44\xb9\x47\x64\x66\xa0\xee\x77\x39\x2e\xd0\x66\x1f\x23\x62\x2c\x08\xaf\x32\x3b\xf0\xb0\x9c\xc4\x94\x06\x93\xf2\xb1\xce\x9b\x86\xdf\x10\x1a\xd4\x1a\xbf\x7e\xcc\x9a\x36\x47\x5d\xfc\x09\xdb\xa0\xcc\x51\xbc\x7d\x93\xde\x93\x3b\x1d\x36\x64\xb8\x96\x0c\x69\x8e\x6e\x69\xfb\x72\x93\xc7\x05\x19\xde\x47\xc2\x29\x58\x2e\x9c\x82\x19\x1d\x48\x18\x57\x55\x83\xdb\xeb\x62\x7c\x8d\xe5\x97\x80\x72\x67\x02\xe5\x8e\xe6\x78\x2a\x66\xe9\x42\x77\x0f\x66\x76\x39\x81\x2a\x78\x45\x9d\x64\x6d\x46\x01\x12\x16\x5b\x5b\x73\x59\x9d\x6b\x09\x83\xd8\x84\x13\xc9\x4d\xdb\xbd\xaf\x4f\x34\xee\x84\x07\xed\x7c\x50\x75\x58\x74\x15\x96\x4b\x0d\xb7\x09\x38\x5f\x27\xde\xf5\x20\x8a\x45\x91\xd3\x92\x39\x1f\xf0\x3d\xee\xfc\x23\x52\xf2\x8c\x1a\x27\xb2\xff\x59\x3a\xc1\x64\x41\x52\xdd\xa4\x84\x5b\x3e\x22\xbd\x37\x09\xaf\x07\xda\xd2\x22\x98\xcb\x13\xe3\x86\xda\x4b\x33\x39\x7f\xc5\x20\x1b\xc3\x32\x5e\xce\x80\xfa\x3f\xbd\xad\x3e\xe2\x22\x3c\x10\x46\x37\x70\x59\xba\x89\xe2\x1b\xd3\x7b\xda\x0d\xa3\x29\x6b\xa7\x26\xdf\x91\xe6\x9c\xb3\x4f\x93\x57\xa4\xfe\xd6\xcf\x7b\xf5\xef\xd1\x64\xc8\x7a\x75\xbc\x45\x93\xe1\xeb\xd7\x88\x08\x1d\xd1\x65\x1f\x22\x34\xd8\xf1\xdb\x6d\xc7\xeb\x07\x10\x7f\xc6\x48\xa5\xfb\x30\xca\x30\x82\x9c\x66\x79\xc9\x84\x67\x38\x94\x2e\x22\x01\xb9\xcf\x96\xf3\x72\x9f\xd0\x3a\xac\xb0\xe9\x2c\xff\x5d\xfe\xfe\xb9\xae\x6e\xe5\xf3\xc9\x35\xd4\xfb\x42\x6f\x55\xd9\xfe\xc2\x61\x76\xe1\x6d\x06\x67\xd6\xfe\x2c\x9b\x2f\xe4\xcb\xcf\x2a\x0b\xe0\x32\x2e\xda\x3b\x7a\xac\xd1\x08\x83\x1e\x60\xe3\x97\x78\x97\x8b\x6f\x0b\x64\xd2\xe2\xd3\xff\xa1\x80\xb2\xf4\x54\x55\x73\xfa\x46\x31\x9b\x1d\x77\xd5\xa1\xd3\xd5\x97\xbc\x4b\x40\xb6\xe2\x59\xf0\x4b\x7e\xf9\xa5\x40\x99\xd8\xbc\x81\x3f\xef\xab\xff\x03\x7f\x8f\x83\xf3\x91\x4e\x1e\xd4\x91\x57\x01\xa6\x72\x53\x11\x86\x67\x68\x8f\x06\x37\x30\xa0\xed\x60\xd7\xcb\x20\x27\x70\x77\x46\x41\xfc\x55\x8d\xca\x98\x89\xf6\x7c\x34\xcf\xae\x72\xec\x5f\x97\xa4\x5c\xe4\x19\xa9\x9f\x00\x15\x65\xad\x99\xb6\x5f\xcd\x30\xc6\x0f\x8c\xe5\x92\xa1\x73\xcf\xbf\xbf\x50\x38\x63\x2c\x4a\xaf\x1c\xf6\x58\xbd\xda\xb5\x38\x0a\xb4\xac\xcb\x6f\x56\x0b\x9c\x68\xb5\xc3\x89\x76\x6b\x28\xdc\x90\x6d\xe1\xb3\xd5\x12\x26\x59\xed\x60\x92\xdd\x0a\xb9\xa9\x94\xcd\xd0\x8b\xd5\xce\xa7\x2e\x9e\xb3\x99\x66\xb7\x84\xb1\xd5\xef\xd5\xa3\xd5\x0a\xa4\x58\x6d\x9c\x22\x46\x91\x2d\xe0\x32\x4d\xee\xf1\xaf\x2a\x85\x2f\x7f\x61\x89\x87\xbb\x90\xa9\x24\x4a\xc5\x9c\x75\x8c\x39\x3f\x65\xf3\x62\x46\x4b\x0f\xd9\x28\xf7\x45\xf3\xb9\x2c\xda\x19\x20\xc1\x0f\xc4\x0a\x48\xea\xb8\xb9\x06\x84\x81\x26\x42\x92\x15\x07\x54\x22\x9a\x30\x00\xd2\x48\x0a\xdb\x21\x3c\xee\x6f\x47\xb8\xd5\x47\x8d\xed\x9f\x9c\xc8\x36\x3b\x51\x41\x0f\x25\x50\xa5\x21\xeb\x4a\xc0\x61\x8a\x32\x3e\x1a\x3b\x9e\xac\x18\x6f\x19\x33\x26\xa8\xfc\x54\x63\xf4\x7a\xcc\x21\x26\x11\xdc\x28\x24\xe5\x71\x7d\xb7\xb8\xce\x4b\x74\xf8\xa8\xd5\x13\xb4\xc7\x3c\x9f\x57\xd4\x22\x22\x90\xe3\x72\xc6\x3a\x5f\xfc\xb9\xce\x44\x29\xf3\x39\xf1\x26\x5f\x68\x11\x71\x81\xc7\x4d\xf3\xd3\xac\xca\x60\x84\xb5\x4e\x86\x30\xe7\x1f\x11\x7e\xaf\x10\x0d\x7b\x34\x90\xd5\x51\xa3\x15\x99\x5f\x90\xc6\xcd\xf1\x56\x1d\xcb\xa0\x1f\xef\xb3\xfa\xcb\x72\xf1\x53\xc5\xfb\xa7\xf1\xc8\x89\xb5\xdb\x3c\xf9\x2d\xc9\x23\x0a\xa0\xe1\xb8\x99\x91\x5a\x04\x78\x0b\x16\x2c\xda\x1a\x6f\xc6\xdb\x69\x03\xb9\xdb\x41\x12\xc4\xf0\x8c\x82\xde\x1a\xde\x46\x41\xe7\x31\x47\xc4\x65\x40\x8b\x35\x82\xb3\xaf\x37\x9d\x96\x42\xce\x23\xec\x58\x0c\xfd\xbe\x6f\x8a\x48\xde\x41\xab\xb0\x88\x49\xe4\x4e\xb7\xe5\x29\x41\x22\x95\xb6\xd7\x4b\x98\x8d\xa8\x86\xdc\x34\xeb\x78\xfa\x0d\x5c\x81\x56\x2c\x55\xbc\x28\xa1\x13\x9b\x48\x76\x63\x4c\xae\x59\x22\x12\x67\x08\x89\xc8\x06\xb5\x19\x04\x8f\x8f\x1e\xad\x2c\x63\xb5\x26\x2f\x5f\x3d\x75\x1e\xba\x0b\x35\x19\xbe\xa4\x53\xd4\xb7\x52\x21\x8f\x74\x94\x3c\xeb\x34\x19\xbe\xa2\x43\xd9\x5d\xa6\x70\xa0\x52\x25\xcb\xf0\xe5\xa5\x23\xec\xec\xbf\x69\x70\x58\x0a\xbc\xd5\x21\x02\x6f\x34\x0f\x2b\x17\xc2\x3d\x3e\xa7\xe9\xea\x4a\x4c\x9c\x90\x7f\x99\xce\xdb\xb2\xed\x40\x53\xec\x3b\x4d\x06\x3c\xaa\x4c\x2f\xcc\x79\xf9\xf7\x65\xbe\xf4\xc7\xc9\xe8\x3a\x64\xbd\x93\xd1\xbc\xd5\x3f\xf3\x55\x2f\x21\x6b\xa9\xcb\xbc\x59\x54\xf2\x66\x50\x75\xa0\x2d\xa6\x77\x7b\x7a\x08\x0e\xc3\x9e\xb2\x6b\x2a\x6e\xad\xef\x8d\x58\xd4\x02\x98\x40\xdc\xd1\x49\xfe\x27\x24\x58\x76\x47\x7a\xe1\xdb\x6d\x59\x97\x95\x55\x6e\x6f\x47\xb8\x49\x85\x9d\x1b\x31\xad\xd4\xc7\x76\xe2\x56\x3d\x52\xe4\x6d\xd8\x94\x6e\xb8\x92\x35\x26\x18\xae\x15\xf2\x8e\xed\xd4\xa7\x56\xd9\xd7\x31\x59\x8b\xe3\x0a\x40\x83\xec\x0a\x75\xc4\x1c\x75\x35\x8f\x97\x44\x73\xd1\x24\xaf\xc9\x74\xc5\x91\xd2\xbf\x74\xa4\xd1\xbd\x94\xa1\xe2\x5e\x9c\x1c\xbe\x3b\xdc\x3f\x65\x5d\x90\x12\x88\x72\xdc\x32\x0f\x0f\xc1\xd1\x87\x8f\x9f\xad\x54\xbc\x29\x17\xb3\x9c\x13\x71\x09\x7a\x35\x8d\x7f\xd7\xc8\xef\xd3\x01\x2b\x95\xc7\x1f\x31\xfc\xfa\xe1\x6a\x12\xbb\x8d\xe2\xcb\xc1\x25\xbd\x88\x08\x30\x0d\x7a\x99\xb6\x6d\x17\xee\x06\x62\xdd\xf3\xad\x0a\x17\xe5\xdd\x40\x98\xc5\x51\xd2\xbf\x63\x66\x18\x39\xae\xc3\x8e\x53\xe8\x47\xda\xc6\xc7\xb6\x1e\xbf\x54\x7c\xaf\x23\xdd\x33\x18\x54\x00\x5c\x79\x3c\x98\xe4\x3d\x85\xe3\x63\x5e\x0b\x1f\x85\x79\x83\xaa\xdb\xd8\x71\x73\x01\x60\xef\xe9\x52\x43\x75\x77\x4b\x19\x13\x57\xd5\x58\xca\x1a\xaa\x28\x31\x4b\x76\xc3\x0c\x65\xb5\x21\x4b\x34\x55\xde\xdb\xd9\x12\xce\x99\x4c\x1f\xe2\xd8\x1c\xe2\x09\x4c\xd0\x0d\xa2\xc5\xf8\x83\x64\x45\xc1\xa4\x68\x07\xc5\x41\xde\x8c\xeb\x62\x01\x4b\xd5\xe4\x21\x69\xe8\x25\xb8\x61\x0a\x40\xca\x15\x99\x09\xa5\x4e\x9a\x63\x59\x20\xfe\x12\xb9\x20\x5d\x88\x62\x12\x5a\x0b\xad\xaf\x33\x01\xda\x49\x3e\xcb\xdb\x7c\xe3\x58\xf4\xd4\x81\xb4\xdb\x86\x09\x71\x18\x25\xfd\x7c\xb0\xe1\xbf\x90\x6e\x68\xb8\x83\xb4\x5c\x65\x63\x14\xde\x5e\xe9\x83\x35\xf5\x58\x12\x11\x54\x76\x84\x8a\xdc\x27\xd0\xb7\x13\x00\xa2\x60\x90\xa9\x66\xa7\x7d\xd3\x4a\xf7\x35\xcf\xac\x5e\xf7\xcd\xea\x0c\x3d\xb8\xfa\x67\x75\xa6\xcf\xea\x44\x57\xbf\xda\x14\xe5\x4e\x00\x6c\x94\xcd\xab\x69\x6b\x4b\xe5\xc0\xed\xfb\xf3\xc2\x7c\x3f\xa8\x6e\xcb\x87\x87\xcd\xe3\x87\x07\x01\x66\xf8\xda\x89\x54\xa6\x80\x51\x4a\xe0\x7f\xd4\xbe\x3a\xd7\x90\x83\x17\x0b\x84\x01\x6c\xd1\xf1\x97\xcb\xea\xf7\x0e\x15\x00\xc6\xa8\xb3\x49\x51\x75\x29\x5a\x8b\x37\xbd\x1b\x02\xbd\xd2\x76\x90\xc3\x69\xb9\xea\x61\x80\xdd\xe9\x0c\xb0\xd9\xf2\xaa\x28\x7f\x5e\x5e\x76\xb6\xdc\x1e\xc6\xd8\xfe\x4a\x72\xf8\x52\x5a\x60\x67\xe3\x56\x60\x9b\xce\x7c\x5b\x5d\xc5\x25\xa7\xec\x93\xb4\xf7\xa6\x84\x13\xb6\xcc\xcd\x27\x9d\x25\x77\xd1\x28\x66\x8b\x58\x51\x9d\x4d\xb7\xe4\xaf\xbd\x4f\xaf\x2c\xd6\xd7\x29\x06\x75\x27\x47\x42\x4f\x73\xbd\x6e\x91\xa9\x25\xdc\x0e\xd9\x0c\x2f\x2d\x6f\x35\xaf\x4b\xad\xb4\x58\x43\x48\x71\x37\x17\x71\xb7\x4c\xe3\x6e\x6d\xc7\xfa\x72\x8a\xbb\xb5\x16\xfb\x16\x24\xf2\xc4\x56\xec\xd3\xf8\x20\xdd\x1c\x8e\xf6\x75\x0a\x3f\x3c\x48\x3f\xe1\x9a\xa2\x6d\x8e\xcc\xa2\x15\x3c\xc6\xc8\xa3\x4c\x87\x65\xde\x7c\x1f\x49\xff\x7d\x4e\xf3\x47\xd8\x7c\x81\x03\xf9\xc3\xad\xff\x20\x5a\xff\x42\xc1\x77\x3c\x2e\x2c\x3e\x20\x82\xed\xec\xe8\x23\xa2\xed\x8d\xbb\xc5\x09\xea\xb9\x00\x42\x46\x5f\x1b\xba\xc1\x3d\xf2\xe0\xf7\x0c\xbe\xe1\xe9\x2a\xbe\x61\x2d\xf9\x86\x45\x4c\x9c\x43\x64\x4f\xec\x1e\xec\x16\x69\x93\x64\xe9\x32\xb9\xc0\xd7\x23\x78\x9d\x26\x40\xe7\x63\x4c\xda\xeb\x28\x99\xb3\x8c\xab\xc0\xf0\xa8\x85\x14\xf4\x16\x22\x5e\x31\xb3\x1f\x29\x71\xe6\x3f\xbc\xc7\x1a\xdb\xec\x89\x33\x7c\x16\xc5\xb3\xc7\xc7\x0c\x4f\x27\x6e\xdd\xb8\x07\xec\x3d\xcd\x32\x53\x3b\x3b\x79\xb5\xf3\x47\x19\x69\xc6\x9e\x4e\x86\x6c\x73\x6b\x6d\xe9\x64\xf8\x82\x49\x28\x7b\x47\x03\x25\x25\x9c\x01\x38\x1b\x1a\xb2\x5e\x38\xcc\xb8\xef\x1c\x45\x3e\xcf\x65\x7d\x87\x64\x25\x6c\x84\x80\x9d\xfb\x54\x55\x2d\x73\xb6\xdc\x95\x04\xc4\xaa\x23\x0e\xc1\xef\x38\x6a\x7b\x2b\x48\x3b\x8b\x71\x7b\x65\x71\x54\x4f\xda\xac\x96\x9c\x5e\x98\xd1\xb1\x95\x33\xf2\x56\x42\x36\xac\xaf\x0a\xa4\xfb\x2b\x88\x28\x7e\xbe\x3a\x9c\x65\x07\xcf\x36\xce\x87\x2b\x0d\xe5\x60\x54\x3e\x00\x3a\xb2\x8c\x91\x0f\xe0\x04\xe7\xf2\x0d\x97\x10\x54\x22\xb5\x4f\x29\x24\xb2\x14\x5b\xaa\xc6\xa2\x91\x51\x1e\x3f\x25\xbb\xab\xca\x40\xcd\x89\x59\x8c\x39\xdc\x5d\xd2\x7b\xb8\x88\xe6\x54\xb7\x4b\x43\x14\x9b\x48\x7f\xb3\x16\x6f\x1d\x5d\x24\xe9\xb4\xa9\xbc\x22\xc0\x9a\x90\xc1\x7c\x1a\x9c\x06\x85\x57\xd3\x31\x45\x1b\x94\xaf\xea\x1a\x46\xa5\xe8\xf6\xab\x7c\xd6\xe0\x9a\x0d\xa3\x2e\x12\xab\xe7\x20\x6d\x7a\x0f\xcc\xe5\xca\x03\x73\xac\x1d\x98\xb4\x2d\x54\x87\xba\x58\xac\x6a\x93\xe9\xeb\x46\x1c\xa1\x22\x22\xab\xe8\x24\xf9\xf4\x28\xdb\xbd\x31\x92\xed\xe4\x5a\x60\x6a\x1e\x96\xd7\xe9\xd9\x0f\xf1\xf0\x45\xfc\xfc\x75\xfc\xe2\xf9\x79\x3c\x49\x9f\x3f\xff\x21\x9e\xa3\x73\x56\x4d\x42\xe5\x7c\x46\x09\xaa\xe2\x9b\x74\x13\xe3\x97\xf7\x61\xfa\xad\xad\x9e\x63\xa4\x27\xe3\xc7\x74\x38\x8c\xaf\xd2\xcc\x3a\xc0\xef\xf8\x4c\x3b\x14\x92\xd0\x6e\xa7\x3c\x7d\x9e\x4f\xe9\xcc\x36\x6b\xd9\xe7\xba\xa7\xcc\xea\xf3\x5d\x2d\xbe\xd8\xb3\x7d\x63\x7d\xa1\xc7\xc6\x72\x8e\xbb\x3d\x13\x9b\x8b\xfa\x5c\x78\x83\xd2\x31\xc7\xd7\x0f\x8e\xeb\x3d\x35\x3c\x2a\xf5\x47\x07\x48\x95\xff\x09\x43\x14\x68\xeb\xeb\xc7\x28\x2a\x3e\x35\x48\x2e\xf6\x47\x47\xc9\xb5\xff\xe0\x30\x1f\x47\x85\xa6\x92\x20\x76\x62\xea\x1e\x41\x0a\x1f\xf1\xed\xe0\xe1\x41\x25\x9c\x2d\xc2\x08\xc0\x65\x35\x73\x80\x92\xb4\x5e\x3f\x5a\x8c\x93\xe2\xce\x83\x97\x86\xda\xf8\x35\x2e\x53\x0b\xa1\x49\x95\x61\x5f\x15\x80\x53\x67\x1d\xc5\x72\x2b\x94\xcd\xc8\x2a\xe5\xb7\x6d\xc4\x8a\x63\xfb\x06\x55\x75\xb8\x8a\xaa\xca\xe2\xa5\xa0\x8b\xe2\x05\x12\x44\xf3\xdd\x31\x19\x87\x25\x77\xbb\x78\xc6\x2c\x23\xf2\x5b\x6e\x9f\x7b\x51\x52\xf7\x64\xd2\x62\x8c\xe2\x1b\xc8\xb9\x7b\x78\x18\xc3\x21\xe2\x66\xc3\x27\x52\xa7\xc9\xad\xad\x3b\xa8\xb3\x48\xef\x24\x5c\xc3\x48\x20\x19\xe8\x8b\x08\xa9\xdf\x46\xb0\xbc\xb8\xbb\xd3\x74\xa6\x51\x6c\x63\x1a\x87\x04\x0e\x5c\x05\xc3\x29\x4b\x39\xe1\xea\xdc\xac\x26\xdc\xa6\x80\x80\x4d\xa6\xed\xfe\x3f\x5b\xbe\xe9\x3b\x39\x92\xe1\x8e\x49\x9d\x39\x18\x1d\xe8\x37\xfa\x62\xcf\xb9\x91\x0c\x5f\x7d\xe7\xd2\x64\x8e\x32\xe9\x0a\x01\x29\x5d\xd0\x81\x36\x68\xf2\xba\x65\x9d\x01\x5a\x4d\xe4\x97\x10\xd5\x4f\x9a\xb3\x52\xc4\x51\x16\x82\x51\xc9\xb0\x3d\x20\x2e\xb4\x16\x39\x02\xc7\xf7\x1e\xce\xf9\x82\x3c\x48\xf1\x4e\x95\x0e\xbf\xb2\x27\x4e\xbf\xc6\xe1\xf6\xa2\x8e\x26\x7a\xfa\x48\x83\xb6\xab\x81\xd7\xeb\xe5\xae\x39\x36\xb8\x6e\x77\x05\xd2\xf6\x31\x71\x6d\x2e\x46\xf9\x60\x5a\xd4\x0d\xbb\xb6\x1a\x45\xb9\x72\xf1\x08\xaf\xa1\x9e\x47\xb7\x81\x4e\xf9\x76\x00\x68\x23\xaf\x0f\x94\x7e\x87\x3c\x11\xa1\xbd\x6c\x81\x08\x8b\x5b\x90\xbe\x79\x70\x68\xa4\xd1\xd3\x92\x4a\x8f\x10\xbb\x28\x6e\xfd\xec\xee\x13\x6b\xac\x61\x19\x74\x86\xca\xa2\x98\x04\x45\xfb\xab\x8b\xc4\x1c\x6b\x4c\x03\x5d\x52\xc7\x82\xe7\x27\x08\x7d\xcf\xa8\xd9\xdf\xc8\x92\x8f\xe8\x31\xff\xcc\xd2\x9d\x51\x46\x51\x14\x46\xb3\xed\x6d\x94\xa1\x64\xc4\xad\x40\xd1\xc8\xe0\xfd\xf1\x5f\x0e\x2f\x0e\xff\xe3\xe8\xe4\xf4\xe8\xc3\x9f\x1f\x1e\xb4\x9c\x4f\x87\x94\x87\x3e\xef\x19\x38\x0b\x20\x05\x50\x95\x81\xa8\x78\xa0\x5d\x32\x54\x85\x86\x7e\x61\xbf\xf5\xb5\xb3\x40\x6f\xb6\x32\xf3\xe8\x60\x44\x3b\x6d\x99\x2e\x49\xa3\x7d\x79\x76\x7d\x9e\xe2\x1f\x62\xb9\xe3\x03\x94\x4f\xa7\xd0\xd7\x31\xa5\x08\x5f\x26\x53\x5e\x78\xac\x03\xa1\x01\x0a\xdd\x17\x32\x7c\x50\xcf\x91\xae\x71\x72\xd8\x73\x18\xe6\xfc\x47\xe9\x3f\x64\x34\x87\xa1\x8e\xcf\xe6\xe7\x7a\x27\xf5\x25\x80\x79\x9d\xb6\xe3\x8d\x80\xd1\xcd\xf9\xe8\x06\x2a\x0a\xea\x9a\xa1\x21\x48\xec\x62\x70\xf4\xe1\xe4\xf0\xd3\xe9\xc5\xfb\xbd\x4f\xff\xf6\xf9\x63\x52\x86\x3a\x00\xe2\xc9\x59\x36\x98\x53\xcf\x08\x3e\xe7\x31\xd2\x4d\xf4\x68\x68\x7a\x58\x10\xb7\x5b\x59\x9e\x75\x80\x3b\x3f\xd3\xe0\xdd\xdf\xde\xe9\xe1\x7f\x9c\x5e\xec\x1f\x7f\x38\x3d\xfc\x70\x0a\xc8\xd9\x68\x2e\xd3\xf7\x89\x55\x4f\x9b\xdf\xc4\x2b\xbb\x12\x9b\x3d\xf9\xee\xbb\x78\xf5\x56\x07\x8c\xb6\x0e\xbe\x72\x58\xf7\xdf\x39\x5e\x41\xd6\x50\xea\x08\xf3\xad\x36\xa2\x08\xc8\x9a\x74\xc9\xb4\x1a\xbc\x7f\xff\xf9\xe4\xf4\xe2\xf3\xc9\xe1\xc5\xde\xe9\xe9\xa7\xa3\xb7\x9f\x4f\x0f\x93\x61\xac\x12\x3f\x7e\x3a\xfe\x08\xf3\xf8\xd7\xe4\x79\xfc\xf3\xde\xc9\xc5\xc9\x11\x06\x75\xf8\xe9\xa7\xc3\xfd\xd3\x93\xe4\x25\x25\xbd\x3d\x3e\x7e\x77\xb8\xf7\xe1\xe2\x2f\x7b\xef\x3e\x1f\x26\xdf\x53\xda\x87\xcf\xef\x0f\x3f\x1d\xed\x8b\xb4\xe1\x2b\x4a\xfc\x78\x7c\x72\x74\x7a\x84\x50\x34\x72\x5f\x72\x15\x00\xef\xa7\x77\xc7\x7b\x07\x87\x07\x56\x8b\x70\x38\xb0\x59\x34\x90\xf4\x92\xbb\xcc\x01\x6b\xbc\x26\xbc\xa2\x48\x91\xb3\xbf\x67\x8c\x6d\x01\x15\xf7\x5a\x80\xd3\xe5\xb2\x25\x0e\x25\xe7\x34\x9c\xf3\x51\x63\xfc\x72\xc6\x92\x33\xde\x2f\x5b\xa2\xea\xde\xe7\xed\x75\x35\xa1\x2c\x40\x6b\x45\xb3\xbf\x6c\xda\x6a\xae\x1a\xdc\xda\xca\x06\x17\x4e\xea\x4f\xa2\x67\x52\x30\xe6\xd6\xeb\xb6\xd3\x98\xc5\xb5\xf7\x75\xb8\x99\x41\x39\x38\xfb\xcb\x49\x56\x4f\xb0\x43\xae\x11\x18\xfa\xe1\x30\xcb\xa0\x78\x15\xee\x90\xcc\x9f\x19\xc3\xba\x7f\x57\xdd\x4a\xc5\x9d\x11\xe1\x2f\x22\x00\x9a\xa6\x00\xaa\xd4\xa8\x38\x3b\x4f\xc7\x40\xaa\xb9\xdf\x10\x18\xac\x80\xa6\x47\xfd\xd5\x17\x58\x9d\xb2\x0d\xe8\x62\x7f\x16\x1c\xc6\xd3\x9f\x39\x13\x6d\x6a\x80\xc7\xe4\xc6\x63\xf1\xd6\x40\x46\x22\x3e\x62\xce\x07\xd6\x58\x7a\x6a\x60\x04\x95\x44\xd9\xe3\x4f\xd3\x96\xc7\x30\x07\xe0\xc3\xad\x50\xf5\x05\xab\x97\xe1\x34\xae\x06\xee\xf2\x47\x10\x8b\xf2\xb2\x65\x4f\x71\xb9\x31\xb0\x34\x74\xe3\xa4\x98\xe4\x87\xd3\x29\x2c\xd3\xa6\x2b\x6c\xef\x18\x51\xf6\x2d\xdb\x1a\x10\x21\x6b\x16\x36\x56\xbe\x28\xfd\x01\x4e\x54\xd8\xe3\x9e\xd2\xc6\x3e\x12\xa5\x59\x8b\xe8\x26\xef\xaf\xe5\xdf\x86\xa2\xfa\xf1\x4d\x5e\xcf\xaa\x6c\x92\x4f\xfa\x3b\xd9\xb7\x53\xd1\x83\xcb\xa6\x17\xd4\x0f\x0f\x9b\x3e\x90\x62\x05\x5f\x3a\x15\x77\x60\x4a\xcd\x6f\xfa\x00\xb8\x2d\x92\xad\x31\xcb\xe4\xde\x31\xc1\x9d\x9d\x8c\xd1\x84\x85\xd3\xfd\xd1\x41\xb7\x08\x2e\x3e\xec\xbd\x3f\x4c\x02\xa4\x8e\xbf\x25\xb3\xe7\x62\x12\xc4\xe6\xc6\x4b\xee\x39\xfc\xbe\x67\x6f\x88\x2c\x63\xe9\xcb\xe2\xda\xb2\x17\x49\xe6\xca\xc6\x44\x1b\x86\x5a\x9a\xac\x8f\x49\x26\x8c\x44\x8a\x3e\x48\x91\xa4\x03\x46\x24\xf9\xd6\x89\xc8\xf2\xc3\x0b\x33\x57\xe0\xb9\x04\x35\xf5\xed\xdc\xc4\x6f\x4f\xb2\x33\x6a\x7f\x5c\x8d\x34\x05\x59\xd2\x02\x75\x21\x48\xcd\x95\xe5\xcf\xda\x73\x66\x75\xe7\x2a\xb4\xfe\xce\xa3\x62\xa6\x69\x01\xd2\xa4\x32\x8d\x02\xa2\xc7\xa4\x2c\xae\x53\xf4\xcb\xa1\x9c\x2a\x3c\x3c\x84\xe4\xa7\x03\x6d\x92\xe1\x96\x8a\xc8\x1a\xd3\xca\x4e\xdf\xc8\xf2\xf6\x0c\x0b\x15\x2d\x51\x4a\xf8\xc3\x8f\xd2\xaf\x07\x2a\xf7\x55\xb6\x3e\x97\xf7\xac\x5f\xad\x6e\xdf\xa3\xc0\x29\x7c\x6f\x60\xb4\x23\x7b\x8f\xe4\xe7\x5b\x5b\x9b\x32\xc7\xd8\x26\x98\xc3\x96\xb5\x28\xdc\xa8\x7b\x51\x08\x96\x1b\xbe\x91\x4d\xf4\x6c\x29\x2c\xc4\xb1\x45\x75\x7a\x43\x3b\x64\x3b\x6d\x96\xbc\x19\x67\x0b\x22\xd8\x61\x3a\x84\xaf\xcc\xee\xaa\xe4\x53\x18\xcb\x1c\x85\xb1\xc2\xa7\x30\x86\x3a\x00\xdb\xdf\xa4\xc1\x37\xa8\x35\xd6\x38\x4a\x5d\x47\x07\x3e\xdf\x15\x59\x58\x0f\x9c\xdd\x1f\x6d\x73\x5b\xd0\x54\x6c\xb5\xd2\xb3\x7e\x28\x40\xf6\xea\x13\x1c\xed\x8b\xec\x32\x00\x37\x36\x41\xa4\x56\x4c\xc7\x29\x68\x44\xe4\x1c\xa2\xda\xea\xf4\x4c\xf5\x9a\x73\xb4\xb3\x5b\x85\x45\x94\x64\xf0\x07\x06\xda\xf2\x40\x55\xb3\xce\x66\x43\x5b\x2b\xb1\xc2\x76\x83\x00\xaa\xe5\x5d\xb5\xc4\xd1\x56\xf3\x02\x48\x58\x5a\x3e\x05\xa2\xd6\x07\x22\xd8\x4b\xf7\x1a\x3c\x2c\x62\x80\xf7\x7f\x11\xa1\xcc\xaa\xd2\x62\xb3\x87\xf8\xcd\x48\x04\x74\x42\x6d\x02\xbb\x7f\x04\x71\x2d\xba\xb9\x73\x78\xc1\x77\x73\x94\xc8\x75\x70\xf0\xcc\x47\x7b\x1e\x07\xc1\x76\x65\xd8\xbf\xd7\x0e\x8d\x03\x9d\xac\xed\x63\xad\x45\xeb\xf8\x60\x9b\x8c\xc0\x50\xfe\x57\x61\xf4\x1a\x7c\xa9\xe0\x64\x62\x8d\x39\xcf\x54\x90\xb4\x8e\x27\xa3\xda\x95\x37\x35\x3d\x3b\xb1\xfa\xdc\x72\xff\x88\x8f\xe8\x03\xc3\xd7\xaf\xe3\x95\x93\x54\xae\x98\xa4\x32\xc2\x8f\xb0\x40\xff\x69\xc8\xdb\x43\xf3\x02\xdf\x08\x92\xe5\x83\x7b\x2c\x56\x4d\xcf\x29\x10\x76\xca\x0b\x24\xc9\xec\x9d\xa4\xea\x1c\x2f\xfb\x34\x45\xf0\x58\x3c\x35\x45\xbe\x99\x31\xee\x8e\x8d\xb8\x3b\x6a\x08\x32\xf9\x8e\xf8\x64\x5e\xf4\x98\x0c\x39\x73\x6d\x3d\xc5\xef\xd6\xb6\x88\xd2\xdd\xf8\x68\xaa\xfe\xb1\xe6\x1a\x85\xcc\x07\x35\xb4\xde\xab\x46\xac\x79\x5c\x23\x1e\x07\x7a\xc7\x67\xcc\xd9\x21\xf8\x7c\xbe\x68\xef\xe4\xf9\x6d\xb0\xbf\xb8\xe4\x2f\x75\xb6\xe8\xe3\x7a\x3d\xfb\x5b\xf8\xe3\xd9\xdf\x36\x7e\x7d\xf6\xe6\x1c\x7d\x80\x8d\x53\xa6\xd2\x98\xf5\xf1\x2d\xf5\x37\x40\xcf\x60\x3d\xbc\x10\xd3\x6d\x63\xa8\xe9\x12\x77\x57\xb2\x56\x7a\x16\xdb\x19\x2d\x7e\xec\x22\x6d\x22\xb3\x23\xc4\x8b\x0f\x72\xab\x4b\xf5\x94\xa1\x4c\xbd\x45\xef\x6d\xf1\x0c\x4f\x7e\xfc\x43\xfc\x19\x7c\xc0\x6b\x12\x16\x14\xf7\x11\x8a\x5e\xb4\x43\x1f\x6a\xd9\x79\x1c\xac\xfe\x99\xbb\xbb\x78\x23\x4d\xa8\x2d\xd5\xad\x39\xd6\x98\x60\x8d\x89\x5d\x63\x1e\x49\xf3\x96\xc9\xd9\xfc\x7c\x84\x7f\xd2\x1b\xdd\x01\xd6\xbf\x0e\x37\xd0\xc4\x1a\x4f\xc6\xed\x39\xfa\xf7\xfa\x26\x12\xfa\x34\x15\xb4\x46\x66\xc3\x68\xb4\x5e\x30\x10\x78\xe4\x57\x72\xe4\xdb\xdb\x0b\x6e\xfe\x2e\xbd\xc2\xb1\xdc\xe1\xe7\xb5\x2b\xb0\xf9\x0e\xf7\x30\xc0\x4f\xf3\x74\xfb\xce\xd8\xad\x90\x1c\xdf\x39\x5b\x02\x12\x9b\x70\x73\xea\x19\x4f\x3c\xc5\x41\xdc\xc5\xe4\x78\x58\x39\x38\x69\xc2\x6b\x0a\x66\x25\xf5\x3f\x9b\x70\xda\xa9\x85\x2a\xc7\x26\xf1\x14\x50\xdd\x53\x7c\x45\x73\x6b\x98\x4b\x21\x26\x7d\xc3\x26\x0c\xae\xdb\xf9\x2c\x20\x27\x41\x6d\x76\x45\x98\xd0\xb8\x61\x47\x42\x82\x0f\x47\x21\xc0\xee\x6c\xe7\x7c\x94\x9b\x4c\x34\xfa\xb0\x60\x83\x92\x32\x87\x13\x39\x7b\xb5\x92\xb3\x77\x1f\x25\xc3\x97\xe4\x9f\xdb\xdc\x46\x80\x1f\x86\xb1\xb3\x8b\x92\xe1\xab\xe7\x7e\x8e\xd2\x6a\x33\x21\xcd\x8c\x40\xca\x5c\xeb\xf4\xac\x0c\xef\x3f\xe5\xcd\xa2\xc2\xfd\xa4\x69\x64\x48\xa9\x16\x64\x9f\x14\xf3\xc5\x2c\xf7\xe7\x9d\x66\x0b\x7f\xc6\x61\x89\x1e\x2a\xf2\xec\xa6\xa7\x22\xab\x0e\xf5\x7c\x90\xa4\x05\x3d\xf5\x2c\x71\x81\x53\x40\xb3\x02\xf4\x17\xd8\x2b\xb3\xd9\x1d\xc6\xf2\xf4\x67\xb3\xaf\x29\x76\x35\x45\x1a\x52\x6e\xb1\x73\xd7\x76\xd5\x94\x46\xac\x6d\xce\xe1\xc8\xea\xeb\x5e\x59\x7d\x65\x09\xdc\x49\xca\x27\x45\xed\x86\x40\x02\xcd\xb7\x3a\x0c\x2c\xa7\x1a\x95\xfd\x4d\x51\xf6\x32\x2d\x70\x3b\xff\x84\xb2\x00\xaa\x89\xb1\x60\xc6\xe9\xfd\x9c\x5a\xc6\xf9\x4b\xe0\x0c\x31\xa5\xa1\x40\x26\xde\xc3\xf9\xdf\x95\x10\x80\x33\xa5\x99\x8d\x12\x43\x1e\x2f\xdb\x58\x7b\x03\x0a\x16\x2e\x4f\xf4\x01\x5a\x1b\x2b\x3f\xc0\x25\xfe\xc0\x07\x1e\x01\xd9\x9f\x71\x9c\x30\xf8\x73\x4e\xfe\x24\x3b\xb1\xe0\x78\xb5\x91\x66\xc6\x9e\x80\xc8\x7d\x94\xde\x2c\x20\xc0\x0c\x76\x3f\x4a\xd3\x26\xa7\x59\x7d\x85\x5e\xde\x98\x43\x2d\xee\x89\x91\xe1\x3c\x52\xc4\x0f\x36\x3a\xca\x9a\x9a\x66\xb3\x8e\xc7\xc9\x05\xdb\xd2\xb3\x52\x03\x72\x7a\xa3\x45\xda\x76\xf4\xd0\x34\x6d\x4d\x19\xcd\x68\x91\x4e\x77\xa7\x32\xbc\xe9\x5f\x8a\xfc\xf6\xe1\x61\x2a\x30\x16\x3b\x3f\x13\x0e\xea\xe8\x70\xb8\x8e\x27\x23\x77\x78\xcb\x76\x17\x90\x70\x1b\x4f\xd2\xa5\x6f\x90\x6d\x25\x87\xf8\xf0\xb0\x88\x12\x28\xba\x80\xa2\x2d\xaa\x6c\x74\x56\x99\xdd\x08\xe6\xe9\xf5\x2e\xad\xac\xa3\x83\xf0\x3a\x4a\x82\x20\x86\x33\x4c\xa5\x4c\x28\x05\x0e\x29\x5d\x8c\x39\xe8\x96\x44\x3c\x87\x29\x18\x5d\xb1\x24\x26\xa0\xf4\x19\xa6\x07\x28\xdc\xa6\x2e\xa5\xd7\xf0\x68\x74\x32\x9d\x88\x20\x7c\x9e\x46\x69\x99\xc6\x37\xd8\xa8\xe8\xe8\x9d\xde\x76\x5e\x52\x78\xdf\x3b\xd9\xf6\x84\x4e\x34\xbd\xed\x6b\x54\xe0\x57\x92\xd4\x0e\xaf\x69\xb2\x54\x0c\x7b\x36\x8f\x6f\x22\xa0\x0f\x76\xce\xd3\x2b\xf8\x19\xe2\x39\x37\xf3\xb8\x0e\xff\x4a\xf1\xaa\xb6\xa3\x93\xe1\xce\xab\xb8\x07\x03\x24\x43\x8e\xa5\x60\xa2\xa1\xd5\x46\x2d\xe6\x71\xf0\xbe\xc0\x50\x7b\x84\x81\x00\x09\x4a\x8d\x07\x16\xa4\x49\xc5\x06\xb1\x15\x2b\x2c\x21\x55\x9e\xd8\x38\x42\x2a\x96\x76\xaf\x88\x39\xbb\x37\x57\xe9\x25\xf6\x29\xa8\x79\x32\x34\x1d\x0b\xce\x21\x03\x8c\xf7\x79\xb9\xd4\xd2\x16\x77\xdd\xcb\xb2\x6b\xe6\xa0\x5a\xc2\x28\xcc\xae\x1c\xd4\xd9\x95\xf1\xa2\x77\x88\xdf\x25\x5a\x53\x29\xbf\x17\xad\x91\xd0\x21\x26\x99\x82\x3b\xd9\x48\x30\xc7\x73\x00\x13\xab\x5e\x38\xf8\xa8\x7c\x23\xcd\x5b\xf5\xd6\x59\xb7\xc7\x9a\x86\x9a\xf6\xce\xaa\x68\x5a\xc2\xe7\xae\xe1\x77\x55\xd6\x0d\xa5\xd3\x51\x33\x52\xde\x57\x5a\xcf\xe5\xe6\xb7\x12\xf4\xb1\x50\x8a\xf6\x0d\x36\x06\x97\x6f\x9f\xc8\x74\x46\xbe\x71\xfc\x93\xee\xd5\xd4\x12\xee\xd2\x97\x97\x73\x0d\xa0\x9d\xc9\xba\x4a\xa9\x96\xe3\x6b\x0e\x41\x65\xa6\xe9\x53\x45\x09\xc6\x68\x28\xc5\x84\xfb\x2f\xd7\xb9\x68\xe3\x91\x3c\xe0\x19\xe7\x5f\x52\xc5\x72\xc3\x41\x27\x49\x3d\xa2\x49\x6a\x7d\xc7\x16\xea\x6c\x17\xbb\x03\x36\xd6\x2b\xdc\x58\x8e\xd1\x8d\xb6\x97\xec\x8b\x50\x9d\xde\xcf\xc8\xd7\xbb\x13\x88\x58\xdd\xcf\x1c\x77\xf1\xa1\x9b\x46\xc1\x31\x37\x87\x11\x06\x21\x41\x7a\x5b\xd7\x23\xcd\xbd\x8e\xe5\x45\x85\xc7\x47\x64\x1e\x68\xd6\x1a\xd4\xba\x69\xbc\x11\x6c\x63\x87\xfc\x4d\x5b\x36\x1a\x5c\x14\x1b\x15\x2a\xfc\x12\x3d\x58\x4a\xcb\x5f\x3f\xbc\x1a\xa3\x16\x7f\xcd\xf0\xa8\x02\xf6\x44\xd6\x29\xc9\x9a\x0b\xe9\x09\x38\x1e\x85\x06\xa6\xd6\x8e\xcf\xe7\x88\x4b\x6f\xc3\xfc\xbe\x5a\x47\xc3\xd7\x36\x4e\x10\x7a\x63\x77\x36\x11\x47\x99\x9f\x85\x3f\xb3\x4a\x46\xda\x93\xc7\xc9\x51\xd9\x56\x1d\xfd\x26\x0c\xd1\xf7\x54\xf6\xa4\xa3\xe3\xf4\x2b\x33\x05\x70\x57\x6a\x0e\xfa\xf5\xb7\x73\x62\xd8\xa6\x35\x79\x0e\x84\x2b\x99\x3c\xa9\x10\x73\xd3\x01\x49\x7d\x7a\x5f\x4d\x96\x33\xe4\x9a\xf0\xdc\xe6\xd1\xa8\x42\x57\x3b\x56\x1d\x72\x5e\xec\xa4\xa2\x51\x9b\x95\x94\x37\x47\xe5\x31\x5a\x5e\x13\xc4\x90\xcf\xd0\x7c\x44\xef\x29\x38\x5d\x2d\x46\xdc\x37\xcd\x8e\x6a\x3c\xd5\x1b\x64\x42\x12\xb9\x46\x43\x01\x3a\xad\xe3\xab\x8b\x47\xf6\x31\x53\x0f\x54\xc6\x40\x4b\x17\x6c\xf8\x23\xe1\xca\x8d\x83\x19\x99\xc1\x68\xd3\x5c\x04\xcf\xf4\x17\xe9\x22\x72\x4b\x9e\xbe\x36\x6b\x34\x9c\x44\x7e\xd1\xce\x70\xcb\x37\x6f\x59\x08\xe4\xa9\x21\xb2\x1e\x63\x22\x44\xf1\x51\xc2\x8d\x25\xdf\x80\xd3\x07\x7d\x59\xb1\x4d\x23\xf3\xcc\x61\x95\x9e\x9c\x18\xd0\xa9\x27\xa8\x05\xa3\x9d\x2c\xdc\x2c\x1f\x1e\x3c\x2e\x70\x94\x67\xea\x86\xd8\x1d\x21\xfe\x50\xd0\xe6\x5a\xc4\xcf\xc4\xd0\x9f\xbe\x56\x25\xfe\x23\xb1\x8d\xa4\x06\xb7\xb6\x4a\x8a\xd1\xc9\xfc\xc9\xa7\xeb\x41\x05\x61\x1f\xa6\xd7\xdb\x9b\xcd\x64\xd5\xc6\x2f\x7c\x62\x9b\x64\x51\x15\x5b\xa2\xda\x2b\xed\x29\x0a\x5d\x5b\x08\xef\x45\x0b\x9e\x23\xd8\x52\x3b\xb0\x9f\x94\xb4\x6a\xfc\x66\x39\x5a\x4a\x89\xd5\x0c\xba\xb9\x24\x86\xe7\x4c\x8a\xd3\x67\x03\xe3\x33\xaa\xf5\x11\x2a\xe2\xa1\x41\x76\x16\x2f\xa2\x8e\xd1\x91\x41\xb7\x74\x43\x46\x63\x3c\x39\x59\xb1\x57\xe1\x32\xe6\x98\x0f\xb6\x79\xa3\x6b\x65\x0b\x7d\x13\x8e\x4c\xe0\xc3\x63\xb4\xb6\xdf\x5c\x42\xcd\x8b\x8b\xc5\xb2\xbe\x32\xca\x23\xba\xc0\x0c\x6d\xfe\xde\x66\xa5\x2f\x2e\x7d\xd3\x4b\xb1\x5a\x48\x2e\x79\x35\x8c\x7d\x28\x2e\x61\xd6\x84\x85\xe0\x92\xe1\x4b\xb2\xbd\xf0\xe0\x37\x40\xb9\xaf\xbc\xcc\x8c\x57\x6b\x9b\x3f\x10\xd6\xcb\x94\x26\x54\xce\x2b\x42\x20\xc1\x06\x96\x43\x8c\xd2\x46\xd3\x85\x59\x11\x96\x6f\xd0\xbd\xfd\xe6\x52\x4e\x3e\xda\x08\xdf\x17\x61\x6b\xce\x69\x14\xeb\x05\x52\xe9\x57\xb7\x1d\x74\x17\x4a\x53\xed\xa3\x8a\x8a\xb0\x0e\xd9\x33\x26\xcc\x0a\x8a\xa3\x4d\x9b\x07\x72\x35\x0b\x53\xd5\xbb\xdd\x3d\x6e\x07\xe2\xfe\xd2\xe4\x94\x6f\x24\xdd\x06\xf4\xa8\x30\x53\xf8\x78\x6d\xd1\x93\xc8\x33\x22\x2e\xbd\xed\x32\x56\xf9\xa8\xad\xc9\x4f\xa1\xf4\xf0\x6a\x09\x61\xc9\xd5\xbb\xf9\x91\xdd\xb0\x0a\xdd\x54\xaa\x8d\xe7\x34\xfa\xd2\x36\xad\x38\x14\x20\x7a\x90\x18\x0a\xd1\xe2\x55\xb9\x70\x61\x75\xb3\x0f\x34\x3e\x01\x95\xd1\x66\x0a\x0d\xc2\x75\x3e\x82\x16\xde\xc8\x38\x5e\x39\x7c\x99\x3c\x65\xef\xc5\xfc\xa3\x40\xbc\x17\x7b\xdf\x3f\xf6\x62\x69\x4f\x96\xde\x49\xcc\xef\x39\x79\x8c\x83\x3d\xdc\xcc\xb0\x67\xec\x5b\xaf\x53\xc6\x26\x1f\xbd\xd2\xc7\x5c\x5c\x62\xac\xab\xde\x73\xc9\xd5\xae\xda\x1c\x76\x1e\x0f\xfb\x1d\x5f\xd4\x91\xf4\x8b\x9c\xa3\xaf\x3f\x67\x85\xd6\xd1\xd6\x56\x03\x39\xe8\x12\x1a\x85\xeb\xe1\x26\xbe\x01\x99\x82\x69\x55\xdc\x52\xc4\xa5\x16\x1d\xc1\x71\x24\x2e\x1f\xfd\xe1\x55\xfd\x9a\x18\x50\x66\xc6\x88\x0d\x4b\xc9\x7e\xe8\x5f\x29\x6e\x1d\xa1\xde\x6b\x3a\xfd\x68\xfb\x76\x0f\xfb\xdd\xe8\xc9\xec\x77\x12\xb2\xaa\x43\x3d\x8d\xc1\x02\x3d\xe7\xbd\xaa\x9c\x7f\x6b\xcc\x15\x40\xe1\xe4\x55\x40\x9f\x59\x33\xea\x99\x31\x28\x81\x07\x9d\x1e\xa2\xc0\x5a\x1d\x97\xf9\xf9\x48\x21\x38\xe5\x14\x41\xc4\x04\xec\x47\x3a\x16\xe0\x22\xc7\x2b\x49\xd9\x7d\x03\x9d\x2f\x8c\x9e\x80\x48\xe7\xc4\x98\x31\x93\x83\x96\xaa\xae\x3d\x74\xb5\x69\x9c\x52\xcb\x1e\x9d\x8b\x57\xeb\xeb\x84\x1b\x76\x68\xf3\x41\x77\xef\x05\xaa\x55\xa6\xc8\x1b\xa8\x9d\xc4\x17\x55\x7f\xc4\x49\xb3\x39\xbc\xad\xda\xb5\x31\xcd\x72\x77\xe0\xad\xcb\x66\xdd\x66\x5d\xba\xeb\x3a\x4e\x0f\xa4\x22\xf7\x85\xdc\x3c\x8a\x7e\x22\x27\x19\x2a\xf9\xe8\x80\x8e\x05\xd3\x57\x27\xac\xde\xce\x55\xe7\xce\xa8\xfa\xb1\x54\xb1\xcd\x36\x89\xa2\xef\x2e\xcc\x27\xd0\x8d\x45\x3e\x09\xe1\xda\x00\x24\x12\xfa\x5a\x2f\xd1\x09\x2a\x4e\x8f\x90\x02\xa3\x15\x1f\x26\x5b\x6e\x16\x94\x06\xbe\x08\xce\x21\x59\x78\x03\x22\xe9\xf1\x7e\x42\x1a\xe5\x8a\x1a\xa5\x36\xba\x60\xec\x56\x35\xc2\xd4\xb5\xe5\x8a\x81\x7c\x8b\xf0\x2d\xc4\x05\x03\x57\x31\x21\xc1\xfe\x3c\x74\xef\x0c\x1d\x12\xf2\x00\xb2\x7c\x12\x90\x6d\xa4\xc7\x3e\xd8\x19\xd5\x3f\xb6\x6b\x40\xb2\x66\x05\x75\xf4\xa8\x4a\xf0\x04\x24\xaa\xb8\xab\xf0\xf2\x28\x85\xeb\xad\x80\x6c\x97\x3b\xd2\xf1\x84\xee\x24\x42\x8e\x03\x87\xd4\xc1\xd0\x19\xfb\x0a\x48\xb5\xba\x23\x87\xaf\x84\xcb\x75\xe8\xb8\xde\x55\xd3\xba\xcb\x43\x60\xdd\x4e\xb7\x67\x4f\xcf\x97\x3e\xed\x8b\x6e\xe7\x6c\x6e\xfa\x5a\x79\x64\xe6\xb9\x5f\xea\x72\xed\xd2\x00\x93\xf4\x9e\xaf\x9e\x4c\x62\x6b\x77\x51\xfd\xa0\x12\x8b\x36\x45\xa7\xbb\xf3\x74\x6a\x09\x58\x6e\xd0\x39\x18\xa0\x8c\xa2\xc1\x18\x77\x45\x83\x9b\x1d\x9f\x6b\xd6\x3b\xac\x5b\x7c\xa9\x62\x75\x91\xc6\x00\xbe\x12\xd3\x26\xb3\xd8\xba\x60\x27\x99\x9d\xa2\xae\xdc\x49\xd3\x9b\x85\x8b\x6b\xaf\x3d\xad\xe1\x06\x31\x46\x5d\xc0\xae\x40\xb2\xd0\xb4\xd8\x26\x31\x20\x19\x46\x71\x7c\x37\x01\x72\x6d\x5d\xd7\x87\x2e\xe6\xfd\x1a\xcd\x76\xc4\x05\x62\x45\x58\xe7\xfd\x8a\x53\x52\xae\x97\x39\xb4\x50\x47\x36\x85\x5d\x4b\x72\xa5\xdd\x9d\x0c\x24\x2b\x7b\x32\x90\x7c\xec\xb8\x40\x51\x3f\xd9\xd5\x8f\xd0\x3b\x56\xed\x5b\x74\x53\x6f\x32\x86\x4a\xad\xcd\x95\x68\x14\x84\x04\xba\xbf\x99\x18\x1d\x5d\x76\xac\x39\xb6\xad\xad\x85\xc6\xea\x70\x18\x17\x61\x34\x80\xd2\xe8\x95\x56\x99\x74\x85\x5d\xd3\x28\x23\xce\x6b\x18\x58\x6e\xfb\xc2\x11\xf1\x2d\xf0\x52\x6e\x77\xc4\xa1\xa7\x64\xa4\xb4\xa7\x0a\xc6\x55\xca\xe0\x47\xbe\x51\x58\xfa\x81\xe8\x4b\xc6\x30\x96\xa5\x0d\xc4\xd2\x05\xa2\x71\x68\xf8\xa1\x68\xf7\x69\x6b\xab\x70\xe1\xc1\xf8\xc3\x74\xd7\x13\xdd\x5f\x93\x66\x99\xe3\x91\x07\x17\xcf\xba\x53\xd0\xc9\x82\xd0\xe3\x5b\x5c\xc4\xb9\xe1\xbc\x68\x2c\x3f\x93\xb1\x62\xc6\xac\x07\xfb\x2c\x7a\x1c\x9d\x4c\x7b\x98\x85\xd7\x2b\x98\x85\x93\x74\x36\x70\xb8\xda\x80\x9a\x16\x03\xed\xf2\x8f\x88\x69\x95\x6d\x20\xa0\x93\x2e\xdb\x44\x4b\x24\x3f\x5d\x2d\x0d\x4b\x96\x5f\xe9\x34\xd5\xf6\x00\xf1\x75\xcc\x03\xc4\x37\xeb\x38\xb3\xde\xf4\x86\x4f\x60\xd1\xe8\xc3\xc3\xa6\xf0\x1c\xdd\x79\x36\xb6\x53\x4c\xa5\x60\xf6\x85\x2d\x95\x4b\x00\xbb\xf3\xf3\x2f\x15\xae\xb8\x26\xf1\xf9\x32\xe7\x3c\x51\xd0\xe0\x65\x37\x49\x89\x6e\x96\x37\x7b\xa2\xc7\x42\x9e\x1b\xd5\x36\x12\x0d\xa1\xc0\x17\x21\x4d\x4d\xc8\x72\x0d\xf4\x35\xc7\x13\xe7\xa8\xe4\xaf\x26\x9b\xa5\xc7\xc3\xc4\xab\xd5\xda\x64\x52\x79\xba\x5f\xe7\xb7\x47\x63\x0c\x95\xf3\xba\x1d\xe4\xda\x63\xc4\x99\xbf\x80\xb4\xc0\x80\x9b\xb7\x9e\xef\xd8\x51\xc0\xa5\xdc\xce\xd7\x8d\x32\xe2\xb1\x93\x6d\x58\x46\x50\x1c\x13\x33\xdf\x6f\x42\x01\x3b\xd3\x2e\xd8\x67\x2a\x81\x14\x60\xa5\x69\x1b\x09\x59\xbd\x5a\x3c\xa4\x42\x83\x4f\xb4\x2d\x47\x65\x3a\xdd\xda\x22\x15\xa9\x9f\x60\x51\xc1\xa1\x64\xbe\xa1\x92\x52\xbb\x48\x9e\x3d\xbb\xbd\xbd\x1d\xdc\xbe\x18\x54\xf5\xd5\xb3\xd3\x4f\xcf\x4e\xfe\xf2\xe7\xe1\xf0\xd9\x94\xcb\xfc\xcb\xdb\xac\x29\xc6\x27\xc4\x4f\x87\xd7\x20\x0e\x86\x83\x61\xc0\x98\xe6\x1a\x09\x0f\x5b\x75\x9f\x9d\xd5\xeb\x1e\xea\xf3\xa6\x1d\x5c\xc2\x8a\x09\x9f\xfd\x2d\x44\x8d\xbb\x07\x3c\xc6\xa3\x6f\x31\x82\xe7\x05\xc5\xf1\xfc\x75\x72\x31\xf8\xf5\xdb\xf3\x3f\xfd\xeb\xb3\x28\xee\xcc\xb0\x12\x44\x1e\xf9\x42\x90\x46\xfc\x8c\x0e\x9e\x95\x2c\x30\x23\xdb\xb7\x7f\xcb\xef\xe4\x2b\x91\x18\xfc\x3c\x9b\x55\xb7\x3f\xc1\xd3\x09\x2d\xd1\xa4\x78\x68\x38\xed\xb4\xce\xca\x86\xb4\x16\xc6\x77\x49\x01\x69\xb2\xad\xe6\xae\x1c\x23\x42\x5a\xb6\x15\x8a\x85\xf1\x0e\x28\x72\x20\xe5\xe3\x2c\xbb\x83\x4c\xb8\x80\xcd\x3e\xc2\xb6\xc1\xc8\xb7\x2c\x14\x81\x84\x13\x74\x11\xac\x12\xa0\x7f\x27\xd0\xbf\x22\x26\x4f\x56\x40\x0f\x64\xf0\xe5\x31\xfa\xd6\x3b\x3a\xc0\x54\x7c\x62\xe6\xfd\x6e\x01\x94\xd6\xb8\x9a\x35\xd0\xb9\x19\x3e\x40\x43\xa2\xf7\x63\x61\x8a\xaa\xbf\x1c\x4e\x8a\x36\x03\x0a\x43\x4b\x14\xf2\xe9\x82\xde\x6a\x6c\x89\x3e\x56\x55\xf5\x44\xc8\x6e\xc7\x75\xd5\x34\xc7\x75\x21\x75\x8a\x62\x04\xbf\x7a\xca\x4f\x0b\xe8\x48\x11\x03\x0a\x21\xda\x6e\x52\x08\x81\x2c\x1c\x6c\x19\x11\x33\x08\x36\xd8\xe8\x25\xaa\x83\x03\x1d\x37\xa9\xb3\xab\xab\xae\x13\x00\x43\x24\x40\xf9\x05\xd0\xe6\x1c\xda\xc2\x1f\x0e\x82\x2c\x5e\x0e\x45\x21\x7e\x13\x96\x2a\xfc\xf2\xa1\xfa\x4b\x36\x2b\x48\xee\xde\x50\x02\xdf\xb5\x30\x17\x43\x0f\xbd\x65\x1f\xc5\x45\x7c\xcd\x6e\x71\xe1\xa1\x98\x4c\xc4\x64\x5e\xd7\xf9\x94\x3f\x8c\x4f\xef\x32\x39\x01\xa8\x75\xf7\x93\x94\x7b\xe3\xea\x3e\xfc\xfb\xb2\xb8\x11\xd4\xf5\x58\x2e\x8f\x02\xe6\x25\x9e\x65\x97\x52\xf2\x3b\x53\xf5\x51\x86\x0a\x5f\x9a\x55\x18\x45\x1a\xbe\x33\xcf\xca\x62\x9a\x53\xda\x1c\x7a\x07\x07\x08\x77\x86\x0a\x73\x0a\xfb\x08\x16\x09\xbf\xab\x87\x77\x74\x0d\xc3\x7a\xf9\xa4\xc8\xe4\xef\x9f\xeb\x6a\x29\xc4\xdc\x73\x86\x05\x3f\xcb\x09\x9a\xa3\xed\x27\xac\x3e\xfe\x38\xec\x27\x5e\x41\x25\x2d\x19\x52\x35\xd2\x81\x06\x5b\x45\xd4\x83\x43\x11\x8e\x48\xf9\x82\xaa\x83\xd7\xd5\x6c\x22\x25\xec\x8b\xaa\x51\xda\x06\x8b\x3a\x9f\x29\x09\x3e\xb9\x56\xd3\xfa\x04\x67\xcf\x04\x15\x83\xe9\xa3\xb5\x04\x4f\x9d\x03\x10\x51\x33\x03\xd2\xaa\x19\xce\x25\x2a\x16\xd3\xba\x85\x87\x6e\xdd\x36\x40\xb9\x5c\x56\x02\x04\xcd\xb8\x92\x6b\x83\x83\x51\xaa\x4d\xd2\xe4\xd9\x1c\xfd\x18\xd3\x44\x36\x24\xbe\x17\xc3\x6c\xae\x33\x55\x07\xfd\x22\xe3\x17\xf0\x01\x8a\xc6\x0d\x7e\x06\x5e\x17\xb0\xe7\xf6\x71\x73\x89\x72\xf5\x58\x3d\x1c\x54\x63\x98\x57\x78\xe0\x2d\x48\xee\x1d\x80\x8e\x80\xb1\x8b\xe1\x91\xbb\x5b\x21\xb6\xcf\x2e\xd9\x51\x92\x78\xa3\x95\xc7\xcf\xe8\x65\x59\x3c\xaa\xe5\x8d\x7c\x95\x4c\xb4\x42\xbe\x2b\xa0\xbf\x4b\xf4\x27\x4e\x53\x7c\x3b\xaf\x26\x08\x16\xc2\x1e\xd9\x02\x76\x2a\x05\x3b\x55\xf8\x63\xbf\xaa\x91\xba\x11\x8b\xaf\xcd\xe7\x88\xe5\xa0\x3c\x3e\x9e\x10\x9c\x10\x14\xf8\x26\xf6\x8a\xf4\x2a\x28\x0c\x24\x1c\x43\x54\x89\x1b\x25\x3e\x0c\xf8\xf5\xdb\x31\xbf\x07\x1a\xa2\x09\xe8\x31\x50\x3b\x23\x80\x9d\x16\x68\x5b\x83\xce\x80\x6f\x71\x86\x6f\x02\xfa\x92\x61\xd8\x0a\x1f\x32\xc7\x14\xe0\xfb\x58\xbd\x07\x26\xc6\xe4\x5c\xf1\x16\x18\x63\x17\x59\xf4\xc2\x39\xac\x93\x42\xe9\x14\x93\x23\xe8\x70\x2d\x25\xc2\x32\xbe\x0b\x14\x96\x09\xe0\x01\xe7\x23\xe8\x76\x7c\x80\x4f\xb8\x77\x03\x7d\x21\xb3\xbf\x40\xf4\x78\xbe\x08\xf4\xe5\x12\xd0\x33\xe1\xe5\x40\xae\x96\x00\x7e\xe1\xf0\x0c\xe4\xa2\xc1\x77\x84\x9f\xc1\xf9\xbb\xee\xd5\xb6\xef\x53\xc0\x45\xa2\x67\x7d\x5f\xfa\xd1\xfd\x52\x18\x65\xe4\x22\xaa\x89\x38\x3c\xde\x15\xe5\x17\x19\x36\x47\x66\xd1\xe2\xc3\x8c\xc8\xe2\x05\x92\xfb\x26\xbb\x21\x2a\x0d\xb7\x31\x23\x51\xaa\xca\xd8\xf7\x47\x6f\x0b\xa2\x2b\x6b\xb4\xd1\x79\x9c\xb2\x7a\x3a\x40\xfc\x91\xa3\x23\x08\xac\x11\xe6\x42\x07\x8e\x0b\x44\xd6\xf5\x4b\x6b\x40\x83\x42\x5f\x13\xa2\x48\x24\xa2\xf4\x74\xda\xa9\x38\x53\xd2\x45\xc6\xd2\x65\xbb\x8c\xd3\x7b\xd8\x4b\x2d\x3b\xcd\x97\x4e\x27\xf1\xb9\x90\xfe\xf5\xc5\x59\x03\x4f\xb4\x9c\xe8\x81\xd4\x90\x30\x36\x00\xab\x16\xa1\xcb\xf7\x59\x7a\xff\xbe\xf8\x1d\xb0\xf7\xfd\x42\x7e\x31\xb9\x67\x04\x61\xce\xbe\x60\x1a\xe5\x24\xf3\x1e\x9f\xb1\x2b\xcb\x73\x54\x57\x90\xa0\xc4\x67\x89\x7f\xf1\x59\x9e\xc2\xd2\xab\x26\xfa\x68\x21\xa5\xae\x30\xf8\x6b\xb5\xdc\x80\xef\xdd\x14\x93\x7c\xb2\x91\x6d\xfc\x46\x1f\xfc\x0d\x93\x16\x1b\x6d\x05\x29\x78\x9a\x6e\x4c\x8b\x7c\x36\xe9\x62\x10\x97\x1b\xbf\xc9\x4f\xfd\xb6\x71\x4d\x97\xcc\x7a\xb0\x71\x0a\xf0\x86\x32\xb3\xd9\x46\x4d\xb6\x0e\x50\x19\x3b\xf1\x6d\x05\xbd\xe0\x16\x06\x1b\x47\xd3\x8d\xf6\x3a\x17\xed\x35\xd0\x1a\xfc\x5c\xe6\x1b\x70\x3c\x61\x07\x37\x70\x5d\xff\x36\xd1\x4c\x64\x7e\x1b\x6c\x1c\x43\x85\xfa\xb6\x68\xf2\x78\x03\x80\xb6\x91\x17\xf8\xae\x77\xa0\x82\x37\x39\xda\xdf\x06\x18\xc8\x56\x52\x4c\x2b\xe0\xf6\x4f\x01\x96\xf8\xce\x7f\x09\x70\xed\x8b\xbe\xfc\x21\x80\x29\x95\xb7\x66\x80\x30\x7b\x24\xa1\xd7\x5f\xac\xb5\xa7\x29\x48\x59\xdb\x72\x37\x44\xbc\x11\x3b\xe9\x62\x5f\x26\x46\x06\xb5\xbd\xef\xcc\x90\xd3\xba\xb6\x67\x49\x52\xdb\xb5\xaf\xef\x66\xeb\x0b\x22\x8b\xbe\x71\x2c\x07\xf5\x15\x43\x28\x9c\xa6\xb4\xef\x67\x5d\xa6\x04\x98\xcf\x96\xc2\xc2\x1a\xc9\x70\xe8\x77\xa7\xf1\x6a\xb5\xd2\xbd\x89\xd7\xa5\x4a\x59\x68\x18\x40\xd1\xa7\x84\x6d\x16\x5d\xb2\x0f\x01\x9b\xb4\x64\xc6\xfa\xcf\x53\xdc\x6a\xeb\x6c\xf1\x96\x79\x92\xb6\xe0\x13\x3b\x9d\x71\xb0\x2c\x64\x16\x2f\xe1\x2a\x31\xe9\x0c\x52\xea\x81\x5d\x95\x38\x56\x6e\x6c\xad\x11\xfb\x2a\x9f\x01\x35\x30\x33\xf9\x0c\x68\xd4\xd2\x97\x87\x52\xfe\x58\x45\xf7\xfa\x05\x76\xd2\xe7\x72\xee\x0d\xf0\xe5\xab\x8d\x8c\xb7\x95\x4d\x7b\xac\xe4\x7a\xc1\x9d\xb0\xd7\xcd\x7f\x86\x12\xc9\x6a\x15\xe8\xff\xb1\x86\x29\x86\xad\xcf\x59\x39\x76\x14\x85\x61\x5e\xc0\x37\xb0\x55\x16\x06\x85\xb2\x30\xa8\x4c\x59\x9e\x8c\xe4\x50\x88\x53\x74\x94\x6d\x6d\x6d\x66\xb0\x3b\xc6\xa8\xc2\x4c\x06\x08\xe2\x39\x45\x3f\xab\x1e\x55\x55\x3f\x9b\xcd\xaf\xe4\xe8\x28\xb1\x9a\x5b\x44\xc5\x5d\xca\xa3\xf6\x1a\x26\x69\x03\x31\x37\x0e\x51\x60\x6f\xc3\x65\xfd\x06\x77\x78\x63\xcc\xa1\xf7\x01\xa9\x62\x5d\x44\x8d\x1d\x23\x4c\x33\xc6\x4b\x55\xc4\xc5\xb8\x74\x23\xe7\x99\xb2\x5f\x98\x87\xe1\xa8\xfe\x11\xda\x27\x4e\x8a\x52\xce\xaa\xa5\x62\x56\x95\xaa\x3c\x11\x89\x10\xbf\xbd\x99\x4a\xaf\xb9\xf2\x63\x55\xd7\x01\x52\x80\x29\xa2\x92\xf5\x26\xe0\x7a\x10\x51\x7c\xcb\xec\x9c\xa2\x73\x76\x1a\x5b\xad\x1b\xfe\xfd\xf5\xda\xba\xa1\xfa\xbe\x37\x23\xfe\x31\x0c\x70\xbb\xb0\x4a\x83\x0c\x45\x8b\x86\x0b\xd2\xde\x4d\xc8\x71\xad\xcc\x45\xb5\x08\xbb\xf0\x9b\xdc\x7d\x34\x42\x8b\x4b\xa5\x28\x00\xb3\xd4\x52\xb8\xc1\x2a\xf5\xe9\xda\xc9\xaf\x96\xfd\x5f\x45\xde\x7f\xff\x57\x05\xd0\x6a\x62\x76\xc7\xb5\xfe\x5d\xfe\x10\xba\xdf\xb0\x75\x0e\x85\x80\x47\x7c\xbb\xee\xff\x76\x95\xd6\x2b\xbe\x5d\xf3\xb7\xab\x58\xe8\x15\x55\xfa\xd7\xa5\x76\x15\x7a\xfe\xb0\x76\x5c\xe7\x42\x59\xf5\xa1\xe8\xef\x03\x6e\xc0\xfe\x3e\x14\xdc\x87\x2c\xee\x9a\x8e\x33\xbd\x1f\x85\xf6\x51\x74\x4a\xd4\x33\xf3\xf0\xae\xc7\x20\x26\x61\x75\x17\x4f\x82\x64\x1d\xea\x0d\x9d\x29\xfa\xfa\xfb\x23\x6c\x1b\x78\xc3\x50\x45\xe8\x31\xd7\xec\x34\xc7\xef\x40\x0d\xa6\x21\x6a\x35\xd6\x40\x12\x7b\x95\xd6\xbb\x89\xd5\xeb\xa3\x5d\x6b\xd9\x59\xd3\xa0\x17\x8a\x31\x24\xc8\xcf\xa1\xbf\x0c\xf5\x82\xd1\x65\x4a\xa9\xd1\x9b\x02\xba\x47\x43\xdb\x7b\x3d\xe8\x45\x32\x03\xa2\x28\xdf\x13\xfb\x94\x9a\xc4\x38\x49\xed\x6d\x65\xa5\x55\x70\x9e\xd5\xb9\x5d\xb2\x88\xa7\xc5\x8d\x9d\x98\x79\x54\x15\x9d\x03\xe0\xf5\x6a\x2d\x42\x6d\xbb\x6a\xb7\xc8\x63\x0c\x1f\x89\x35\x1c\x8b\x3c\x9f\x32\x37\x1d\x63\x64\x0f\x0a\x94\xa7\x65\x8b\xa7\x82\xb7\x76\xe4\x40\x97\xde\x14\x6d\xae\x17\x68\x8c\x02\xc4\x47\xec\x2e\x49\x9c\xca\xaa\x0f\xc7\x68\xff\x65\x39\xe8\xed\x7c\xd0\xcf\x84\x5b\x0d\x3d\x59\xb0\xa6\xc8\xc0\xa7\xcb\x84\x21\x63\xbc\xa7\x45\x6a\x24\xe9\x5d\x9a\xea\x59\x4c\x19\x1f\x49\x7e\x78\x27\x89\x12\x7e\x1e\x75\x29\x59\x43\xb2\xa8\x2e\xf7\x5d\x7e\x95\x8d\xef\xba\x4e\xce\x3d\x06\x8b\x37\x5e\xaf\x8a\x90\x71\xa5\xdf\x1f\xf3\x7a\xda\x05\x07\x70\xae\x94\x87\x5a\xfa\x49\x5e\xdf\xe4\x35\x5b\x8a\xb3\x7f\x91\x7d\x2d\x97\x7d\xb5\x75\x43\xbd\xf4\x07\xe5\x11\xf1\x01\x26\xf9\xa2\xce\xc7\x82\xb0\x13\xb1\x01\xf0\x6a\x21\xba\x38\x9a\x0a\x39\x41\xc8\xd4\xda\x45\x3a\x36\xe5\x45\xf1\xad\x4a\xf9\x29\xc3\x2d\x7d\x37\xba\x48\x27\x83\x5b\xa0\xe8\xf6\x0d\x67\x33\x17\x18\x44\x40\xcf\x10\xc5\xc3\x5b\x6e\x19\x43\x0a\xcc\x61\x9f\x91\x94\x80\x06\x12\xc4\x01\x5f\x79\x82\x78\x3e\xe0\xa7\x08\xe3\x0c\xc8\x25\x99\xdc\xcf\x33\x74\xb9\x08\x7f\x63\x41\x3b\x25\x2a\xe6\x1d\x50\x7c\x48\xe2\x61\x34\x6a\xd4\xa7\xc7\x21\x25\x9f\x88\xdb\x04\x5b\x56\x01\x36\xb9\x8b\x8b\xb2\x68\x0b\xe2\x2c\xe9\x5a\x02\xc6\x5d\x60\x60\xaa\x10\xa0\xe6\x3d\x8f\x98\x42\xd8\x24\xd9\x40\x7b\x8b\x0d\xe8\x24\x17\xb1\x01\x9b\xe4\x36\x56\xb6\x02\x7b\x18\x32\xaf\xa4\x70\x77\x62\xb2\x92\xf9\x60\x45\xee\xaa\x9a\x6f\xef\x8e\x0e\x56\xd7\xc6\x12\x31\x03\x31\x79\x2f\x1e\x4e\x45\x24\xdf\xe4\x70\x60\x26\x68\xf9\x19\xda\xe3\xb1\x11\xba\x5e\xaa\x4b\x8e\x97\x4c\x4d\xab\x2f\xed\x91\x9a\x13\xf4\xc6\x9f\x11\x17\x0d\x6d\x5a\x86\xdd\x64\xa0\xbf\xca\x3c\x09\xbd\xf1\xc0\x4c\x88\xf1\xae\x2c\x30\x08\xdc\x41\xb5\xb7\xf8\xe2\xa2\x59\xe0\x65\x35\xb9\x14\x9d\xef\xa0\xfa\xbb\xbd\x9e\xba\xdd\xd1\xad\x30\x8a\x60\xf0\x3e\xb2\x2b\x2b\x10\xf5\x37\x22\x8b\xa8\x9c\x2e\x81\x1a\xb5\x81\xeb\xfd\x86\x06\xe6\xd5\x5f\xea\x0a\x1a\xdf\xd3\x93\x9d\xaf\x76\x99\x91\x82\xbe\x0f\x3a\x76\x5e\x97\x24\xf1\x1b\xb7\x6d\x4f\x4b\xf4\x38\xf2\xc9\x85\x2f\x2e\x3e\x1d\xee\xed\x9f\x5e\x1c\x1c\xfe\xe5\xf4\xf8\xf8\xdd\xc9\xc5\x9f\xdf\x1d\xbf\xdd\x7b\x77\xf1\xf3\xf1\xf1\xbf\x5d\x5c\x78\x83\x15\xaf\xae\x22\x50\xd1\xd6\xd6\x5a\xc5\x84\x49\x3d\x0d\xb2\x88\xf5\x13\x26\x59\xc6\xfa\x71\x90\x2c\x62\xef\x19\x99\x94\xb1\x85\xfb\x93\xeb\x98\x55\xa5\xe6\x71\x87\xc7\x93\x9b\xd8\x40\xb9\xc9\xfe\x63\x34\x3a\x95\x11\x96\xd3\x60\x67\x30\x7c\x3e\x78\x1e\x68\xb1\xb1\x4e\x1d\xf6\xae\x76\x30\x27\xdf\xbd\x5c\x65\x80\xb0\xca\x03\x83\x37\xd8\x96\x79\x8a\x27\xaf\x3b\x07\xc6\xdd\x3c\x27\xaf\xbf\x8b\x57\x9c\xe0\xc9\xeb\xd7\xb1\x7d\x7e\x27\xaf\xbf\x8f\xbd\xa7\x77\xf2\xba\xfb\x2c\x9e\xc3\xc9\xf7\x3b\xb1\xf7\x10\x4e\xbe\x7f\x1e\xf7\x1e\xc1\xc9\x0f\x5d\xa6\x0a\x5a\xf1\xc3\x77\x76\x5a\x77\xfc\x27\x3f\xbc\x8a\xfb\x4e\xec\x64\xb8\xd3\xd9\x1c\x9b\x07\x36\x64\xbd\xec\x31\x47\xb6\x8f\x6b\x48\xef\xc0\x40\xa7\x75\x32\x1c\x0e\xe3\x7e\x4e\x8e\xf7\xac\x86\xcc\x0e\x3e\xe6\x51\x9d\x0c\x9f\x53\x73\xda\x91\x0c\x57\x5a\x82\x5e\x77\x22\x27\xc3\xef\xf1\x92\xfb\x7a\xb5\x0e\xb0\x46\xfe\x31\xb8\xf0\xa2\xac\x13\x05\xb5\x87\x4c\xa9\xdc\xeb\x5d\x41\x41\x62\x04\x07\xc6\x63\x56\x53\xb9\x4c\x1d\x8a\x06\xff\x01\x2e\xaa\xea\x73\x47\x07\x82\x83\x82\x6e\xd7\xb1\xa1\xa3\x03\x76\xd0\x95\xd4\x4a\x29\xd6\x29\xe0\x63\x02\xf8\x86\x92\xfc\xf0\xba\x67\xfe\x5c\x92\x79\x7d\xed\x3d\x35\xc0\x27\xee\xf0\xc2\x3e\x21\x9e\x44\xe4\x6a\x69\x72\x9e\x4e\xb7\xb7\xe3\xd9\x19\x3e\x92\x89\x99\x7c\x36\xdc\x11\xd9\x0c\x99\xaa\x47\x4f\xaa\x58\x65\x8b\xa9\x53\xdd\x3a\x93\x89\x84\x03\x1d\xd1\x2d\xd5\x68\xde\xe7\x38\x4c\x4d\x38\x61\xd3\x83\xe3\xde\xb8\x50\xc2\xc1\xd0\xe6\x10\xa8\xe6\x1d\x8c\x71\x2e\x4d\xe4\x83\x4b\xf8\x1b\x68\x46\xf2\x32\xf2\x51\x67\x28\x1f\x10\x57\x27\xf0\xd8\xca\x07\x9a\xb7\x78\xd8\x1d\x76\x11\xb6\x77\xd6\x0b\x91\x70\xd5\x2e\x26\xac\xe8\xf5\x72\xec\x60\x3b\xb0\x8d\xea\x03\xa1\xc1\x00\xdb\x7e\x19\x28\xeb\x7a\x48\x5d\xdc\x05\xd2\xbe\x3e\x00\xd4\x1a\xd8\x06\xf6\xc1\xe4\x72\xd6\x8d\x82\xcc\xec\x03\xd4\x4b\x08\x74\x43\x7b\x4a\x91\xc3\xe8\xac\xed\x45\x32\x79\x62\xd0\x8d\xee\x39\xfd\xf7\xa2\x0d\x4c\xd3\x7b\x4a\x17\x5e\x21\x74\x0b\x7c\x4a\xaf\x6e\xb4\x66\x04\x7c\x30\xbd\x03\x0c\x99\xe3\x43\x5a\xb5\x08\x3a\x13\xfc\x40\x88\x3a\x95\x15\xbe\x08\x20\xa5\x1b\xe2\x07\x5f\xf2\x3b\x54\xbb\x08\x0c\x6b\x7c\x4c\x5d\xe0\x53\xd0\xd9\xe4\x63\xda\x92\x9b\xef\x2c\xf1\xd9\xe3\x84\x6a\xa0\x33\xc8\xe7\x0c\x64\x48\x07\x86\x5d\x3e\xa7\x57\xa2\x17\x9d\x75\xbe\x48\x97\x03\x95\x46\xfa\x9c\x2c\x3e\xcb\x96\xfa\xc1\x02\x7f\x02\xcd\x3c\x3f\x60\xa1\x7f\xe0\x33\xd1\x0f\x1a\x99\xa0\xad\xd0\xce\x40\x9f\xfc\xd2\x1f\x29\xa8\xe8\x76\xfa\x41\x8b\x2f\x63\x7a\x09\x0c\x83\x7d\xce\x91\x73\xde\x99\xed\x73\xba\x1a\xb3\x66\xbd\xcf\x39\xdd\x74\xb1\x15\x7f\x70\x8b\x3f\x01\x86\xdf\x0f\x2e\xc8\x81\xab\xe2\x2f\x1f\x1d\x04\xdb\x4c\x34\x86\xef\xb3\xf6\x7a\x50\xc3\x81\x56\xcd\x01\xc9\xb2\x75\x54\xf8\x1c\xef\x9b\xcb\x10\x7d\xc2\xc6\xf7\x1d\x26\x50\x36\xa9\x9a\x8a\x77\xd1\x59\x1e\x7b\x0a\x1a\x06\x9b\xe8\x90\x8f\x8f\xce\x53\xc1\x0e\x0e\xe7\x83\x6b\x23\x01\xbe\x3b\x70\x9b\x21\x6d\x71\xb4\xe3\x29\x59\x99\x47\x6f\xd5\x57\x7e\x6b\xcb\x97\x3a\xe8\x5a\x20\x36\x0f\x6a\x9a\x5b\xed\x29\x21\x5d\xb8\xe9\x6b\xe1\xe1\xc1\x9b\x3c\x50\x2d\x85\x68\x89\xca\xce\x0b\x4e\xab\x1e\x77\xfb\x55\xda\xa2\xbd\x5c\x58\x21\x2a\x2d\x9e\x32\xc7\x23\xcd\x3d\x93\x7b\x3e\x03\x64\xb9\xe8\x6c\x6e\x17\x6f\x66\xe4\xa7\x5f\x28\xd0\x35\xe8\xb7\x3f\xb3\xcd\x81\xa6\xd1\xd6\x56\x76\x36\x45\x23\xe5\x29\xc6\x47\x18\xc8\x55\xb2\x3b\x0e\xc5\x3a\x89\x76\xbd\x63\x73\x44\x28\x5d\xdd\x58\xd4\x8c\xab\x28\x81\x66\x68\x2f\xfd\xf1\xb6\xb4\xea\xd8\xe0\xd7\x37\x80\x0e\xcb\xb1\x8d\x13\xb1\x5d\xa1\x11\x35\x56\x4e\xc3\xc1\xca\xcd\xbc\xb9\xb3\xa2\x93\x22\xf4\x8c\xfe\x11\x6e\x21\x56\xf5\xbf\xae\x8b\x76\x6d\x6f\xd5\x5f\x8e\x3e\x1c\x1c\xff\x72\xf1\xf3\xde\x87\x83\x77\x87\x5a\xe7\x09\xdd\x3e\x3c\xa8\x77\x3c\x23\x77\x43\x18\x8b\x40\xc0\x38\x94\xf0\x6b\xc6\xc2\xc1\x0b\x65\xf5\xca\xbf\xe9\xfa\x2a\x53\xcc\x1d\x71\x42\x57\x11\xcd\x3c\x35\x84\xc4\x01\xfa\xbc\x5b\x1f\x28\x7a\x37\xa0\xf6\xca\x8e\xb8\xb5\xb9\x1f\x54\x99\xf0\x7d\x85\x8e\xe1\xcf\x54\x16\x7a\x84\x97\xef\xf4\x21\x4c\x88\x92\x6b\xdf\xce\x58\xef\xab\xd3\xf8\x1a\x76\x10\x71\xaf\xe1\x97\x4c\x34\x1f\xe3\x95\xc2\x49\xcd\x67\xc9\x7a\x9f\x90\xfc\x78\x07\xf4\x5f\xdd\xac\x39\x71\xb2\xdd\xbc\x44\x36\x18\x2f\x46\x12\xaf\xbf\xaf\xca\x02\x6e\x39\xc8\x88\xd0\x90\x60\x31\x0d\x37\x17\xd2\x6a\x1e\x23\x33\x4f\xe1\xb0\xbe\xd6\xaa\x35\x23\xef\x87\xe7\xdc\x9a\x56\x10\x05\x56\x40\xe1\x61\xd4\xe8\x5e\x4b\xe0\xea\xeb\xfd\x38\x54\x6b\xf9\x71\xa8\x06\xda\x9b\xe1\x8b\xa1\x32\x94\xfb\x2d\x87\x0b\xd5\xc0\x4c\xf0\x39\x56\x90\x65\xf4\x44\xb8\x9d\x77\x37\x8b\xf9\x1f\x8d\xe3\xe8\xf5\x1a\xd0\x7f\x01\x77\x29\xf4\xe4\x07\xca\xb5\xe9\xf3\x64\xf8\xe2\x87\xde\x68\x8e\x78\x89\xf9\x3a\x87\xdb\x74\xaf\x12\x2c\x51\x29\x28\x95\xa1\xf9\x44\xb2\x20\x92\xd3\xd6\xb1\xe7\xef\xec\x8d\xf2\x51\x65\xb7\x22\x24\x56\x56\x2b\x1c\x29\xd3\xb2\x87\xaf\x0c\xa1\xab\x54\xad\x10\x4e\xa3\x35\x59\x0c\xf9\x40\x1e\x2d\xc8\x84\xa9\xd0\x24\x2f\x61\xe1\x33\xfb\xa1\x31\xcc\x33\xf4\xd5\x04\x97\x74\x39\x28\x48\x50\xe3\x6c\x55\x92\x1c\x63\xe9\xd8\x6b\x6a\x63\x84\xfb\x56\xd5\x35\x08\x87\xff\xa6\x13\x71\xa2\xe4\x38\x15\xd2\x95\x40\xa5\x7f\x4e\x02\xa4\xfb\x9c\x08\x4a\x8a\x9e\x0c\x9a\x47\x4f\x50\xed\x3e\xa0\xa0\xff\x76\xb8\x14\x16\x1a\x64\x6a\xaa\xa1\xe2\x61\xa1\xed\x0d\x62\xb8\x42\x81\xa8\x8a\x74\xab\xc1\x65\x68\xf8\x5a\xb7\x4c\x77\xb4\x56\x96\x64\x44\x64\x98\xf1\x98\x21\xfd\x85\x0c\x45\x5a\x06\xed\xa1\x6e\xa3\x92\x08\x4d\x1d\x47\xe7\xb3\x81\x23\xfa\x42\x69\x0a\x24\xbb\xd2\xaf\xd1\xcc\x8a\x1f\x1f\x4f\xb1\x01\x23\xad\x88\xaf\x59\x3c\x30\x49\xef\x15\x8f\x3f\x46\xbe\x7f\x23\x38\xfc\x63\x9d\x51\x30\xe1\xed\xec\x09\x30\xef\x1b\x40\x32\xfc\xfe\x7b\x8f\x2f\xe2\xd7\x6b\x58\x8f\x78\x05\x54\x3a\x53\x45\x8a\xb2\x2a\x6f\x70\xe6\xc2\x7f\x07\xf7\x2a\xd6\x38\x8e\xec\x96\x69\x13\xde\xbf\x3f\xfe\xfc\xe1\xf4\xf0\x80\x49\xfc\xcf\x1f\xf4\x57\x0c\xd9\x87\xb7\x75\xe5\x7c\x88\xd5\xe5\x3d\x3e\x88\x34\x1e\xa2\x41\xac\x67\xe1\xe6\x98\xa6\x7e\x40\x1c\xfc\x23\x54\x51\x44\x55\x15\xe2\xdf\xc3\x32\x91\xac\xfd\xa3\x03\xf4\xf4\xaa\xb5\x12\x4f\x07\x6f\xb3\xf1\x17\xa0\x8c\x8f\x0e\x3a\x9e\x26\x54\xf0\xa4\x62\x27\xf1\xc0\x79\x57\x4c\xf3\xfd\xbb\xf1\x2c\x4f\x96\xb1\xa7\x18\x8f\x50\xa8\x3c\x2a\x46\x93\x87\x17\x25\xb4\x74\x64\x6b\xc8\xf6\xce\x89\x14\x13\xb0\xa1\xab\x09\xee\x64\x3b\xc0\x56\xa7\x3f\x30\xb8\x40\xa2\x1e\x96\x82\x98\x53\x11\x2e\xf0\x42\x58\x66\x8b\x54\x56\x43\x12\xfe\x72\xa9\xc1\xb0\xc0\x3b\x58\xc9\x4a\x5f\xa8\xb5\x80\xca\x02\x7a\x81\xa7\x75\xa1\xe2\x2c\xdc\x41\xa7\x98\xf4\x3d\x02\x2e\xdc\x30\xd0\x3d\xb0\xaf\x5f\x80\x34\xc7\x33\x94\x3b\xa3\x98\x47\xeb\xc6\xfa\x63\xc0\x4e\xc2\x81\xce\x5e\x7b\x78\x5d\x72\x10\x67\xec\xf9\x85\x04\xd4\x11\x72\x2e\xca\x6c\xe6\x01\x58\xfd\xd5\x00\x5b\x73\x0c\x80\xfa\x11\x98\xb5\x02\xe6\x8a\x8e\x2a\x79\x97\xb1\x7a\x3b\x85\x5e\xa9\x3c\x2c\x80\x48\xee\x45\xd1\x92\x9b\x1e\x62\xef\x82\x59\x0e\xd4\x66\x32\x41\xbf\x0f\xd8\xfd\x12\x96\xa7\x34\x1e\xf7\x8c\x53\x9e\x41\xce\x48\x49\xa5\xde\x14\x86\xf9\xbc\x57\xf9\x15\xe4\xaa\xd4\xf7\x2d\xa4\xf6\x3c\x2a\x41\xde\xa2\x3c\xde\x51\x8d\xa8\xb5\x93\xc6\x35\x9f\xf2\xe9\x29\x33\x70\xe3\x0a\xce\xdb\x47\x9b\x07\xab\x86\xe3\x80\xc8\x04\x50\xb7\x5a\x51\x97\xc8\x96\xfa\x19\x8e\x3c\x7a\x74\x00\xf3\xfe\x21\xf2\xf8\x72\x74\xe1\x2f\xc2\xbc\x19\x03\x40\xfc\x23\xa2\x8f\xeb\x93\x0c\xe7\x88\xcb\x52\x8e\x9d\x01\x6a\x33\xd9\xbf\x0c\x70\x27\x8f\xf3\x42\xfb\xf2\x1a\xbb\xd9\xbb\x0e\x44\x17\x01\xb5\xa1\xfa\x2f\x2f\xe6\xa3\xe9\x87\x1c\x8d\xca\xb2\x1a\x7d\x08\x3c\xc6\x7d\x99\x89\xe5\x0c\x8f\xe1\xe2\xfb\x8c\xae\x8c\xe3\x6c\x7b\x3f\x9e\x1b\x79\x57\x73\x19\x6b\x3b\xa9\xf4\xec\xa4\xd2\xdc\x49\x9e\x55\xcf\x39\xcc\x91\x55\xe0\x63\x65\xaa\xc7\xd8\x4a\x5e\x81\x95\x2d\x74\x12\xca\x0f\x6f\x02\xc2\x14\x8f\x0f\x0f\x48\x2e\x4e\x29\x05\x7e\x65\xd8\x89\x4d\x7e\x7d\x7a\xf9\x50\xb1\xb8\x55\xeb\x87\x2b\x97\xb2\x72\xef\xce\xa1\x12\xb1\xec\x10\xf2\x95\xcc\xe5\x2f\x8f\x4d\x67\xbf\x33\x12\xad\xf8\x7e\xf6\x29\x07\x54\x36\x2e\x66\x39\x59\x0b\x66\xca\x42\x5b\x50\x7f\x18\xe9\x41\x2c\x8c\x50\xdb\x73\xce\x47\x62\xb9\x13\x80\x80\x46\x2d\xb2\x15\x8d\x4b\xba\xb1\x46\x7c\xbf\x56\x97\x35\xef\x03\x44\x55\x1b\x75\xc8\x1d\xca\x0e\x12\xef\x15\x5f\x01\xe2\x02\x09\xe7\x7c\xf2\xf6\xce\xa7\x57\xad\xaf\xa2\x54\x78\x32\x3c\x29\x2e\x91\xe8\x7b\x7b\x07\xd0\xf5\x38\x4d\xd2\xaa\x28\x3d\x41\xd4\x0d\x03\xf0\x37\xbb\xfc\x73\x96\x73\x40\x35\x53\x83\x74\xca\x34\xe1\x8a\xbb\x99\x47\xbe\x28\x64\x99\xc3\xe1\x4e\x6f\x18\x7e\x53\xbe\x14\x07\x1e\x7f\xaa\xaf\xd7\xf6\x5b\x2f\xc5\xa3\x3a\xe5\x63\x8b\xe9\x48\x82\x4f\x1a\xf1\xcd\x72\x6e\x91\x96\x52\x86\x57\xb8\x1a\x45\xba\xa0\xc8\xb7\x14\x3a\x22\x13\x26\x41\xc5\xf4\x17\x40\x39\x2a\xf1\x2e\x93\x15\x4c\xcc\x7a\xed\x5a\x28\xa9\x41\x6f\x02\x50\xe8\xe7\xd3\xf7\xef\x48\x64\x34\x04\xf2\xf1\x07\x24\x3a\x7b\xbf\x9b\x64\x7e\x72\x2f\xee\x23\x2e\x8d\x45\x81\x4c\x83\x1a\xa8\xd2\x03\xe2\x11\xbb\x64\x6a\x52\x58\xda\x44\x9d\x26\x8c\x50\xcc\xd6\xe4\xe7\xc4\xd5\xb4\x1a\x08\x62\x7b\xc7\x02\xd6\x5d\xa2\x87\x9a\xb0\xa5\x20\x2c\xa7\x1c\x51\x75\x06\x34\x8f\xfe\xbe\x40\x11\xa8\x08\x4c\x33\xce\xca\x4f\x39\x19\xf2\x51\x68\xd3\x9c\x42\x35\x48\xdf\x36\xa3\xa5\xd6\xd0\x26\x56\x7c\x74\x52\xe2\x31\x46\xf0\x8d\x1e\x23\xcf\x82\xf6\x2e\x99\xe4\x7b\x4d\x9c\x6d\x2e\x98\x64\xb8\xf3\xdd\x2a\x51\xb7\x2b\xd2\xf6\xae\x16\x28\xf1\x3a\x7e\x7a\xb1\x24\x43\xd6\x49\x70\x77\x89\xb1\x54\xe0\xca\x85\xb6\x6b\xaf\xbf\xc6\xc6\x41\xf9\xe9\x91\x88\x5f\xf3\xb3\x43\x28\x41\x73\xc7\x6a\xbd\x92\x07\x8d\x59\x46\x96\x86\xbb\xc1\x06\xc1\x86\x4c\x67\x84\x6d\x0d\x5b\xc8\x6e\x54\xd3\x8d\xdf\x82\xed\xde\x9a\xdb\xc1\x6f\x83\x20\x09\x02\x8f\x03\x44\xc3\xe9\x9c\xc7\x7f\x18\x7a\x94\xbb\x0d\x3d\x9a\x2f\xe8\x1a\xc9\x66\x9c\xc8\x43\xf0\xc8\x0d\xba\xb2\x7b\x74\xd6\x8a\xe8\x91\xef\x7c\x01\x8f\x6e\xc3\x12\xd6\xe2\x87\x01\x9a\xf5\x7f\x42\x17\x02\x6f\xf7\x4e\x0e\x51\x13\x77\x45\xd9\x83\xc3\x9f\x8e\x3e\x1c\x5e\xbc\xdf\xfb\xf0\x57\x00\xaa\x9d\x74\xf1\xfe\xf0\xd3\x9f\x0f\x0f\x6c\xf3\x3b\x35\x19\x52\x02\x9b\xbf\x33\x28\xa9\xd1\x2d\x85\x14\x55\xa4\x11\xec\x16\x68\x79\x8f\x49\xc8\xa3\x0f\x7f\x8e\xe2\x5b\xc1\x04\xb9\x96\x0e\xb0\x30\xa9\xdd\xc4\x42\x82\x06\xc3\x62\x16\xe3\x86\x36\x18\xfc\xbd\x0d\x37\xaf\xa4\x36\x92\x54\x28\xc4\xa0\xe2\x90\x3e\xb1\xb4\x94\x94\x8b\xa6\x92\xaf\x05\x2c\xd0\x1f\x39\x53\x74\x02\x20\xf9\x32\x98\xe3\x85\x93\x38\x35\xe2\x31\x1a\x59\x73\x4b\x1a\xee\x9e\xe9\x45\xaa\xe4\x44\xd1\xe3\x42\x73\x1f\xb9\x1b\x40\x55\x7c\xf1\x78\x20\xfc\xc2\x4e\xb1\x0a\x23\x26\x97\x33\xe5\x35\x07\xba\x70\x53\x97\x69\xb1\xb5\x55\x0c\x2e\x58\x74\x78\x00\x1b\xf0\x6d\x51\x4e\x00\xfb\x7a\x16\x59\x01\x08\x79\x81\xa6\x17\xf0\xbf\x81\xff\x4b\xec\xda\x34\x2a\x65\xed\xbd\x65\x5b\x61\xed\xf7\xd9\x82\xf4\xa0\xdd\x64\xd2\x69\xf0\x65\xa0\x47\xc4\x82\x3c\x7b\xa5\x85\x8a\x95\x25\x9c\x95\x5e\xa7\x47\x08\x86\xdb\x10\xbe\x4b\x31\x71\x7c\x0b\xeb\xe1\xc1\xc9\x89\x38\x10\x83\xaf\xf4\x2e\x7d\x69\x1c\xe2\x0f\x5a\x63\x39\xe5\x90\xfe\xc3\x22\x33\x59\x24\x62\x27\x63\xdc\xc3\xc7\x47\x9b\x1f\x27\x16\x94\xe5\xff\x4f\x5e\x75\xd1\x33\x93\x6f\xbe\x4b\xe5\x40\x92\x2a\x7c\x81\x31\x6e\x56\x91\xe4\x6c\x92\xe3\x49\x4c\x2a\x60\xe7\x21\x17\xb0\xd6\x3f\xbb\x34\x42\x22\xc2\x36\x01\x5c\xb5\xb5\x15\x54\x44\xa7\x74\x73\x96\x7b\xd2\x60\x8b\x1c\xc3\xc1\xa0\x30\x26\xa1\x9e\xdb\x90\x2d\x11\x91\xa0\x42\x9f\xaf\xfc\xc9\x16\xe6\x2b\x37\xf8\x7f\xda\x47\x2d\xd7\xbb\xb8\x31\xb2\xc5\x62\x76\xc7\xa4\xad\xb2\x3e\x41\x3a\xa4\xf5\xe7\x8c\x8c\x88\x8e\xe5\x2e\xcb\x9c\xd3\xb4\xde\x2d\x93\x25\xad\xf9\x47\xc3\xcb\x9a\xff\xe3\x7d\x9f\xed\xf9\xe8\xe3\x23\xbb\x29\xf6\xab\xa3\x4f\xbd\xda\xe6\xd7\xfd\xda\xe6\x13\x2f\x33\x6f\xbe\xb6\xb6\xb9\xad\x5c\x65\x2a\x7c\x93\x55\x91\xd4\xac\xbf\x5a\xa1\x39\x7e\xe7\xe1\x1e\x1e\xba\xe4\xdc\xbe\xad\x20\x8e\x67\xf3\x34\xaf\xa9\xfc\xa5\x47\x7b\xfc\x5d\x35\x56\xf4\xe4\xef\xfa\xa0\xec\x02\x64\x7e\x6f\x8c\x4c\x31\x2c\x95\x6a\xb8\xcd\xb1\xbc\x90\x14\x21\x49\x4e\x0a\x28\xed\xcc\xc7\xad\x4b\x34\xbe\x77\x99\x9a\xa7\x66\x50\x9f\x63\xd1\x51\x21\xaa\xda\x07\xa2\xe8\x73\x93\xcb\xce\xcd\xb3\x05\x77\x04\x7b\xf6\x51\x50\xa0\x64\xf6\xca\x3d\x76\xfa\x70\xe2\x30\xaa\x4f\xc3\x7b\xc6\xeb\x82\x65\x1a\xc5\x1f\xd2\xf7\xe1\xbd\xc0\x20\xc7\x1f\xf6\x0f\x99\xf1\xa8\xa1\x14\x4e\x30\x4e\x54\xa7\x8c\x40\x4f\x92\x0f\x7b\x80\xd6\x26\x47\xa9\xfc\x94\x81\xa1\xd0\x5b\x04\x46\x6b\xb2\x52\x3b\xab\x6e\x33\x5d\xa8\x2f\x79\xb3\x90\xa1\xbd\xdf\x9f\xdf\xc5\x13\x64\x66\xa4\x0f\xa1\xb2\x2f\x79\x52\x85\xa7\x73\xbb\xb7\xd0\xbe\xf6\x31\x7f\x21\xa1\x65\xae\xf2\x10\x98\xa6\x01\x26\x2b\xd1\xda\xe3\x13\x05\x0e\x8a\xc9\xca\x7c\x6c\xe0\x13\x73\x64\x3c\xc3\x89\x79\x1d\xa8\xc9\x17\x0a\x62\x2b\x3a\x63\x97\x70\x7a\xb3\xba\x80\x6e\x50\x6a\x16\xb1\xf9\x1b\x16\x35\xf6\x18\x7f\x49\xef\x35\xaa\xd2\xe2\x7f\xe4\x3a\xc5\x09\x68\x3c\x16\x6b\xc8\x2c\x65\x1e\x5a\xe9\xce\xa8\x54\xfe\x38\x47\xe5\xf6\x76\x44\xc4\x12\x9e\x06\x8f\x9e\x55\x62\xd9\xbd\x13\x0d\x7b\x39\xd0\xcb\x21\xc5\xe8\xd4\x4b\x3f\x21\x83\xd6\x93\x21\x79\xb2\x4f\x7e\x41\x6b\xdc\xd7\xae\xdd\xa4\xbd\x7e\x6d\x40\x59\xf9\xa9\x93\xb2\x0b\xc7\x9e\x9d\x06\x55\x93\xf6\x51\xdb\x6e\xfe\xbe\x62\xbe\x34\x29\x37\x7a\xa9\x12\xa8\x8b\x72\x2f\x9b\x8d\x34\x92\xd5\xb5\x87\xb8\x45\xd2\xb2\x86\xcc\x46\xbd\x7f\x3a\xdc\x3f\x3c\xfa\x0b\xbc\x92\xb7\xb0\x13\x89\x41\xde\xa5\xf7\x1e\x2e\x37\xba\xf2\x23\x91\x48\x77\x45\xe9\x39\x42\xef\xd6\x2c\x47\xec\x95\x86\x78\x9f\x1a\x57\x54\xb0\xf4\x4e\xac\xf4\xb1\x14\xa7\x6a\x9c\x70\x3f\xf9\x2f\x78\xdf\xab\xe4\x36\x72\x24\xaa\x0c\x0b\x52\xb1\x59\xa0\xa6\x57\xb6\xbe\xa9\xdf\x24\x1c\x0e\xfb\xa1\x8f\x03\x60\x6a\xb6\x8b\x8b\xbf\x96\x60\x5f\xfa\x65\xef\xcc\x72\x5d\x17\xa5\xc5\xe6\x6a\x28\x74\xbd\x14\x05\x1d\xfa\x59\x8e\x14\xdd\x96\xa9\x64\xba\x8d\x36\x61\x64\x42\x5d\x4c\x0d\x07\x52\x10\xfb\x2f\xf4\x33\xfe\xd5\x4e\xd3\x38\xb9\x46\x75\x4d\x6e\x44\xb9\xc6\x42\x90\x16\xf8\xfa\xb9\xb0\xeb\x4b\x0c\xd9\xd9\x2d\xdc\xba\x5c\x52\x55\x35\x07\xf7\x0d\xcb\x65\xae\xca\xb2\x19\xe6\xf6\x7a\x93\xe9\x3f\x55\xf5\x58\x08\x81\x50\xc0\x29\xa0\x62\x1f\x2c\xc8\xa1\xf1\xe7\x84\xbe\xef\xc8\xe2\xda\x98\x8d\xfc\xbe\xae\xa9\x4e\xf3\x79\x97\x77\x67\x4e\x7a\x11\xea\x39\xd2\x7d\x56\x57\x40\xf5\xc3\x9a\x2f\x84\xd9\x53\x4b\x89\xee\xfc\xba\x04\xce\xf9\xbc\xcb\x9a\x85\x15\xba\x3d\xec\xcc\xab\x0d\xe0\xc8\xe3\x16\x39\x25\x92\xa7\x43\x09\xf0\x34\xb9\x0b\x23\x29\x7b\x0b\xfd\xd5\xa8\xb7\xa8\x7b\x10\xad\x94\xfc\x3c\xb5\x3d\x3a\x6c\xe8\x99\x55\x71\xbc\x8a\x2d\xe2\xcb\x0a\xd7\x81\x5a\xdf\x74\x39\x86\x6a\x61\xff\xcc\xb2\x44\x5d\xe0\x04\xbb\x9e\x86\xb8\x48\xd8\xcc\x84\x94\x79\x24\x78\xb6\x48\xae\x3c\x2e\x89\xef\x0a\xc9\x31\x6f\x2d\x3a\x6e\xdc\x25\x28\x24\xad\xb4\x68\x2d\x89\xb3\xef\xb3\xec\xc4\xc2\xbb\xcd\xf2\xd5\xa0\x33\x70\xec\xd6\xd6\xef\xbd\x42\x63\x13\x21\x79\x38\xf8\xec\x4d\x2e\x95\xb8\x4c\x71\xd6\xf4\xf3\x9e\xe3\x6e\xdf\xb7\xe9\xfd\xa3\xc9\x6f\x29\x23\x64\xa5\x50\x9c\x86\xce\x89\x41\xf7\x51\x9d\x28\xd5\xbf\xac\x0b\x0f\x2c\xe2\x55\x2c\x27\x2b\x35\x14\x5e\x46\x7a\x58\x7f\x0f\x0f\xbd\x67\xc9\xa3\xe4\x48\xf9\x71\xa0\x31\x62\x9b\x72\x8a\xec\xc0\x03\xb7\x21\x3f\xac\x51\x53\x40\x83\xc9\x12\x9c\x0a\xa9\x4b\xd4\x81\xc7\x26\x9b\x3a\xff\x36\x50\x86\x1c\xd8\x7c\xf4\x92\x41\x96\xc8\xa7\x07\x26\xaa\xef\x45\x7f\xa4\x8d\x22\x92\x2e\x08\xf2\xb3\xe2\x1c\x23\x10\xc7\x15\x29\x47\x4d\xc3\x4c\xf7\x16\x40\xb7\x65\x74\x0c\xc6\xbb\xe8\x71\x4d\x81\xa8\x21\xf1\xec\x61\x44\xe2\xf4\x58\x8b\x99\xdf\x2d\xca\xab\x93\x1c\x7a\x15\x1c\x3c\x79\xfa\x86\xf4\x1c\x55\x91\x21\xcc\x14\xab\x3d\x16\xe8\x9b\xa5\xaa\x7e\x19\xff\xa8\xbf\x1f\xd0\xc9\xca\x9b\xd1\x49\x78\x4d\xfa\xa0\xd2\x88\x81\xda\x47\x03\x54\x06\x01\xd0\x2f\xcc\x5d\x81\xc4\x2d\x40\x7a\x30\xb9\x7e\x6f\xf3\xa1\x73\x3d\x3f\x44\x19\xe6\xda\xa7\x61\xd1\x3f\x25\x84\x23\x47\x3d\xa7\xf8\x88\x57\x65\xdf\xdc\x3d\x3c\xb0\x56\x86\xf7\x56\x29\xdb\xf7\xe5\xa1\x1e\x0b\x6a\xec\x65\xbb\xe1\x93\x24\xcc\x85\x58\xe3\x76\x13\x15\xf9\xde\x46\x37\x28\x51\xe2\x25\xf0\x30\x06\x4d\x47\xd8\xd5\x3a\xed\x56\x58\x94\xba\x21\xb8\xaf\xa4\xb8\x1a\xa3\x67\xf9\x3f\xee\x08\x7f\xe3\x95\x3a\x26\x71\xa6\x2f\x67\x41\x64\xf2\xe1\xb4\x34\xd6\xfd\xc8\x73\x86\xd3\x07\xbd\xa7\xbb\x38\x63\x48\xf8\xbc\x52\xe5\x46\x90\xb6\xc6\x35\xc6\x84\x40\xbd\x42\x09\xc8\x56\x50\x40\x75\x98\xd8\xa1\x77\x64\x3f\xab\xaf\xa4\x93\xb8\x1e\x3b\x24\xe6\x6b\x57\xdc\xc4\x4b\xfe\x40\xf4\xa4\x76\x09\x45\x5b\xf6\x0d\xbd\xf3\xd3\x28\x26\x13\x5d\xec\x33\x61\x62\x37\x69\x5e\x57\x22\x57\xf5\x62\xad\xab\x92\x55\xc9\xbc\x2b\x75\x37\x25\xab\x98\xf5\xed\x91\xae\xd7\xe1\xd0\x57\x31\x29\x95\x58\x4b\xab\x4a\x9f\xa2\xa6\x11\xb7\x7f\x0c\x71\x89\x46\xee\xe0\xd1\xab\x8e\x26\x5b\x91\xeb\xb7\x53\x03\x42\x33\x1f\xfd\x7d\xe4\x52\x76\x2b\x28\xc2\x8b\xb0\x5a\x41\xcc\x8f\x58\x51\x78\x4d\x4a\xbd\x50\x5a\x4c\x9d\x4e\x15\x12\xee\x0b\x9f\xfe\xe4\x60\x82\x96\x6c\x75\xb5\x6c\x66\x77\x42\x83\x0e\xfb\xff\x4b\xd1\x5e\xb3\xe4\x17\x5d\x3e\x84\xb0\xd6\x30\x94\x28\x3a\xc8\x90\x78\xe7\xab\x4f\xce\x5b\x47\xc1\xc9\x27\xc5\xb3\x45\x76\xd2\x81\xa7\x26\xd7\xeb\xc7\x84\x3b\xb1\x97\xb0\x44\xd9\x7e\xef\xbc\xaf\xb7\x6a\x7b\xab\x6b\xeb\x57\xd8\x50\xc4\x6d\x3a\x95\x9d\x1d\xa9\x27\xeb\x3c\xd5\x69\xc5\x27\x2e\xdd\xd7\x46\x13\xa3\xb6\xbe\xbb\x17\x17\x4c\xee\x53\xc8\x6a\x46\x28\xb0\xe1\x10\x48\x9b\xc3\xdd\x30\x4f\xe7\x88\x5f\x4c\xa1\x42\x18\x91\x0b\x14\x8e\x00\xfb\xa4\x71\x35\x9a\x3c\xe1\x42\x5b\xb3\xf8\xe3\xb4\x28\x61\x8f\xde\xdd\x6b\x43\xd6\xfa\x4e\x1c\x1c\x25\xa5\x72\xa4\xaa\x78\x79\xcf\x61\x81\xf9\x38\x17\xfa\x0d\xd0\x88\xde\xd5\xc3\x04\x21\x99\xaa\x3f\xcb\x0d\xf6\x65\xae\x5d\x57\x20\x99\x9f\xd3\x59\x43\xb1\xf2\x7a\x58\x2b\xe1\xcd\xe0\x6a\x99\xd5\x68\x78\xb0\x8a\xc0\xdd\x0e\x06\xc1\x36\x05\xee\xf0\x8d\xb2\x67\x3b\x51\xcc\x20\xc6\xf9\x9d\x94\x0c\x5a\xf8\x9c\x6a\x40\x79\x1c\x7d\x0a\x3f\x77\xc2\x68\x79\xb3\x94\x5c\xbb\x78\x5f\xfc\xbe\x63\x44\xf2\xbf\xd3\xfb\x4e\x5b\x7a\x2f\x7e\x9b\x35\x79\xf2\xd9\xf0\x45\xe3\xf6\xc5\xf8\x9a\x66\xc9\x9e\xa2\x4b\xaf\xcf\xb1\x6e\xdb\xae\x0d\x1f\x56\xc0\x81\x34\xed\x08\x33\x1e\x07\xd3\x80\xa4\xaa\x4c\xfa\xc3\xad\xcd\x52\x25\xd5\x98\x89\xce\x89\x75\x8a\x84\x24\x9b\xd7\x3f\x2a\x1c\xfb\x98\x17\xa0\xa3\x48\x2b\x72\x56\xa2\x3d\xa4\x99\xc0\x1c\x18\x09\xd7\x2b\x72\x2b\x24\xe5\xff\x13\xd3\x1f\x11\xca\xfd\x1f\x5d\x2b\x58\xd6\x28\xd7\xe1\x75\xa0\x5c\x8b\x19\xfa\x63\xff\xfb\x29\xfd\xb1\x3e\x3f\x1a\x5f\xe1\x28\xe3\xab\x5d\x5c\xac\xf0\x82\xa0\x09\x1c\x93\x1f\xbe\x5f\xc7\xef\x85\x47\xd9\xad\xc7\xbf\x45\x27\x6b\x84\xbc\xe7\x8e\xef\x0b\x53\x92\x08\x45\x5e\xf4\x16\xa1\xec\x97\x2b\x94\xeb\xfa\x04\x8a\xc9\x90\x41\xff\x94\xfa\x5d\xac\xa4\x89\xf0\x46\xd0\xe9\xa4\x86\x90\x42\x80\xb1\xa4\x8b\xc9\x90\x7d\x95\xac\x10\x25\x42\x91\x57\x3e\x93\x91\xd5\xee\x38\x35\x45\x3f\x5b\x80\x8a\xd1\x56\x78\x55\x60\xbc\x4c\xdd\xbf\x91\xab\x0e\x5b\x51\x00\x12\x79\x40\xd5\x1d\x86\xc6\xab\x7f\x81\x54\x0e\x1e\x31\x40\x2e\x85\x1d\x4e\xef\x4a\x15\x12\x89\x57\xbe\x78\xe1\xce\xf2\xc6\x51\x39\x9e\x34\x3d\xa3\x52\xdd\xa7\x73\x62\xe4\xf8\x95\xfc\x7e\xb5\x5f\x49\xaf\xd7\x0d\x34\xa2\xaa\xbf\x7c\xa8\x4a\x5e\xb4\x72\x23\xd7\xd6\xc6\x46\x94\x6c\x7b\xb9\xed\xe4\xe9\xd5\xda\x02\x7c\x4b\x12\xaf\xb4\x28\x35\x31\x33\xd0\x88\x45\x78\x9f\x25\x41\x16\xc4\xd9\xe5\x65\x0d\x0f\xf0\x17\x9e\x27\x13\x76\x95\x20\x1e\x20\x05\xba\x08\xaf\xf0\x17\x9f\xdb\x02\x51\x75\x20\x1e\x20\xa5\x29\x26\xf8\x8e\x3f\xe8\x7d\x1e\x1d\x7d\x07\xf4\x13\xc4\x97\x49\x70\x09\x7f\x11\xa9\x07\xf8\x17\x9e\x27\x05\x3c\x4e\x0a\x7c\xaa\xf0\x09\x4b\x15\x57\xf0\x54\x5c\xc1\xd3\xac\x1a\x7f\xf9\xfb\xb2\x42\x6f\x08\xdd\x33\xa4\x57\x93\x3b\x48\x81\xbf\xf0\x8c\x5e\x3a\xa0\x9f\xc2\xf7\x78\xc0\xbf\x01\xc6\xd8\xb9\xc9\xa0\xdb\xfc\x1b\x50\xac\x7b\x44\x8e\x81\x78\x80\x94\x82\xfc\x6a\x14\xd8\xe2\x18\x15\x2a\x83\x31\x69\x45\x8e\xab\x19\x3e\xce\xe8\xe9\x8a\xfd\xdf\xcb\xa7\x80\xc3\x7d\x04\xf8\x97\x9f\x29\xba\x45\x20\x9f\x20\x0d\x5d\x65\x4c\x02\xb4\xd5\x84\x07\xb4\x21\xc7\x30\xfc\x80\xab\xf0\x8d\x1e\x20\x65\x0a\xfd\x80\x3f\xf0\x54\x64\xb3\x0a\xdd\x6d\xd0\x2f\xbe\xdf\xe0\xcb\x0d\x3c\x61\x75\xac\x8d\xad\x43\xbb\xf9\x3c\x09\xf2\x39\xfe\x5e\xe6\x13\x7c\x84\x1f\x20\xf0\xd0\x21\x36\x45\x2b\x90\x4f\x98\x76\xa5\x06\xdb\x3d\x53\x3a\x06\xfb\x0f\xf8\x17\xde\x81\x40\xca\x29\x78\x41\x45\xee\x3b\x28\xdc\x08\x86\x32\x80\xaf\x5c\x0f\x93\xe0\x7a\x08\xbf\xcf\xe1\xf7\x39\xfc\xbe\x80\xdf\x17\xf0\xfb\x12\x7e\x5f\xc2\xef\x77\xf0\xfb\x1d\xfc\xbe\x82\xdf\x57\xf0\x8b\x8e\xc9\x02\xfc\xcb\xcf\xd8\x2e\xff\x62\x6c\x01\x8c\x2a\xc0\xd1\x12\x30\x34\xc2\x1c\x46\x05\xb3\x0e\x73\x5e\x50\x50\x12\x78\xa4\x5f\x78\x9f\x03\x28\xe0\x0f\x3c\x19\x7e\x3c\x50\x2a\x0c\xcf\x00\xb9\x2f\x97\xf0\x19\xf8\x03\x4f\xf9\xdd\x55\xce\x7e\x3d\xe0\x37\x10\xa1\x47\x02\xfa\x81\xb7\x1c\x7d\x95\xc0\x6b\xce\x3e\x4b\x66\xf0\xc1\x59\x81\xbf\xe5\x17\x7c\x2a\xbf\x04\xf1\x3c\x2b\xd0\xb1\x47\x86\x16\xdf\x68\x6f\x07\x8f\x0b\x7c\xaa\xbf\xe0\x63\x8d\x25\xc8\xad\x0a\xfb\x53\xc1\xbf\x18\x4d\x82\xdf\xf1\x09\xd3\x70\x2d\xe0\x5f\x7a\x26\xf7\x1e\x39\xc1\xb2\xcc\x60\x1e\xe1\x0f\x3c\x55\xcd\xb8\x2e\x16\x30\x18\xf9\x14\xc4\xcc\x3e\x4d\x24\x1b\x35\xc6\x05\x87\xeb\xad\x5a\xb4\x62\xbd\xc9\x27\x4a\xa3\x99\xac\xc4\x2c\x56\xcb\x96\x40\xc3\xbf\x41\x0c\x85\xa1\xd4\x22\x03\x08\xa2\xcb\x10\xf8\x81\xb7\x82\x02\x0b\xc1\x7b\x21\x22\x0c\x2d\xe8\x8d\x9f\xaa\x2b\xde\xd0\xf2\x29\x88\xff\x9e\x04\x7f\x0f\xe2\x1a\xe3\x3c\x40\x5b\xe8\xc7\x03\xfd\x77\xd4\xcb\x4b\xd8\x65\xf8\x37\x88\xa1\x38\x94\x6b\xb2\x39\x94\xc1\xbf\x41\x2c\x47\x25\xc7\xd4\x08\xe2\x23\x10\x0f\x81\x08\x43\x22\x3d\x93\xc0\xfb\x3c\x23\x27\x26\xf8\x03\x6f\xd5\x12\x6e\x47\xf0\x4a\xbf\x01\xc7\x22\x09\xf0\x2f\x3c\xb7\x75\x85\xb1\x28\xf8\x37\x10\x31\x46\x02\xfa\x09\x30\x54\x00\x3c\x2f\x2f\xf1\x69\x3e\x47\x46\x69\x20\x1e\x30\x05\x3b\x48\x7e\x54\x28\xa8\x4e\x40\x3f\xf0\xc6\x28\xa3\x65\x9c\xd1\xa2\x6f\x13\xf4\x6a\x02\xa7\x10\x63\x33\xf9\x04\x69\xb8\x1d\x20\x01\x7f\xd0\x1b\x1c\x3c\x5e\xe3\x2f\x2d\xf0\x96\x57\x78\x8b\x41\x7e\x02\xfc\x1b\x88\xd0\x26\x01\xfd\xc0\x1b\x2c\x81\x16\x5d\xbb\xd4\x19\x3a\xd6\xa1\x9f\x20\x86\x45\x04\x2b\x68\x09\x83\x5f\xc2\xc8\x03\xc0\xe8\x41\x42\x7f\x63\xf4\xa0\x0f\x78\x8f\x7e\x82\xf8\x16\x91\xd9\x2d\x62\xb3\x71\x51\x13\x5a\xe5\x5f\xc4\x21\x53\x42\x20\x53\x98\x85\x7c\x36\x2b\x16\x88\x42\xc5\x43\x10\x03\xa8\xae\x68\x6d\xe7\xb4\xb6\x73\x7e\xce\xea\x3f\x63\x9c\x05\x3c\xb9\x02\xf3\x1d\x57\x79\x43\xab\xbc\xf9\x82\x6b\x07\x47\x89\x7f\x03\x15\xf3\x26\x10\x0f\x90\x52\xcd\xee\xae\x70\x5e\xc5\x03\xa7\xf0\xb7\xe4\x13\xc7\x0a\xc9\x66\xdd\xf7\xcc\xf7\x20\xe6\x70\x25\x1c\xa7\xa4\x69\xd1\x87\x0f\xfe\x85\xe7\x1b\x9c\xe6\x9b\x2b\x9e\x0b\x9e\x07\x78\xe6\xc5\x40\x3f\xc1\x23\x32\x19\xbb\x43\x37\xd3\x3d\x65\x7d\x2d\x51\xe9\x27\x11\x4d\xb2\x09\x4f\xf4\xb5\x5d\xcf\xee\xc9\x98\x2b\xd2\x29\x95\xc7\x1f\xbd\xa2\xad\x64\x99\xea\x29\x77\xb2\x85\xf7\xb8\xcf\x52\xcb\xff\xab\xdf\x74\xb6\xb0\x68\x08\xb8\xdb\xd0\x91\x28\x64\xaf\x63\xb4\xad\xad\x4a\xf6\xfc\xb4\xb9\x13\x57\xa5\xee\x0a\x8a\x12\x3a\xb7\x47\xdd\x2b\x39\xfe\xe9\x5e\x3f\x2f\xf8\x85\x6a\x09\x17\x0f\x4e\x6b\x46\xba\x6a\xd4\x4d\xc5\xb6\xdd\xd4\xcf\x8b\x2e\x0d\xdd\x8c\xa5\x95\xee\x85\x34\x34\x14\x8b\x02\x09\x94\xb7\xe2\xf4\x17\xaa\x44\x67\x65\x5c\x9f\x4b\x75\x2d\x9b\x19\xa2\x4b\xe0\x5a\x75\x67\x67\x19\xc1\x66\xf7\xec\x2a\x94\x0b\xae\x38\xe7\xca\x28\x19\x5b\x5b\x63\x8a\xa7\x11\x62\x58\x0d\x8d\x55\x0c\x6f\xea\x16\x47\x0a\xb1\x5d\xd5\xb1\x30\xd3\x46\xf6\x95\x1b\x3d\xc1\x5a\x5a\xc9\xcb\xee\x2e\xe1\x5f\x58\xc9\xeb\xe7\xeb\xfa\x38\xb4\xdd\x16\x5a\x1b\xc9\x31\xf3\xf9\xfe\x6b\x02\x72\xa3\xbe\xc1\x95\x0a\x79\x23\x07\xd9\x31\x73\x35\xae\xde\x89\x66\x29\x11\xc5\x5d\x25\xc2\xf4\x0f\x0f\xae\x20\x99\x73\x22\x27\x6e\xac\x66\xbb\x35\x1d\xc0\xcd\x60\xa2\x6e\xa8\x64\xac\xf1\x53\x55\x93\x1d\x0d\x29\xaa\x4b\x2e\x7f\xa5\x1b\xb5\x5c\xec\x56\x03\x62\x32\x1f\x88\xb8\x7f\x49\x35\xda\x47\x29\x5e\xf4\x48\x3e\xfc\x3e\x76\x0e\x3c\xfe\x9d\x98\xe0\x8a\x1d\xae\xe5\x48\xf7\x26\x66\x0c\xa0\x63\x66\x10\x9f\xc2\xf5\x05\x96\xc7\x55\xf8\x9e\xc2\xf7\x11\x5b\xe9\x14\x79\x37\xe8\xbf\xc5\x34\x39\xa0\x20\x1b\xcc\xd2\x69\xb3\x2b\x29\x01\x80\x47\xd2\x94\xcb\x07\x6d\xf5\x79\x01\x8b\x71\x1f\xcd\xdb\xf8\x82\x20\x70\xc3\xfe\xc9\x89\xd7\x13\x76\xe3\x8b\x04\xb9\x5c\xed\x3d\x7b\xbc\x06\x26\x9b\xf5\x68\x28\x2f\x9e\x8c\xca\x31\xf5\x98\x76\x5d\xf7\x79\x91\x9e\xb8\x4a\xc2\x73\xff\x65\x53\xe8\x25\xe7\x0d\x50\xbd\x39\xba\x3f\x83\x99\x17\x1d\xe8\x94\x93\x75\x45\xdd\x3b\x71\x87\xf2\x78\x05\xd4\xd5\x75\x51\x51\xb9\x47\x5f\x77\x61\x79\x69\x41\x05\xe6\xc5\x40\xfa\xde\x8a\x2f\xe1\xa5\xcf\x47\xcc\xef\xe9\x7d\xc3\xce\x77\x01\xed\x95\x4b\x20\xe9\x6b\x8a\x80\xf4\x29\xbd\x0b\xef\xbb\xc0\x6a\xc8\x7b\x4c\x87\xf1\x6d\x7a\x4f\xc4\x0a\x94\xa5\x2b\x14\xfe\xd6\x14\x6c\x09\xe8\x47\xf8\xe1\x9b\x01\xc6\x59\xaa\x39\xec\x12\x35\xcb\x94\x34\x3c\x08\x82\x19\x9e\x88\x08\x86\x5f\x22\x5f\xe1\x97\x89\x47\x0c\xc2\xc4\x34\x19\x3c\x31\xfd\x02\x0f\xb7\x97\xdc\xa5\xf7\xe9\xb3\xbf\x61\x5c\xc9\xbd\x6f\xff\xd7\xb9\xf8\x4d\x2e\x7e\x1d\xfc\xfa\xed\xaf\x13\x0c\x32\x89\x5e\xab\x1f\xe3\x63\xf8\x63\xa1\xcb\x51\x61\x68\x79\x2a\x44\xad\x31\xa9\x0b\x66\x01\xa6\xf7\x96\x72\xcd\xc4\x62\x7e\x9b\xb5\x56\xeb\xb5\x01\x36\x98\xad\xa3\xd7\x86\x76\xb0\xba\x72\x98\xb0\x47\xbf\x3d\x53\xbb\xef\x7c\x37\x00\x62\xed\xc7\x67\xc1\xb6\x4a\xda\x0e\xde\x04\x86\xaa\xd1\x05\x1f\x4c\xb0\x7d\xca\xd3\xec\x8a\x65\x13\x7b\xe5\x44\xc3\x0c\x68\x16\xb7\xad\x97\xdd\xe7\x10\x94\xc2\x6e\x0e\x32\x2b\x9c\xe5\xa7\xdb\xe9\x13\x6d\xb0\x58\xb2\x4c\x83\x1f\xb5\x8e\xaa\xe3\xad\xea\x37\xe8\xa9\xa2\xce\x92\xa7\xd2\x62\x70\x14\x58\xfa\xd2\x53\xba\x76\xf8\xeb\x68\x5c\xaf\x24\x50\x15\x20\xd3\x4f\x70\x02\x60\x78\x6e\x68\x93\x11\x76\x3a\x27\x1d\x1f\x89\xbd\x81\xc0\x91\x2e\xc5\x79\x90\xb0\x4b\x4f\x30\xab\x41\x35\x0a\x21\x51\x5a\xda\x25\xba\x4e\xa0\x29\x11\xf2\x62\xcb\xed\x34\xd8\x08\xb6\x51\xfe\x43\x2a\x19\x5e\x87\xd0\x92\x33\x4d\xb3\x86\x4d\x8f\xdd\xa6\x7d\x42\x83\x51\x57\x11\xbe\x31\xc6\xea\x8f\xb1\x6f\xf6\x56\x4e\x49\xdf\x69\xd7\x01\xba\xd5\xad\xdd\x07\x17\x17\x78\x41\x8e\x54\x9c\x10\x7e\x7f\x54\xc2\xbd\x32\xfd\xfd\x4c\x57\xba\x31\x29\x89\xf3\x5d\x4f\xa2\x08\x38\x99\x0a\x83\x6f\x76\x4c\xeb\x29\xd7\x75\xa9\x94\xdf\xbf\x11\xfe\x80\x38\xd9\x67\x1e\x2d\xea\x62\x50\x11\x05\xb1\x6a\xf0\xbf\xab\xa2\x0c\x83\x40\x85\x63\x09\x82\x7f\xaa\x14\x78\xf6\x47\xa5\xc0\x4f\xa0\x94\x27\xe4\xbf\xa5\x5f\x1c\x26\xb4\x4a\x66\x6b\x49\x87\xc5\xb1\xce\x85\xba\xa3\xb7\x80\xa5\xdf\x6a\xde\x55\xcc\x42\x0a\xca\x5d\x11\xc4\x16\x9e\x46\x7c\x2e\x06\x68\x7b\xea\xda\x0b\x84\x16\x4a\xa5\xca\xb4\xe9\x38\x69\x2c\x23\x0c\x62\xe2\x5a\x82\xe1\x4a\xc0\xed\xcd\x0d\x2f\xc9\x0a\x8b\x1a\x23\xfc\xb2\x8c\x96\x2e\xba\x20\x2c\x50\x3c\x3c\x20\xff\x16\xf0\x4b\x8a\x8b\x82\xcc\xd4\x1c\xd4\x52\x46\xbb\x87\x2e\x6a\x29\xa3\x24\x44\xc1\x2c\x6c\xe9\x72\x92\xd5\x13\x3c\x45\x48\x5c\x82\x89\x56\x9c\x64\xec\x22\x2e\x0e\xaf\x28\x99\xce\x68\xf9\x31\x12\x1c\x7b\xbe\xd5\x41\x46\x78\xc0\x1a\xa7\x19\x7c\x0d\xe9\x19\x61\x20\xe7\x85\xd5\x98\x4c\x99\x15\x74\xe0\x61\x0c\xe3\x86\xba\x3a\xf6\x1b\x63\xbc\x0e\x96\x12\x12\xb8\x16\xd1\xa6\x23\xf3\xab\x80\x42\x84\xaa\x63\x5f\xba\x03\xc7\x0e\xf2\xe3\xc8\x53\x63\x6b\x6b\x01\x05\xa1\x67\x63\xf8\xb1\xa7\x01\xd3\xc4\x44\x14\xe9\x78\xd4\x3b\x23\x1e\x64\x5f\xc6\x63\xb4\x2c\xf8\xa7\xcc\x0a\xaf\xe0\x27\x66\x05\x20\xf7\x58\xac\x6e\x81\x0f\x0f\x7f\xfd\x02\x25\xec\xce\x56\xea\xf7\xc5\xc1\x3b\xac\xee\xf0\x6c\xae\xa1\xd7\xdc\xc2\xaa\x55\x57\xac\xd4\x8a\x95\x56\xb1\xa2\xff\xda\x43\xe1\x82\xfc\x59\x02\xf9\x93\xf6\x46\x6f\xed\xde\x2c\x59\xbb\x11\x88\xbf\x66\xc4\xdf\x8d\x00\x2e\x00\xc2\xb7\x0e\xe7\x74\x9d\x06\xda\x5f\xd4\x91\xda\x80\x85\x70\xb2\x05\x85\x65\x52\x26\x94\xf7\x1a\xa9\x06\xb1\xdc\xd5\x55\x8d\x24\xca\x12\x32\xd5\x04\x96\xf5\xa6\xb4\x01\xe0\x22\xec\x1b\x9e\x0e\x52\x3c\x2b\x62\xd9\x19\x34\x2f\xae\x56\x94\xdc\xae\x58\x19\x1f\xba\xb0\x5b\x40\xd9\x6c\xf5\xda\x50\x00\xf1\x2f\x8f\x4c\x36\xb6\x34\x3e\xa9\xfa\xbf\xe4\x83\xe4\x29\xcd\x6f\x59\x40\x56\xeb\xee\x05\xba\x67\x46\x8f\xcb\x9e\xd9\x1a\xaa\xd6\x8f\xf1\x3c\x2c\x34\x21\xba\xa8\x23\x29\xe7\xf8\x5a\xfc\x8e\xa3\xd8\x71\x29\xef\xbf\x12\x26\x2f\x89\x19\xe0\x89\xbf\xbb\x32\x66\x43\xbf\x88\xf8\x69\x96\xc4\x8a\x70\x81\x2b\x84\xcc\x7f\x34\x62\x81\xf7\x06\x98\x0c\x79\x8c\xae\x64\xd5\xeb\x8c\xd2\x23\x60\x75\xc5\xa9\xc8\x1d\x59\xed\x76\x7f\x8d\x48\x85\xef\x54\xe4\xc5\xd3\x3a\x5b\xf8\xf8\x84\x7d\x37\x70\x27\x64\x95\xcd\x4b\xcc\xbc\xbc\xc4\xc6\xe1\x25\x2e\x15\x49\x2e\x19\x87\xe4\x3f\x73\xae\xd8\x86\xc5\x1a\xec\xb7\x9f\x48\x78\x24\x99\x6f\x95\x9f\xf9\xa6\x98\x61\xda\xbd\xeb\xd1\x63\x1d\x69\x6f\x31\xc7\x49\xad\x15\xcd\x11\xdf\x3e\x61\x3c\x61\x0c\x1b\x83\x92\x30\x41\x47\xad\x53\xef\x84\xc2\x0f\xc7\x01\x87\x21\x0e\x2c\x8e\xdc\x78\x95\x0f\x55\xdf\xdc\x25\xaf\x5e\xff\x5f\x61\xd6\xe1\xe2\x5b\xed\x2e\x55\x5b\x7c\x7d\xcc\xa1\x5a\xf1\x81\x24\xf6\x32\xb2\xab\xd5\x6c\xa2\xc2\xc3\xc8\xc9\x5c\x7e\x4d\xe3\xb2\x5e\x96\x5e\xc7\x3a\xe3\xf4\xbe\xe7\x40\x4b\x82\xdf\x7a\x72\x7e\xdb\x98\x03\xcd\x81\xb1\x2b\x31\xce\x2f\xfa\x70\xbe\xda\xf8\xcd\x87\xfd\xa3\xdf\x06\x4a\x9a\xf4\x1b\xfd\xae\xa8\xaa\x11\x15\x58\x8f\x02\x53\xbb\x04\x4b\x92\xb9\x77\x0a\xc3\x61\x8d\xbc\x56\xe8\x95\x5c\x2b\x3c\x96\xf2\x17\x2a\x5c\x08\xdc\xa6\x9a\x70\xd3\x21\xeb\x50\x39\x49\xde\xe3\x2a\xf4\x23\x4f\xce\x8d\xf5\xcb\x31\xfb\x51\x55\x7e\x81\x7d\xf9\x78\x79\x70\xe9\xe1\x35\x06\xe2\x56\xfa\x87\x06\xb2\xaa\x8f\xc8\x46\x8d\x62\x7b\x22\xd6\x06\x76\x57\xc5\xbe\xc4\x79\xfa\x57\xea\x80\x14\x7c\x08\x01\x26\xcf\x22\x5a\xbb\x0f\x46\x2d\x5f\x37\x4a\xb3\x1b\xe8\x4d\x42\xfb\xa8\x46\xf4\x7c\xd5\x67\xad\x7a\x6b\x7c\xb8\xf6\x90\x59\xa2\x2b\xeb\x68\xe0\xae\xb3\x70\xd6\x68\x66\xad\x8e\x3e\xd5\x90\xa7\xdf\x1f\x35\xb5\x56\xc0\x6d\x42\x0f\xeb\xeb\x3a\xed\x6f\xc3\xee\xb1\x69\xa5\x9e\xeb\x56\xea\x78\x3b\x1a\x2c\x32\x64\x1b\x60\x87\xf5\x61\x75\x39\xc4\x74\x1a\x08\x35\x5c\xf1\x0d\xb6\xaf\x8e\x3c\xd1\xb5\x9f\x22\xec\x3c\xc8\x3c\xf9\xee\xf9\x93\x24\xde\x5a\xce\xb3\xd6\xf3\x79\xf5\xfd\xda\x6e\x86\xff\x9b\xd1\x45\xc5\xfc\xea\xab\xc8\xa2\x23\x54\x69\x11\xe2\x9b\x24\x38\x7a\xff\xe7\xff\x4f\x69\xa4\x77\x55\x36\x89\x83\x19\xfc\xfd\x1a\x0a\x89\x94\x2e\xe3\x20\x67\x39\xf3\x7f\x23\xfa\x68\xb5\x87\x42\x4d\x74\x29\x40\xa8\x19\x01\x88\x1b\xa1\x66\x59\x60\x46\x9d\x77\xa4\xff\xeb\xd1\x4a\x18\x49\x3f\x9f\xd0\x81\x23\xdd\xe6\x64\x6b\x2c\xe9\xe6\xa9\x25\xbd\xf4\x2e\xe9\xb1\xb3\xa4\x67\x1e\x92\x6d\xe1\xf5\xe2\x3d\xf5\x4b\xd9\xae\x5d\x62\x6e\xa2\x98\xea\x72\x9b\x8c\x07\x24\x7a\x12\x1b\x65\x8e\xf2\xa1\x9b\xb4\x59\x67\xb7\xb0\xd2\x97\xdc\x21\xb5\xba\xe6\x66\xe7\x8e\x0f\x17\x47\xa6\xaf\x73\xde\x59\x2b\x9b\xe0\x3c\xfa\x1f\xbc\xa3\xee\x45\x30\x54\xf2\x8b\x97\x4f\x12\xb7\xb8\xc8\x79\x78\xd8\x1c\xca\xc8\xa9\xd4\x82\xe0\x12\xe4\xbb\x42\x26\xf7\xd8\xab\x56\x30\x55\xf6\xcc\x42\xa6\x94\x5b\x6d\xb3\xad\x61\x6e\x74\xb0\x33\xd5\x6b\xf9\x70\xe0\xa8\x15\x74\xff\x87\x06\x6e\x54\x99\xcd\xb4\xdd\x6d\x93\xce\x0a\x6c\xa0\x77\x72\xa4\x1d\x9a\xe2\x63\xa2\x09\x69\x0e\x3b\x18\x6b\x7d\x20\x69\x80\xa7\x2d\x51\x15\xba\x28\xe3\x4b\x09\xce\x3c\xc7\x48\xe2\xa4\x78\xd2\xa7\xcd\xb0\x1a\x4f\x31\x90\x66\xe4\x61\x41\xf0\x63\xba\x08\x7c\xe8\x2f\x79\x2e\x0d\x1a\x1e\xfd\x3e\x68\xfc\x73\xae\xb7\x11\xb7\xaa\x7d\xa0\x1a\x98\xc8\xdc\x98\x9f\xb5\xe7\x8f\x3e\xb7\x37\x4f\xb7\xa7\x9b\xa9\xca\xc1\x12\x84\xd0\x54\xce\x47\x84\xe7\x71\x20\x4a\x04\xb1\x5b\x0b\xd7\x56\xd4\x37\xd7\xe2\x53\x2b\x5a\xa6\xb5\x00\xf4\x49\xb0\x4d\x56\xe9\xfa\x9c\xb8\xa2\xa8\x58\xd0\xba\xc7\x62\x22\xe5\x72\x40\x4b\x86\xb4\xd6\x85\x13\xc8\x9e\x86\x2d\x9e\x11\x0d\x45\x85\x34\x61\x0f\xf7\xbf\x44\x5b\xe8\x62\x1a\x92\x7a\x57\x15\x48\x6f\xee\x9c\x89\xfb\x9c\x59\x81\xe4\xad\x5b\x05\xec\xf7\x4c\x4f\x93\x66\xa3\x46\x23\x87\x46\x51\x93\x1a\xef\xb2\xf2\x12\x92\xff\xbe\xcc\xeb\x3b\x0e\x77\x56\xd5\x7b\xd0\x5d\xd6\x0a\x3d\x2b\x49\x9e\xbc\xfd\xff\x9c\x1c\x7f\x18\xb0\x14\xbd\x98\xde\x31\x7b\x70\xfb\x9b\x73\xe2\xca\xa6\xa2\xa3\xe7\xdf\x20\x1a\xdc\x01\x74\xb6\x94\x44\xd9\xf4\xcd\x78\x34\x96\xc1\xaa\x00\x79\x9d\x8d\x89\xbd\x3f\x61\x7e\xe2\x84\x58\x1f\x30\xbe\x8c\x1e\xb8\xd4\x8d\x5a\x54\x93\x68\x74\x1d\xde\x30\x80\xae\xd2\xf9\xd9\xcd\x39\xbc\x5f\x69\xf0\xbb\x42\x0b\x0b\x65\xc4\x6f\x9c\x95\x37\xab\xb4\x7b\x56\x52\x66\xce\xb1\x91\xbc\x7a\xf5\x8f\x32\xe5\xfe\x31\x3d\xa1\x3e\x5a\x71\xb5\x23\x61\x3c\x94\x57\x7b\x43\xb5\xdd\x06\xf7\x9d\x88\xf5\x53\x27\x62\xe5\x3d\x11\x0b\xe7\x44\xcc\x1c\xef\x69\x95\x75\x9a\x15\x03\x56\xc0\xe5\xe3\x0c\x97\x70\xbd\xc6\x51\x76\x2c\x94\x76\x95\x3a\xda\xb9\xcf\x4d\x98\x6e\xc0\xd4\x4f\x0b\x66\x1a\x2d\xb8\x86\x16\x59\xa3\xe9\x49\xfe\x67\xaf\x03\xcb\x56\xe4\xfb\xd5\xb6\x22\x4f\x90\x5c\xc2\x57\x8d\x70\x2e\x12\xde\x13\xba\x4b\x0c\xc3\x4a\xda\x03\x8f\x96\xb5\x25\x1f\xa3\x3b\xb6\x6a\x98\x26\x5d\x47\xcd\x3c\xf6\xdd\x30\x47\x16\xf2\x62\xc6\x8e\xe6\x2d\xa7\x3d\x54\x4a\x69\x0d\xe4\xb7\xec\xb1\x21\x0c\x4e\xaf\x73\xf2\x99\xbb\x1d\xfc\xb6\x81\x90\xdf\x68\x96\x8b\xc5\xac\xc8\x27\x1b\x6d\xb5\xf1\x23\x2b\x39\xbf\x51\xdc\xa4\x0c\x26\x0c\x9b\xdb\x28\xa6\x1b\xbf\xc9\xcf\xfd\xb6\x51\x34\x1b\x6d\xbd\xcc\x07\x52\x0a\x0a\x9f\xff\x4f\xf9\xfa\x46\x03\x98\x1d\x71\x16\x02\xc5\xed\xc3\x34\x83\x8f\x63\x27\xbc\xee\x78\xd1\x14\x9e\x44\x56\xbc\xc0\x64\x4d\x94\x43\x29\x02\x24\x17\x14\x03\x7d\x20\x96\x1e\xc9\x24\x86\x17\x9b\x85\x9c\x9d\x14\xe4\xbd\xad\x44\xfa\xaf\x06\x1c\x5c\x01\x4e\x15\x38\xb8\x7a\x53\x8f\xb6\xb7\xeb\xa8\x3c\x03\xac\x9d\x9d\xd5\xe7\xa8\x0b\xc7\xb2\xc8\x32\xc5\x24\x3a\x07\xb8\x52\xa3\x57\xaa\x25\xe2\x5e\xa6\xc5\xae\xe3\x32\xb6\x81\x96\xb8\x5f\x51\xd2\x3d\x03\x32\x2f\x47\x4b\x40\xef\x94\xc4\x00\xc3\x03\x3c\x34\xde\xd3\xa5\xf0\xbd\x59\xf4\x50\xf8\x59\x2f\x09\xdf\xac\x81\xb0\x96\x4f\x21\xac\xb1\x17\x61\xcd\x1c\x84\xf5\x95\xe4\xfa\xd8\xc2\x66\x33\x31\x60\x41\x9c\x77\xc4\xfb\x2a\x64\x76\x22\xf4\xf8\x25\x32\x2b\xe2\x4c\x10\xe6\xcd\xb9\xe6\x65\xee\x5e\x27\x6b\x93\x3a\xe6\xfd\x5b\x3f\xae\xa2\xdd\x05\x71\xae\x6d\x75\x97\x84\x47\x0b\xc9\x2e\x47\x2e\xca\xdd\xb3\xf3\x84\x14\x4d\x9e\x40\xac\x1e\x54\xc1\x8e\xdb\x7a\xbd\x73\x18\xb4\xd4\xa6\xe7\xd3\x28\xb9\x55\xdd\xf0\x22\xad\x33\x8d\xb4\xa6\x94\xf3\xc7\x28\xf1\xb6\xb4\x99\x6b\x2f\xfd\x08\x50\x6b\xea\x6c\x07\x1a\xfb\x8a\x4b\x88\xba\x00\xac\x22\xe9\xf5\x8b\x46\x7c\xfd\xc7\xe8\x7b\x11\x36\x22\xb3\x08\xdb\x68\x35\xed\xad\x54\xa7\xec\x7a\x71\x99\x6e\x6a\xd0\x01\x1c\xb2\xe9\x9b\x8c\x91\xd4\xa0\x7a\x78\x28\x61\x93\xa3\x96\x50\xa5\xb9\x6e\x7a\x92\x48\xce\xd6\x25\x92\x99\x2a\x1e\x49\x3b\x6e\xb3\x17\x30\xfa\xf4\xec\xbc\x73\x17\x84\xba\xba\x59\x0d\x2d\x4b\x84\x08\x58\x62\x87\x74\xf4\x05\x36\x5b\xbe\x69\x46\x0d\x60\xb3\xe2\xac\xd1\x91\x52\xc5\x86\xba\x94\xca\x98\x8c\x8f\x8b\xaa\x6b\x90\x92\x4d\x2d\x44\x63\x75\x57\x16\x35\x1f\x5b\x74\xe8\x64\x15\x1d\xfa\x5f\x94\xd4\xd4\xe9\x4a\xa4\x33\x56\x5b\x6f\xea\x5a\xe9\x52\x45\x5c\xee\x02\x3c\x0d\x60\xa3\xc1\x4f\x6d\xd0\x0b\x72\x15\x4e\x84\x16\xf8\x40\x85\x55\x46\xb7\x43\x02\x49\x7e\xa2\x35\x12\x91\x2b\x0f\x34\x58\x11\x93\x09\xa7\x54\x39\x98\x2c\xe1\x54\x1e\x13\xa7\x68\x54\x0d\x30\x1e\xcb\x69\x25\x86\x82\xec\xf5\x90\xa2\x52\x51\xfc\xdf\xc9\xc7\xaa\x40\x7d\x06\x78\x22\x8d\x45\x34\xb9\x2a\xa5\x67\xed\xca\x68\x38\x4b\x8b\x6d\x19\x13\xe4\x9e\xa2\x2b\x27\x45\x8c\xf6\x6d\xd9\xa3\xa5\x6b\xce\xbd\xbf\x2d\xca\x49\x75\x8b\x2b\x5a\x85\x89\xde\xda\xf2\x24\xb2\x5f\x91\x4d\xd8\x33\x14\x99\x0b\xa3\x2f\x5f\xc1\xf4\xc0\x86\x8e\x34\xaf\xd7\xd2\x17\xdf\x20\x2b\xc7\xd7\x55\x4d\x61\x58\x2a\xf5\x7a\x3c\x9d\xa2\xc8\x15\x55\x3d\x29\x04\x2a\x65\x67\xf2\x4d\xe4\x0a\x3b\x79\x02\xdc\x5e\x1b\xee\xe0\x49\x88\xda\x6c\x5a\x8b\x56\x7b\x7a\x6b\x46\x5b\x78\x46\x2e\x77\x77\x12\x64\x4a\x8a\xc8\xd1\x91\x84\xd3\x0c\xf9\x4b\x18\x72\x4b\xcc\xd0\x48\x9e\x73\xd8\x8c\x90\x6c\x34\x38\x05\x33\x31\x05\x21\xa1\xd4\xba\x33\x14\x88\x45\x82\xf8\xd6\x88\xdd\x70\x97\x78\x60\x9a\xe5\x66\x7a\x39\x78\x83\xd9\xd0\x33\xe1\x55\x76\x77\x9a\x2e\xa0\xbb\x33\x4f\x77\xaf\xd3\xe9\xf6\x18\x0e\x5f\xb5\xd8\x8c\xe5\x35\x9a\x88\x33\xa0\x6e\xc9\xf1\x4b\x3c\x91\x9d\x86\x83\x97\x7b\x36\x4f\x27\x83\x71\x35\x9b\x65\x8b\x26\x9f\x98\xeb\x63\xbe\x7b\x9d\x4c\x69\x8d\xcc\x77\xa7\xc9\xf5\xa3\x15\x5e\x52\xa3\xf4\x3c\x6b\xdd\xec\x88\xb1\xa6\x83\x25\x9c\x37\x53\x18\xe5\x44\xf3\xfe\x86\xc3\xdd\x0d\x4b\xd2\xf6\x85\x8f\xe3\xc6\x80\x73\x8e\x5f\xde\x68\xb9\xf0\x40\x8e\xd6\x29\x23\x4a\x8c\x1a\x94\x8b\x9b\xa3\x67\xcf\x60\x32\x03\x03\x63\xf0\xd7\x80\x0d\xc8\xce\x72\xe5\x76\xaa\x64\x45\x84\x9a\x5e\xad\xfe\x56\x54\xc4\x01\x87\xde\xd0\x0b\x9e\xed\x22\x65\x52\xde\x9d\x84\x97\xd1\xb3\x71\x18\x9d\x77\xd8\x80\x22\x9a\xcf\x0b\x5c\xe8\x62\x94\x78\xf7\xec\x87\x60\x95\x68\x35\x08\x56\xbc\x3f\x4b\x40\xda\xb0\x74\xf1\x5c\x78\x53\x48\x2f\x73\xc5\x08\xb0\x04\x52\xd3\x8f\x42\x5d\x1a\x7a\x5e\x21\xa9\xb8\xe4\x50\x0b\x18\x9c\x60\x6b\x6b\xc6\xc5\x17\x7d\x6b\x6c\xd1\xad\xb1\x86\xcc\x61\x60\x03\x54\x62\xe1\x96\x22\xa0\xd4\x1e\xd0\x45\x58\x1c\xdd\xb4\x42\x07\x60\x2a\x31\x58\x14\xb7\xb0\xc0\x62\xdc\x3b\xd8\x23\xd4\xc0\x4c\x36\x00\x13\xbc\x90\x4b\xd6\xce\x8b\x8d\x36\x90\x5b\xc2\xa3\x60\x69\xd0\xef\xf9\x78\x89\x50\xd5\x23\xd8\x28\xe2\x59\x08\xce\x7e\xaa\xea\x7d\x39\xa1\xbc\xd5\x3a\xf2\x19\x8a\x68\xb2\xcc\xbd\x31\xca\xd3\xc8\x3a\x8e\x10\x44\x56\x7e\x6e\x50\x15\x70\x6b\xcb\x83\xe5\x17\xe9\x3d\x12\x02\xd4\x60\x93\xcc\x76\xeb\xa4\x42\x47\x97\x5d\x42\x01\x48\x57\x3b\x46\x17\x42\xf4\xe1\xeb\x72\xc2\x01\x62\xfa\x3b\x9c\x0c\x5f\xbd\x88\xfb\xfb\x0b\xd9\x28\xc1\xf8\x61\x6d\xff\x02\xff\xbf\x94\x60\x74\xd7\x9f\x85\xff\xfa\x33\x75\xa5\x15\xd7\x0e\xbf\xc7\x95\x5e\x48\x93\x60\xc9\xf1\x99\xac\x25\xbc\x38\x55\x86\xc4\xff\x54\xf9\x45\xdc\xa6\x3e\x8d\x7d\xc5\x2c\x0e\xbb\x40\xbb\xb1\xe5\x83\x38\xa2\x5c\x49\x4b\xfc\x98\x0e\x91\x3d\xde\xc2\xf5\x21\x8a\xf3\x94\x98\xc8\xc2\x47\x13\xda\xed\xe5\xa4\x58\xac\x49\x11\x74\xd6\xb4\x29\x42\xe1\xfb\x1d\x34\x10\x76\xa2\x04\xf4\x2c\xd3\x7b\x25\x59\xf4\x5c\x49\x54\xd7\xfb\x2d\x03\x3d\xb2\x12\xf3\xae\xb2\xfa\x5a\xa3\x6e\x32\xae\xc4\xe4\x89\x6b\x89\xec\xbb\x03\x8b\x8e\xa9\x14\x59\x1e\x58\x3b\xa9\x81\x9f\x83\xdf\xea\x1c\x7c\x02\xd8\x1f\x64\xe1\x33\xf4\xfc\x9c\xfc\xd9\x1f\xa7\xfd\xff\x3b\xf2\xa0\x9f\x8e\x5c\x67\xb1\x28\x7f\x58\x6d\xe1\xed\xe2\xd4\x3a\x17\xab\xa6\xf8\x3f\x7a\xb0\xb0\xd0\xf5\xcf\xd2\xe1\x23\x81\x4b\xcd\x48\x74\xab\x03\x23\xe7\xe8\xf5\xe8\x27\x19\xd6\x08\x31\xe6\x7d\xf7\xdd\x24\x8b\x81\xba\x6d\x72\xd3\x4b\x7e\xd1\xbc\xc5\x48\xf5\x30\x38\xf1\xe5\x74\x73\x88\xb1\x27\xbd\x35\xeb\xc1\x74\x06\x37\x4b\xaa\x91\x8b\xd5\xde\xb0\xf3\x2b\x0c\x69\x38\x4e\xcf\x96\x71\x73\x3e\x2a\xc2\x52\x53\x37\xae\x04\xfe\xc2\x93\x51\x1b\xcc\x2f\x75\x86\x56\xa8\x8d\x87\x57\x3d\xc6\xf5\x86\x80\x99\x91\x13\x2e\x3a\x56\x9d\x7e\x26\x9b\xc3\xf8\xd2\xe8\x48\x4f\x08\x49\xcf\x18\x47\xde\x71\xef\xc4\xf5\x2e\x39\xd3\x8c\x80\xde\x96\xe1\x24\xf3\x98\x55\xd0\x51\xa3\xcc\x73\x72\xf7\xaf\x5c\x7b\x51\x99\x31\xe2\x5e\x90\x72\x83\x39\x5f\xc9\xf0\x3b\x8c\x60\xff\xc3\xda\xd6\xd2\xd1\xfd\xc5\x40\x57\x88\x1e\xb0\xe7\x2e\x5e\xe7\x98\xae\x2c\x8b\x3f\x45\xb1\x28\xaa\xc2\xf5\x8b\xc2\x5a\xe2\x71\x8d\x3e\xf7\x9a\xde\xa2\x47\xc2\x0d\xf1\xcf\x84\x6f\xc2\xdb\xde\x82\xec\x4b\xfe\xfd\x3a\xdf\x6c\xde\xd2\x09\x18\xde\x9f\x14\xf3\xc5\x2c\xd7\x72\x92\x8f\xf1\x21\x86\x57\x7e\x97\x67\x37\x46\xfa\x32\x66\x44\xf6\xff\x92\xf7\xa7\xdb\x6d\x2b\x59\x82\x28\xbc\xfa\x6f\x3f\x05\x85\xee\xd6\x21\x4b\x21\x9a\x94\x87\x63\x83\x86\xb5\x9c\x1e\x3a\xdd\x79\x3c\x2c\x5b\xae\xac\x6c\xa5\xca\x05\x91\x90\x88\x36\x09\x30\x01\xd0\xb6\x4a\xe2\x93\x7d\x3f\xbe\x47\xba\xaf\x70\xf7\x10\x33\x02\x14\xe5\x73\xaa\xfb\xde\x75\x7f\xd8\x22\x62\x1e\x76\xec\xd8\x7b\xc7\x1e\xec\xb4\x52\x28\x34\x80\x44\x94\x95\x91\x8a\xb7\xe5\x79\xbe\xc8\x3e\xa5\x17\x70\xa4\xc9\xaf\x80\x9d\xbd\x12\x4c\x83\xdb\x69\x27\xe2\x4f\x19\x6c\x7d\x46\x8a\x04\x76\x06\xfa\x70\xff\x32\x7c\x07\x28\xcd\x36\x1a\xe3\x29\xfd\x77\x5c\xe6\x7c\xaa\x93\xf9\x92\x5f\x76\x57\x70\x4b\x02\x75\x7c\x2d\x5d\x10\x7d\x63\x4f\x3a\x97\x64\x81\x7b\x25\x0d\x70\x5f\x29\x47\x2e\x2f\x94\x5f\x94\x73\xe3\x7e\xe4\x07\xfb\xc6\x79\xd7\x67\xef\x38\x03\x76\xa7\x83\x9f\x19\x29\xe9\x90\xf3\x12\xf8\x24\xef\x25\x64\xfa\x35\x6c\x23\xcd\xa1\xe5\xf5\xad\x7f\x81\x65\x2c\x4c\x2e\x33\xad\x14\x20\x36\x2f\xf2\xcb\xfe\x62\xd7\x82\x9f\x08\x18\x1c\xa7\x6c\x0a\x18\x5c\x47\x8e\xc6\xcf\x0d\xd6\x50\x28\x46\x01\x76\x3b\xde\x62\x7f\xde\x1d\xc4\xb5\xdd\x82\x3a\xf3\x9f\xd0\x9c\x3a\xbb\xbc\xea\xcf\xb0\x0c\x86\x68\x7c\x03\x54\xc7\x0f\xb5\x37\xcc\xe4\x50\xb3\x2a\x0b\x48\x3a\x4d\xfa\x1f\x2b\xad\x2d\xb7\x48\xfc\x3e\x98\xac\xd7\xdb\x9e\xb4\xa1\xf3\xfb\x73\xe7\x12\x08\xc3\x9e\xb9\x0e\x5a\xb0\x6f\x2e\x05\x80\xee\xac\x68\xdc\xce\xcd\xdd\x10\x3e\x20\x96\x75\x3f\x93\x48\x3e\x3e\x30\x64\x75\xf0\x34\x1a\xfa\xba\x83\xed\x92\xb4\x36\x12\x62\x2d\xa8\x30\x44\xf7\xb6\x43\xea\x99\xfb\x77\x71\x07\xf3\x90\x33\x81\x40\x2c\x53\xd7\x1f\x80\x9c\xb5\x0f\x17\xc6\x45\x40\xdb\xd0\xd3\x0d\x5f\x66\xbc\x86\xb8\xd1\xcb\x94\x39\x83\x1b\xb7\x4c\x6a\xf3\xb9\x81\xcb\xb4\xd2\x92\x1b\xbc\xcc\x3c\x00\xbb\x71\xcb\xcc\x5b\x0a\xc6\x2b\x73\xd2\x35\xfb\xa0\xe3\x91\xb5\xef\x02\x13\x94\x8c\xf2\xde\x28\xbf\x8f\x26\x12\x99\x4c\xb7\x91\x7d\x6d\x82\x92\x39\x7a\x5f\x32\x2a\x59\x0b\x89\x52\x84\x32\x99\x55\x7d\xcb\xaa\x16\x50\xca\xa0\x64\x2d\xac\x4f\xb1\xc8\x38\xeb\x9f\xff\x7b\x08\x60\xde\x71\xae\x64\xb7\xe0\x6a\xfe\x90\x5e\xda\x4c\xa0\x75\x45\x4b\x47\x96\x31\x7a\x15\xbd\xee\x3e\x5a\xf1\x03\xa2\x04\xdb\x07\x2b\x7e\x40\xb7\x79\xf0\x58\xc5\x0f\x89\x2e\xec\x38\x54\xf1\x43\xd2\x73\xed\x3a\x52\xf1\x43\xa2\x7a\xc3\x07\x2a\x7e\x48\xc4\xeb\x36\x91\x40\xf8\x30\xc5\x8f\x68\x1e\x5b\x8f\x52\xfc\xe8\xf1\x5d\x49\xeb\x8e\x63\x14\xff\xfa\x48\xb4\xcf\x40\xfc\x78\x2c\x82\x87\x26\x7e\x7c\x24\xfc\xa3\x11\x3f\xbe\x2f\xbc\x83\x11\x3f\x7e\x28\x5a\xc7\x22\x7e\xec\x74\x25\x0f\x45\xfc\xd8\x21\xf2\xe5\x91\x88\x1f\x3f\x16\xa1\x03\x11\x3f\x31\x2c\x40\xd7\x99\x8f\x9f\x8c\xfd\x32\xac\xb6\xfc\xc4\x8c\xd3\x3d\x4a\xf1\x78\x64\x9a\x35\x27\x09\x92\xc7\xa2\xeb\x20\x41\xe6\xfd\x0e\xed\x97\x20\xc8\x03\xfd\x48\xe5\xdb\x67\x0c\x72\x1e\x88\xae\x23\x06\x99\xb4\x94\xed\x13\x06\x39\xd4\x5b\xd7\x11\x8a\xc7\x0f\xd0\x69\xcf\x93\xed\x66\x69\x41\xbf\x94\x24\x80\xbc\x58\x94\x65\xd5\x87\x95\xf9\xa7\x6c\x70\x0f\xfe\x04\xa2\x00\x93\x93\x23\x52\x56\xb8\xb9\x19\x0d\x0e\x8a\x0d\xeb\x8a\x05\xbc\xcc\xe4\x6d\x5c\x8d\x7b\xf2\xbc\x48\x17\x57\x75\xee\x4b\x8e\x14\x5a\xaa\xdb\x16\x44\xf2\x12\x93\x64\x3d\x6e\xc8\xbb\xf2\x3b\x1b\x0c\x7d\x01\xde\xf7\x2d\x6b\xf3\x53\xb0\xaf\xf8\xf4\x4c\x86\x7c\xff\xd4\xa0\x1f\x93\xd3\x11\x7c\x33\x2e\x41\x0f\x29\x63\xc1\x32\x72\x8b\x6f\x99\x0e\x75\x3e\x19\x31\x2b\x48\x50\x44\x95\x34\x15\x98\x2a\xa3\x01\xe8\x76\xe8\xf7\x2a\x25\x2c\xc9\x48\xd4\xc3\xac\x40\xa7\x50\x32\x37\x41\x07\x2a\xe4\xf5\xcc\xea\xb1\x55\x66\x4c\x2f\xe4\xbf\xa5\x75\xe3\x4c\x25\xc0\x5c\xb5\x7a\xc6\x20\x6f\x39\x30\x11\x3f\xa6\xc0\xdc\x01\xa9\xea\xc8\x10\x32\xf4\xbd\xdd\xae\x63\xeb\x1f\xea\x8a\x9f\xd8\x8f\x1e\x6a\x4d\xa2\xab\xe4\x72\x81\xcf\x8d\x30\xc8\x7e\x33\x5c\xa6\xab\x7e\x3b\xbe\xca\x75\xa4\xc1\xae\x37\x45\x3a\xb8\x87\x6a\x79\x11\x5a\x19\xab\x74\xe4\x0e\x44\x74\x52\x36\xe9\xa2\x97\x17\xb2\xa3\x1e\x3a\xcf\xeb\xf5\x97\xf5\x20\x8a\x0b\x8c\x9f\xac\x32\x06\x22\xd2\xa3\xe9\xd1\x16\xfa\x45\xb3\x1f\xa1\xa2\x32\xbc\xb5\x57\x56\xba\x5e\x16\xd1\x5b\xd3\x12\x00\x90\x8e\xc7\x12\x6a\xf6\x1e\x8e\x1d\x9f\xc0\x44\xf4\xd1\x6a\xb4\xa3\x1a\xf7\x60\xea\x28\x64\x51\xc7\x32\x09\x38\xe1\x81\xdc\x9f\x37\xc5\x4f\xee\x8f\xae\xf8\x13\xfb\x43\xae\x8f\x7b\xcf\x7a\x53\x83\x1e\x5a\x9b\xf3\xa6\x6b\x5b\xf0\xb3\x63\x4e\x42\x0d\x60\x51\x5e\xf6\xe5\xf6\xb2\x5f\x44\x41\x63\xa6\x94\x13\x48\x80\xc1\x0c\x9b\xf2\x75\xfe\x23\x9b\xf5\x8f\x06\x07\x51\x6f\x09\x87\x9e\x60\xdd\x9e\xae\x9c\xd9\xdb\x34\xe4\x4e\xa5\x63\x11\xc4\xde\xc8\x84\xfc\xfa\x5d\x0b\xf0\x57\x38\x75\xa8\x4a\x65\x66\xcf\x73\x0f\x4e\x5d\xee\x26\xd7\xd9\x65\x2b\x85\xbb\x57\xd3\x61\xe7\xdc\xc9\x29\xd8\xef\x5c\x58\x1a\x1c\xe0\xe0\xbb\x02\x19\x5e\xc1\xbb\x83\x17\x57\xbc\xde\xe8\xf5\x3f\x2d\x87\x6f\x5e\x7e\x79\x7e\x72\xf2\xf1\xcd\x9f\x3e\x9f\xbc\xfa\xf2\xee\xf9\xdb\x57\x67\x09\x9c\xec\x99\x60\x35\x23\x54\x5d\x40\x69\x52\x33\x4c\xab\xcb\x3a\xf1\xf4\x76\x33\x4a\x45\x49\xe5\xef\x5f\x81\x2f\x15\xb0\x92\xd5\xec\xaf\x55\x1e\x88\xf2\xa2\x7c\xd8\xb4\x17\xe3\xb4\x13\xa5\x1f\x8e\xcf\x86\xdf\xb1\xb5\x7a\x52\xa2\x72\x3a\xfe\x77\x73\x03\x97\x0c\xfe\x60\x55\x8d\x6b\x9c\x5b\xdc\xb0\x6b\xd0\x02\xe3\x4e\xd6\x28\x6e\xd8\x08\x79\x61\xb4\x44\x5b\xed\x18\xd1\xda\x59\x13\x86\xd4\xcd\xf1\x1a\x49\x74\xf8\x4a\xa5\x2f\x52\x3f\xcb\x27\xf9\xc1\xc1\x40\x2a\x88\xe8\xfc\xd3\xfc\x4c\x0a\xdc\xc4\x4a\x5c\x90\x8e\xb6\x0c\x0b\xf1\x2e\xfb\x8e\x34\x85\xa1\x0e\xf0\xa5\xff\xe6\x26\x0a\xc8\x01\x29\x6b\xd0\x79\xcb\xc8\x89\x6a\x44\x89\xee\xbc\x35\xde\x8e\x8d\xea\x2a\xfa\x3a\xc1\xa3\x52\x93\xbf\x6f\x5a\x36\xfc\x65\x3d\x97\xd0\x77\xa3\x76\x31\x46\xf7\x8e\x17\xc9\x1a\x7d\x26\x24\x85\x1d\xbd\xb3\x0c\x5d\xb3\xdb\xb7\x49\xb7\x8a\xed\x1d\x5e\x88\x15\xad\x45\xd0\xc2\x8f\xa3\x52\x44\xb7\x12\xca\x58\x8e\x9e\x84\xbb\xc6\xb8\x90\x7d\xb1\x4b\xb2\x37\x4b\x20\xc6\xde\x14\x4d\x89\xaf\x00\xbc\xa4\x32\x46\x7c\x2a\xd5\xc7\xcb\xd3\x31\xec\xd6\x74\x68\xc3\x69\x7f\x0e\x60\xb1\x00\x80\x1a\x49\xbf\x2c\x3b\x98\x1f\x62\xdb\xc7\x58\x43\xc7\x31\x08\x9e\x50\x7e\xa7\x80\xe3\x77\x51\x95\x4b\xa2\x2d\x29\x8c\x81\xfe\xb2\x73\x94\x75\x31\x39\x19\x34\x65\xe5\x6f\x93\x6a\x97\x33\x2f\x97\x5c\xd6\x7c\xbb\xb9\x56\x9d\x25\x19\x6b\x9a\xf6\xf9\x3b\xc1\x85\x39\x75\x72\xcf\x08\x02\xec\x75\xca\xb4\xb1\xa4\x90\x08\x65\x41\x16\x92\xb1\x57\x0e\xd7\x85\x96\x94\x9f\xc3\x4c\x38\x86\x1a\x58\xaa\x8c\x9f\x4b\x4a\x31\x1e\xe8\x1b\x64\xb5\xd1\x90\x12\x78\x91\xd8\x63\x60\xf1\x9c\xce\xa1\xcb\xaa\xfd\xfd\x96\xdf\x28\x99\xdc\x1d\x98\x65\xcf\x3a\x68\x1e\x34\x4d\xd8\x20\xc1\xef\x49\xef\x75\xdc\xf2\x60\xb2\x4c\xb6\xf4\x84\xf5\xc4\xb7\x60\x73\xe2\x12\x91\xa0\x21\x93\xc5\xd5\x5d\x91\x22\x9e\xad\xe5\x71\xd5\xbf\xe2\xbb\xb1\x16\x33\x58\xd0\xf8\xdb\xfe\xfe\x25\xe3\x8a\x51\xf7\xb9\x56\x67\x66\x39\xc0\xea\x3c\x7c\xa8\xbe\x60\x2f\x72\xa8\x17\xfd\x8d\x41\xf8\x55\x02\x8d\x95\xab\xfe\x60\x72\x79\x7a\x69\xba\x3e\x48\x16\x02\x6b\x6a\x6c\x84\x95\x0f\x5f\x0d\x28\x51\x63\x25\x6a\x91\x55\xe7\xda\xe9\x6a\xe3\xaf\x6c\x0f\x85\xf5\xe9\xec\xcc\x78\xfc\xdf\x16\x33\x45\x90\x37\x32\xb9\x1d\xf4\xfb\xd8\xfa\xdd\x55\x2b\x8e\x9e\xe2\xd6\xa1\x2f\xb9\x95\x1b\x85\x43\x1a\x51\x06\x5c\xb2\x74\xf2\x4e\xf1\x93\xdd\x4d\x76\x3d\xbe\x29\x1e\x3f\xbe\x8f\x3c\x62\xcb\x7b\x84\xcb\x16\x6a\xff\xb8\x70\x1d\x05\xcc\x9a\xe5\x03\x0d\x39\xc7\x6a\x0e\x92\xca\xa0\x5f\x63\xfd\xe2\xaa\xd7\x99\x06\xe1\x92\xeb\x6c\x11\x65\xa5\xca\xb7\x18\x05\xc7\x2c\xe5\xfd\x3b\x50\x3f\x50\x69\x3b\x84\xf5\x1a\x79\x4b\xe5\xb3\xb8\x12\x74\x27\x4f\x4f\x19\x4f\xc0\x8d\x2d\x11\x06\x5d\xce\x4c\x70\x6c\xd0\xb6\xba\x3d\xd4\xd2\x19\xaa\x50\xca\xeb\x93\xca\x0c\x56\xeb\xa0\x97\x14\xb2\x13\x2e\xec\x1a\xdf\xb7\x4b\x0b\x22\x4b\x8b\xad\xd1\x3a\xa1\x18\x0c\xb2\x97\x0f\x9a\xa4\x74\xc1\x2e\x3d\x53\x71\x2c\x44\x81\xcc\x75\x41\xbc\xf5\xb5\x43\xa8\x02\x7d\x61\x2e\xdc\x91\x30\x37\xf1\x48\xdd\xbd\x23\xbe\x7a\xe1\x4a\x85\xde\x39\x0d\x5a\x46\x57\x89\xd0\x9c\x4c\x38\x48\xac\xac\x81\x3d\x62\xab\xa8\x4e\xc3\xd2\x76\x81\x81\x3d\x2d\xab\x82\x4e\xc3\x0a\x76\x01\xb2\xa5\x21\xf4\x60\x95\xa6\x04\x2c\xa9\x73\x58\x86\x3e\x55\xea\xb3\x0d\x87\x44\x75\xc7\xf2\x0c\x9d\x34\x4d\x79\x87\x0b\xdb\xb1\xf2\x74\x58\xc3\x19\xea\x7b\x01\xce\x15\x67\xa0\xeb\x1f\x5a\x6c\x1e\xd0\x1c\xd3\x96\x52\x9c\xb6\xe0\xc7\xa8\x25\xb0\x84\xb0\xe5\xa5\xd9\xf2\x52\x6d\x79\x8e\x22\xf3\xd3\xf2\x0c\xf5\x89\xc8\xb5\x9b\xb5\xe9\x53\x7b\xd3\x1b\xf2\xbb\x96\xf6\xa7\x03\x03\x00\x2b\x9c\xd9\x62\x20\x15\x2f\xf3\xd3\xd5\x19\x37\x7a\x01\xd8\xd7\x81\x88\xd5\xd9\xa4\x48\x2e\xd8\x2b\x31\xd0\xb6\xcf\x7a\xd1\x81\x8e\x5f\x25\x2a\x0c\x11\x54\x91\xcf\x35\x0f\x46\x0a\xa6\x41\x2d\x48\xb0\x86\x04\x8d\xc2\x90\xb0\x1e\xf1\x37\x07\x89\x9b\x87\xb7\xad\xdc\x11\x53\x50\xee\x95\x95\x23\x6d\x24\xe6\x6a\xb3\xc8\x63\x5e\x35\xd0\xcd\xd2\x3e\xcd\x79\x9f\x30\x51\xef\xd3\x7c\xeb\x3e\x61\xd5\x43\x66\xbc\x60\x77\xe6\x8e\x56\x9e\xa1\x67\xe0\x34\xca\x37\xdb\xaf\xd9\x55\x0d\xf4\x80\xc4\x0c\xb0\x65\x35\x07\xae\x37\x9b\x91\x85\x4e\x60\xc9\xa3\xbd\x36\x5a\xda\x7b\x63\x91\xc2\x56\xa7\x4f\x0b\xb5\xd5\x29\xea\x64\x5f\xf4\x51\x2d\xb6\xc0\xa3\x99\x23\x31\xf2\xfe\x82\xbc\xa5\xe6\x68\xa5\x72\x5e\x65\xe9\xd7\xcd\x5e\x8e\x46\x00\x72\x5d\xca\xb3\x67\x23\xa4\x66\xd0\xbf\x1e\xfa\x74\xd6\x68\xc5\x52\x6d\xf3\x9f\xfd\xd7\xc9\x78\x78\x84\x22\xac\x36\xe9\x88\x81\x13\xf0\x14\x28\xa7\x0a\xe2\xcd\xbb\x4f\xaf\x3e\x9e\x7c\x79\xfb\xfc\xe3\x5f\x3e\x7f\x68\xe5\xbe\x7d\xff\xcf\xaf\xbe\xbc\xfa\x97\x37\x9f\x28\xe0\x7e\x84\x8a\x7b\x91\xf8\xf8\x8a\x92\xdf\xbd\x7f\xf9\x0a\xbd\xef\x73\xe2\xc9\xab\x7f\x39\xf9\xf2\xe2\xfd\xbb\x93\x57\xef\x4e\xb8\x19\x8b\x48\x8b\x44\xc0\xc5\x8d\x24\x70\x7a\xa9\xf2\xe9\x17\x85\xfc\xc7\x48\xf7\x30\x76\xa9\x96\xff\x16\xd5\x12\xf9\xde\xa9\xa3\xa0\x7f\x15\x7f\x66\x3b\xf9\x20\x89\x64\x68\x68\x76\xd3\x13\x90\x69\xc5\xa5\x08\x08\x11\xe2\x5c\x38\xac\x2f\x5c\x1a\x36\x83\x19\x17\x01\xc7\x1b\xa1\x40\x42\x4f\x76\x76\x75\x21\x09\x4c\x0e\x9d\xe5\x99\x30\xda\xc1\xb3\x4c\x78\x1f\xa3\xa4\x76\x0d\x10\x8f\x4e\x99\xab\xec\x82\x9d\xe2\xe7\x49\x3b\x88\xa9\xc8\x95\x2f\x08\x62\xba\x59\xf1\x09\x2a\xaa\xd8\xa1\x50\xd9\x0b\x96\x5a\xe9\x10\xb4\x1c\x48\xd4\x89\xb9\x9a\x6f\x26\x96\xeb\xb9\xe4\xfa\x4b\x5e\xdb\x6a\x38\xe4\x1c\x5a\xbd\xa6\xaa\x90\xa5\xce\xa0\xa4\x27\xcd\x1a\x35\x52\x36\xd2\xb3\x20\xec\x11\x69\x96\xdb\x4e\x70\x17\xc9\xb7\x32\x9f\xf5\xa4\x26\x7a\x76\x21\xfd\xd4\xe2\x4f\x59\x0b\x33\x60\x22\x9c\x81\x9a\x6b\xf8\x45\xc7\xba\x66\xff\xc6\x2d\xe7\xc6\xf5\x60\x7f\x7f\xaf\x0c\xa5\xf6\xd7\xa7\xf5\x59\xd2\xc0\x7f\x7c\xf1\xac\x5a\xbc\xf6\xe1\x11\x0e\x6f\x9c\xa0\x6b\xcf\xb5\x56\xb9\x4b\x52\x4d\xa0\xae\x9e\x8d\x0d\x12\xb9\x48\x58\xdd\x6e\x85\xef\x98\xa3\xc9\xea\xd9\x7c\x32\x07\x1c\x72\x71\x3a\x3f\x33\x2d\x9f\xce\x0f\x8e\xce\x26\x56\x63\x17\xe4\xb7\x98\x5c\x40\x5a\x21\xe4\x94\x51\xb2\x9b\x6a\x26\x3a\x1b\x84\x74\x88\x71\x42\x6a\x5e\x33\x9a\x97\x65\x45\x88\xf7\xdb\x14\x98\xa1\xca\x10\x19\xfa\xd7\x7a\x60\x76\x50\xaa\x3f\x26\x21\x19\x9c\xb3\xc7\x56\xc0\xbc\xcc\x12\xc2\x29\x98\xa3\x16\x51\x13\xff\x39\xba\xe2\xa7\x93\xc9\xf1\xf2\x42\x3e\x7e\xe4\x00\x99\x38\xcb\x70\x53\x45\x46\xdb\xae\x63\xd8\x66\x1a\x38\x85\x1d\x6b\x10\x3a\x71\x63\x35\x06\xc6\xbd\xd7\xdf\xc3\x18\xc7\xd0\x82\x0b\xb8\x66\xd0\x9b\xb6\xd3\x44\xe7\x90\xde\x16\xdf\xce\x57\x2d\xbb\x83\xc3\x11\xa9\x18\x69\x22\x9e\x49\xf3\x14\xbe\x55\x3a\xe2\xb3\xf3\x31\x69\x99\xb9\xc2\x0c\x6b\x28\x4b\x6a\x91\xcc\x05\x2a\x4f\x9d\xb4\xa4\x18\x99\xa2\x55\x02\x55\xa6\xf2\x3e\xe0\x4e\x98\xda\x17\x28\xf4\x45\xcd\x45\xfc\x82\x94\x75\x8f\x00\x95\xdc\xe1\x2a\x73\x56\x8e\x1c\xd7\x9b\xa7\xdf\xd0\xca\x74\x5d\xe4\xff\x58\x67\x3d\x0c\xc2\x14\x91\x59\xea\xf0\x17\xf2\x72\xec\x1b\x96\x92\x2e\x97\x0a\x7b\xb0\xbf\xaf\xbb\x2c\xe0\x5c\xc0\xb2\xb8\x5d\x47\x24\xe7\xe8\x71\xec\x87\xda\xe9\xb1\x28\x8b\x43\x59\xa7\x87\xb7\x7f\xaf\x2e\x7b\x25\xbe\xc8\xa2\xdb\xb6\xbc\x86\x21\x64\x35\xbe\xa5\xcd\x86\x91\x17\x89\x21\x67\xb7\xf0\x26\xc6\x33\xaa\xec\xa7\x2e\x11\x2e\x6a\x74\x91\x9b\x02\xa2\x9a\x63\x6c\x4d\xa4\xd0\x5a\x1e\x8d\x6b\x20\x00\xe8\x88\xa1\x93\xfc\x83\x24\x3f\x8e\x7a\xe4\x2d\xa3\xd7\xcc\xf5\x23\xc4\x92\xa2\x66\xf6\xe0\x4c\x46\x07\x39\x86\xd6\x8c\xdb\x85\xac\x67\x13\x60\xaf\xa5\xe3\xb9\xa7\xd1\x41\x7a\x10\x3d\x1b\x2a\x3f\xe5\x84\x23\x2b\x79\x08\xf6\xf7\xd5\x2f\xf4\x36\xac\x40\x86\xfc\x0c\x57\xb7\x30\x9d\x38\xd2\xa8\xf7\xa6\xe9\x7d\x4f\x61\x8d\x50\x5b\x69\x06\x9b\xc7\x9b\x8b\xa2\x1f\xf6\x6f\x3e\x44\x77\x40\x58\xf0\x53\x96\xf5\xe6\x4d\xb3\x8a\xef\xdd\xbb\x38\x1f\x2e\xb3\x7b\xb4\x59\x87\x72\x83\x0e\x69\xe1\x01\x19\xf5\x96\x00\x4b\x00\x1c\xc4\x56\xd2\x63\x59\x24\x00\x9b\x09\x43\x8f\xc6\xb5\x51\xae\xa5\x23\x13\x4f\x37\x46\xba\x8b\xed\xf5\x9b\xc1\xc6\xa6\xf3\xd4\x91\x28\x30\x02\x6f\x14\x4d\x66\xed\xa8\xa8\x00\xc8\x33\x0e\x9b\x21\x2e\x14\x1c\x31\xac\x7c\x59\xa6\xab\x2f\x0a\xb7\x46\x36\x10\xd6\xda\xac\xc3\xb3\xb6\x1e\x0c\xb6\x38\xed\x92\x90\x42\x9c\xe8\xd4\x8f\x0a\x9b\x03\x1c\x57\xfd\x1c\x65\x4f\xea\x42\x68\x95\x81\xe6\x83\x67\x4e\x5f\x21\x70\xd0\xdb\x31\x4e\x06\xd7\xb0\x0e\x9a\x5a\xad\xd9\x4f\x77\xd9\xaf\x45\x06\x70\x27\x9c\x05\x5b\x1b\xa9\xf6\x5d\x5c\xfd\x53\x14\x45\x76\xf8\xdf\x47\xf7\xe0\x19\x34\xb0\x99\xa2\x2c\xb8\x9f\x22\x7d\x9b\x6e\x72\xfd\xd6\x05\x23\x22\x13\x74\xb8\x48\xfb\x39\x00\x43\x5d\x03\x8d\x8a\x7d\x2c\xf1\x16\x5d\x9e\xea\x34\x77\x47\x2e\xd2\x7c\x91\xcd\xbe\xcc\x32\xd6\x05\x2b\xab\x2f\x38\xbd\x2f\xe4\x01\x25\x12\xd7\xb2\x4e\xac\x6b\xe3\x2b\x99\xe4\x00\x6f\xb3\x80\x6e\x07\xda\x74\xed\xa1\x3d\x32\x4a\xaa\x1e\xb5\xe2\x76\xb4\x6d\x00\xae\x5b\x78\x90\xa5\xda\x1d\x98\x0a\x32\xd1\xd3\x1c\x52\x35\xd2\xbb\xd1\xbd\x7f\xfd\xfb\xec\xe0\xbf\xde\x13\x97\xc9\xb5\x73\x59\x06\x9e\xb4\xa6\xde\x75\x6a\x49\xc7\x34\xb9\xa0\xb5\xcc\x2d\x69\x61\x63\xc2\xc8\x26\x47\x00\xb0\xad\x17\x02\x04\xdc\xda\x7a\x18\x28\xce\x04\xc7\xbd\xc9\xb4\xb4\xc6\x46\x0d\x13\xb6\xf2\x27\xd3\xed\xfd\xfd\x35\xfa\xf1\x37\x09\x42\xf9\x9b\x5f\xd0\x5f\xd4\xc3\x97\xd7\xb0\x53\xde\x4e\x13\x26\x3c\x34\xd4\x52\x81\xa2\x0d\x2f\x24\x1c\x3a\x23\xb0\x30\x97\x77\xa3\x33\x6c\xfa\xfc\xd2\xbe\xbc\xef\x12\x88\xb6\x3b\x74\x6b\x47\xfc\x54\xff\xca\xdf\xee\xce\xc4\xb9\xf2\xb5\x67\xb7\x14\xc3\x0c\x0f\x3c\xf1\xd8\x94\x31\x9b\x27\x89\x92\x8c\x15\x66\x7a\x91\x82\x94\xfc\x03\x73\x48\xba\xe4\x68\x4e\x98\xf3\xb3\x6e\xdb\xc0\x4c\x11\x66\x17\x4a\xc7\xca\x55\xe2\x74\xf6\x25\xd5\x86\x2f\x26\x2c\xe9\x66\x83\x2a\xdd\x9d\x21\xb8\x99\xd9\xf2\xda\x2c\xac\x10\xc5\x0b\x91\xd7\x7e\x9d\x5c\x74\xb5\x56\x05\xf4\xb6\x43\x9b\xd9\xf2\x33\xf3\x64\x97\xa8\xb5\xd7\x14\x21\x3b\x6e\xbf\x1d\xf7\xb2\x4d\x20\xdc\xeb\x93\xdd\xad\x8e\xa1\x21\x15\x25\x8a\xf4\x77\xc8\xf6\x54\x7b\x78\xa4\x24\x19\x4c\xca\x56\x20\x75\x35\xae\x89\x11\xbc\x66\x0b\x91\x13\xe9\x94\xcf\x7d\x4c\x24\x8e\x8f\x8d\x02\x2b\xb4\xc5\xab\x94\x96\x53\xad\xb3\x27\x05\x80\x9b\x33\x99\xd2\x72\xd9\x67\xfa\x8a\x1f\xe1\xaa\x8d\x47\x77\x89\x68\xcb\xc7\xd6\xf8\xdb\x12\x45\x42\x2f\xdc\x46\x9d\xe9\xe5\x6b\xa0\x31\xf8\xb1\x02\xee\x7b\x60\x79\x17\x9d\x21\xba\xd0\x2c\x93\xdb\x7a\x9d\x57\x75\xa3\xde\xed\xfa\x95\x09\x2e\xd2\x22\x7c\x99\xd9\xb5\xfc\x15\x2a\xa6\xb7\x20\xbd\x6d\x9a\xa2\x62\x7e\xe9\x2d\x1f\x60\xb8\x4e\x4e\xcf\xba\xc4\xbd\xa1\xfe\xe7\x40\x3c\x5b\xcd\x0d\x80\x0a\x61\x2b\x50\xb4\x5c\x9d\x54\x13\xb8\xe7\x75\xd3\x52\xee\x45\xf6\xe1\x7d\x2b\xee\x77\x99\x8c\xc8\xab\x8a\x29\x28\x51\x76\xfe\xac\x64\xd9\x62\x63\xe7\x62\x34\x1e\xde\x55\xed\x2b\x8d\x69\xa2\xa5\xb2\x6e\x52\xe0\x80\xac\x93\x35\x7d\xe4\xb9\x85\x3b\xdc\x8d\x87\x36\xa4\x91\xbb\x34\x72\x1d\x4c\x32\xa4\xc3\xb8\x33\x03\x82\x96\xbe\xe9\x4e\x86\x99\x1f\x4a\xa0\xea\x66\xa4\x0d\xef\x19\xed\xb5\x55\x51\xff\x28\x17\x84\x88\x65\xc8\xb5\x24\x39\x45\x30\xaa\xc1\xf0\xf1\xb9\x38\x2f\x91\x4d\x9e\x7d\x9a\x56\xe5\x62\xf1\x41\x6a\x79\x62\xdc\x8c\x7e\x65\x59\xb7\x00\x16\x53\x34\x73\xdb\x9d\xa6\x0d\x55\x6c\x46\xe2\x03\x96\x49\xf5\xf7\x35\x19\x21\x7d\xb0\x46\x43\x57\x5c\x1a\xb8\x2f\x4e\x4a\xb8\x2f\xd7\xc3\xe6\x7b\xf9\x5c\xde\xcf\xb4\x66\x95\xb2\xe6\xbe\xfe\xc2\x3a\x61\x14\xc5\xcb\xdb\x64\x0e\x24\xf1\xd7\x37\xef\x5e\xbe\xff\xeb\x97\x3f\x3f\x7f\xf7\xf2\xb7\x57\xb1\x65\xcc\x7a\xcc\x5b\xc9\xa5\xea\xac\xf9\x73\x17\xc2\x18\x5c\xb7\xe0\x27\xc9\x36\x82\xec\x74\xb9\x6f\xaf\xac\x1c\x12\x7a\xe1\x00\x86\xbb\x6e\x95\xd2\xd8\xd2\x94\xdd\x08\xdf\xa3\x68\x87\x65\x0f\xc5\x1c\xaa\x14\x6d\x93\xca\xa8\x69\xe4\xff\x79\x49\x54\x0a\xd2\xa4\xd4\x80\x43\x07\x0c\xb8\x03\x19\x1f\xf2\x4e\x3d\x4c\xb9\xce\x2e\x5d\xc8\xbb\x9f\xc1\x87\xad\x1d\x43\x62\x11\x87\x40\xd1\x53\x90\xd8\x01\xc3\xe3\x96\x18\xee\x16\xf0\x5e\x2b\x0f\x98\xd5\xfc\xdf\x31\x68\xec\x80\xb5\x23\xf4\x48\xbc\xe0\x24\xf8\xca\xaa\xd7\x56\x09\x4d\x38\x2a\x21\x1d\x39\x2a\x45\x34\xfd\x6a\xe8\x1a\x54\xf5\x4b\x62\x82\x75\xa4\xf4\x0a\x08\x09\x0c\x1a\x88\xa6\x50\xce\x75\xb0\xb4\xae\x03\xa3\x1c\xfb\xf0\xc9\x6d\x8a\xcc\x41\xeb\x29\x1b\x11\xc4\xbf\x8e\x7e\x46\x91\x36\x68\x80\xe5\x1d\xf6\x78\xfc\x68\x2c\xb6\x9f\x75\x28\xf2\x88\x2e\xb4\x9d\x03\xba\xba\xca\xab\xdd\x37\x72\xc0\x54\xe1\xce\x5e\x87\x1d\xf2\x28\xec\x41\xca\x8b\x9a\x68\xdb\x47\x7b\x56\x49\x1e\xca\x95\x4a\xb3\x36\x9e\xb5\xb5\xf7\xbb\x70\xed\xb5\x21\xd7\x4a\xa3\x05\x2b\xda\x73\x01\xce\xcd\x64\x5b\x8b\x16\x17\x56\xba\x47\x00\xa6\x76\x96\xb3\xa4\x71\xe5\x67\xc9\x39\xc7\x96\x2e\xae\xf0\x66\x1c\xaf\xad\x3c\x9c\x6f\x3c\xb5\x12\x8c\x51\xcf\xc2\x4a\x55\x86\x86\x2b\x93\x66\x1f\x83\x8b\xce\x37\xf8\x36\xa1\xf4\x3b\x03\x9b\xdc\x62\xf5\xea\x01\x47\xfc\xc4\x64\xf9\x1b\x0f\x67\xe6\x49\xf8\xcd\xbf\xa5\x51\x3e\x7e\xdc\xe5\x4b\x67\x3c\xba\x4b\x88\x57\x45\x8b\xf5\xb5\x07\x05\xf5\x43\x52\xe4\x18\xa1\xcc\x37\x8c\xd5\x3a\xfe\x6c\xab\x22\xcf\xd0\x94\x09\x40\xf2\xf4\x62\x4e\x90\x76\xfe\x62\xce\x0c\x1c\xf3\xe7\x53\xba\x77\x2d\x6f\xdd\x40\x18\xd7\xba\x51\xb8\x0f\xd2\xf3\x7c\x91\x7b\x81\xd0\x0c\x39\xbf\xbf\xdf\x8f\xde\xbc\xfb\xf0\xf9\x84\x74\xba\xc8\x25\x05\xf2\xc0\xfb\xfb\x1c\x77\x9a\x12\x91\x26\x00\x32\x0b\x1f\xc9\x9e\x7f\x7c\xf5\xdc\x2d\x09\x19\xe8\xbe\x8f\x13\xa7\xfc\x62\xf6\x6a\x96\x93\x92\x24\xeb\xb4\xea\xc1\xbc\x31\x72\xb1\xb6\x39\x39\x0a\x78\xa4\x7e\x2a\xcd\x34\x23\x91\x51\x9c\x09\xed\x88\x82\x5c\x63\xc4\x14\x7c\x38\x38\x3f\x98\xd6\x71\xed\xba\x20\xc9\x06\xc6\x33\x31\xc9\x9c\x74\x56\xc8\xcd\x16\x7b\x2c\x19\x5a\xdd\xe3\x8e\x0c\xdd\x01\x4c\x1a\xf4\xa5\xb5\xbf\x8f\x74\x2c\xba\xca\xeb\x1e\x0e\xe6\xb3\xd3\x32\x3d\x1e\x72\x5a\x93\x43\x8e\xb7\x32\xed\xd1\x90\x8e\x9e\xee\x99\x9d\xb7\x90\xd4\xab\x49\xa4\x3b\x1b\x6b\x60\x94\x4d\x9e\x6d\xac\xc4\x57\xc5\x6c\xa3\xa5\x6a\x6d\xb7\x1e\xb0\xc3\x81\x7d\x57\x57\xe9\x6d\x0e\x70\x26\x85\xd4\x39\x53\x72\xbd\x41\xc2\xde\x12\xf4\xf0\x0e\x8b\x0e\xff\x34\x87\xd2\x4b\x81\x24\x09\x07\x34\x6e\x59\xda\x77\x4a\xe3\x97\xdd\x48\xc9\x62\xc3\x77\xbd\x74\x41\xd2\xb7\xc4\x20\x37\x37\xb2\xff\x11\xb5\x0b\xf4\xa6\xa8\xc3\x0b\x6d\xc5\x38\x93\xbe\x68\x4a\xf6\xb8\x43\x4b\x1f\x78\x4d\x2a\x61\x7a\x65\x02\xec\x58\x70\x5f\xfc\xed\x48\x0a\xe1\x6e\x86\xf1\x7d\x53\x0a\x6f\x5a\x3f\xb9\x4d\xc8\x39\xf1\xae\xa0\x49\x90\xda\x99\x5c\xfb\x3f\xea\xef\x8d\x00\xda\xba\xdd\x04\xe5\xc1\x35\x2f\x0f\x29\x4b\x3b\x02\x62\x55\xb1\x61\x6d\x2d\x37\x49\x5c\x3b\x1c\xab\x3a\x28\x2d\x7e\x4c\x68\xd8\x41\x68\xf1\x98\x9d\x2a\x18\x7c\x16\x8f\x1f\x3e\x14\x21\x74\x06\x19\xbf\x12\x22\xfe\x09\xb3\x9d\x8b\x83\xcc\xf8\x97\xba\xff\xa8\xed\x03\xd5\x72\xff\x9d\x56\xcf\x1b\x60\xf7\x60\x89\x2f\x6e\x6e\x1a\x5a\x69\xde\x19\x8f\x1f\x56\x91\x3b\x59\x4d\x56\xd7\x1c\x51\x4d\x7a\xa0\xe2\x84\x4c\x2b\xe5\x0d\x00\x59\x5c\xb4\x74\x6a\x64\xd7\xfc\xae\xab\xf4\x28\x32\x92\x9e\xc3\x31\xd6\xc0\xee\x2a\x7b\xa8\xf1\x1e\x03\x58\xad\xcf\x61\xee\xfd\x11\x96\x4d\x6b\xbe\xca\xa0\x85\x8b\xc1\x20\x8e\xa2\x90\x88\x7f\xd5\x2f\xa9\xfd\x92\x82\xcc\xac\xfa\x3c\x0e\xf4\x76\x62\xc9\x51\x33\x4b\x8e\xaa\x06\x71\x80\x9e\xd6\x8a\x49\xfa\x54\x39\x4b\xd9\xdf\xdf\xc3\x41\xa6\x03\xd2\x07\x31\xd2\x47\x3d\xa4\x74\xe0\xc9\xe2\xd5\x29\xd3\xe0\xaf\xda\x16\x8d\x86\x7f\xa5\x57\x32\x50\x2b\x6c\xf9\x0b\x1c\x91\x22\x4a\xf1\x2c\x49\x95\x0a\x0a\x6e\x60\x2a\x57\x2b\x1d\x0c\x72\xeb\x01\x5a\x6f\x41\x8a\x2b\xdf\x98\xaf\x01\x69\xa7\xc8\x38\xba\xd6\x0a\xe6\x46\xd9\x15\xd6\xa8\x46\x37\xc6\x66\xfc\x53\x4b\x85\x60\x2d\x2d\x06\xa2\x08\x7d\xc5\xd0\xdf\x15\x07\x68\x1d\xc8\xa7\xa9\x1c\x37\x6f\x30\x59\xf5\xa7\x37\x37\x72\x81\xf5\x34\x16\xe4\x6a\x7b\x7a\x9c\xc6\x35\xf2\xe9\x93\xc9\x3c\xb9\x40\xfd\x66\xf9\xfc\xb0\xa4\x28\xec\xfb\xfb\x73\x86\xac\x35\xff\x82\x5e\xfa\xcb\xa4\x80\x72\x53\x01\x57\x86\x40\xef\xdb\x7b\xe3\x9b\x1b\xca\x93\x13\x5a\xf5\x17\x07\x07\x4f\x67\xf2\xa5\xe0\x16\xda\xd6\x96\x75\x5e\x24\xd1\x30\x42\x7f\x6b\x6a\x37\x66\x09\x1a\xfe\x2d\x95\x9c\xde\x92\x55\x05\x18\x5b\x74\xff\x16\xb2\x0b\xef\x93\x53\x4b\x93\x61\x57\x76\x4e\xdd\x41\x43\x37\x60\x50\x22\xe6\xdc\x86\x4a\x1b\xa0\x75\xd6\x78\xd8\xa8\x70\xc0\xd7\x77\xa6\x4f\xd2\x85\x18\x1b\xc8\x7c\x76\x38\xb6\x4f\x4c\x33\x88\xb5\x22\x26\x7b\x3b\x05\xb6\xf9\x5b\x56\xd5\x80\x07\x95\xe5\x6a\xcb\x40\xc2\x3c\x91\x32\x44\x4f\x30\xc6\x22\x8c\x0a\xe1\x23\xa7\x02\x7b\x63\x41\xc8\x96\xd5\x9c\xa7\xf8\x08\x26\xf0\x19\x69\x6f\x04\x59\x03\xd3\xc9\xc9\xf7\xf2\xc3\x3c\xad\xdb\xb6\x0f\x78\x77\x4e\xfb\x00\x54\xdc\x25\xd7\x13\xd8\x41\x14\x71\x0a\xf5\x60\x35\xf5\x5c\xc9\x56\x5a\x6d\xb5\xda\xd9\x88\x2f\x4a\x7c\x07\x34\x32\x30\xf1\xaa\x2e\xac\xf5\x9a\xf2\xde\xc1\x05\xf2\x32\xab\xa7\x70\xfd\xa5\x24\x5f\xae\x45\x5e\x9b\x52\xef\x2f\xe2\x5c\x7c\x7a\xf5\xe1\xf9\xc7\xe7\x27\xef\x3f\xc6\x17\x01\x3e\xb9\x83\xb0\x6e\xc9\x9f\xc7\xa3\xed\xd1\xd9\x5c\x17\x95\xb4\xff\x91\x4a\xb3\xbc\xc3\x99\x47\xca\xee\xc7\xbd\x62\xa0\x44\x1e\x8d\x0c\x55\x1b\x68\x49\x5b\xbf\x54\x2c\xb6\x68\xcc\xa1\xcd\xa5\x0e\x9f\xdf\x2e\xbe\x73\xf6\xcb\xd3\x1c\xb5\x0d\xd1\xc8\x04\x5f\x43\x93\x92\x2f\x4a\xfa\x5d\x6d\x24\xa5\xdf\xef\x7c\x82\xf3\xcf\xa3\xd1\x6d\x6a\xbd\xca\xf9\x4f\x72\xa4\xe4\x74\xbd\x01\xb4\x78\xbd\x99\xa4\xc3\xef\x28\xf6\xb9\x45\x53\x45\xa7\xe8\x13\x68\x56\x62\x4f\xaf\x29\x3a\x8a\x41\x27\x85\x52\x2b\xe4\x5d\x59\xfc\x96\x5d\xa6\xd3\x2b\xd9\x2e\x66\xb3\xe7\x2f\x53\xa6\xb3\xc0\xc6\xd2\x25\xb1\xc7\xd8\xad\x95\x62\x8f\xd1\xd9\x2a\x33\x40\x7d\x53\x75\xbc\x0d\x12\x3c\x98\x3b\xa9\x6b\x1e\xfd\x22\xd9\x62\x01\xa1\xdb\x13\x70\xa0\x8b\xd3\xd1\x59\xd2\x28\x35\x1c\xab\x57\x80\xad\xae\x55\x80\x45\xf8\x82\xfe\xe6\xa6\x5f\x95\x17\x1c\x36\x02\xc1\x7e\xbe\x2c\x4b\x0c\x77\xc1\x10\x81\xd2\xa0\x17\x46\x3d\x21\x41\x73\x90\x3f\x6a\x64\x9c\x40\x32\xb8\x9d\x5a\x1c\x03\x6a\x69\x6d\x59\x08\xa0\xaa\xd0\x21\xca\x54\xec\x8e\xf6\x4d\xd1\xb1\x57\xba\xb3\x82\x48\x1e\x76\xba\x1d\x5e\x50\x54\xbe\x73\xcd\xe5\x70\x7c\x68\x11\xe3\xef\x6c\x12\xe2\x70\xbb\xc0\x20\xc9\x45\x86\x0d\x49\x05\x85\xee\x26\x42\xf3\xc5\x0b\x28\x38\xd6\x04\x9f\x91\x74\xa3\xb4\xc5\xa1\x51\xf9\xdd\xe2\xfb\x21\x54\x03\xb8\xe1\xe6\x5e\xc0\xee\xfc\x95\x8f\xfc\x2b\x25\x6c\x1e\x59\x4a\x59\xe9\x2d\xef\xba\x6d\x6f\x5f\xbb\x3d\xdb\x8e\x47\x3b\x6b\x6d\xa6\xb3\x45\x56\xdd\x3f\x22\x91\xe0\xf5\x8b\x3f\xbf\x7a\xf1\x97\x4f\x9f\xdf\x92\xb5\x23\x19\x3a\xc6\xd1\x2c\x6d\xd2\x43\xd6\x93\x21\x1d\x87\x7a\xbd\x8c\x44\x3a\x9b\xbd\x90\x1f\x27\x25\x2b\xab\x06\x58\xf1\xc2\x62\xe9\x50\xef\x8d\xb4\xe5\xfa\xd1\xb3\x48\x44\xbd\xe8\xa0\x1a\xb6\xbb\x3b\xf8\x25\x89\x7e\x39\x68\x0e\x7e\x89\x9e\xfd\x82\x24\x48\x5a\x7c\xcc\x60\xe0\xad\x1e\x14\x3d\x5a\xb2\xfb\x5d\x13\x92\x3b\xd4\xe8\x60\x52\x62\xd8\x65\xe0\x74\x6b\xd4\x41\x46\xe3\xa8\x91\x72\x47\x6c\x0f\x31\xa7\x6d\xb7\x2f\xc5\x8a\xf7\x47\xad\x11\xf0\x3c\x63\x5a\xdd\x9d\x15\xe1\xf4\x52\xbc\xb2\xb9\xdb\xfd\xfd\x37\xfa\xe1\x2b\xe8\xa4\x19\xc9\x7c\x72\xc4\x8d\x17\xe2\xdb\x40\x84\x49\x45\x8c\x9f\x36\x67\x93\x82\xa9\x98\xfe\x79\x7f\xaf\xa6\x28\x81\x03\x81\xe9\x89\x72\xad\xcd\x1f\x93\x0e\x5b\x10\x5b\x31\xcf\x5e\x49\xff\xbb\xff\x9d\xde\xe8\xc2\xde\x76\x79\xc0\x05\x93\x4d\xf2\x4d\xff\x2d\x29\x68\x20\xc3\x69\xb5\x81\xaf\x05\x3c\x9e\x30\x5b\xd4\x9a\x2b\xb2\x3b\x75\xff\xed\x69\x86\xca\x1e\x40\x48\xe3\xaf\xe4\x8d\x79\x65\x45\x52\x93\x02\x99\x66\x34\x6d\x5b\x8d\xc0\xf0\x4d\xd0\xfe\x39\xb1\x4e\x89\xa6\xf3\x0b\xbb\x11\xef\xa9\xb6\x61\xf5\x94\xfd\xfd\x4b\x58\xce\x4c\xc5\xac\xd8\x1b\x49\x82\x73\x6f\xec\xb0\x46\x5a\x89\xc1\xed\x7d\x6a\x76\x13\x33\xac\xbd\xaf\x89\xc1\x38\x46\x65\xc7\xfe\x4b\x18\x4f\x6c\x37\xb8\xc0\x6a\x2f\xf9\xed\x6d\x39\x6c\x11\x89\xa8\xec\xaa\x90\xf4\x4b\xd5\xa6\x2c\xde\x48\x75\xdf\x80\xb4\x3f\xe0\xa4\xc8\x93\xbf\xcf\x6f\x23\x72\x5c\xb5\x0b\xd7\x53\x11\x23\x3b\x23\xbd\x5c\x6e\x7d\x21\xfd\xd6\x16\xe6\x5f\x06\x25\xa6\xd2\x3b\xd1\x2c\x5b\x55\x19\x3a\x69\x9e\x19\xe7\x44\x36\xcf\x21\xfb\x7d\x53\xe8\x6d\x34\xde\x8a\x58\xd7\xab\xc9\x15\x23\x63\x3f\x2a\x9c\xb7\xb9\x29\xe9\xb3\x88\x15\x33\x59\x8e\xdc\xaa\xf6\xb1\xa5\x5d\x35\x6b\x13\x46\xfd\xb9\xab\xec\x33\x40\xcf\x46\xcb\xa1\xa6\xbd\xc5\xf7\x64\xd5\xb6\x2a\x17\x6f\x91\x20\x3c\x49\xc6\xe2\x7d\xf2\x44\x7c\xc0\x8f\x4f\xf8\xdf\x3b\x34\x29\x93\xbb\xfc\x06\x15\xd5\x95\xed\xfe\x9f\xae\x6c\xfe\xee\x83\xe0\x37\xb9\xb7\x7c\x47\x78\xe8\x12\x85\x40\xe2\x0b\x9b\x25\x38\x76\xd3\x9d\x86\xe4\x52\x47\x4a\x81\xd9\x9b\xa1\xd3\x3c\x9c\x0d\x8b\x4c\xd0\xe8\x9d\x94\xa1\x01\xc5\x56\xe8\xcd\x2d\x23\x93\x75\x56\x7d\x09\xf7\x87\x27\x93\xad\x6b\x51\x28\x46\xaf\xd1\x49\x72\x72\x73\xe3\x7c\xbf\x87\xe5\xbb\x18\x66\x05\x1a\x6a\x5a\x8f\x96\x72\x20\xe4\x79\x5c\x1f\x6a\xd3\x9d\x04\x86\xbe\x51\x88\xfe\x80\x54\x7d\x26\x0a\x1a\x55\xc8\x84\x3c\xfe\xe6\xc5\x4e\xe5\xb7\x3b\xd1\x69\x72\xde\x11\x24\xf8\x85\xf4\xcd\x88\xec\xc0\x9b\x61\x7b\x09\x28\x08\xaf\xf6\x73\x3a\x74\x4d\x58\x95\x99\x0c\x2c\x22\x36\x29\xd0\xb7\x9f\xef\x79\x96\x54\x7e\x71\xed\xe6\x01\xcd\x4c\x19\xde\x0c\x66\x0b\x73\x27\x86\x49\x33\xbe\xe5\xf0\x8b\x54\xaf\x95\xe5\x31\xf7\x07\xf0\xb9\x1a\xcd\xc1\x36\x87\x80\x04\xa5\x9d\xd4\xe7\xe4\x4d\x2b\xa0\xff\x73\x8e\xf7\xaa\x15\x2d\x5e\xa1\x2e\x4c\x8d\xd1\xc6\xde\x10\x75\x85\x43\xcf\x66\x12\x56\x51\x3b\x6c\x9d\xd4\x68\xbd\x20\xa6\xbc\x38\xa1\x95\xa5\x19\xae\x6d\x5f\xb0\xd2\x11\xec\x14\xad\xdb\x84\x56\x07\x26\x2d\x7c\x47\xed\xb8\xe3\xb9\xfc\x23\xb3\xfc\x7a\x92\xdc\x2d\x6c\x04\x87\xfd\xe8\x6c\x8e\x6c\x70\xc2\x4d\x6a\x31\x2f\x3e\xdf\xf2\x72\x42\xe9\x19\x30\xac\xaa\x9b\x73\x54\x96\x79\x33\xdc\xd2\xbc\xdc\xc9\x8d\x68\xc1\xed\x2d\xf4\x14\x1d\x1a\x40\x29\x5b\xf4\x91\x80\x12\xc7\xd0\x32\x50\xa8\x25\x0b\xea\x43\xe6\x27\xba\x87\x91\x0c\x0f\x6f\x68\xc7\x00\x80\x4e\xfc\x80\x64\x87\xda\x99\xe3\x7e\x1b\x22\xd4\x30\x50\x89\x52\x45\xe4\xee\x61\x2d\xf5\x1b\xfb\x46\x41\x08\xde\x7d\xad\xee\x55\x6d\x0f\x51\x20\x3f\x9f\xb5\xba\xc2\x98\x88\x0e\xae\xa0\x75\x69\x3d\xdb\xa1\xf3\x35\x14\xb2\x92\x06\xfe\x64\xd0\x48\x0f\xf0\xf4\xd9\xb7\xb2\x60\x27\x3a\xc8\x82\xc0\x72\x6c\x59\x7d\xd2\x16\xfb\x64\xad\x53\x61\x35\xac\x88\x96\x40\x93\xdd\x54\x49\x66\x01\x2f\x96\xd1\x2b\x80\x7d\x13\x49\x81\x4a\x2c\xde\x69\xf3\x65\x70\xe3\x3d\xf5\xfe\x80\xcb\xa5\x28\x9b\xf1\x44\x75\xae\x43\x4b\x2a\x28\x3b\x6e\x1c\x91\xdd\x97\x58\x7a\x73\x72\x94\xc8\x9c\x5e\x8c\xb6\x59\x86\x56\xa2\x8d\x15\xfd\x10\xe9\xc3\x09\x8d\x23\x84\x18\x9a\x81\x51\x05\xc6\x1d\x34\xf5\x5c\x49\x5f\x6b\xf2\xc1\xd7\xa0\x77\x32\x26\xd7\x82\x94\xcb\x58\x28\x4e\xcc\x76\x09\xab\x57\xc9\xdd\x16\xca\x2c\x32\x19\x4f\x2a\x63\x23\x69\x59\x50\xa2\xdc\xfc\xb4\x3a\x38\x38\x9b\xa4\x13\x69\xee\xa5\x97\x29\x1d\x4c\xea\x63\x7c\x67\xa8\x8f\xf3\x24\x8d\x97\x43\x57\xd6\xd6\xc7\x08\x3d\x68\x16\xac\xfa\xc0\x01\x15\xd2\xbd\x89\x35\x08\x60\xf4\x43\xa9\xd0\x73\x3a\x2c\xb2\x1f\xcd\xa7\xfc\x1c\x55\xac\x36\x14\x71\x4c\xbb\x56\xd0\x2e\xb9\xf2\x8d\xf5\x01\x3c\xc0\x78\xe0\x8b\x64\xe3\x82\x0c\x04\x5f\xc6\x15\x3e\xa2\x91\x3e\xaa\xf4\xdc\x1f\xa7\x62\xb5\xae\x2e\x51\x58\xbb\xde\x4c\x14\x52\xd4\x8b\x9b\x5c\x79\xd7\xa0\x97\xaf\x53\x38\x16\xa8\x78\xa3\xdd\x52\x19\x16\xea\xcd\x76\xe3\xff\x5b\x55\x0c\xee\xa2\xed\xbc\x55\x0d\xc7\x25\x52\x21\xeb\x41\x58\xb5\x20\xf8\xca\x65\xd1\xa0\xf1\x98\xfd\x2b\xde\x42\x82\xc6\x63\xd6\x23\xea\xa6\x40\xa1\x44\x07\x93\xbf\x85\xfe\x04\x06\xff\x51\x90\xe1\xdf\x59\x51\x5b\x5e\x61\x33\xe9\x4e\x40\xf9\x1c\x89\x33\x61\x0e\x1c\x2b\xdb\xb1\x93\x81\xa1\x63\x9d\x2b\x2c\x17\x26\x00\xf1\xd4\x46\x33\x38\x1c\x0b\xcb\xd2\x96\x6b\x6b\xcf\x2b\xb2\xb1\x52\x7e\x6c\xfc\x37\xbc\xbb\x8d\xc6\xb1\x06\x76\x46\xc3\xa5\xba\x87\xd1\x84\xc7\x20\xe3\x03\xee\x3e\x02\xcb\xf4\xf8\x67\xfb\x47\x3c\xe6\x9b\x70\xdd\x65\x08\xb6\xa1\xf3\xf6\x31\x34\x9d\xfb\xe0\x8d\x01\x2d\x94\x66\xfa\x75\xb0\xbf\x1e\xfe\x29\x9d\x7e\x85\xd3\x6c\x3b\x16\x1a\xde\xea\xb9\xa7\x3f\x13\x4b\xa0\xfd\xfa\xae\x89\x92\x69\x19\x50\xd4\xd2\x28\x91\x22\x3a\x6d\x05\x0e\x0c\xa8\x7c\xbd\xc5\x20\x64\xd4\x13\x77\x43\xf6\x18\x46\x07\xec\x62\x91\x02\xde\x28\x5e\x68\xfb\x28\xf3\x50\xd6\xcd\xfd\x5d\xec\xc0\xea\xe1\x70\x67\xc8\x7b\x2d\xf1\xbf\x6f\xc9\x35\xf9\x21\x8d\xd9\xa4\x5d\x75\x17\xbc\x7d\x16\x4c\x28\xa1\x23\xad\x64\x34\x91\x8e\x6d\xe4\x7d\xa7\x2a\x26\x85\xfb\x44\x51\x28\x5d\xf7\xe2\x34\x27\xaa\xbd\x15\xff\x31\x1f\xa8\x2b\x68\xd5\x4f\x99\xc1\x98\x60\xe1\x84\xdd\x9d\xad\x13\xdf\x83\xce\x01\xfa\x73\xa8\x3d\xfe\xa2\xbf\x16\x52\x67\x9c\x5d\xe4\xbc\xcc\x56\xcd\xfc\x60\x0c\x97\x99\x4c\x60\x8f\x48\x25\xea\xf3\x23\x3c\x02\xc5\x5d\x1e\x1c\xe8\xa8\xbf\xd5\x46\xda\xb6\x5b\x81\x5d\x1c\x02\x60\x7e\x70\x20\xe9\x89\xbd\x11\xe9\x6e\x4a\xf5\x8c\xe0\x22\xe8\x25\xa8\xa4\x5b\x0c\x7f\xce\x95\x8a\xf4\xf2\x45\x51\x7e\x58\x53\xba\x66\x2f\xd0\x3f\x09\xf0\x24\xff\x59\x05\x16\xb4\xc6\x84\x3b\xd0\xa0\xf3\x49\xa5\x24\x3a\x3f\x3c\x14\x73\x24\x88\x8f\x01\x22\xe3\x14\x61\x54\x4d\xa5\x63\x2f\xd5\x4c\x0a\x35\x13\x39\x10\xa7\x0e\x15\xc5\x58\x7e\xed\x9e\x0a\xbb\xa7\x2f\x5b\xbb\x72\xc0\xa6\x63\xa9\x10\x24\x6e\x6e\x14\x7b\x2e\xd4\x9b\x3a\xae\x60\xc9\xab\x17\x02\x9a\x52\x03\x0d\x32\x51\xe8\xdb\x83\xd8\xaf\xda\xe7\x04\xd1\x14\x1d\x35\xf3\xd1\x1d\x18\x80\xc8\x74\x30\xa0\x61\x18\x2a\xb9\x16\xa9\xc8\xf1\xd1\x8a\x55\x00\xd2\x1f\x7d\x07\x60\x30\x0f\x6d\xf0\x29\xce\xa4\x01\xb6\x29\xae\x8e\x0b\x59\xfc\xce\x7f\x5d\x93\x0b\x91\xee\xc6\x3a\x77\x1d\xdd\x2c\x31\x93\x3b\x87\x83\x30\x95\x07\xc1\x82\x68\xab\xf0\x73\xf9\xa0\x3d\x17\x25\x0c\x1f\x58\xd4\x14\x40\x59\xaf\x58\x35\xd8\x6b\x3d\x0b\x96\x40\x2e\x16\xfb\xfb\xb8\x16\x37\x37\x9d\x63\xa0\x85\x2c\x09\x82\x8a\x0e\x74\xe0\x04\xbe\xe9\x06\xfc\x86\xcd\x20\x25\x04\x64\x24\xd1\x6d\x71\x39\x30\x9e\x00\xe7\xb3\xe9\x42\x2c\x44\x27\xeb\x9d\x6b\xbf\x52\xdb\x4b\xfd\xb4\x20\x15\x0c\xdf\xf7\x96\x53\x86\x14\xb9\x65\x88\xa0\x56\x8b\x83\xeb\xa2\x5d\xbd\x71\x1b\x20\x06\x37\x34\x20\x15\x55\xb3\xbb\xef\x01\xa9\x7e\x75\x21\x9b\x3c\x50\x1b\xe5\x5c\x1d\x70\xd0\x2d\xeb\xf2\x31\x67\x43\x16\x2d\xde\x8a\x03\x4e\x0c\x62\x4e\x67\xc0\xca\x07\x85\xb5\x5e\x14\xb8\x4c\x74\xec\x56\x38\xf9\xe6\x46\xc5\x14\x6a\x65\xb1\xfc\x5c\x04\xc0\xd2\x17\xf9\xb1\x57\x0c\x73\x84\xb3\x81\xf0\x86\xca\x21\x86\x02\x4c\xb5\x64\xd4\x3b\x47\xe0\x6a\xd9\x7f\x73\xbc\x0b\x84\xb4\x82\xc3\x77\x38\x90\xe1\xa4\x5f\xe0\x5f\xe1\x40\x64\xef\x48\x3d\xdf\x42\x2b\x13\x6d\xbc\x8b\xad\x1c\x51\x03\x5f\xb3\xab\xb7\x39\xda\x04\x47\x6c\xe3\x74\xed\x7a\xa6\xa1\xd5\x72\xdd\xd1\x50\x92\xed\x8c\x86\x12\x1c\x47\x34\x4c\x69\xb5\x5f\x95\x4c\x67\x40\xf7\xf3\x40\xef\x16\xf6\x53\xc9\xa1\x52\xeb\x7d\x81\x8d\x6a\xab\xe3\x7e\x09\xd4\x82\x50\x0e\x32\x30\x64\x5d\x81\x4a\x49\xa1\x74\xf8\x5d\xd1\x8b\xac\x92\xe0\x55\x61\xc3\xa4\xb2\x2d\x2f\xcf\x19\x80\x50\x85\x41\x68\xa7\xf6\xc1\x78\x23\xee\xa1\x45\xf0\x0d\xc7\x1a\x71\xb5\x9b\x81\xca\x21\x8b\xcc\xb5\x52\x67\x52\x1c\xde\xeb\xb2\x3a\x49\x2f\x1d\xc3\xcb\xda\x86\xc7\xf5\x96\x10\x38\x6d\x5d\x96\xf1\x76\xab\x40\x0b\x40\x28\x2a\x0e\xb7\x6a\x8c\x28\xec\x15\x29\x31\x1c\x10\x09\x64\xd9\x2d\x40\xfb\xd1\x98\xdd\x76\x04\xf4\x22\xb2\x21\x9c\x81\x74\x3a\xff\x98\x5d\x74\xe4\xcf\x32\x99\x8f\xaf\xcc\x33\x23\x04\x79\x5e\x43\xda\x49\xd9\xf6\xc4\xda\x2f\x87\xf6\x68\x50\x95\x06\xe3\x13\xaa\x6e\xa4\xd4\x48\x62\x08\xa7\x35\x14\x65\xed\xda\x5e\x95\x5d\xd4\x88\x93\xe8\x19\xb2\x30\xa3\x44\x78\x12\x92\x64\xd6\x22\xd0\x96\x25\x1a\xd6\x46\x0b\x54\x3d\x2a\x5f\xd5\xac\x8f\xfa\x04\xd8\x1f\x20\x39\x19\x71\x79\x62\x21\x6d\xaa\x9f\x24\xc5\xb1\xf9\xba\xde\xc4\xfa\x83\xfd\xda\x36\x1b\xa1\x87\xe5\xec\x89\x8d\xe6\x68\x1e\x99\x87\xd9\xa4\x39\xa9\xbd\xf1\x80\x9c\x02\xb1\xb8\x08\x90\x76\x0e\xbe\xe5\xfa\xca\x2d\xe4\xb9\xbb\x76\x3c\xa7\xb3\x3f\xf7\x12\xf0\xae\x4a\x28\x6e\x73\xba\x5b\x6c\xac\x13\x71\xed\xb8\x78\x77\x41\x71\xe8\x34\x0c\xe7\xb1\xf5\xee\x4d\xf3\xf9\x09\xd3\x09\xa3\x00\xc4\xf7\x2b\x2a\x6d\x25\x01\xa5\x2e\x54\x33\xc2\x27\xe2\x6a\x10\x57\x9b\x96\x5a\xef\x9d\xf4\xc2\xa6\xa8\x17\x56\xa1\x03\xbd\x76\x2f\xd8\x1e\x5c\xc8\xe8\xab\x2d\xce\xda\xf9\xe8\x3c\x86\x06\x88\x05\x36\xda\x3a\x9a\xe1\x2b\x88\x06\xf3\x70\x3c\xb3\xb4\x8d\x0b\xa4\xd5\xd3\xff\x2a\xf3\x42\x62\x37\x32\x74\xf2\x9f\x0f\x8b\xb0\xd7\xb8\x92\x82\x0a\xe2\x01\x1d\x90\x49\xbb\x72\xff\x11\x03\x4f\x87\xad\xb1\x4b\x3c\x8c\x89\x45\x2e\xc7\xe2\x35\xd9\xbc\x53\x88\xa1\x8b\xac\x92\x91\x23\xd0\x5e\x64\x0a\x40\x53\x5d\xb6\x42\xbf\x5b\x5d\xc1\xb9\x26\xff\x72\x03\x61\x9d\xd8\x46\xb6\x44\xf5\x1c\xe4\x62\xd4\x5f\xfa\xca\x8f\x11\x3e\xac\x53\x3c\x3e\x14\xd1\xb3\x67\x05\x2b\x1e\xa2\xf0\xc0\xab\xcb\xdd\x58\x38\xee\x58\x58\x46\x66\xaf\x2a\xa4\x3d\x0c\x09\xc5\xc6\xdb\x15\xce\xa5\x91\x7c\xc0\x12\x7e\x3c\xde\xae\xdd\xb8\x8d\x64\xc0\x29\x33\x15\x20\x7d\x44\xc8\x0f\xdc\xbe\x17\x56\xca\x6e\x24\xc1\x78\xbb\x22\x8f\x7b\x02\xf5\x57\xd3\xb7\x5c\xa6\xe1\xfb\x5f\x52\xde\xdc\xbc\x90\x5e\x8a\x91\x69\xd6\x2a\x78\x7d\x55\x4c\x5a\x64\x5f\xa2\xec\x41\x0b\xff\x91\x36\x20\x1f\x29\x28\x07\xfe\xc7\x3a\x07\x8c\xd1\x23\x4f\x3e\xbd\x7f\x8b\x0e\xaa\x83\xe8\xdf\xc8\xef\x4e\x51\x36\xbd\x7a\x95\x4d\xf3\x8b\x3c\x23\x9f\x4a\xd1\x41\x3f\x82\x02\x25\x14\x18\x46\x40\x62\x48\xbf\x4e\xca\x4c\xc3\xd8\x95\xee\x19\x0d\xdf\x82\x5e\x04\xb8\x0f\xb7\x0c\x6a\xc9\xf9\xbe\x56\x5b\x13\x55\x0f\x9c\x84\x52\xd2\x64\xd6\xe7\x40\xc1\xe9\x5e\xa2\xe2\x58\xd6\x30\x37\x62\x7e\x97\x7d\xa3\x2d\x6e\x4d\xf0\x4d\x41\x8e\x6c\x60\xf0\x35\xcf\xaf\xc0\xf9\xa1\xbe\x22\x5c\xbf\xf8\xbd\xc6\x6f\x9c\x5a\xbd\x5e\xad\x16\x38\xd5\xa6\x54\xeb\x20\x7a\xb0\x93\x14\x64\x03\x53\x32\x39\x71\x2d\x33\x29\x1c\x45\x9f\xd2\x56\xc0\x7e\x35\x6c\xe6\x69\xf3\x91\x3e\x5d\xb9\x59\x7e\xfb\x4c\xc9\x93\x93\xeb\xf8\x47\xc9\x88\x52\x9e\x6e\xcd\x4b\xb1\x6d\xba\x69\x60\xba\x72\x07\x6b\x4c\xdb\x3e\x5d\xe5\x3f\x8b\xe6\xab\xb0\xf6\x3a\x19\x4d\xd6\x4f\x73\xf5\x9e\xb2\x56\x2e\x87\x50\xa8\x97\x8b\x35\x4d\x03\xc7\x3e\x6d\x39\xe3\x19\x98\x38\x8b\xc1\xb5\x43\x31\xa5\xfe\xc8\x0c\x17\x87\x0b\xf1\xad\xf5\x16\x8e\x9e\x54\x15\x87\x77\x09\x60\xbf\x75\x1d\x4a\x5e\x87\xc6\x9f\xb3\x5c\x8b\xc2\x9b\x77\xcf\x7e\x86\xf0\x76\x3b\x73\x3d\x34\x85\xb7\x11\x87\x4c\x57\xa0\xb5\x06\x99\x72\x64\xc4\xbb\x97\xe2\x63\x1d\x59\xe7\xbd\xd8\x3a\xf4\xdc\xda\xc2\xc0\xd0\xbd\x2d\xd3\xc1\x3e\xa0\xc3\x7f\xa3\xfd\xdf\x06\xad\xeb\xae\xf1\x1b\xdb\x0e\x79\xe8\xd0\xcf\x68\xe6\xf9\x19\x45\x9d\x3a\xf2\x95\xcb\x6d\x4f\x9c\x93\xe8\x47\x4a\xb8\xd3\xb1\x24\xd3\x2b\x4c\xc8\x77\x3b\x97\x40\xdb\xb2\xe3\xb2\x35\x39\x04\x1b\x84\x67\x3b\xbd\x13\x7a\x51\x2e\xae\x00\xcb\xa4\x36\x96\xb9\x33\x7a\x91\x1b\x95\xee\x74\xde\xb8\x53\xf7\xc0\xb1\xef\x65\x5c\x70\x9f\xc6\x59\x0f\xfe\xa8\xb3\xb7\xb8\x1d\x12\x46\x93\xdc\x80\x40\xae\x8e\x3d\x80\xb1\x12\x69\x13\x7b\x9a\xea\xaa\xb2\xcb\xcd\x4f\x2c\x5d\x07\x9c\x77\x6f\xed\x6a\x0b\xea\x98\xff\xef\xc0\x15\x28\x59\xda\x82\x28\x2e\xfe\xcf\x80\x9e\x02\xbb\x1d\x6e\x36\xee\xf2\xdf\xda\x90\x97\x69\x10\x3b\x5d\xd3\x3e\x4f\x39\x61\x91\x4c\x1d\x98\x5b\x28\x10\x5b\x6c\x6c\x18\x13\x51\xab\x8f\xc8\x5a\x98\x39\x2e\x4c\xfd\x3d\x47\x2f\x6e\xc6\x95\xdc\x34\xad\xb3\xa8\x58\x2f\xcf\xf1\xb1\x95\x3e\x18\x93\x44\xb1\xd2\xd7\x9c\x50\xea\x39\xfa\x6c\x48\x0b\x9d\x9c\x71\xb2\x5c\xbe\x38\xe4\x39\x4f\xab\x2c\x67\xdf\xb2\xea\xaa\xcf\x96\x6d\xed\xdb\xc5\x68\x86\xfa\xc2\x5c\x1b\xa4\xb4\x8e\x85\x2e\x2c\x7d\x9f\xc6\x5a\x9d\xd4\x4c\x75\x66\x34\x41\xd4\x4c\xd5\x86\xfa\xa3\x3c\x8e\xe8\xde\x8d\xe2\xcc\x3e\xc8\x1f\xb3\xcb\x57\x3f\x56\xc7\x7a\x7a\x96\xba\xef\xd2\xf6\x8f\x93\x39\x40\xc4\xb1\x3c\x50\x53\xd6\x6e\xeb\x25\x70\x10\xca\x94\x0f\xc5\x6b\xd1\xc4\x2f\xc1\xbd\xa9\x32\x55\x76\x09\xfb\x18\xb9\xee\xa1\xbf\x05\xbd\x76\x5d\x6e\xf1\x7a\x47\x3e\xc2\xb7\xab\x7f\xfa\xcc\xd7\x8b\x24\x7a\xfa\x34\x2d\xca\xe2\x6a\x59\xae\xeb\x67\xcf\x22\x71\x4e\x76\xe0\x3f\x12\x38\xf4\xe2\x63\x72\x4d\x4b\x15\xc3\x59\xe0\x35\xc3\xc0\xb3\xe5\x02\xbf\x15\x74\x0c\x48\x93\x2f\xb6\xcd\x22\x30\xaa\x07\x42\x17\x26\x4a\x38\x1b\x08\x5e\x30\x4c\x2a\x95\x14\x88\xc1\x0e\x93\x24\x00\x02\x33\x58\x5c\xc5\x25\xba\xe1\xc4\xde\xc8\xea\x2a\x93\xfe\xf2\xce\x85\x5a\x3e\x48\xae\x05\x6a\xe2\xc4\x3f\x64\xab\x90\x32\x15\x70\x4d\xc1\xdf\x35\xff\xc5\x65\x89\x17\xa2\x9e\xa7\xf0\xf7\xc2\xb8\x9c\x8c\x95\x62\xc6\x50\x2d\x5e\x1d\x89\x68\x6a\xe9\x65\xc8\xfe\xa4\x62\xc6\xb9\xd2\x20\x44\xe9\x42\xb8\xb2\xc9\x87\x0f\x1c\x96\xac\xfa\x63\x60\xf3\x47\x1f\xbb\x5d\x94\x6d\xd9\xcb\x18\x38\xb1\x0e\x2d\x8a\x60\x98\xe9\xf1\xf8\x0e\x9e\x66\x89\xcf\x5c\x48\xcf\x2e\xc0\xa8\x7e\x58\x63\x04\x06\x5b\x90\xe9\xba\x6f\x2a\x6f\xd5\x85\x0e\x07\x32\xf7\x42\x87\x5f\x4b\xf7\x67\xd0\x9d\x72\x2b\xd3\x12\xca\x04\x86\x26\x9f\xf8\xcd\x43\x03\x3e\xf2\xc3\xa2\xfd\x25\xbb\x8a\x1b\xfa\xc5\xfe\x78\x0a\x8a\xc6\x65\xda\x76\xc2\xe5\x29\x6c\x93\xc1\x7d\x9b\x3d\x0d\xf5\x22\x6f\xe0\x4c\xdd\xc0\x32\x88\xbf\x5b\x0a\xc5\xc6\x18\x6e\xc9\xc4\xe2\x6e\x86\xf6\x13\xce\x50\x0e\x4c\xfe\xa2\x81\x0d\xd8\x09\x43\xd6\x96\xe3\x05\x47\x90\x8c\x50\xf0\xd6\xe9\x85\x8a\x5a\xea\x0f\xd0\x9b\x54\xe5\x7a\x93\x2a\x6c\x1d\xa2\x62\x8b\xbc\xa0\xcb\x25\x4f\x87\x62\x11\x41\xd7\x1d\x9c\x1a\x6e\x0f\x91\xaf\xfc\x8e\xe3\xd1\x39\x29\x3f\x35\x00\xf3\x53\xb6\x55\x41\xcf\xfb\x32\x53\xe9\x4f\xc1\xb0\x66\x57\x8e\x77\x23\x56\x11\x66\x41\x89\xd9\x05\x72\x9c\x97\xd4\x56\x39\x47\x2c\x8f\x36\x45\xe7\xe9\xf4\x2b\x15\x33\xf0\xec\x02\x79\x7e\x2b\x90\xa7\x8e\x8e\x3e\x74\x6f\x7b\x30\x71\x82\x54\x7a\x23\x33\xce\x7a\xdc\xf0\xff\xd3\xb0\xb8\x6c\xe1\x46\xeb\x1f\x76\x78\x12\x91\x51\xfc\xd3\xa1\xef\xe1\x83\xdc\x31\x5a\x2d\xb4\x9e\x57\xd1\x53\xb6\x34\xae\xea\x1b\x53\x9e\xa1\x71\xfb\x85\x2a\x71\xa8\x89\xce\x3d\x38\xef\x10\x76\x29\x02\xed\x8b\xae\xbe\x42\x7b\xa9\xc1\xd7\x6f\xba\xa3\x78\x51\x36\xc0\xe6\x3c\x5f\x2c\x10\xe2\xc5\x7c\x6b\x57\x3e\x3c\xdc\xd6\x57\xab\xbc\x8d\x3b\xa8\xbf\x59\x72\x3a\x17\x14\x44\x0d\xf5\x59\x30\x90\x80\xb5\x7f\x7f\xad\xd2\xd5\xca\xc3\x32\x72\x29\x67\x46\x9d\xd0\xcc\x25\x50\x2e\x34\x65\xaa\xea\x03\x50\x57\x5d\x7f\x0a\x5d\x98\xc3\x38\xfb\x0a\x75\x39\x08\x1f\x3b\xf6\x1e\xe7\xd6\xf4\x3b\xec\x3a\x8a\xec\x7b\x66\x32\x75\xf0\xff\x7a\x48\x72\x52\x54\x77\x2a\x6f\x47\x5d\xee\xa1\x8d\x1f\x3c\xbe\xb3\x8b\xb1\xdb\x14\x25\xbd\x33\x1c\x8f\x47\x26\xaa\x71\xeb\x08\xc3\x85\x4c\x5a\x84\xf6\x09\x8e\xc7\xf7\x1f\x13\x76\xdc\xc9\xb3\x68\x77\x34\x7a\xef\x9d\x21\xe4\x5e\x00\x9f\x1b\xd0\xdc\x30\x18\xa9\x9e\x76\xca\x3c\x62\x14\xc1\x77\x89\xbb\x78\x2a\x9d\x9a\x57\x2b\xdf\x48\xa2\xb1\xf4\x93\xda\x81\xf3\x5f\x1a\x7c\xd2\x38\xf8\x18\x11\x0a\xdc\x89\x1c\x77\xaa\xef\x61\xa4\x8a\xbc\x0b\x28\xeb\x0f\xdf\xb8\x03\x0d\xf4\x84\x09\xee\x99\x0e\x03\x96\x94\xfd\x12\x8e\x39\x35\xa0\x35\x8a\x2c\xc8\x1d\x6c\x7c\xcf\xba\x7f\xfc\xfc\x46\xbb\xcd\xaf\xcb\x82\x45\x4e\x72\xfb\x24\xac\x27\x16\x8f\x39\xc8\xb7\x9a\x8f\x39\x41\x95\x69\xbd\xd4\xfa\x79\x17\x97\x8a\x3d\x5d\xb0\x17\x7d\xf7\xb6\x5a\xdf\xae\x21\x38\x6d\xbd\xe8\xd8\x01\xdc\xcd\xa5\x4f\xd4\x7f\x21\x42\x54\x00\xbe\x6c\x6d\x27\x98\xb7\x7b\x0e\x74\xa7\x07\x79\xa6\xe2\x96\xd9\xc5\xe3\xa3\xd1\xcf\xa8\x1e\xe3\xc9\x3a\xba\x8b\x83\xdc\x9f\x26\x8e\xb2\x30\x92\x2e\x77\xa4\x8d\xf2\x2e\xda\x28\x48\xe9\xfb\x04\x53\xbe\x9d\xb8\x49\x43\xc4\x4d\x67\x90\xa3\x20\x3b\x3a\xfd\x3d\x54\xc4\x7a\xe3\xd1\x4c\x77\x25\x0d\xd6\x48\x32\x9d\x2e\xc4\xf4\x0c\xc9\x99\x9d\xef\xf9\xd5\xff\xd3\xee\xf9\xf2\xa7\xef\xf9\xfc\x77\xdd\xf3\xb5\x73\xcf\xa7\xf2\x9e\xbf\xd8\x89\x45\xf9\xfd\xf7\xfc\xce\x77\x75\x37\xf7\x7c\xf4\x33\x3e\x41\xad\xf0\xb1\x5e\xec\x26\x0b\x25\x6e\xc5\xd7\xfe\xe1\x90\x07\x29\xab\xa7\xe9\x8a\x94\x85\x5f\x97\x95\xa4\x62\xe8\x44\x59\x5b\xbd\x01\xe6\xba\xb6\x16\xbd\x92\x8b\x7e\xed\xde\x2b\x9e\x77\x70\x24\x2f\xa8\x9c\x77\xfd\xb0\xa1\x20\x49\x2f\xb8\x9c\xb4\xf5\x4f\xfb\xd6\x9b\xb4\xf1\x2f\x12\xc2\x50\xc7\x79\x1c\x3d\xad\x57\x29\xbe\x65\x2a\x9f\x79\x9c\xa3\x8c\xb1\x0e\xa2\x67\xf4\xf4\xf0\xf4\x1e\x16\xc3\xa8\x97\xbe\xea\x6b\xc0\xba\x4b\xbe\x8d\x93\xf3\x41\x33\x16\xb4\x58\x33\x61\xa9\x1a\x98\x7d\x48\xf7\xbe\xa5\x74\x4d\x66\xef\x6d\xc5\x4b\x94\x2f\x0f\xa4\x3e\x78\xe0\xcd\x1e\xe5\xc2\x18\x72\x83\x0e\x8a\xf7\x1f\xb0\x40\x93\x35\xfb\xe8\xa8\x45\x4b\x99\x2a\x0c\x2c\xf1\xc3\x6e\x77\xb9\x5b\xd4\x01\xbd\xbb\x30\x08\x24\x00\xcf\xc4\xaf\x1f\xed\xac\x85\x32\xb8\x9e\xf5\xbf\x0c\x99\xc2\xc9\xa6\x65\x31\xcd\x17\xf6\x9d\xb4\xbf\x7f\xe5\x18\x9f\xec\x76\x83\xcd\xf2\xca\x72\x58\x5a\xff\xc6\x82\x0d\xe3\x1d\x7b\x6a\x9f\x79\xf6\x10\xaf\xee\x26\x85\xa3\xda\x43\x49\xb6\x0c\xd3\xb9\xdd\x5c\x3b\x15\x7c\xaf\xc0\x81\x5d\xf9\xee\x90\xa5\x19\xa9\x6f\x52\xa2\x25\xd9\x96\xc2\xea\x61\x63\x7f\x05\x63\x11\x66\xe1\x49\x4f\x66\x7d\x34\x77\x5b\x6a\x9f\x8f\x4b\x8e\x7a\x98\x0f\x26\x76\xb0\x99\xe6\x59\x61\xc7\x50\x5d\xca\x87\xea\x6a\x88\xee\x74\xa0\x5f\x9c\x97\x71\xd7\xf4\x65\x05\x90\x0e\x18\x55\xa1\xce\x9a\xcb\xb6\x92\x79\xc5\x2b\x45\x96\xf2\xc4\xdf\x5c\xbc\xcb\xd0\x0c\x85\x62\xbb\x07\x17\x1a\x90\x96\x76\x32\xc5\x4f\x94\xa5\xfd\x44\x99\xb9\xdb\xa7\x82\x1a\xf4\xcb\xd3\x14\x55\x93\x36\x9b\x96\x3f\x09\xc5\x16\x53\x90\xcb\xa0\x4f\x2b\xc1\x3b\x94\xd7\x14\x84\x1c\xe6\x20\x37\xe9\xb8\x2f\x0d\xa6\xe0\x06\x22\xef\x0f\x68\xc3\x9b\xb5\x67\x7a\x1c\x48\x53\x96\x56\x71\x20\x2f\xa1\x77\x06\xa9\x66\xd1\x82\x0c\x42\x82\x6d\x6f\x7e\xb3\x7e\x60\x84\x30\x2e\xbd\x02\x64\xd6\x70\x89\x21\x3b\xd4\xeb\x61\x80\x96\x5a\x84\xe8\xae\xd5\x4e\xbe\x24\xd8\xf5\x83\x36\xc4\x71\xe9\xad\x79\xf8\x4a\x99\xb5\x95\xac\x96\x2d\x7d\xaa\xd3\x33\xf4\x31\xe1\x9e\xc3\x4b\x94\xc7\x49\xea\xe0\xd5\x56\xea\x2a\x7c\xda\x15\xc8\x77\x89\x5f\x82\xb5\xf6\xcc\x51\xc1\xad\xaf\x57\xe8\xb1\x09\x9d\xd7\x75\xd6\x18\x08\x74\xbd\x17\x5b\x26\x52\x1b\xf1\x62\xeb\x70\x5d\xe8\xbd\x45\x48\xe4\x16\x76\xc5\x51\xe7\xc9\xe9\x2b\xf1\xe2\x6c\x32\x77\x42\x08\x5c\xa8\x8b\x78\x67\x32\xf2\x7c\xab\xc0\x77\x0b\x2e\x9d\xba\x44\x9b\x33\xd6\x41\x08\xd3\x52\xad\x6d\x68\xd4\x23\x1f\x43\xb8\xa1\x1b\x3f\xb3\x0d\x85\x44\x36\x5d\xea\x96\x72\x79\x14\x4e\xb2\x08\x8f\xce\x86\x55\xd9\xee\x12\xec\xf3\x8f\x84\xe2\x0b\x2f\xc4\x02\xdf\xeb\x3f\x92\x95\xe7\xa6\x42\xb9\xbc\x16\xd1\xc5\x02\xf0\xc4\x9f\x1c\x0c\x10\x09\xef\xe9\x60\xa2\xe0\xeb\xe6\xe6\x72\x22\x9d\xf0\x4b\x8c\x2e\x65\xaa\xb6\x90\x1a\xad\x1b\x94\x28\x20\x55\x74\x82\x30\x42\x38\x20\x1a\xa0\x85\xcb\xc1\x35\x9e\x31\x69\xf8\xf5\x6d\xe2\x1f\xc0\xc6\x06\x37\x7b\xaf\x11\xc5\xd2\x13\x1d\x8b\x7c\x42\x1b\xe9\x2a\xec\x22\xf6\xdc\xb2\xeb\x46\xb5\x5c\xe1\x36\xa9\x0a\x79\xd5\x6e\x66\x16\x74\x82\xe6\x21\x50\x2a\xa6\x9e\x09\xad\x52\x01\xe4\x79\x45\x82\xad\x2f\xc9\x75\xe7\xe8\x58\xba\xe5\x76\x10\x97\x42\xe2\x5c\x4e\x88\x6b\x11\xd8\xc5\xf8\x87\x25\x14\xfb\x28\xd2\x3a\x5d\xa1\xcd\xb6\xa1\xd2\xbe\xfc\x51\x1c\x48\xa7\xc9\xb5\x63\x26\x1d\x62\x47\xda\x5a\x9a\xbe\x46\xe6\xd1\x2e\x1a\x99\xc1\x70\x05\x96\xf7\xfd\xe1\xdb\xcf\x9f\x4e\xbe\x7c\xfe\xf4\xca\xb8\xcf\x41\xbd\x7b\x59\x1c\x55\x5e\xaf\xa7\x3f\xe2\x4a\x4c\x31\xe8\x2d\x46\x4b\x9f\xe1\xd7\x0c\xbf\x2e\xf2\xc5\x42\xfe\x79\xbf\x4a\xa7\x79\x43\x89\x40\x4f\xbf\x4e\x97\xf9\x42\x7d\x7c\x42\x4c\x0b\x3f\xb1\xda\x05\x45\xce\xad\xd2\x59\x0e\x6b\xc2\xda\xb5\x88\x10\x4c\xda\x67\x40\xce\x35\x7c\xa3\x19\x6e\x56\xbd\x2a\x66\xfa\xf7\xdb\xdc\xfc\x26\xcf\xcd\xf0\x55\x92\xf3\x65\xfc\xa1\xbb\x5f\xa1\xe9\x4b\x55\x48\xaa\x5e\x35\x27\x53\xf5\x67\x99\x17\xfc\x43\x06\x82\x7c\x8e\x1a\x97\xcd\x47\xa4\xc2\x21\xb5\xc2\x7f\x38\x5c\x0a\xf4\x5b\x43\xa1\x74\xf6\x96\x82\x35\xe2\x67\x53\xae\x5e\x94\x8b\xb2\x92\xbf\xcd\xcc\x61\xdd\xcb\xaf\x99\xfe\xf1\x32\xad\xe7\xf2\xa5\x5c\xa6\xfc\x96\x17\x19\x50\xe6\xfa\xdb\xaf\xfa\xd7\x7c\xd6\xcc\x31\x1e\x3d\x50\xee\xcf\x8b\xe9\x9c\xfa\x68\xac\x55\x42\xf7\x55\x08\xb1\xf0\x2b\xcf\xbe\xff\xa9\xc4\x31\xfe\x18\xe3\x7f\x47\xf8\x1f\xfc\xbb\xc2\xaf\x2b\xfc\x82\x66\x37\x18\x71\x41\xfb\x0b\xa3\xd7\xe3\xf8\xda\xde\xad\x08\x3f\x0e\xe5\xe2\x45\xf6\xd6\x45\xf8\xfb\xf0\x82\x3e\x22\xb3\x8d\x9c\xcc\xe1\x48\xda\xdb\x18\xb5\x92\x22\x6f\x63\x23\xe7\x33\xb2\xb6\x39\xe2\x9f\x87\x40\x8d\x45\xd6\x8e\xab\xe4\x65\xae\x93\x79\xf3\x55\x06\x79\x29\x8f\x82\xdb\x1e\x05\x12\x23\x17\x14\x22\xfb\x2b\x0a\x82\x43\x14\x48\x8c\x5c\xa0\x88\xec\xaf\xc8\x82\x90\x08\x7f\x1e\x4e\xf1\x77\xe4\x00\x0b\x67\xe8\x85\xf7\x01\x26\xe2\x84\xc3\x99\x4a\x89\x3c\x08\x52\x05\x16\xfc\x1d\x79\x00\xa5\xb2\xbd\x0e\x18\xbe\x54\xe6\x77\xfc\x8a\x6c\x60\xa3\xf0\x06\x87\x29\x7d\x44\x1a\xc4\x22\xf9\x23\x0a\x59\x72\x78\x9e\x28\x08\x2b\xed\xee\xcb\x96\x9d\x9a\x06\x3c\xc7\xef\xef\xa7\xdb\x42\x1a\x48\x1d\x99\xbb\x38\xfd\x87\x8e\x38\x9e\x8e\xf3\x66\xaa\x58\xb4\x40\x96\x09\xbd\xc0\x0b\x42\x6e\x03\x9a\xa1\xf9\x10\xfc\x93\x1d\xc0\xeb\x1c\xfe\x14\xda\x91\x3b\x64\xe8\xdf\x9c\xaa\x2b\x58\x5f\x9b\x4d\xd0\xd1\xfd\xce\x91\x07\xe4\x48\x9d\xf0\x03\x71\x2b\x1c\x81\x60\x75\xf9\x21\x07\x48\x46\xc5\xfa\x21\xc5\xc3\x21\x7a\x68\x25\x16\xd9\x45\x63\x25\xfd\x06\x9f\x1b\xff\x79\x04\x75\xb1\x2e\xf7\xf7\x59\xf7\x7d\xb6\xbf\x3f\x4b\x92\xb5\xe2\x3f\xd1\xa3\xd1\x8c\x34\xa1\xf6\xbe\xdd\xdc\xec\xad\xfa\xdf\xd8\x97\x77\xd2\x4c\x98\x77\xb5\x5f\x45\xe6\x72\x2e\x62\x69\x05\x6c\x64\xcb\xb9\x44\x42\x44\x04\x74\x51\x43\x31\x7c\x92\x99\xc8\x87\xe9\x14\x16\x61\xbd\x40\xb1\x8d\x74\x18\xfd\x52\x06\x43\xa2\xb8\x12\xa2\xda\x38\xcf\x20\xf4\xb6\x47\x9e\x64\xe1\x0a\xb5\x5e\xf1\x39\x42\x0b\xc0\x6c\x7a\x99\xa2\x13\xc0\x1d\x5f\xef\x3f\x5d\x15\xcd\x3c\x6b\xf2\x29\xd5\x37\xd2\xea\x40\xb8\x11\xf5\xd4\x51\xa3\x04\x86\xda\x6b\x05\x28\xfd\x9a\x5d\xbd\xbf\x30\xae\x15\xe0\x94\x2f\x16\xe5\xf7\x57\xff\x58\xa7\x0b\xf2\xa6\x50\x3a\x21\xc5\xd0\x3d\xfa\x35\xaf\x49\x7c\xbd\xc2\x99\xcf\x3e\x92\x83\xab\xca\xa8\x05\xc5\xd7\xe7\x1c\x47\x2b\x5e\xf4\xaf\xe1\x20\x70\x69\x36\x8d\x10\x32\x9a\x95\x93\x27\xa3\x62\x29\xd7\x15\xc0\x67\x20\x27\x9c\x01\x8d\x05\x8d\x9d\x5e\xe0\x00\xfe\xb4\x58\xc3\x95\x3d\x24\x74\x46\xa6\x16\x6f\xb3\x62\xcd\x09\xaf\x11\x76\xf9\xe7\x5f\xb2\xab\x97\xe5\xf7\x82\x3f\xde\x96\x70\xd6\xbd\xcf\xcf\x2b\xfe\x30\xa7\x79\x8e\x60\x7b\x46\xcf\xe8\xec\x9b\x91\xff\x7c\xe3\x3f\x92\xbd\xbc\xce\x28\x88\x13\xce\x3f\x9e\x0b\x27\x60\xa1\x6f\x78\x5c\x6a\x8d\x46\xa9\xca\xd8\x33\x83\x8c\xfb\x53\x8e\x88\xa7\x22\xb2\x34\xad\x88\x2c\xfb\xfb\xfd\x59\xd2\xe0\x28\xe4\x10\x06\x13\x76\x24\x6f\x9a\xc2\xa5\x88\x43\xa3\x6d\x95\xd4\x2b\x10\x23\xbb\xdf\xca\xb6\x56\x32\xf6\x2a\x7d\x5e\x49\x25\xc6\x1e\xad\x40\xd5\x2f\x07\x56\x45\x6f\xf5\xac\xca\x72\x03\xdc\x14\xd3\x18\xb6\xe3\x5a\x0c\x5d\x59\x51\xbc\xcc\x09\x89\x1f\x3e\x16\xa1\xf3\x11\x3f\xba\xf5\x5d\xdc\x3b\x1c\x40\xc1\x8e\x3a\x63\x57\x88\xf0\xd1\x00\x1a\x97\xba\xe1\x93\x01\x5f\xbf\x0a\xff\x60\x00\xd9\xfb\x90\x2e\x98\x5d\xdc\xf1\x92\x27\x84\x55\xf9\xbd\x7f\x24\x1e\xde\x1f\x74\xbe\x8f\xb7\x59\x6e\xaa\x38\xcd\xf2\x45\x9f\x7e\x01\x25\x33\x2b\x97\xfd\xc1\x3f\x15\x83\xa0\x51\xdf\xd1\x76\xe5\x3a\x8b\x06\x6f\x21\xa4\x76\xd4\xb0\xcf\x4d\xbe\xb0\xde\xda\x02\xa8\x2a\xf7\xb0\xd1\x8b\x45\xbe\x3a\x2f\xd3\x6a\xa6\xd0\x52\xda\x81\xae\x7c\x34\x46\x67\xc3\xc3\x65\x3a\x13\xe0\xc7\x69\x74\xea\xe5\x13\xb8\xaa\xcc\x85\x97\xf9\xb2\x4a\x2f\x55\xde\xca\xcb\x3b\x29\xd7\x32\x76\x9d\x71\x1a\xa3\x33\x3f\xbf\x51\x39\x73\x2f\xe7\xaf\xf3\x2c\x5b\xa8\xcc\x99\x1b\xd2\x11\x8e\x03\x39\x70\x36\x9e\x52\x6d\x81\xd6\x37\x17\xdf\x5e\xb6\xed\x05\x5d\x4c\x8b\x6c\xe7\xf5\x39\x1e\xf6\xdb\x11\xed\x37\x44\xa6\x84\x18\xf6\x46\x36\x92\xd5\xe9\x0a\xc5\x62\xf6\x06\xc5\x48\xf9\xf4\xeb\xae\xed\xbe\xa0\xc2\x81\x86\x29\xc3\x6f\xd9\x42\x2a\xbb\xb6\x6f\x55\x09\xf5\x62\xb2\x5b\x7d\xad\xae\x76\xef\x04\xca\x06\x5b\x5f\x5d\xf9\xcd\xae\x77\xb9\xdb\xb8\x36\x14\x0d\x35\xba\x6e\xbc\x36\x67\xe5\x1a\x6a\xbd\xb8\xcb\xb2\xbf\xb4\xaa\x04\xfa\xb0\xb2\xfd\xbe\x00\xea\x77\xee\x04\xcb\x86\x5a\x87\xf4\x40\xb3\xc8\x1e\xdd\xa1\x65\x2c\xde\xd1\x38\x64\x05\xdb\xc7\x08\x7a\x77\xea\x01\x2b\x74\xf6\x81\x7e\x37\x03\xbd\xfc\xc8\x77\xde\xe1\x97\xaa\x7c\x57\x1f\x90\x17\xe8\x82\x03\x95\xdc\xa1\x0f\xae\xd0\xd1\x09\x65\x06\x7a\x79\xff\xed\x6e\xab\x45\xe5\x3b\xfa\xc0\xbc\x40\x17\xcc\xe2\xde\xa1\x0f\xae\xd0\xd1\x09\x65\xb6\x7a\x01\xf2\x7f\xe7\x0e\xa0\x6c\xb0\xed\x72\xe5\x35\x4b\x2c\xcd\xae\xed\x32\x79\x16\x68\x98\x32\xbc\x96\x73\x24\x16\x76\x6d\x99\x28\x8b\x50\xcb\x94\xe1\xb5\xfc\x55\x92\x4f\x3b\xb6\xad\xa8\xad\x40\xeb\x32\xab\xdd\xfe\x87\x2a\xab\x77\x5e\x96\xbf\xa8\xf2\xe1\x1e\x28\xaf\xdd\xc5\xe7\x9d\xb7\x93\x89\xc3\x70\xe3\x9f\xfd\x0d\x5d\x94\xe9\xce\xc8\xe7\x37\x2c\x1b\x68\x17\xd3\xbd\x66\x33\xb4\xa5\xda\xb5\x5d\x32\xbc\x0a\x35\x4c\x19\x5e\xcb\x4b\x4d\x7e\xef\xd8\xba\xa1\xd7\x03\x3d\xe8\xcc\x50\x2f\x6f\xcb\xdd\xb1\xcd\x5b\x5d\xa1\xab\x17\xcc\x0c\xf5\xf2\x7e\x77\xb0\x7f\xab\xca\x77\xf5\xf1\xbe\x05\xfc\xdc\xc5\x1d\x30\xda\x5b\x5d\xa1\xb3\x93\x36\x4e\x5b\x4a\xf6\xe6\x2e\x7d\x84\x61\x54\x66\x79\xed\xaf\xd2\xba\xd9\x79\x2b\x3e\x50\xe1\x40\xdb\x94\xe1\xb5\xcc\xd6\x19\x3b\xb6\xfc\x91\x0a\x07\x5a\xa6\x0c\xaf\x65\x76\xff\xbe\x6b\xd3\xec\xa8\x3d\xd4\x36\xe7\xf8\x8d\xaf\xcf\x97\xbb\x5f\xb7\x9f\xb8\x74\xa8\x71\xca\xf1\x1a\x6f\x90\x88\x7f\x81\x7a\x96\x3b\x0f\xff\xc4\xaa\x12\xe8\xc6\xca\x0e\xf5\x75\x07\x02\xe8\x44\x95\xef\xea\xa5\x4d\x02\x51\x17\x77\x39\xcb\x27\xba\x42\x57\x27\x81\xb3\x4c\xbd\xdc\xe9\x5e\x3f\x31\x35\xba\xfa\x09\xdd\xec\xdf\x91\x57\xda\xb5\x0f\x62\xac\x42\xcd\x53\x86\xdb\xf2\x06\xdf\xfa\x95\x28\xe4\x6a\x88\x4c\x12\x0a\x11\x99\x56\xbe\x1a\x12\x77\x23\x3c\x09\xc7\xd5\xd0\x62\x4d\x38\x13\x38\x02\x4c\x5d\x5d\xd1\x27\x20\x2b\xf8\x5a\x93\x38\xd2\xa6\xbd\xaf\x86\x16\xf1\x4e\x99\x48\x33\x43\x2a\xfc\x51\x9f\xb8\xcd\x9c\x02\xbf\x4c\x22\xd2\xa6\x2a\x19\x7e\xeb\x0c\xa4\x27\x65\x3a\xfc\x54\xc9\x4c\x02\x72\x3a\xfd\x56\x19\x84\xe3\x38\x1d\x7f\xaa\x64\xde\x10\x4e\x67\x69\x33\x65\x00\x85\x84\x69\xe5\x0a\x3f\xf9\xc2\xba\x1a\xd2\x2d\x27\xb4\x20\xea\x8a\x25\xbe\x98\xc0\x04\xca\xd5\x90\xa8\x1a\x61\xc9\x70\xae\x86\x92\x1c\x91\x89\x4c\x09\x50\x2a\xfd\x14\x5a\xba\x43\x69\x9f\xa9\x3f\xba\x78\xaf\x86\x78\x57\x0b\x47\x02\x75\x35\xd4\xd7\xa1\xce\x20\xc0\x95\x19\xf8\x5b\x67\xbc\xa7\x11\xa9\x3b\xc7\x24\xf3\x3a\xe8\x8b\x42\x58\xe2\x2a\x99\xcc\xa3\x60\xbc\x7a\x35\x24\x64\x8c\x09\x8c\x0e\xa5\x4a\x2e\x26\x48\x24\x76\x25\x43\x5f\x50\x12\xa3\x9e\xab\x21\x63\x2c\x4c\xb2\x71\xc5\xd5\xd0\x42\x36\x3a\x93\x37\x5e\xa1\x06\x9d\x2c\x67\xa6\xcf\xb3\xce\x50\x7b\x66\xce\x20\x66\x31\xec\x5f\x0d\xe9\xc0\x6c\xb4\xce\xd5\x0b\x34\x3a\x7e\x35\x78\x75\xfa\xe2\x6c\x68\xcb\x44\x13\x48\x20\x71\xce\xb9\x23\x99\xbc\x12\x19\xc5\xbd\xd7\xc2\xe8\x60\x78\x03\x54\xcd\xf2\xca\xc9\xec\x49\x49\x01\x2c\x49\x77\x09\x1f\x85\x94\xb8\x87\x55\xe6\x50\xc5\x91\x3a\x7b\xc9\x56\xce\x14\x4a\x72\xab\x28\x54\xfa\x60\xfc\x96\xbc\x42\x83\x44\x92\xc5\x0f\x2c\x6f\x76\x34\x83\xab\x89\x27\x2d\xbd\x1c\x6a\x98\x34\xdf\x04\x55\xe6\x93\x81\xda\x7c\xf3\xee\x9a\x6f\xb5\x93\x49\x6a\xcb\x3c\x2f\x87\x36\x1c\xcb\x90\xa6\x33\x0c\xf6\x6c\x0f\xca\x29\x6a\x64\x99\x97\x46\x96\x79\x95\xac\x5b\xcd\x12\x22\x32\x9f\xf2\x90\x25\x75\xab\x20\xa3\x14\xe8\xfc\x08\x3a\xaf\x86\xe7\xeb\xa6\x29\x8b\x8e\x01\xb4\xe4\xb3\x94\x6a\xa3\x26\x93\x6a\x0e\x9a\x97\x46\x90\xe8\xa5\xbd\x77\x16\xd7\x1c\x2d\x2f\x8d\xe6\x3a\x6d\x4d\x81\xd0\x9f\xfb\x89\xa7\xc0\x4f\x69\x9c\x06\x35\xda\x73\x93\x18\xe5\xb9\x69\xde\x50\x0c\xa6\xb3\xd3\x10\xc9\x25\x8b\xd6\xd8\xec\x03\xeb\xa5\xba\x63\x34\xa7\xd4\x4b\x93\x07\x34\x59\xb5\xda\x56\x28\x23\xb9\x68\x65\xc9\xf3\x9b\xcc\xdb\xfb\x8d\x97\x8c\xf5\xe9\xac\xbc\x44\x53\x49\xbe\x59\xf6\xaf\x58\x05\xe8\x45\x72\x65\xbd\x4c\x7d\xa3\x53\xa4\x9e\xa4\xca\xed\xef\x4e\x2f\x06\xe2\x85\x23\x17\x3e\xbf\x5d\xb6\x6e\x89\x7a\xe3\x47\x47\xdb\x64\xee\x5d\x62\xde\x78\x7c\xf4\xab\x08\xcb\x5c\x21\xeb\xc9\x16\x91\x7c\x48\xfe\x0b\x79\x63\xd1\x2d\xfe\x85\x6c\x77\x30\x96\xf4\x17\xf2\x1e\x88\x0e\x01\x2f\xe4\x3d\x14\x21\xf9\x2e\x64\x3c\x12\x1d\xe2\x5d\xc8\xfb\x55\x84\xa4\xbb\xf1\xf8\x61\x87\x56\x8c\xfb\x62\xd0\xd2\x91\xb9\xab\x2b\xff\xca\x53\x78\x2f\x1c\x9b\x98\x96\x5c\xbd\x4c\xae\xa7\x6a\x73\x5e\xa6\x4d\x1a\xf0\xec\x16\x39\x05\xe8\x7d\xfb\x38\x1b\xba\xb5\xe4\x03\xb4\x93\x08\x70\x55\x0d\xd3\xf5\xe5\x52\x39\xf4\xec\xe3\x4b\x57\xdb\x4c\x22\xb0\xd5\x34\xf3\xed\xa6\x87\x7f\xc4\xcc\x31\x9a\x21\x3f\x20\xfe\xbe\x91\xde\xd5\x53\xeb\x8e\x23\x75\x9e\x29\xe4\x70\x95\x4b\xbf\x9f\x1a\xb6\x07\xf9\x38\xf6\xfb\xbb\x9b\x78\x59\x6e\x0c\x66\x12\x83\x00\x86\xb8\xc8\x2f\x95\x05\x97\x4a\x7d\x4b\xaa\x2d\x89\xf4\x2b\x5f\xa4\xf4\x84\x86\xbd\x26\x85\x7c\x49\x67\x05\x4e\x13\x26\x75\xf8\x06\x51\xff\x45\x3a\x35\xf1\xca\xa5\x4b\x6e\x52\xff\xee\x70\x62\x9e\x26\xe8\x78\x9b\x7c\x7d\xc3\xdf\x24\x3d\x4e\xfb\xc5\x20\x46\x5f\xdd\xd2\x85\x90\x74\x71\x37\x94\x3e\x56\x3e\x30\x2d\x92\xcd\x8e\xdb\x49\x31\x6a\x88\x22\xb4\x93\x63\x03\xa2\x69\xd8\x89\x78\x5e\xbf\xf4\x8a\x62\x84\x17\xdb\x4f\xdb\x49\xb5\xce\x62\x27\xe5\x75\xba\xa8\xe5\x9a\xe4\xb5\x45\x11\x7d\x02\xfc\xbd\x82\x06\xda\x85\x6f\xb5\x5b\xbb\x9b\xe3\x49\x85\x7e\x4e\x48\xfd\x80\x9e\xcf\xae\x29\x5a\x04\x1b\x2a\x50\x6a\x9c\x0a\xe9\xf3\x9d\x4b\xb9\x53\x78\x47\xaa\x9d\x84\xd7\x29\xb6\x35\xab\x2a\x12\xef\x55\x4b\x1f\x86\x74\x63\x92\x0f\x11\x6e\x35\x5f\x66\x70\x11\x2e\x57\x21\xe7\x90\xd9\x50\x67\xdf\xdc\xa0\x2b\x99\x61\x51\x7e\xef\xd3\xb3\xbd\xbf\x0f\x64\xb3\x85\x8b\x5a\xab\xcf\xcd\xa4\x74\xbd\x6d\xb8\x44\x65\x5b\xaf\xd8\xdf\xb0\xbd\xd1\xc4\xf2\xbe\x6e\x01\xe4\xc4\x27\x50\x8f\xdb\x14\x6b\x9c\x39\x90\xa1\x5c\x39\x04\xe0\xa2\x05\x15\x1b\xe1\x91\xc4\x1d\xfe\xe0\xdd\x11\x79\x75\x8e\x03\x84\x75\x8c\x96\x0a\xb8\xfc\x7f\xa2\x1d\xa1\x38\xb2\xbb\x41\x1b\x0f\x0b\xd5\xb5\x81\xb1\x6e\xad\x1c\xd4\xe7\x1c\x3c\xac\x81\x7a\x76\x7e\x08\xe4\xc3\xca\xde\xd6\x4c\xb7\x9f\x79\xe9\x30\x89\x0e\x74\x73\xc6\xfa\x09\x21\x7c\x63\xcc\x6d\x3c\x94\x63\x32\x1c\xac\x43\xa6\x7c\xf8\x56\xaa\xbb\x4c\x6a\x74\x7d\x6c\xa1\xce\xc4\x45\x82\x26\x4a\x05\x9c\x34\x79\xf6\xf8\x01\xde\x86\x44\xe0\x7e\x30\x5a\x9e\x95\x60\x7f\x24\x4e\x96\x3d\xf5\x04\xc3\x3b\x9b\xb1\x90\xbf\x55\x6b\x70\x68\x6b\x91\xb9\xa3\x73\x07\xeb\x1b\x1f\xa2\x8d\x5c\x33\xaf\xb2\xec\xb9\x8c\xc5\x4c\x28\x84\x02\xc9\x79\x56\x8a\x1d\x05\x7f\xde\xbd\x4a\xd8\x43\xab\x87\x7f\xe2\xf1\x23\xb2\x45\xbc\x7f\x67\x8f\xc8\xbb\x5d\x94\xe6\xe5\xbd\x44\x5b\x6c\xa4\x75\x67\x12\xa9\xfd\xcc\x35\x69\x13\x7a\x34\xec\xdd\x1d\x1f\xff\x1f\xa6\x44\xee\x6f\xd7\xa8\xfe\x43\x16\xb8\x4b\x7b\x21\x77\x73\x80\x08\x6f\xdf\x47\x6f\xcb\x19\xfa\x85\x45\x1d\xd8\x26\xe3\x6b\x09\xc8\xdf\x38\x17\x0b\xe9\x22\x4a\x5e\x2d\x4d\xb5\x40\x1f\x48\xec\xa7\x63\x9e\x5f\x34\xfa\x2b\x5d\x98\xdf\xcb\xac\x49\xf5\x47\x95\xad\xe0\x78\xf2\x6f\x6c\x4d\x5d\x4b\xd0\xb5\xd3\x2b\x5e\x7b\x72\xd0\x21\x5a\x17\x86\x83\x0a\xb3\x35\x6a\x5a\x71\x68\xf2\x63\x8c\x15\x1c\x8f\xe8\x95\x6a\x4b\x2d\x20\x7f\x0b\x53\xe9\xe6\x06\xd3\xd6\x2b\xab\x99\x6c\xa8\x1a\x18\xa1\x94\x33\x77\x44\x2d\xb7\xf6\x7f\xe7\x2e\x02\x80\x54\xef\x0a\xf4\x5b\x39\x18\x7b\x83\x21\xed\x89\xe8\xdc\x5f\x38\xf6\x0c\x95\xbb\x6b\xd4\xfe\x3e\xa8\xfc\xe7\x3c\xfb\x8e\xb3\x7b\x9b\x61\xd3\x75\x1b\x28\x7d\xf8\x4b\x93\xeb\x1a\xd0\x7a\x56\xfc\x8b\x84\x35\xfa\xf8\x9b\x84\xc2\x05\x6a\x7a\xff\x8b\xfd\xf1\xb7\x9f\x87\xcf\x16\x1c\xe6\x82\x05\x39\x41\xcb\x60\xce\x92\x4c\x7c\x44\xd0\xc2\x8c\x57\x13\xa3\x10\xa8\x39\x3e\x8a\x1f\xd0\xdf\x31\x42\x13\x97\xae\xd5\x41\xb0\xf1\x5f\x90\x16\x73\x8a\xa0\xd3\xf3\x21\xc6\x05\x93\xaa\x6c\x04\x4e\x75\x35\x95\x9f\x00\x54\x4d\xa9\x54\x72\x9d\x82\xe8\x93\x2c\xbd\xcc\xfe\x25\x04\xc6\x94\xa1\x58\x45\x2e\x45\x2c\x23\x2e\xe8\x41\x39\x94\x84\x27\x4b\x47\x48\x51\x97\x9a\xfa\x5b\x57\x53\x7f\xb3\x9b\xfa\x9b\x6e\xea\x6f\x7e\x53\x27\xe5\x2a\x04\xf8\xe9\x5d\x00\xdf\x07\x22\x48\xdf\x05\xc6\x77\x77\xcd\xfd\xc7\x60\x5e\x1f\x94\x73\x7c\xdc\x58\xa3\x50\xc7\x26\xf2\x4f\xec\xa4\x29\x69\x5e\xce\x9c\xb4\x4e\x78\xdd\x02\xe3\x2d\x50\x2e\x03\x6b\x9e\xff\x0c\xb2\xe9\x58\xdb\xdd\x23\xec\xff\xe4\xfd\x1b\x66\x9a\x60\x49\xd1\x76\xc0\x0f\x9b\x9a\x0d\x31\xd5\xf8\x05\xc5\x2f\x69\xea\xa6\x42\xf5\x33\xe3\x49\x01\x4f\x59\x32\x42\x3e\x35\x75\x40\x53\xe5\xfb\x9c\xbc\xe5\xbf\x94\xca\xf1\xda\x57\xab\xe1\x4e\x11\x14\x6f\x6e\x94\x1e\xfc\x5f\xa9\x25\x29\x6a\xe1\x10\x16\xf9\x22\x7c\xc0\x39\xef\xe6\x26\x78\x0d\x6c\xdd\x99\x96\x06\x6c\x90\x8e\xfb\x0f\x12\x4a\xb5\x04\x1e\xd9\xa2\x49\x83\xf8\x85\x73\x14\x56\x90\xe5\x22\x7a\x0a\x79\x69\x65\x1d\x66\x43\x2b\x2d\x26\xff\x83\xf0\x2b\x88\x67\x38\xc7\x69\xf2\x6f\x76\x93\x7f\x0b\x34\xe9\x14\x08\xe4\xeb\x1e\xff\x27\x9f\x1c\xfa\xfd\x56\x05\x70\xfc\x23\xc4\x37\x3b\x47\x33\xb2\xb5\x4a\x2b\xa4\x92\x83\x6e\x0e\x5a\x1c\x61\xd3\xb6\xf3\x65\x4e\x2e\x6c\x03\xac\xbc\x1c\x7c\xe7\xef\x37\xd0\x07\x8a\x02\x8f\x43\x89\xda\xae\x39\x0e\xe5\x62\xb8\x44\xf6\x67\x91\xd7\x6f\x0a\xdb\xa6\x13\x83\x0e\xfb\x89\x18\x1d\xa5\xc3\x2a\x59\x0a\x14\xdc\xe2\x2d\xbd\xe9\xbd\xbd\x60\x67\x1d\x46\xbf\x14\x25\x41\xa4\xa2\x16\x6b\x74\xc1\xb0\x27\x99\x67\xa7\x6a\x5f\xba\xdd\x9a\x8a\x85\x15\x2e\xb0\x35\x99\x91\x98\x1a\xf6\x5d\x6f\x09\x5a\xc6\x8e\x48\x37\x59\x9e\x1c\xa7\x4b\xac\x62\x02\x0c\x62\xe3\xe4\x65\x59\xf7\x42\x06\xdf\xdc\xc4\x66\x4a\x8f\x75\xab\xc1\xf5\x06\xe3\xec\xf5\x5a\xf9\xba\x95\xae\xb5\xde\x68\x2f\xcd\xc2\x19\x5f\x47\x9c\xe7\x2e\xa8\x11\x00\x87\x93\xe2\xa9\xf6\x46\x6a\xf9\x84\xa0\xe0\x05\x7a\xf0\x1e\x1c\x60\x3c\x96\x72\xf8\xfe\x4f\x9f\x5e\x7d\xfc\xe7\x57\x2f\xbf\xbc\xfa\xf8\xf1\xfd\xc7\x20\x8c\x61\xc1\xca\x5a\xc2\x63\xfb\xc3\xe0\x9f\x01\x1f\x3d\x35\x6d\x8c\x25\xd3\xd1\x58\xd2\xea\xd7\xac\xb0\xbb\x53\xc5\xc1\x58\x2d\x74\x0e\x0b\xbd\xd9\x48\x9b\x7b\x7f\x95\x64\x68\xbc\x00\xa0\xec\xb0\x7e\x80\x2c\x27\x95\x59\xbf\x4a\xad\x1f\x46\xa5\x6e\x30\xf4\xa5\x3c\x98\xfe\x4c\x2a\x5e\xdb\x1c\xa1\xac\xde\x6b\x4f\x0a\x6d\xd5\x68\xb4\xfa\x87\x85\xac\x6b\xbc\x05\x2d\x58\xa3\xb0\xd3\x6d\x38\xab\xcc\x02\xac\x69\x01\xb6\x9e\x77\x58\x9e\x52\x85\x4f\xad\x84\x3b\x9a\xf8\x3a\x64\xa6\xd7\x76\x4d\x76\x7f\xbb\xcc\xdd\x42\x7c\x80\x16\x3e\x17\x64\x14\x96\xcd\x98\x4a\xfc\x50\xd6\xb9\x94\x97\xa2\x5d\x85\x4f\x8b\xc6\x23\xe1\x13\x95\x90\x54\x65\x17\xc0\x97\xcd\x39\x89\x44\x81\x75\x5b\xc6\x55\x48\x23\xbd\x01\x60\xf6\x56\xbb\x70\x96\x7f\x88\xaa\x45\xb0\x42\xf2\x55\xcb\x34\x63\xfb\xb8\xe1\x1e\x26\xc1\xc4\x83\xbb\x08\xef\x89\x76\xa9\x14\x69\x32\x10\xec\x7d\x3f\xf3\xa9\x12\xdf\xb3\x38\x6c\x95\x9b\xd4\x98\xc0\x0c\xfb\xfb\xe5\x31\x86\xf8\x59\xd7\xf3\x21\x6c\xf5\xe2\x8a\xfd\x84\x00\xbb\x5a\xa8\xf4\x3e\x7f\x97\xc7\xa7\xd9\x19\x8a\xc0\x00\x48\xd0\x71\xc9\x29\x14\x74\xdc\x32\x87\x1d\xeb\x15\x5d\xdb\xff\x60\x77\x49\x92\x8d\x9c\xc6\x80\x85\x46\x14\x85\xb7\x34\x91\x09\x4a\x38\x49\x4d\xd2\x6f\x0e\xb2\xa1\x92\x0c\x3c\x6f\xf0\x91\xe1\xbf\x55\x50\x1c\x0e\x77\x03\xbf\xb4\x87\xa8\x9b\xe2\xe9\xd3\xf1\x23\x39\xf4\x47\x0f\x1f\x1e\x8d\x03\x11\x83\x1e\xb4\x24\x46\xee\x88\x2c\x4e\x6c\xb5\x48\xa7\x59\xbf\x12\x6e\x71\xed\x8f\xaa\x29\x3f\xe3\x19\x7a\x81\xee\x11\x06\x1b\x45\x36\xdd\x3b\xec\x0f\x07\xf7\x2e\x43\x3d\xef\x2e\x01\xb2\x22\x3e\x99\x81\x94\x22\x5a\xd6\x87\xe8\xd3\xdf\xda\x9c\x69\xba\xcc\x10\xd7\x11\x55\x76\xef\x5f\x0f\xa1\xc4\xbd\xf6\x2e\xe9\x52\x31\xcc\x9f\xc6\xd2\xe2\xfb\x7d\x88\x54\xeb\x00\x84\xf2\x71\x46\xfc\xec\xde\x28\x46\x43\xcd\xe3\xbd\x31\xfc\x6d\x06\xc7\x54\xd0\x8a\xfe\x4f\xa2\x6f\x19\x94\xfd\xd8\xfc\x64\x67\x38\xe8\xf3\x1c\x4a\x2a\x8a\x5a\x9d\x97\xe3\xbd\xbd\xfe\xf8\xd1\x7e\x67\x7e\x1f\x23\x1f\x42\x87\x80\xe7\x6c\x88\x24\x23\x2f\x0a\xfc\x1e\x02\x49\x93\x0b\x30\x49\xb4\xd8\x83\x16\x0b\x18\x5a\xed\xbd\x3d\x98\xad\xe5\x6b\x5f\xb9\x90\x08\xba\x0f\x42\xdb\xbe\x88\xc1\x54\xda\x15\xef\xa1\xbd\x71\x43\xa2\xe2\x6f\xe9\x82\x12\xb1\x8c\x74\x49\x6f\x85\x07\x44\xaf\xed\xa8\xe2\x03\x9d\xf9\x47\x1a\xba\x42\x0c\x9f\x65\x54\x1d\xbe\xf2\x26\x5b\x72\x53\x9e\xb9\xac\x15\x9a\xe2\xb8\x15\x72\x20\x1b\xd6\xe4\xc3\x06\x4e\x37\x4a\xa8\x30\x58\x9e\x65\xbf\xda\x94\xcf\xd9\xbb\x7e\x1b\xb3\xa9\xac\x78\xfc\xf8\x57\x5a\xb8\xdd\xf9\x3b\x25\x21\x29\xa5\x34\xfe\x75\x8a\xf2\x74\xc2\x53\x45\xa2\xfc\xcb\x32\x31\x7d\x8d\x6f\x03\x8b\x94\x43\xa1\xb2\x67\x94\xd7\x80\xf2\x3e\xa4\x97\xc6\x2b\x5b\x74\x90\x19\x3f\xfa\x7f\xcd\x17\x8b\xcf\x1c\xfb\xd4\xc6\xec\x39\x7a\x78\xdd\x48\x8f\x9e\x21\x37\x86\xb6\x23\x39\xf4\xb6\xe6\x85\xf1\xf3\x9c\xe7\x01\xc8\x65\x3b\x7b\xd1\xdb\x8a\x15\xbb\xda\x8c\x59\x93\x20\xe4\x59\x2d\x80\x48\x5b\xac\x5c\x68\xb9\xb3\xe1\x92\x2e\xf7\xa9\xf1\x94\x07\x47\xf6\x74\x7c\x06\xf8\xe9\xb7\xf2\xbb\xc6\x4f\x36\xf4\xa8\x67\x94\x2a\x59\x4f\xea\xfe\xde\xde\x5a\x05\x6a\xc4\x76\x81\x82\x2d\x81\xde\xe8\xcb\xe8\x33\xc8\x21\xe6\x05\x30\xc3\x7f\x3e\x79\xfb\x5b\x32\x85\x86\x0f\xb2\x83\xe9\xe9\xd1\x99\x26\x8c\x16\x90\x3a\x3a\x9b\x2c\x0e\x0f\x27\x83\x0a\x76\x1a\xb6\x98\x63\xdd\x32\x59\x6b\x57\xcf\xa8\x9f\x15\xfb\xad\x91\x0b\x50\xff\xe9\xea\x24\xbd\xa4\x60\xcd\x51\x3d\xad\xf2\x15\xae\xe8\xca\x44\xb8\x47\x04\x22\x72\x20\x93\x87\xd0\xe1\xab\x14\x63\x8b\x58\x54\xd9\x45\x92\xf7\x01\xb8\xb0\x3b\x3c\xf1\xe8\x2f\xd0\x0c\x00\xc6\xe3\x84\xd5\xb5\xb2\xf4\x6a\x5d\x38\x96\xdd\xa4\x48\x97\xa3\x61\xff\xb7\xbc\x2a\x0b\x77\xcb\x19\x84\xe9\x80\x60\xd8\x4d\x47\x86\xce\x4e\x07\x91\x22\x34\x16\x91\x36\x5f\xb7\xc6\x73\x91\x16\x9f\xeb\xec\xe5\xfb\xb7\xc7\xda\xea\x9e\x9b\x54\x66\xf4\xd1\x2c\xff\x16\x0d\xa4\x90\x07\xb0\xf9\xdf\xeb\x7f\x7a\xda\xff\xfb\xf7\x83\xc1\xbd\xc9\x7f\x6e\x1d\xd5\xe0\x58\xe3\x47\xa4\x34\xe3\x8f\x14\xd0\xfe\x43\xd1\x1a\x28\xd0\x2a\x1d\xf1\x31\x1f\xb4\x78\xd7\x10\xbe\x6c\x63\xca\x63\xf9\x36\xf5\x35\xbb\x42\x67\x0a\xc3\x8b\x7c\x01\xd8\xd0\x78\x26\xb6\xee\x15\x0c\x4d\x3c\x18\x62\x74\xc0\x7e\xd4\x83\x49\x33\x0e\x33\x6f\x72\x98\xc3\xd4\x6e\x2a\x1f\xc4\x6a\x81\x05\x37\x81\x8b\xf5\x2e\x4a\x1e\xea\x01\x91\x69\x2c\x74\x0d\xd7\xf2\x19\x84\x89\x64\xce\x4d\xf2\x22\x15\x35\x25\x92\x0a\x12\x79\xfd\x2e\x7d\x67\x91\x5a\xd5\xcd\x0d\x6a\x1e\x42\xa5\xd2\xd7\x86\x40\xfc\x8f\x61\x4d\x8f\xa3\xe8\xa0\x89\x75\xdc\x11\xd3\x11\x7a\x94\x4c\x80\x92\xa8\xf2\x25\xb0\x1a\xa2\x39\x88\x56\x3f\x22\x37\x8a\xc0\xa7\x4f\x96\x7b\x1d\x54\xf6\xcc\x6b\x74\x29\xb2\xc8\xea\xfa\x1d\xdd\x2c\x6d\xec\x63\xd7\x89\x1f\x10\x39\xfa\xb0\x45\x8e\xfa\x92\x20\x0e\x61\xa4\x54\xd3\x36\x41\xcd\x06\xd7\xc0\xb5\xdd\x71\xf0\x65\xd2\x57\x9b\x7a\xd8\xa2\x0f\x83\x94\x4f\x1b\x9b\x67\x1b\xd7\x27\xe4\xa6\xb2\x5f\xb9\x13\x7e\x40\x75\x5f\xbd\x01\xa1\xa1\x0f\xf0\xca\x7f\x2e\xc7\xf4\x91\x97\x8e\x6a\x15\x90\xce\xfe\x8c\xdd\x1a\x70\x89\x24\x61\x27\xb9\x1b\xb7\xa4\x7a\xbb\x0d\x39\xf4\xcc\x36\xa2\x6d\xe3\xfd\x70\xfb\xfb\xe5\xb7\xee\xc8\x97\x0f\x7f\x82\x9a\x44\x58\x0c\x92\x11\x7d\x00\x50\x38\xae\x8a\xd2\xcc\x95\x14\x10\x78\xc1\x68\x3f\x8a\xa3\xfd\x74\xb9\x9a\x44\x22\x7a\x86\xbf\x2f\x1b\xfc\xf9\x14\x7f\x2e\xf0\xe7\x2f\xd1\x2f\xf0\xf3\x1f\xeb\x92\xd2\x7f\xc1\xf4\xff\xf2\xe3\xe8\xd7\x49\xb4\x01\xc4\x79\xef\x74\xff\xd9\xd3\xe8\x97\x33\x87\x22\xd6\xb3\xbf\xeb\xeb\x93\x3c\x18\xc8\xf8\xb6\x54\x8f\x0a\xba\xaf\x72\xe5\x41\x44\x1e\xf4\x14\x79\x6f\x79\xda\x26\x69\x62\x8e\x60\x52\x1f\x97\x48\x9a\x2a\xfa\x4c\xa6\xe0\x49\x1d\xc4\x8d\xa8\x50\xcc\x90\x06\x7c\x94\x78\xbc\x59\x26\xc5\xcb\xb0\x47\x2a\xa4\x05\x07\xb2\x85\xd3\xbc\xb9\xf6\x7d\xa7\xb3\x57\x58\x43\x61\xc8\x8b\xa5\xa9\x52\xf4\xbf\x84\xfc\xba\x8e\xac\x3e\x98\xb8\xa7\x6d\xd3\xba\x00\x02\x2d\xc6\xe3\x23\x7a\xe4\x0f\x35\x08\xe7\xef\x71\xf0\x3c\xde\x25\x72\x29\xca\x17\x32\x36\x36\xe8\x2b\xb1\x42\x83\x62\x85\x00\x80\xee\xe2\xbe\xc0\xd7\x68\x0f\x50\xb2\xfa\xd6\x87\xfc\x18\xd9\x11\xbe\x15\x0a\xf2\x82\x1b\xe8\x76\x1b\xd5\xc4\x13\x50\x9e\x41\xd5\x25\x9c\xda\x9e\x24\x6e\x6e\x74\xfa\x79\x39\xbb\x92\x73\x34\x67\xc8\xcd\x0d\xcd\x7b\x77\xe5\x48\x49\xc3\xa1\xfc\x4d\x3d\x0f\xab\x77\x45\xc5\xee\xb2\xe4\xba\x8f\x74\x9e\x4a\x12\x74\xdd\xec\xef\x8f\xef\x63\x38\x6d\xba\x42\xc6\xf7\x81\x4d\x6a\x00\x05\x36\xcf\x92\xfb\x47\x37\x37\x94\xd5\x1c\x37\xf1\x28\x34\xc0\xbb\x04\x65\xa0\x47\x15\x18\x9b\xa6\xee\x4f\xe9\xf3\xec\xe6\x86\xfe\x52\x70\x32\xb8\x8f\x66\xb0\x22\x14\x56\x16\xe3\xdc\x99\xe7\x14\xf4\x3d\x14\x78\x37\x57\x77\x70\x65\x85\x92\xe4\xd9\x1c\x47\xa4\x69\x1e\xc5\xec\xae\x9f\xde\x34\xd5\x33\x37\x9c\xf0\xcd\x1d\x1e\xf5\xf3\x53\xbd\xa8\x30\x5a\x77\x90\x71\x14\xd9\x97\x6c\x40\x65\x02\x30\xdf\xab\x7a\x1a\x47\xaf\xc8\xe1\x71\x24\x3e\xad\x00\x31\x9e\xa7\x55\x0c\x34\x88\x20\x51\x54\x04\x30\x5a\x7e\xc7\x9f\x91\xf8\xbc\x92\x9f\x9f\x57\x91\xf8\x98\x5f\xce\x55\x36\xfd\x8e\x04\x69\xf2\x73\x0a\xfe\x84\x84\x6c\x11\x47\x2f\x29\xa6\x79\x24\xfe\x9a\x43\xe6\xfb\x4f\x91\x20\xd3\x80\xc8\xb2\x13\x88\xc4\xf3\xd5\xaa\xf6\x92\xa4\xe2\x7a\x24\xc5\x57\xe5\xf4\x2b\xd4\x2c\xff\xfd\x03\x2c\x18\x39\x9d\xc1\xc7\x40\x77\xba\x88\x88\xaf\x1f\xc7\x11\xba\xab\xae\x71\x22\x91\x78\x12\x47\x27\xe9\x79\x24\xc6\x47\xd0\x3a\x90\x3f\x15\xfc\xbc\x1f\xcb\xd5\x17\xe3\x47\xd0\x3c\x3e\x2c\xc2\xcf\x5f\xb9\x7b\xe8\x0b\x3e\xa0\x91\xe7\x0b\x4c\x85\xfa\x1f\x52\x00\x9b\x48\x1c\x8d\xa0\x40\xba\xaa\x79\x20\x47\xbf\x9a\x35\xbb\x7f\x44\xab\x75\xff\x3e\x96\xbd\xcc\x70\x6d\xee\x3f\xe0\xdf\xbc\x0a\xf7\x1f\x62\x8f\x33\xf8\x01\xfd\xfd\xb9\x5c\x62\x9d\x5f\x9d\x85\xbd\xff\xd8\x5a\xd8\xfb\x4f\xdc\x55\x7d\x30\x72\xd6\x14\x98\xfc\xe8\x4d\x51\x67\xe8\xb4\x0d\xf8\x56\xbd\xbc\x18\x1d\x3d\x7a\x3d\x8e\x28\xce\x74\xf4\xfa\x28\xa2\xb0\xd1\xd1\xeb\xfb\x11\x85\x6d\x8e\x5e\x3f\x88\x28\x92\x59\xf4\xfa\x61\x44\x41\xa7\xa2\xd7\x8f\x22\x8a\xaf\x12\xbd\xfe\x35\xa2\x20\x26\xd1\xeb\xc7\x11\xc5\x5c\x88\x5e\x3f\x89\xc8\x71\x3b\x34\x38\x8a\xc8\xe5\x35\xfc\xc2\xb6\x8f\xb0\xed\x31\x36\xfe\x00\x1a\x07\xd2\x8c\xd7\x03\x45\x0f\xce\x4e\x1d\x1d\x41\xf6\xdb\xac\x49\x23\x1f\x7b\x75\x69\x76\xe0\x99\x7d\x74\x97\x70\x0f\x46\x5a\x2d\xf0\x29\xd3\x56\x61\xc4\x0b\x6c\xe8\x3f\x12\x6b\x7b\x95\x56\x0e\x9e\x4f\x3e\x27\x48\x3a\x68\x8a\xf7\x78\x6f\x0f\x83\x53\xa3\x54\xc6\xa1\xc8\x1c\xf6\x1a\x4e\x10\x80\x4a\x1c\xf1\x33\x76\x24\x24\x10\xc5\x91\x7c\xbe\x46\x70\x6f\xd2\x38\x92\x4f\xdb\x00\xd7\x08\x70\x71\xa4\x1e\xb4\xa3\x90\x4f\x9c\x47\x77\x11\x2e\x2a\x06\xb9\x91\xca\x14\xb6\xee\xc4\xcd\x0d\x8b\x83\xd5\x9c\x08\x61\x6a\xc9\xcc\xb1\x2d\xd7\x8a\x9b\x00\x12\x7d\xb4\x9b\x18\xb1\x04\xee\x3a\x1f\x88\x55\x9b\x33\x40\xdd\x8e\x24\xfa\x27\x64\x22\x83\x99\xb9\xc5\x36\x43\x31\xc4\x6b\xc7\xd1\xd3\x45\x5e\x7c\xed\xdd\x43\x32\xec\x29\x85\xaf\x7e\xf6\xf4\x1e\xff\x8d\x44\x0a\x3b\x94\xec\xe5\xc0\x73\x55\x8a\xc7\xa5\xb4\xe3\x15\xfc\xc7\x2f\x2b\x16\xca\xeb\xe0\x74\xcb\x36\xe7\x9a\xa3\xf0\xe6\x2e\x9c\x6b\x9a\x5c\x4f\xf3\x6a\xba\x40\xeb\x4e\x54\x22\x46\x77\x03\x22\x5b\x2c\xf2\x55\x4d\x49\xe8\xa0\x44\xa0\x7b\x41\xf5\x37\xad\xfe\xbb\xf4\xdd\x88\x29\xab\xb4\x99\xd3\xdf\x72\x71\x75\x89\xcf\x87\xfc\x53\x55\xc0\x92\xe9\xc2\xae\x50\xa1\x3b\x32\x7c\x41\x69\xc8\x99\x04\xbb\xa2\xdb\x1b\x6d\x80\xf2\x3b\x1d\x8b\x5f\x9e\xb2\x7b\xb3\xde\x72\xbd\x68\xf2\xd5\x02\x16\x9d\xdc\x75\x3d\xfb\x45\x60\x4c\x00\xca\x7b\x16\x61\x94\x63\x28\x1c\x3d\x25\x0c\xfa\x0c\xe9\xdb\x7b\xf2\xe7\x19\xb0\xe2\xa7\xf7\x75\xd6\xd3\x06\x2f\x7e\xf8\x53\xc9\x52\x15\xec\x81\x4c\x33\x55\x16\xdc\x5a\xfd\xed\x92\x4b\xd1\x8f\x33\x0c\x91\x06\x7b\x19\x63\xde\xf1\x53\x58\x32\xce\xa4\x1f\x67\x02\x00\x2e\xa5\xac\xa7\xcb\x74\xc5\x39\xf4\x03\x06\x00\xc7\xe6\xf4\xa8\x35\x04\xd5\x2d\x64\x5f\x56\xe5\x5a\xd6\xd1\x5f\xf6\x70\xb2\x4b\xf4\x5c\x48\x8d\xc3\xe1\x5e\xcc\xea\xac\xe1\xd2\xe6\x0b\x46\x97\x56\xe9\x92\x0b\x31\x67\xcf\x45\xd4\xef\x33\xd1\x54\x81\x61\xf0\x2a\xf8\x0b\x50\xae\x1a\x1a\x45\x5c\xe3\x4f\x7c\xd7\xad\xc9\x0e\x18\x7f\xad\x85\x1a\x23\xfc\xa4\x9a\xf8\xf7\xa2\x2c\x1b\xfc\x3b\xcf\xd2\x19\xfe\x9d\xc5\x53\xf8\x80\xff\x24\x30\x2d\x18\x96\x16\x1a\x94\x16\x00\x49\x0b\x06\xa4\x85\x0f\x47\x0b\x06\xa3\x85\x86\xa2\x85\x01\xa2\x85\x0f\x43\x0b\x06\xa1\x05\x43\xd0\x82\x01\x68\x11\x40\xcf\xdb\x44\x2e\x6d\x21\xca\xa3\xbb\x70\x68\xe4\xef\x19\xa8\xdb\xcc\x3a\xbf\x93\x41\x96\x38\xdf\x9a\x93\x74\xb9\x12\xae\x3b\x91\xc4\x5a\x01\xa3\xff\x94\x9f\xa3\x5a\xb1\x51\x84\xb1\x12\x27\xd8\xa8\xc1\x6e\x1b\x2f\x72\x81\x79\x93\x91\xe2\xc0\x3c\x19\x51\xcc\xf0\x92\x3b\xb8\x8f\xcf\x94\x0a\x4f\x52\x4a\x9a\xe4\x07\x25\x79\x7e\x94\xee\x50\xa5\xec\x0e\x89\x51\x60\xc7\xd2\x67\x9a\x20\xbc\xa6\x30\xaa\xa5\x72\xae\xdb\x1c\xe6\x9b\x49\x0e\x5c\x16\xf6\x84\xbe\xe4\x06\x36\x3d\x5d\x2a\x4c\x7b\x17\xa7\x9f\x6a\xc2\xc7\x46\xca\x8e\x86\x99\xa8\x35\x22\x11\x97\xa5\x2f\xa7\x17\xd6\xc6\x8e\x4f\x02\x3c\xc5\xa3\x9d\x59\x24\xfd\x94\x50\xee\xef\x5b\x68\x13\x88\xf4\x32\x89\xac\x25\x42\xb2\x5e\xa3\x52\x6f\x68\xc7\x4e\xc1\x38\xa2\x7b\x00\xf9\x3c\xc4\xcf\x3b\xe1\x70\xd6\xce\xdf\x15\x7a\x69\x86\x77\x91\xf3\xab\x45\x86\x95\xe5\x4b\xf4\xf8\xfa\x87\x32\x33\x23\x85\x42\xf6\x3c\x6a\x71\x52\xde\x0c\xa5\x95\x36\x92\x78\xe2\xca\xae\xf9\xb7\x1d\x6b\xa2\x32\x61\x0c\x9d\x66\x6e\x4b\x99\x95\x1d\xba\xb3\x6f\x11\xa8\x07\x9e\xfe\xa2\xc3\xff\x3a\x8e\x06\x9e\x28\x5d\x3e\xf4\xf5\x4f\x9f\x1f\xfe\xcf\xb3\xf0\x5b\xdf\xa3\xbb\x30\x81\xe6\xad\x6f\x60\x3f\xf6\x1d\xd2\x6b\x9f\xbd\xe1\xf3\xab\xd5\x3c\x2b\x58\xa9\x10\x5f\xfb\xc2\x8f\x7d\xa6\x54\x0c\x53\xa6\xd1\xfc\x84\x80\x54\xbf\x95\x24\x2d\xb1\xa5\x64\xb0\xd4\x9b\x8e\x0a\x8d\xf6\xba\xac\x4e\xd2\xcb\x3e\xe7\x0a\x19\x42\x07\xda\x8b\x31\x94\x0d\xa7\xf6\x65\x2a\x1a\x7c\x68\xa3\x0b\x7a\x21\xda\x48\xd9\x8e\xef\x44\x2f\xf4\x02\x63\xd2\x7e\xcb\x2e\xd3\xe9\x55\x28\xe7\x1d\x11\xbd\x96\xac\x45\xca\x53\xb8\x29\xb4\x8c\xb0\xf2\x36\xe1\x07\x9c\x50\x1c\x38\xaf\x6a\xfc\xc4\x3c\xe8\xb8\x83\x89\xc7\xa3\x07\xa2\x6b\x34\x90\x19\x94\x8d\xfe\xba\x9d\xcc\x0f\xc9\x4c\x8c\xf6\x11\xbb\xd0\x95\x74\xef\x9a\x42\xa1\x63\xa0\x11\x92\x16\x0c\xd6\x89\x15\x68\xfe\x6d\x5e\x10\x63\xd8\xcb\x7e\x4c\xb3\x15\xe3\xfe\x29\x29\x3f\xcc\x26\xbd\x35\xa9\x22\x65\xbd\xa2\x2c\x0e\x97\xaa\xe0\x2c\xfb\xd6\xcb\x0c\xda\xe8\xc1\x1d\x41\x85\x2e\x00\xd3\xf4\xc8\x19\x45\x6f\x89\xe1\x5d\x2e\xb3\x5e\x5a\xcc\x7a\xe9\x6c\x46\xcf\xb7\xe9\xa2\x37\xcf\x16\x2b\x28\xd5\x93\x53\xad\x87\x28\xd9\x5a\xd4\x99\x0c\x44\x7f\x6a\x4d\x00\xc9\xa6\xd1\xc4\x19\xe9\x1b\x75\xab\xf6\xfe\x39\x2f\x17\x6c\x87\xd0\x8b\x0e\x1a\x7d\x4e\xee\xfd\xb7\xfa\xde\xa5\x68\x0b\x67\xa7\xa7\x8b\x83\x83\xb3\x0d\x5c\x29\xcd\x1c\x38\xc4\xde\x7a\x78\x51\xa1\x97\x92\x93\xf2\x43\xb9\x4a\xc6\x62\xbd\x09\x09\x8f\x7e\xbd\x8b\x15\x0c\xaf\xb7\xf5\xac\x73\x73\xd3\xd0\x2b\x30\xcc\x9e\xb8\x2d\x15\x1f\xcc\x46\xf6\x56\x9c\x79\xde\xcd\xa8\x2c\xf0\xa9\x33\x4f\x8a\x9e\x55\x8c\xdc\x2b\xe4\xca\x96\x72\x2b\xd1\x3d\x49\x31\x3a\xae\xf6\xc5\xde\x2f\x30\x46\x38\x76\x31\x21\xe2\x3d\xf0\x74\x8d\x2a\x54\x52\x92\xb2\x07\x17\x74\xb5\xbf\xcf\xaa\x92\xc4\x64\xc0\x55\x95\x9b\x0e\xf3\xe5\x8a\x3b\xa3\xa5\x47\x46\xe5\x35\x8c\x80\x02\x5a\xb0\x93\x08\xd6\xa8\x04\x1a\xf0\xfe\x70\x84\x51\x62\x72\xc6\x57\x62\xeb\x83\xda\xa4\x74\xae\xc6\xaa\xab\xbf\xfd\xfd\xdb\x07\xb2\x4b\x99\x7e\x04\x03\x8c\x06\x7b\x49\xc2\x11\x33\xef\x70\x31\xfe\xba\x13\x9f\xb7\x07\xe7\xee\xe6\x66\x2f\x14\xa6\x02\x69\xac\x63\x27\x18\x3f\xf1\x94\xed\xb7\x33\xa3\x2a\x90\x84\x54\x05\x02\x58\x18\x33\xf1\xdd\x74\x10\x7a\x14\xfb\xf5\x27\xde\x07\x48\xfd\xe1\xcd\xbb\x0f\x9f\x4f\x58\x8e\xa6\x3a\x00\x18\x39\x65\x04\x8e\x92\xb4\x93\x57\xff\x72\xf2\xfc\xe3\xab\xe7\x6e\x19\x75\x51\x5d\x93\x4f\x7a\x62\xfd\xd2\x26\x53\x7f\xd1\xc4\x14\x7f\x47\xea\xe3\x90\x0c\x81\x22\x62\x0d\x97\xa8\x2c\x0d\x3f\x96\x40\xf2\x10\xeb\x27\xe3\xf9\x13\x33\x58\xd7\xdf\xcb\x6a\xc6\x9c\x1f\x3a\x27\x46\x46\x0f\x28\xfd\xe9\x9c\x59\xbd\x85\xc5\xf1\x09\xd5\xcb\xba\xa2\xe4\xef\x59\x46\xae\x36\x43\x07\x7d\xab\xfe\x8b\x73\x25\xef\xef\xdf\x57\xf3\xc4\x9d\x70\xf5\x50\xba\x75\x50\x94\xfe\x09\xa9\xdb\xfc\x7a\x17\x19\x7b\xc6\xa2\x81\x48\x86\x86\x15\x45\xa2\x5f\x40\x95\x5e\x14\x8a\x71\x9e\x8d\x75\xbc\xac\x2a\x19\x4f\x8a\x67\x15\x29\x1e\x36\xa6\x34\x6a\x1e\x52\xe8\x2a\xb8\x55\x8f\xb3\x83\xa8\x87\x72\xcf\xc1\x81\x79\xba\xcc\x42\x70\xb3\xb3\xd7\x61\x57\x6d\xb9\x65\x2a\x83\x0a\x7c\x9b\x09\x7c\xdb\xb0\xcf\x2f\x84\x80\x25\x7d\x41\x3f\xbf\xe8\x4b\x2b\xd3\xcc\x97\x88\x34\xe8\x48\xbb\x42\xc3\x53\xeb\xdd\x35\xa0\x98\xd7\x66\xc2\x7e\x6d\xd1\x7c\xfe\x25\x2a\x87\x6b\xf7\x4f\x7c\x54\x6b\x08\x46\x1d\xcf\xf2\xef\x12\x04\xae\xbb\xba\x47\xe0\x7b\xdb\xf7\xa5\x53\xe2\xfa\xa9\x2d\xce\x79\x64\x52\x5b\x1f\xee\x0b\x5c\x91\xf2\x34\x3f\x4b\xcc\x7b\x08\x7c\xc1\x45\x8a\x6b\xa9\x9f\x71\x19\x3a\xe4\xbb\xac\x79\x5c\x77\xe7\x16\x9a\xc2\x5d\xde\x08\xfc\x17\x30\x5d\xb1\xb0\xb4\xe5\x5a\xaf\x75\xc7\xa8\x5b\x1c\xe3\x7f\x89\xad\xd6\x5a\x0c\x42\xa4\xfb\xe3\xbb\xc8\x3f\xe1\xd4\x02\x84\xdd\x3b\xfd\xd7\xf4\xf0\xdf\x47\x87\x4f\xbe\x9c\xdd\x03\xee\xb4\xa6\x68\xcb\xbf\x43\xaf\xf1\xf1\x5d\x44\x8f\x5a\xfc\x57\x05\x42\x3e\x8b\xac\xa5\x7f\x64\x48\xd8\xb6\x04\xae\x43\xbd\xe8\x56\xfd\xa1\xc7\x3b\xbc\x2d\x8b\xad\xac\xe4\xc4\x65\x61\x0b\x15\xcc\x42\x2a\xde\xe3\x99\x56\x72\xd4\xe1\x12\xed\xcf\x5b\xa9\xdf\xb3\xf3\xaf\x79\x63\xe5\x38\xd7\xef\xcd\xcd\xf5\xe6\xf6\x2b\xf8\x71\xeb\x26\xb3\x90\x90\x35\x14\x18\x2f\x50\x0c\x05\xba\x2f\x00\x0c\x5a\x24\xe8\xcb\x40\x89\xaf\x29\x75\x78\x0e\x83\xc2\x77\xe2\x16\xde\xb0\x5b\x01\x5a\x9c\x70\xf6\xe3\xed\x72\x07\xdb\xfd\x7a\x98\x0f\x07\x16\xf1\x5f\x4f\x7b\x7f\xaf\xfe\x5e\xfc\xbd\xf9\xfb\xc5\xd9\x3d\x64\xd9\x9e\xf6\xf7\x0e\x0f\x6f\x50\x8a\x7b\x53\x94\xac\xed\x74\x83\x02\xf0\x1b\xf9\xbb\x6e\xae\x16\xd9\xc0\xd4\xfa\xfb\xbd\x67\x50\x31\xf7\x4c\xe0\x33\x4b\x36\xdc\x6c\x58\xa8\xaf\x37\x6a\x57\xa2\xd1\x12\x2f\xf7\x90\x3c\x82\xdb\xdc\x4a\x24\x32\xd0\xed\x95\xb0\xa2\x11\x1c\xa1\xac\xca\x7c\x29\x82\x9c\x15\xad\x32\x0e\x3d\x46\xa7\x8e\x22\x24\x3c\x25\x7d\x9a\xd3\xd1\xd9\xfe\x7e\xa9\x92\xdd\x79\x44\xff\xd7\xff\xef\xff\x0f\x84\xbd\x5a\x57\x5b\xec\x35\xc6\x97\xc1\xe1\xcc\xe8\xa9\x1f\x67\x8e\x5a\x17\x7a\x16\x41\xab\xa0\xac\xc9\x50\x99\xbd\x3f\x12\xe3\x01\xeb\x9e\xb9\x0b\x65\x93\x49\xf9\x0e\x70\x77\x17\xbb\x41\x5e\x1e\xcb\x96\x4c\x3a\xb6\x28\x08\x83\x17\xdd\xf7\x4a\x81\x88\x7c\x2f\x80\x1f\x6f\x6e\x32\xc0\x8d\xf8\x9c\x0a\x7f\x2c\xb6\x41\xb7\xd7\x60\x7b\x81\x8a\x80\xfb\x02\xbd\x98\x06\xd4\xf8\x42\x68\xf6\x2e\xe6\x7c\x8e\x8e\x30\x42\x43\xc3\xd2\xb6\x86\x7e\x60\xc2\xd7\xec\x8a\xbe\xe1\x2f\x7e\x7e\x21\xa3\x3a\x4a\xe1\x9f\xa8\x52\xbc\x37\x0e\x8d\x63\x47\xd5\x47\x43\x0e\x55\xfd\x16\x49\x71\x17\x5d\x5e\x80\xd6\x7e\x8b\xfc\x6e\x30\x55\xea\x76\x35\x87\x63\xde\x43\xe1\xaf\xed\xc0\x52\x29\xf0\x95\xd8\x48\x0b\x57\x5e\xd9\x4a\x5d\x02\x2e\xc5\x8d\x11\xb1\x2a\xc5\x7d\x14\xb3\x4e\x9a\x67\xf9\x24\x07\x1a\x8e\xee\x75\xbc\xce\xfd\x8b\xfc\xa7\xee\xad\x9f\x10\x45\x5d\xf8\x8a\x42\xee\x6e\xb3\x86\x0d\xed\xef\x71\x2e\xf5\x03\x62\x54\x88\xe7\x57\xfb\xfe\xfd\x47\x6e\x3c\xdc\x0e\x35\xa3\x39\x5e\xf6\xba\x5c\x6e\x29\x16\xfe\xd7\xe8\x00\xab\x39\x31\x6f\x9d\x80\x8e\x52\x0b\xe7\x78\x14\x23\xb2\x01\xf6\x6e\x64\x4c\x17\xeb\xe0\xbd\xba\x76\x22\xf1\xb8\xc1\xfc\x4d\x60\x1d\x8b\xa4\x5d\x24\xeb\xe1\xa7\x57\x1f\x9e\x7f\x7c\x7e\xf2\xfe\xa3\x58\x25\x40\x3c\x63\x9c\xf6\x08\x7f\x24\x23\xc0\x98\x43\xfc\x31\x86\x1f\x31\xfe\x38\x8a\x36\x62\x9e\xdc\x3b\x4d\x86\xf1\xd9\xbd\x4b\x31\xf3\xc5\x34\xa5\x48\xa5\x64\x46\x5c\x40\xc1\x11\x02\x6d\x8b\x08\x56\x70\xb1\x84\xfc\xa5\x31\x83\x58\x2a\x83\xa2\x6f\x00\x15\xcb\xb3\xc9\x3a\x69\x0e\xfa\xcd\xf1\x2a\x5e\x0c\x0e\xa0\x82\x58\x62\xc4\x8b\xe2\x60\x2e\xe6\x07\x09\x7a\x99\xc3\x2e\xb0\xbf\x8d\x16\xb4\x5c\x6a\x50\x17\x57\x09\x2b\x37\x8a\x57\xc9\xd5\xf1\xe2\x00\x37\x77\x04\xbb\x37\x31\xba\x4d\x8e\x4e\x64\x72\x39\x28\x55\x3c\xc9\x57\xb0\xc4\x30\xf6\x31\x09\x70\x7a\x14\x60\x4b\xab\x53\x5d\x42\x2d\xa3\x4a\x05\x5f\x75\x80\xf2\xc1\x96\xb2\x40\x33\xfa\x98\x42\x6f\xd7\x53\x62\xa6\xc7\x7b\x36\xd7\x35\x70\x9d\x68\x06\x58\x84\x17\x78\xde\xed\x85\xc9\x21\xe9\x60\x85\xf3\x3b\x7d\x71\x06\x53\xb4\x97\x88\x92\xd4\x2a\x0d\xb4\x1d\xdd\xdc\xa6\xe6\xd3\x5b\x24\x81\x3e\x10\xc5\xe3\xd1\xfd\x0e\x42\x6c\x67\x83\x28\xdf\x67\x14\x10\x2e\x6d\x62\x25\x1c\x4c\xfe\x49\x8b\x42\x36\x15\xa9\xed\x45\x7e\xce\x03\x8f\x06\xdc\x8e\x49\x88\x7f\xe5\x26\x5a\x14\xae\xd7\x44\x5d\x4d\x55\x65\xfc\x19\x1f\x8d\x28\x6a\xce\x93\xbb\x3a\x61\x21\xad\xfc\x8b\x42\x39\x27\x93\x8e\x7c\x95\x57\xb2\x12\x16\x15\x69\x43\x5f\xbb\x60\x63\x05\xbc\x1d\x7e\x21\xcf\x4e\x75\xc2\x22\x4e\x61\x67\x2d\xa4\xd8\xad\x76\x98\x3c\xe4\xb1\xd8\x90\x92\x6b\x42\xfb\xf6\x27\x20\x3c\x79\x43\x9e\x92\x6f\x53\x2f\x0f\x46\xab\xb2\xdb\x39\x67\x96\x8d\xe0\x48\xb0\x6f\x22\xbb\x84\x7c\x0e\xab\x48\xb0\xc9\x67\x1d\x88\xd0\xe2\x59\x33\x69\xe0\x60\x33\x5b\xeb\x56\x81\x24\x68\xd7\x70\xba\xce\xfc\xb2\x65\xde\x04\x85\xc0\x77\x98\xa4\x14\x3f\x92\xcd\xaa\xdf\x39\x20\xc3\x90\xc0\x21\x70\x6f\xae\x71\x59\x54\x7c\xac\x35\x6d\x1c\x90\x02\x1c\x2f\x17\xc9\x33\x25\x00\x85\x41\x62\x51\x81\xd2\xb7\xa9\x74\x0c\x3b\x56\x41\xa4\x30\x87\xaf\xc8\xb5\x82\x84\x01\x94\x64\xa7\x9b\x47\x5b\x4a\x09\xab\xdc\xfd\xad\xe5\x10\xdf\xa8\x92\x0f\x6e\x29\x29\x2a\x53\xf6\xe1\xad\x65\xd1\x2a\x5c\x95\x7e\xb4\x43\x69\xb4\xf0\x07\xca\x0b\xe1\xa5\x4e\xc6\x22\xb5\x40\x62\x7a\x38\x1e\x4c\xa6\xcf\xea\x49\x0d\x40\x91\x9e\xd6\x87\xe3\x33\x4b\x94\x53\x03\xd6\xc7\x66\xd9\x96\xcf\xb4\x6b\x23\xf9\x05\xdc\x52\x6b\xb5\x63\xdc\xc5\x68\xb2\x92\x2d\xaa\x5d\x82\x96\xb6\x6f\x14\x16\x68\xed\x95\x4c\x95\xb3\xc2\x0f\xb5\x55\xb6\x8b\xd4\xa3\xee\x72\xc2\x2d\x79\x7f\x5b\x49\xf4\x5d\xcc\x65\xa5\xb3\x05\x74\xb0\xbb\x97\xd2\xed\xb8\x08\xaf\xda\x62\xb2\xa0\x55\x5b\xb8\xab\xb6\x80\x55\x93\xfd\xc8\x85\xb3\x3b\x4a\x35\xe6\x47\x6d\x11\xfb\x88\x95\xde\x2b\x4b\xa5\x7c\x2d\x63\xc7\x05\x9a\x7c\x03\x45\x88\x16\xcb\x13\x4b\x17\xdc\x1c\x3a\x07\x7b\x24\xd7\x1b\x69\x79\x6f\x8e\xd8\x71\x1b\x89\xf8\x49\x89\x8f\x68\x44\x79\x16\xfb\xd5\xc8\x8c\xb3\x1c\xf8\xe9\x49\x29\x94\x72\xba\x3d\x27\x40\xab\x3b\xcd\x0a\xf7\xfe\xff\x45\x13\x73\x41\xb8\xa5\x52\xbc\x33\x4e\xa4\xb9\xda\x5e\x30\xed\x21\x26\xf2\x5a\x40\x39\x24\x4c\x4a\xfe\xd9\x23\xde\x00\xbe\xf6\x2a\x5a\x5f\xb4\xf7\xe0\xb1\x23\x16\xc1\x12\x86\xa6\x63\x3d\x8a\x4a\x9d\xcf\x54\xd2\xfa\xfd\x0a\xe8\x7c\xb7\x29\x4c\xf0\x5a\x83\x24\xcb\x6f\xb0\xe4\x82\xfd\xc5\x19\x93\x5d\xbc\xcc\x2c\x81\xd9\x8e\xcb\x98\xd9\xe2\x9e\x3f\x9f\xae\x55\x7c\xbe\x58\xfc\x16\xbc\x3e\x03\xe0\x70\xdc\xcf\x8e\xc3\xcd\xc7\x1e\x98\x08\xb6\xee\x0f\xc0\xe4\xc5\x45\xd2\xbd\x95\x4e\xd1\x74\x36\xd3\x5b\xec\x82\xb5\x53\xac\x46\x0b\xa7\x1f\x81\x39\xb4\xcc\x36\xe8\xfd\xea\x15\xdc\xa5\x0d\xb6\xe8\x25\x1c\xb5\x52\xee\x43\x4a\x5b\x1f\xf1\x49\x4b\x36\xd5\xb7\x57\x6d\xcf\xca\x23\x07\xea\x05\xee\x13\xfe\x77\x73\x03\x24\x8d\x88\xd0\x84\xfc\x22\x2f\x48\x6f\xda\x18\x05\xe9\x7e\x8e\x2d\xfe\x0e\xd7\x35\x70\x07\x73\xfd\xfd\x7d\xfe\x3b\x4c\x97\x33\xf5\xbb\xdf\x9e\x3b\x36\xb2\x19\x6c\xfa\x11\x90\xcd\xcb\x1c\xb5\x77\x43\x23\xc8\x8e\x33\xda\x2b\xfb\x59\x35\x4c\xd1\x65\x92\x39\xc7\xdd\x61\x03\xf3\x15\x20\x89\x15\x50\xd8\x17\x18\xc6\x20\x07\xf0\x37\x34\x5c\x63\x2b\xbc\xab\xae\x26\x2e\x43\x07\x4c\x84\xe4\x05\xf6\x50\xb5\xdd\xcc\x77\x0f\x29\x42\x52\x83\x6f\xe6\x19\x5c\xe7\x81\x95\x40\x7d\x77\x9b\x66\x54\x61\xf4\xd9\xfe\x7f\x34\xc9\x9e\x32\xb5\x39\x87\x71\xa9\x53\x98\x21\x01\xc6\x82\x67\x3c\x3d\x54\xa0\x46\xcd\xd7\x63\x53\x16\xf1\x51\xbd\x9e\x4e\xd1\xcd\xbc\x9b\x7a\x91\xe6\x8b\x75\xa5\xa8\x58\x99\x3a\x98\xb4\xba\x49\x46\x2e\x33\xad\x7d\xe9\x03\x3d\x40\x1e\x20\x0a\xf2\x6a\x7b\x8c\xd6\x8a\x38\x79\x60\xa9\x97\xf5\xe5\x20\xee\x03\x6a\xc6\x9c\xd1\x31\x25\xc4\xf2\xb6\x94\x34\x2f\x17\x12\x25\x79\x9e\x5f\xf1\x86\x9a\x26\x90\x6b\x92\x8f\xe8\x72\xb3\x0f\x69\x48\xbd\xe9\xd5\x74\x91\x45\x03\x68\x3d\x4f\xc8\x96\xfe\x38\xe7\x66\x4b\x81\x95\xeb\x72\xf1\x2d\x13\xaa\x99\x41\xac\xd3\x48\x3f\x8b\x45\x18\x29\x1a\x85\xca\x7e\xf0\x12\xb5\x78\xfd\x4a\x99\xdd\xac\x81\x8c\x24\x84\x8a\xf8\x77\x8a\x26\x6e\x97\x97\x59\x95\xcd\x80\xa4\x30\x1f\xe4\x63\x05\x5d\x2a\x01\x3e\x9d\x26\xf4\x6b\x40\x0b\xd2\x4f\x61\x6c\x15\x8c\xad\xcf\xea\x00\x75\x7f\x8a\x8a\xb2\x34\xce\xca\x86\xcb\x52\x5d\xec\x42\xdf\xfa\xc0\xa1\x58\x05\xf2\x50\x01\x9c\xfd\x14\x97\x0f\x0e\xf5\x94\x37\x1c\xe8\x8a\xa9\xb3\x69\xcf\x46\xfb\xfb\xf8\x9a\x3e\xd5\xd3\x5e\x60\x6b\x4c\xaf\x00\xa6\x56\xa3\x5a\x0c\xec\x50\xc6\x79\x5f\xdb\xd6\xd2\xec\x2b\x33\x59\x80\xdf\xca\x9d\x7a\x25\xa7\x8e\x18\x0d\xa7\x0e\x09\x38\x26\xb8\x88\xe5\x98\x8e\xd0\x29\x45\x60\x4c\xd5\xa0\x2d\x1b\x41\x98\x32\x72\x25\x74\xa3\xd0\xd8\x6e\x14\x0c\x2a\x2a\x51\xf0\xaa\x36\xb5\x39\x2d\xcf\x06\x74\xa6\x1c\xc4\x05\xa5\xd0\xbe\x06\xda\xdc\x60\x8c\x57\xdd\x57\x4d\x46\x40\xd2\x93\xaf\xe2\xdf\xac\x39\x59\xc7\x6f\xad\x8b\x4a\xd8\x54\xc5\x79\x6a\xa3\x76\x5d\xeb\x1c\x69\x17\x43\xb8\x1e\x0c\xef\xa6\x65\x8c\xba\x7b\xed\x70\x24\x06\x79\x0e\x58\xdd\xc3\x82\xfe\x77\x65\xd3\x4b\xf5\x9b\x54\x44\x56\x62\xa3\x3d\x79\xd6\xbf\x7c\x79\xf7\xe1\xfd\x97\x2f\x5d\xb5\xe4\xc8\x23\x79\xa6\x65\xe9\x64\xac\x5e\x15\x00\x06\xd6\xec\xba\x86\x0b\xe0\x3a\x9a\x2b\xa7\x41\x8b\x4a\xbe\xfa\xaf\x15\x02\xe9\xc2\x5b\x23\x21\x91\x49\xa8\x44\x79\x5c\x22\x66\xd3\x16\x66\x7a\x45\x71\x00\xbe\xf3\xde\x7e\x4b\x6a\x1f\x58\x27\x47\x0e\x7a\xb7\xd5\x53\xa0\x83\x66\x78\x12\x09\xa0\x6c\x5d\x43\x2a\x11\x2c\xc0\xe6\xe0\x1a\x4b\x38\x56\x40\x2b\xf4\xc8\x99\x24\x38\x8d\xe8\x60\x45\x67\x9d\xa4\x06\x01\xa6\xc2\x77\x68\xef\x85\xfe\x6d\x1c\x2c\x68\xd7\x2c\x15\x82\xc8\x6c\x1c\x90\xe9\x63\x4b\x19\x16\x12\xd3\xc9\x88\xc4\x24\x07\x45\xd2\xb9\xd6\x83\xa9\x12\x6d\x8a\x59\x12\xba\x31\xd1\xef\xc3\x72\x99\xcd\x72\xbc\x39\x02\x73\xb1\xf3\x51\xae\x19\x43\xc2\x49\xbe\xcc\xca\x75\x43\x53\x92\xfd\x71\xbb\x5a\xa4\x05\x84\x53\xf4\x23\x12\x48\x66\x2f\x5a\x0c\xbf\x6e\x3b\x5c\x17\x4b\x01\xec\x2d\xd6\x59\x5c\x88\xef\x15\x87\xa3\x46\x30\x9b\x92\x9f\xe6\x75\x45\xdf\x15\xaa\xc4\x8c\x31\x04\x13\xaf\xc9\x72\x70\xed\xf7\xe4\x58\x6c\x27\x85\x40\x85\x61\x9b\xaa\xf2\x69\x01\x4f\xb6\x53\x67\x8b\x0b\xed\x6e\x1e\x85\x3c\xf2\x30\x4b\x3a\x40\x54\x3a\x14\xfe\x6c\x66\x3c\x38\x90\x30\x83\xcf\x57\x46\x1f\x02\x5d\xef\x51\xfd\x2a\x86\x7f\xe8\x51\x42\x54\xaa\x2d\x41\xa4\x46\xc0\xad\x35\xbf\xe9\xc3\x1d\xba\x92\x45\x51\x4b\x3a\xd3\x5c\x27\x05\xf2\x07\xac\x8b\x0a\xd1\xd8\x36\xe0\xf1\x3e\x3f\x18\x7e\x4b\x16\xb4\xfa\xd6\xb1\x8a\xc4\x54\xec\x8d\x35\x11\x3e\xb5\x9c\x49\x7f\x13\x00\x8d\x22\x92\xd8\x01\x65\xd1\x68\x74\xbc\xe8\x4f\x51\x13\x8b\xce\x4a\x24\x5a\xfa\x06\xf2\x7a\xd0\x32\xf5\x90\x42\xd0\x98\x34\x6c\x64\xbb\x40\x94\xd1\x71\xb7\xac\xe9\x25\x7b\x13\x3a\xc9\xc1\xf3\x5d\xec\x70\xbe\x91\x4a\x03\x80\xd0\xe3\xa7\x41\x89\x00\x4c\x2b\xdc\xf3\x1f\x3c\x9e\xc2\x19\x0f\x6c\xdb\x2d\x6b\x19\x9d\xf2\x42\xb2\x7c\xe0\x0c\x3a\x9b\xab\x07\x98\xe3\x26\x40\x1c\x51\x87\x70\x89\xb2\x47\x94\x41\x3c\xa2\x35\x57\x1c\x96\xbe\x27\x4f\xcf\x06\xfe\xf2\xd3\x21\x0c\x4f\xb7\x08\x4e\xb7\xda\x61\xba\xd2\x62\x58\xc9\x0c\x73\xf9\x40\x54\xa2\x53\x89\xd1\x24\x85\x35\xce\x3c\x7f\x44\x39\xb2\x14\x8d\x38\x38\xa8\x91\xfd\xdb\xdf\x2f\x00\xf9\xd2\xc5\x6d\x36\x91\x2c\xfe\xfe\x43\x57\xed\x7f\xc7\xd2\x84\x26\x8f\x2e\x25\xf4\x64\xa7\xf8\xbf\xa5\x4a\x12\xc2\xd4\x97\x8b\xf2\x3c\x5d\x1c\xf3\x9f\x38\x8c\xcb\x17\x17\xc7\xf8\x5f\x30\x57\x2a\xbc\xf3\x9f\x18\x50\xb3\x62\x04\x5b\xda\x02\x86\x75\x23\x25\x07\x2a\xe4\xbd\x28\xe3\x79\x29\xe4\xfb\xfc\xec\x13\x20\x19\x8c\x05\x76\x26\x74\xd2\x73\x2a\x29\xd3\x28\xd6\x99\x83\x79\xd1\xec\xc3\xab\xae\x28\xbe\x81\x9f\xbe\x2a\x57\x7d\x7e\x44\x99\xf8\xcd\xb7\xeb\xa8\x0c\xaa\xa4\x07\xdf\x7a\x1b\xb6\x1e\x2e\xd6\x32\xbc\xbc\x7c\xa2\x44\xe7\x1d\xf0\x39\x54\x9a\x5f\xff\x03\xbe\x5f\x60\xdb\x25\x6a\x86\xda\x90\xa8\x25\xe7\xe4\xfe\x8b\x55\xc6\x9e\xf6\x33\xf6\xe8\x52\x65\x00\x2d\x70\xf2\xd4\x08\x0f\x0e\x00\x63\x24\x26\xf3\xb4\x38\x13\x78\x2d\x29\xe5\x30\xfc\x6d\xe9\x87\x39\x7a\x13\x96\x9a\x92\x56\x9b\xe3\xa7\x24\xa9\x2f\x91\xb1\xa3\xbe\x12\x08\x03\xb1\x4e\xf2\x3e\xd2\x74\x90\x94\xa4\xba\xfc\x14\xcb\xaf\xb9\xfc\x22\x59\x9f\x4e\xcf\xb0\xc4\x01\xde\x26\x2b\xb8\x60\xd1\xc1\x16\x30\x04\x67\xc9\x42\x3f\x28\x35\xf6\x83\xd2\xf5\x3c\xad\x95\x60\x22\xec\xa1\x91\x65\xc4\x44\xbb\xb3\xa4\xad\x5e\x9f\xb3\x62\x08\x6e\x87\xb7\x14\x25\x49\x96\x2a\x00\x0e\xed\xbc\xad\x55\x05\x88\x7b\xf9\x1c\x82\xd7\xfd\x40\x34\xf8\xc8\xfc\x54\xcb\xa0\xf0\xf9\x01\x9f\xfd\x12\x5c\x3d\x81\xac\x66\x86\x3e\x6d\xad\x71\xa2\x3e\x8d\xf5\x89\x6f\x78\x5a\xbd\x41\xbd\x24\x6c\x04\x77\x71\x52\xbe\x4d\x8b\xab\x80\xcf\x6c\x7c\xd9\x75\x17\xbd\xd1\x92\x47\x3a\xae\xe7\xe9\xf4\x2b\x39\x00\xaa\xd0\xa5\x0e\x51\x86\xe5\x19\xd0\xbc\xf4\xab\x3a\x3b\xae\x62\x79\x7d\xa7\x52\x6a\xad\x3a\xec\x93\x77\xc5\x94\x89\xc9\xf2\x20\x92\x71\x3f\xa2\x33\x16\x64\x9e\xa6\x4e\x12\x52\x79\xe2\x1b\x3e\x49\x02\x90\xf3\x94\x80\xa4\x0b\xba\xe9\x95\xb2\x80\xe3\x48\xcd\xbc\x97\xd7\xbd\x02\x31\x12\xac\x63\xaf\x29\x7b\x3c\x02\xfc\x95\x37\x88\x2c\x22\x60\xce\xf3\xfa\xb5\x6e\x4a\x0e\x11\x1d\x18\x38\xcb\xe9\x7c\x32\xeb\x60\x75\x32\x4d\x0b\xec\xc4\x34\x8e\x05\x7a\x66\x07\x7b\xe7\xd9\x14\xad\xae\x7b\x80\x89\xd0\x2c\x6e\xbd\x40\x50\x2c\xcb\x55\x24\x57\x28\x46\x35\x4f\xa8\x02\x34\x76\x0d\x73\x03\x04\x2a\xdb\x5a\x66\xcd\xbc\x44\x4b\x70\xb5\x74\x71\x50\x14\xcc\x8a\xf8\x49\x1b\x92\x02\x49\x08\x8f\x5a\x7c\x33\x24\xfc\xfd\x46\x3e\x9c\xb5\x16\x99\xd4\xde\x98\x34\xcc\x80\xd0\x7c\xc3\x3e\x3a\xa5\x8d\x31\x72\x06\x74\xe7\x51\x69\x6a\x01\xe0\x11\xb6\x90\xe5\x86\xf6\x31\x56\xa4\x1d\xba\xf9\x9c\x65\x3f\xde\x5f\xc0\x69\x9d\x98\xce\x0f\x89\x62\x12\xd1\x49\x85\x46\x0b\xb0\x7e\x2c\x50\x54\x8b\x90\x2e\x00\x07\xcd\xae\x7a\x97\x65\x91\xf5\xd0\xb5\x40\xcf\x99\x10\x15\xdb\x43\xff\x4d\xc3\x7a\x45\xfe\xd3\x32\x01\x84\x5c\x89\xc1\x70\xd0\x1d\x3d\x5a\x07\xe6\xc2\xec\x46\x8c\x51\x64\x98\xdf\x01\x9c\x91\x72\x48\x19\x3d\x65\x67\x89\xed\x43\x5e\x91\x9f\xc3\xae\xf5\x7c\x5a\xda\x6e\x44\x51\xe4\x9c\x94\xa4\xc8\x6b\x1d\xe4\xc4\x76\x0e\x49\x21\x68\xfa\x68\x51\x63\x56\x81\x7c\x89\xaa\x15\x6a\x06\x22\x7a\x0d\xcc\x65\x68\x45\xb6\x2c\x82\x73\xc2\xbd\x99\x39\xde\x53\x2d\x29\x9b\x68\xba\xe6\x05\xd4\xb8\xbe\x67\x50\x0f\xac\x3d\x6a\x95\x8f\xef\xfe\x87\xe3\x9f\x19\x32\xf0\x7c\x3e\x70\xc5\xde\x9d\x4c\x8e\xbf\x35\x7c\x59\xc2\x7e\x56\xa2\xb3\x4e\x30\xaa\x1c\x7b\x47\xfa\x12\xbd\xfb\x99\xb6\x07\x0a\x89\xb5\x72\xe0\xa6\x2d\xbd\xda\x25\xcb\x2d\x8f\x4b\x4f\xd6\x82\x74\x02\x0b\xa8\x2a\x47\x40\x15\x37\x16\x21\x53\x22\xe2\xc2\x3b\xf5\x04\x18\x1d\xb4\xe1\x8c\x81\x3e\x42\x57\x66\xb0\x4d\x98\xfc\x1b\x40\xb5\x4c\x25\xb5\x39\x99\xfc\x82\xae\x05\x4c\x45\xb2\x99\xd3\x3e\x91\x08\x17\xd3\xa4\x30\x77\x20\x35\x30\xf9\xca\x8e\x8f\x46\xe4\xf5\x9d\xef\xf3\xf8\x68\x4c\x0a\x0c\x4f\x3a\x94\xa8\x43\x57\xbf\xc2\x65\x6f\x09\xe1\xd4\xae\x8e\x12\xfc\x82\xcc\x59\xff\x3a\xe8\xd9\xaf\x1a\xb6\xc1\x8c\x88\x3b\x1a\xa0\xdf\x70\x0c\x14\x49\x60\xa8\x2d\x6d\xa7\xf6\x50\xed\x3b\x79\x55\x65\x28\xe0\xb7\xa1\x19\xa0\x7d\x5e\xae\x17\x33\x3f\xdd\x3c\x15\x32\x24\xb6\x61\x8b\x6f\x1d\xdf\x4c\xab\x40\x79\x1b\xef\x31\xe9\x28\x89\xca\xe1\xfd\xe8\xc0\x64\xfc\xc8\x60\xbf\x72\x30\x26\xa5\x37\x94\xdf\xd2\xf3\x6c\x81\x8f\xd8\xf6\x68\x74\x1d\xef\x09\xb7\x72\xeb\x60\x0c\x73\x96\xb9\x04\x6e\x66\xe5\x23\x82\xe5\x6e\x4c\x54\x69\xbc\x11\xe1\x26\xe1\xf3\xce\x2c\x1a\x3c\x4b\x46\xf2\xea\x6d\x17\xbb\xa0\x83\x4a\x65\x48\xd8\xab\xb8\x3a\x63\xc6\xf5\xcb\x87\xf5\x39\xac\xd9\x1c\x6e\xb8\xe5\xba\x6e\x7a\xf3\x14\x8e\xb3\xd5\x3c\xd9\x8c\xa9\x76\x7a\xd4\x43\x6f\xa5\xaa\xd4\xbf\x0c\x26\x59\x5b\x42\xa9\xd1\x9f\x6e\x86\x18\x45\xa0\x07\x95\x50\x29\x5c\x9c\x7b\x61\xa6\x52\x6e\xe4\xf3\x62\xf6\xa1\xb5\x44\x6e\xa8\x29\xbd\x59\x6a\x93\x85\x45\x87\xd8\xa7\x99\x55\xf9\xfd\x05\x88\x5e\xfd\x58\x01\x07\x05\xe8\xcc\x70\x34\x3d\x6e\x92\x6f\x69\xb9\x45\xbd\xf3\x75\x03\xb7\x53\xd3\x43\x3d\x39\x89\x9d\x8c\xfb\x3b\xc4\x34\x0a\x8e\x4c\x18\xd1\x42\xc9\xd4\x94\x1d\x00\x60\x0b\x81\x5c\x91\x14\xad\xb6\xe5\x22\xa6\x45\x89\xae\xe5\x21\x50\x8d\xe3\xf4\xa0\xfb\x2c\x31\xf6\x83\x28\x7c\x20\x45\x35\x59\x13\xfd\xbf\x36\xb1\x45\x7a\xca\xdb\xdd\x9c\x1c\xb7\x31\x09\x3c\x0a\x64\xf1\x6f\x0b\xbe\x33\x33\xe6\xe7\xf5\x55\x31\xbd\x7d\xe0\x13\x96\x09\x9d\xe4\xd3\xaf\x2e\x46\x95\xcd\xe8\xd5\xe2\xdd\x96\xa9\xad\xbd\xb6\xc3\xa0\x09\xcb\x7e\x46\x54\x7f\xf0\xc9\xa8\xfe\xf8\x93\xa1\xc9\x68\xe2\xdc\xe4\xd4\x3c\x46\x5c\xdd\x52\xba\xd9\x16\xdc\xa2\xec\xb4\x8f\x5e\x36\xe1\x42\xe6\x63\x94\xa3\x0a\x36\x75\xbb\xad\x70\x45\x85\xf1\x78\x5a\xfb\x66\xf9\x9b\xde\x58\xa6\x28\xf2\x9e\xf1\xd0\x75\x4b\x35\xae\xcd\x36\x1f\x8d\xb6\xa8\xb6\xb9\xe9\x8a\x10\x29\x2c\x26\x43\x3a\xb1\x0f\x88\xd5\x2b\x7c\x69\x0d\xa9\x63\x67\xec\xb0\x9e\xcc\x05\xd0\x68\xc4\x38\x20\x94\x03\x6a\x29\xca\x39\x66\x51\xb0\xfb\xe6\x3e\x6c\xdf\x39\x6e\x4d\x29\xfe\xf4\x28\x88\x80\x33\xdb\x6a\x3b\x31\x72\x6c\x1f\xd6\x36\x41\x02\x97\x2b\x4b\x78\xfa\xc8\xea\x9d\x06\x4a\x9c\x0d\xd0\xc1\xbb\xf1\xb9\xfb\x32\x9f\xbd\xf5\x1d\xee\x56\xea\x02\xe7\x8b\x63\xe8\xdd\xc9\x0a\x1c\x29\x37\xb7\xd1\x87\x94\x05\x37\x3e\x51\x86\x32\x7b\x95\xdc\xf7\x86\x78\x36\x40\x81\xbf\xc3\xee\xa1\xdd\xd3\x26\xec\x16\xd8\x1a\x0c\x7a\xaf\x1f\x86\x0a\x29\x18\xe4\x2d\x42\xf5\xc5\x16\x01\x71\x34\x6a\x29\x33\xfe\xec\xde\xda\xfe\x34\x93\xca\xa5\x2d\x01\x79\x96\x62\xdb\xa6\x53\x70\xd5\x5b\xa8\x4f\xbf\x8c\x31\x51\x2b\xed\xa0\x2e\xed\xad\x1e\x48\x12\xe5\xd6\x62\xea\x8a\x39\x76\xb7\xa6\x60\x58\x91\xa0\xfb\x87\x00\x4d\xce\x40\x93\xfa\x3a\x9b\xfe\x04\x73\x03\x2e\x72\xf4\x6c\xf1\xa6\x95\xe0\xf4\xac\x30\x7d\x92\x77\x41\x17\x9a\x54\x6c\xda\xe0\x95\xfe\x87\x83\xd7\x36\x63\x26\x8f\x94\x56\xd0\x26\x4d\xc2\xfe\x92\x65\x2b\x0e\x7d\xa4\x88\xd6\xb1\x4d\xa9\x8e\x37\xde\xea\x65\x28\xcd\xa1\xf0\x95\x79\xcd\x8f\x44\xca\xed\xd4\x35\xc7\xaf\x20\xf7\xdb\xd9\x66\xe0\x06\xf9\xac\x86\x2c\xfe\x53\xdb\x43\x96\xe8\x24\x64\xab\x86\xfa\xb6\x92\x99\x28\x6f\x6b\xd1\x3a\x2f\x58\x88\x01\x34\x69\x55\xe5\xb3\xac\xf7\xfc\xc3\x1b\x29\x7e\x40\xcb\x7d\x94\x4f\x14\xbd\x8f\xd9\xc5\x62\xfd\xc3\xed\x69\xd8\xfb\x5c\xa3\xfb\x80\xb2\xa1\xeb\x90\x6b\x14\x30\xc6\x5e\x59\x99\xd6\x72\x68\x59\xd7\xf7\xc7\x43\xa6\xa6\xc0\x0c\xa1\x93\x01\x35\xa9\x5a\xdb\xde\xc0\x34\xea\xf0\x34\xea\xbb\x4e\xa3\xe6\x69\xa4\xf2\x41\x1a\x2f\x5f\xf8\xf1\x07\xcf\xc0\x08\x3a\x13\x57\x20\x8a\x21\x48\xf1\xa6\xfd\x98\xd5\xeb\x05\x59\xf8\x86\x4a\x2a\xda\xec\xd4\xa2\x27\x84\xa2\x25\xce\x2c\x1f\xda\xeb\x04\x23\xdd\x5c\x6f\x26\xeb\xa7\x56\x6d\xc9\xad\xaf\x95\xed\xc1\xc2\x16\xbc\xae\xcf\x26\xd3\xd3\xc5\x59\x92\xf6\x17\x6c\x74\xb1\xb2\x98\x3b\x43\xd3\xc5\x11\xaf\x50\x24\x24\xe5\x47\x0f\x05\x85\xa3\x58\x85\x01\x83\x18\x0e\x62\x56\xc3\xf4\x97\x44\x78\x10\x89\xb6\x65\xee\x13\xe4\xe9\xc5\x10\x97\xe3\x38\x92\x64\x48\x14\x47\x36\x41\x12\x9d\x49\x92\xe4\xc2\x66\xb1\x0d\xfd\x2c\xc7\x7d\x21\xa6\x62\x05\xa7\xad\x25\x05\x47\x01\xcf\x05\xf4\x19\xb0\x0e\xa0\x33\x09\x9c\xa8\x34\xc1\xdc\x72\xee\x5b\xef\x03\x77\x3f\xf7\xf4\xb5\xcc\x7f\xc0\x04\x29\x3e\x62\x17\x1a\x90\xda\xfa\x48\xbe\x84\xb8\x70\x47\x2a\x65\x94\xb3\x8c\xd9\xf6\x48\x2b\xc0\xbb\x22\x40\xa5\x93\x21\xf7\x32\x09\xec\xa5\x47\xd3\x27\x11\x07\xb6\x8b\x44\xad\x38\x01\x13\x4e\xc9\x93\x90\xe8\x74\xc5\x2c\xe0\x6f\x15\xb4\xca\xc8\xbe\xea\x01\x3f\xea\x7a\x62\x6f\xbb\x80\x1f\x8b\xc7\x41\xf2\x28\xa3\x26\xb1\xf1\x60\x23\x11\xa4\x39\x07\x8c\xfe\xe8\xc5\xc4\xc6\x7e\x29\x80\x3b\x29\x7c\xb6\xf0\xc6\x1a\xf5\xf8\xfc\x0b\x0d\x52\x07\x77\x44\x27\x6b\x07\x2b\xda\x03\xf8\x23\x50\xca\x3d\x95\xe3\x0d\x34\x84\x2d\xa7\x06\x5b\xa6\xa7\xd3\x8e\x69\x4f\x83\xd3\x9e\xde\x79\xda\x53\x9e\x76\x8d\xf3\xfd\x43\x91\xe8\x2e\x33\xce\xe8\x5d\x42\xe8\xe3\x6f\xa9\x7b\x88\xd6\xe4\xc2\x68\xc9\xde\x28\x21\x19\xf6\x05\x2b\xe5\x18\x65\x5d\xef\x1d\x0e\x91\xc9\x62\x20\x16\x9b\x00\x02\xb1\x4f\x2c\xa0\x91\x51\x1b\xa9\xf0\xe9\x87\xaf\x27\x01\x14\x13\x7c\x5d\x74\x50\x27\x23\x06\x27\x29\x1a\xb4\x49\xb2\x0e\x49\x1e\x14\xf4\x17\x41\x86\xc5\xf7\x52\xa9\xa8\xbd\x38\x32\x98\xa0\x95\x42\x45\x64\x98\x02\x1a\x8e\x13\x62\x41\x3e\xf9\xea\x22\x54\xd3\x2e\x41\x09\x91\x74\x23\x55\xa0\x0a\x12\x67\xf2\x87\x9d\xf1\x9a\x42\x10\x38\xd9\x9c\xe4\x4e\x1c\x89\x3a\x6f\xda\x98\x44\x85\x14\xea\x50\x76\x54\xfc\xe5\x64\x21\x56\x71\xb3\x31\x25\x52\x32\x1c\xe7\x51\x14\x55\xa2\xf2\xa9\xf5\x24\x3a\x29\x86\xb6\x70\x17\x23\x8a\x2f\x16\x89\x11\xf1\x72\xb6\x14\xf2\x26\x96\x90\x97\x33\x58\xa4\x9b\x58\x22\x5d\x99\xc1\xf2\xdf\x44\xc9\x7f\x95\x6e\x81\xcd\xb9\xb8\x7b\x50\xef\xfe\x5e\x9a\xf3\x7b\x69\x8a\xef\x0c\x8a\xba\xcc\x07\xc7\x55\x9c\x4f\x9a\xd3\xf4\x2c\x71\x1b\x46\x95\x04\xfd\x24\x0a\xa3\xab\xa5\x9f\x5b\xa5\x7e\x6d\x54\x48\x82\xf2\x5a\xf7\x92\x49\x54\x13\x52\xda\x71\x7b\x6d\x55\xd0\xab\x28\x23\xd4\xdc\x5e\xdf\x11\xae\x70\x2b\x4a\xee\x74\x7b\x65\x5d\x92\xea\x7d\xf9\xf2\x15\x4e\xbc\x73\xb1\xab\x1b\xd0\x52\x37\x43\x44\x70\x73\x83\xda\x47\xe5\x22\x1b\x66\x8c\x4a\x3b\xca\xf1\xb3\xe4\x37\x80\x1d\xbc\xfd\x86\xbd\x57\x9f\x1e\xf6\xea\x79\xbe\xec\x55\xd9\x3f\xd6\x79\x95\xcd\x86\xbd\x79\xd3\xac\xea\xf8\xde\xbd\xcb\xbc\x99\xaf\xcf\x91\x77\xb9\x57\xaf\xca\xfc\x6b\x76\xaf\x22\x34\xf9\xbf\xea\xff\x92\xd5\x0f\x95\x69\x9f\x8b\x1e\x00\x37\x91\x1f\x33\x07\x51\x75\xc9\xe2\xdd\xb3\x03\xa9\xe4\x1d\xad\x85\x1e\x20\x83\x5c\xd1\x3b\x08\x01\x12\x09\xa9\xa9\x33\x0c\x48\x6e\x2c\x5a\x87\x16\x52\x8f\x84\x8f\x28\x20\xf1\xbe\xf0\x70\x03\xa4\xd1\xb8\xdd\x77\x0d\x7d\x78\x21\xe1\x57\xe1\x1f\x57\x48\x7c\x1c\xc0\xab\x8f\xda\x78\xd5\x51\xe7\xb6\xb5\xe4\x3c\xa1\x22\x3e\xe7\x17\x2e\x19\x05\x84\x5c\x79\x6c\x5e\xe7\xb2\x41\x7c\xc8\x46\xfd\x6b\xf7\x19\x33\x6f\x3f\x63\xe2\x5c\x76\x7e\xc4\x44\x3a\xce\x27\x84\xe0\xc8\xe2\xdb\x94\x7a\xde\xcc\xd1\x51\x82\x67\xa9\x9d\xd9\xa4\x14\x9f\xb8\x99\x65\x6f\x95\x0d\xd9\xc8\xf7\xfd\xc5\x6f\x16\xc5\x85\x0c\x49\x75\x59\xdf\x5a\xce\xb1\xf6\xb6\x6c\xca\xbd\x55\x2b\x92\xda\x0b\xfd\x42\x5a\xbb\x4d\x60\x68\x28\x26\x92\xa6\x6d\xf8\x12\x5a\xc1\xfe\x5f\x5e\xb1\xd9\x9a\x42\x87\x71\x8b\x28\x61\x8c\xc9\xcb\xc9\xfc\x90\x7e\x58\x57\xc6\xa3\x3d\xad\x98\xdc\x6b\xbe\xa3\x11\x3f\x9c\x65\x6a\x94\x70\x72\xdc\xd0\x7c\xc9\x98\xc3\x32\x6b\x23\x3c\x6b\xf2\xf8\xb2\x2f\xa4\x2f\x8a\x8e\xd1\x53\x84\x51\xdd\x1a\xb5\x40\x1e\x12\xd4\x5c\x8e\xd1\x4b\x4e\x81\xca\x4f\xf6\x56\xa5\x6e\xf0\x3c\xd4\xea\x08\xae\xb8\x52\xf1\xd8\x0b\x6d\x2b\x72\xef\xd2\x55\x5c\xa6\xf5\x30\x94\xf4\x56\x9b\xd1\xca\xbd\xc5\x77\xf0\x4c\x19\xd8\x07\xfd\x1c\x28\x13\x7b\xc5\xcd\x4c\x43\x17\xf6\x02\xdf\xd1\xe9\x09\x32\x32\x77\x57\x24\xe8\x46\xe3\x24\x79\xcf\x45\x02\x57\x9a\x93\xd4\xcd\x18\x89\x14\x1d\xdf\x9b\xbb\x2d\xda\x00\x82\x6d\xdd\xa7\x21\x6d\x62\x0f\xc2\x9a\x00\x84\x29\xcd\xce\xfe\x35\x72\x1e\x7e\xb8\xdd\xd3\x05\xec\xcf\x99\xfd\xaa\xd1\x28\x06\xc4\x65\x36\x51\xae\x84\xaf\x6e\x45\x48\xfb\xe9\x96\xa1\x19\x14\xe0\x5b\xe0\x3e\x05\x04\x27\x69\x69\x5e\xd0\x5e\xca\xf0\x0b\xb0\x3f\xef\x61\x34\xa0\x5e\x03\xac\x56\xef\xc8\xd2\x16\xa9\xf7\x8c\x0f\x31\xb8\xa9\x5b\x33\x46\x43\x5f\xd6\xf1\x82\x6d\x51\xbe\x55\xd0\x47\x75\x00\x90\xe2\x85\x50\x10\xc2\x6a\x39\xc8\x03\x4c\x85\x02\x12\xb6\x17\x52\x30\x8b\x8a\x11\x17\x68\x31\xc7\xac\xda\x68\xb2\x90\xb6\xce\xeb\xdb\xd4\x44\x52\x84\xc9\x41\xab\xde\x85\xd4\xb2\x40\xbb\x68\xf9\x1c\x91\xf7\x1b\xe4\xd6\x49\x43\xc4\xbc\x32\xf4\x57\x18\x6d\xee\xda\xd2\xd1\x48\xe9\xce\x6f\xca\x15\xd0\x41\x85\xb8\x90\x2a\x25\x01\xee\xb6\x53\xe3\x4a\xee\x72\x81\x5e\x4a\x25\xd5\x1e\xba\x68\xbc\x4b\x63\xdb\x93\xb9\x64\xf0\xbb\xe4\xc6\x5a\xb7\xfb\x7a\xab\x5c\x55\x1b\x7b\x20\x59\xd6\x16\xab\x4a\x1e\xfe\xb4\x44\x1f\x32\xad\x6c\x34\xfb\xb8\x36\x45\x98\x71\x43\x08\xfb\x45\x3e\x42\x31\xfb\xb5\x92\xef\x22\xbd\x5f\xa2\x83\xf2\x20\xfa\xa5\xf7\x7d\x9e\x15\xbd\x35\xe9\x16\x49\x16\x4b\xdd\xa0\x7b\xd1\x44\x36\x16\xec\x6d\xe3\x8b\x5a\x1b\x7a\xd9\xbf\x4d\xd8\x2a\xb9\xe0\x80\x62\x40\x4b\xd8\x4a\xcb\xbe\xed\xf9\x7f\xdb\xb2\xdf\x6d\xc9\x9b\xed\x4b\xde\x84\x97\xbc\xb1\x96\xbc\xd9\x69\xc9\x9b\xed\x4b\x8e\x44\x8b\x5a\xf6\x26\xb4\xec\x8d\xb7\xec\x24\xfc\xc8\xfe\x03\x96\xbd\xf5\x8c\xb7\x55\xeb\x22\xc0\x65\x10\xca\x3d\x3d\x13\x4a\xa6\x05\x3f\x2d\xa1\xd6\xe9\xd9\xc6\x72\x31\xc8\x84\x0a\x73\x56\xc6\xeb\x5c\x36\x5c\x22\xd5\x59\xa3\x8e\x1d\xff\xd2\xa1\x83\xec\xfe\x34\xbf\x5f\xd1\x85\x86\x6f\x9d\x56\x52\x36\x10\x76\x08\xbb\x66\xd0\x6e\x83\xd4\x39\x02\xaf\x86\xf8\xca\xc8\x68\x0a\x9f\x0f\xb1\xdd\x6a\x63\xc5\xb7\x69\x48\x9e\xa5\xec\xb8\xc6\x24\x58\xc1\x94\xb6\x6e\x9b\x46\xd0\x13\x59\xa7\x35\x84\xc6\x68\x0d\x49\xa9\x9a\x34\xb1\x45\x83\x6c\xfd\x9a\xef\x74\x25\x13\x43\xf6\xb0\xba\x02\x10\x3b\xeb\x69\xd6\x0f\xea\x40\x78\xba\x01\xb2\xae\x7e\xe1\x2b\x8e\xb3\x18\xbd\xca\xf2\x9b\x29\xe3\x58\x5b\x9d\x09\x86\x65\xa9\x06\x38\x23\x33\xe9\xdb\x96\x42\x2a\xdf\x38\xcd\xd4\xe5\x32\x0b\xc4\x16\xdc\xeb\x5c\x9b\xdb\xb6\x16\xc0\x83\xac\x40\x8d\xd3\x0e\xd2\x2c\x46\xfd\x7a\x74\xca\x31\x92\xbb\x1a\x78\xc8\x86\xff\xdb\x4c\x82\x72\x3d\xa7\x18\xe4\x00\xdc\x7b\x66\xb0\xf6\x23\x35\xc5\x26\x34\x8e\x71\xd0\x69\xe6\x5e\x86\xf4\x0e\x03\x6b\xcb\xb9\x89\xa5\x9c\x0b\xed\xd9\x3a\xc5\x65\x32\x06\xa6\xa3\xed\xd3\xe3\x59\x49\x96\x81\xd7\xb6\xcb\xd0\xf2\xcc\x76\x30\x46\x0f\xe1\x8d\x71\x17\x8c\x41\xec\x6c\xa1\x6d\x00\x81\x86\xdc\x6b\x61\x25\x87\x83\x07\xbc\x40\x42\x62\x29\x49\xbe\x4f\x22\x8b\x36\x4b\x0d\x8d\x1a\x43\x29\xf2\x53\x84\x2d\x19\x6d\xeb\x60\x98\x3d\x8a\x93\xf5\xbc\xe9\x8f\x06\x6e\x84\xe6\x03\x15\x14\x77\x2c\x5b\x31\x7a\xc7\xa1\x69\xa0\x5b\x66\x47\xb3\x3b\xa3\x6a\xa5\xbf\x93\x8e\xda\x01\xda\xba\x33\xdf\x95\xd9\x7c\x57\x71\x8a\xc2\x92\x33\x8a\x05\x6f\x62\xd0\x0a\x23\x98\x80\xf5\xe0\x28\x3d\x87\x52\x97\xe7\xb0\x2c\x16\x57\x96\x00\xac\x25\xea\x70\xed\x70\x74\x4b\x72\x94\x96\xa6\x4e\x70\x6e\x01\xdf\xc3\x56\xd8\xe1\xa0\x27\x62\x9e\xce\xc6\x28\x6c\x06\xbc\x03\x4a\xf1\x2f\x73\x59\x18\x70\x87\x94\x0b\x9d\x9d\x06\x2e\x1f\xf8\xf7\xd0\x64\x21\xe7\x3e\x9d\xa4\xed\x7e\x36\xf5\xc5\xc2\xa2\x0b\x62\x74\xd1\x69\xfc\xa2\x9c\xa5\xf5\x5c\xfa\x80\x1f\xde\xab\xcb\xe9\xd7\x0c\xdd\xbe\x8b\xd2\x93\x45\xd5\xfd\x53\xe2\x20\x22\x11\xad\x52\x8c\x15\x05\x73\xfe\x96\x63\xa0\xa8\xe8\x6b\x8e\x11\x9a\xd0\x7f\xf7\xe7\x1a\xc3\x60\x45\xcc\x77\xb7\x3e\x9e\xa3\x15\x12\x7c\xa3\x54\x5a\x66\x02\x9c\xe2\xaf\x9a\x7f\x9e\x94\xab\x7c\xca\x3f\xdf\xa2\x1f\x60\x01\xc3\x4b\xf1\xd1\x0d\x78\x6f\x0a\x6c\xda\x42\xc7\xcc\x0d\x0f\x6b\xbc\x86\xe4\xf0\x00\xf6\xab\x6f\x48\x5a\x0b\x7c\x44\x29\x80\x89\xc4\xc7\xda\x8d\x28\xd1\xed\x62\x73\x4b\x13\x3c\xb5\xee\x26\x78\xce\xc1\x46\x48\x9a\x21\x9b\x51\x4b\xa3\x1a\x2a\x54\x43\xd0\x24\xec\x4a\xa5\x9a\xc3\x95\xbb\xb5\x31\x5e\xde\xed\x4d\xb9\xf1\x3f\xac\x9d\x8c\x8f\xee\x1f\x09\xde\xe4\xf8\xa1\xe0\xcd\x07\x90\x19\x13\xc8\xec\x12\x45\xd3\x05\x99\x36\x4c\xc0\xae\xd3\xa6\xc2\x9e\x11\x4c\x40\x3e\xf9\xfc\x12\xd1\x2c\x53\xbf\xcf\x7c\xdf\xa1\xde\x38\xb6\xfb\xdc\xfe\x43\x40\x17\x97\x92\x61\x14\xfe\x3f\xaf\x00\xac\xa6\x28\x91\xc0\x11\xa3\x0b\xd3\x08\x8d\x16\x97\xcb\x94\x0a\xc1\x54\x30\xd0\xef\x5f\xf3\x59\x33\x67\xe0\xc3\xda\xb7\xee\x13\xec\x4b\x63\xef\x53\x53\xc2\x16\x49\xf7\xfe\xbf\x67\x97\x76\x74\xa8\xba\x75\x97\x80\xe0\xc2\x93\x3b\x5d\x94\x75\x76\xeb\x76\x6c\x77\xe0\xb9\x5b\x87\x45\xfa\x2d\xbf\xc4\x60\x1a\xb7\x75\xb6\xa3\xdf\x6c\xab\x33\x77\xbb\x83\xbb\xad\x84\xa1\x00\x84\x79\x6d\x3e\xbe\xcf\xcb\x1c\x51\x4d\xfa\x3d\xbd\xe2\x7d\x7e\xc7\xa8\xcb\xa0\x19\x59\xf8\xf6\xcd\x56\x8d\xaa\xfd\xce\x44\x91\x23\x93\x4f\x87\x12\x31\x1c\xf0\x05\xea\x27\xda\x64\x68\x97\xec\x80\xc5\xe4\x4f\xd8\xe8\x74\x21\x8b\xaa\x9f\x64\xbe\x01\xf8\x06\xee\x8b\x05\xfa\xdc\x19\x0b\x59\x80\x33\x25\xde\x30\xb3\x0a\x0c\xd4\x0c\xf2\x1f\xeb\xdc\x1e\x21\xd7\xa5\x45\xb8\x05\x0d\xca\x85\x32\x78\xd0\x46\x5a\xb8\x7a\xb7\xd4\xe7\x05\x36\xd5\x9d\x53\x40\xaa\x6b\xef\xba\x30\x9f\x69\xa4\x70\xf0\x5e\x03\xd7\x5f\xf6\x3d\xda\xe5\x20\x79\x10\xd6\x12\x29\xec\x04\x61\xf7\x2a\x20\x9e\xb2\x0e\xf8\xe2\xf8\x67\x0a\x37\x2c\xba\x00\x86\xf9\x56\x69\x72\x18\xfd\x17\xe5\xcc\x77\x32\xc0\xe8\xd5\x8a\xaa\x9a\x54\x43\x75\x58\xfa\x11\x87\xa5\xbb\x87\xd1\x74\x55\x18\x78\x37\x33\x30\x79\x39\x52\x20\xa9\x5b\xa8\xc3\x61\xeb\xbd\x89\xff\x67\xe9\x0d\xd6\x42\xa4\x92\xf3\xa4\x87\xe5\xfa\x9e\xbc\x67\xcc\x8a\xb0\x52\x8a\x9d\x51\xba\x19\x72\x9b\x8d\xd6\x85\xca\xe0\x3d\x34\x91\xdf\x55\x7a\x93\x9e\x73\x58\x0b\xc6\xbd\x6d\x9d\x59\x74\xb4\x37\x90\x31\x4f\x0c\x21\x4a\x82\xf8\x86\x02\xa0\x0b\x0e\xa3\xef\x86\x1a\x9a\x48\xd1\xf6\x42\x4a\xb4\x09\x92\x62\x0c\xc2\xbf\xbf\x9f\x2b\xe8\xeb\xe3\x37\xb4\x6e\x0b\xa2\xe9\xc0\xc4\xb9\x75\xbe\xfa\x6e\x01\x22\x31\x64\x4b\xc0\x84\x51\x1c\xf6\x53\xfc\xc4\x96\x44\x2a\x81\xa1\xbf\x16\x98\x36\x70\xaa\x12\x69\x41\x55\x8f\x2b\x22\x45\x4c\xc5\xb8\x46\xf5\x2a\x4e\xab\xfd\x31\x2d\x61\x6b\xa7\x16\xef\x57\xca\xe3\xf1\x9f\x9e\xbf\x38\x79\xf3\xfe\x1d\xea\x03\x98\x85\xd1\x81\xe1\x0f\xa2\xff\x14\xd1\xe2\xd9\x4d\x35\x44\x5f\xc5\x4a\xf1\xe8\x52\x52\x5c\x30\xdc\x7a\x30\x59\x1d\x97\xe4\x8f\x48\x1d\xb8\x35\x5e\x60\xb5\x3e\xba\xab\xcd\x20\x46\xfa\x07\x6f\x4b\xb4\x32\xee\x51\x63\x3d\xba\xf6\xa9\xbe\xd5\x8f\x24\x7f\xe4\x3a\x4d\x4f\x8f\xe0\xff\xf5\x71\x25\xa9\x27\x5e\x78\x4c\xc5\xa9\x73\x19\x5a\x00\x3b\xdb\x1f\xfa\x57\x6b\x0b\xa9\xf0\x57\xbd\x85\x7e\xd1\x65\x7d\x19\xa1\xeb\x3b\xbd\x68\x47\x0c\x41\x17\x09\x15\x9f\x27\x6a\xbd\x8e\xac\xf5\x92\x97\x7c\x7f\x2e\x2e\xa0\xb9\x8d\xd5\x5c\x0d\xa8\xcc\x69\x6e\xcc\xcd\x99\x76\xc6\xc1\x76\x6a\xaf\x1d\xc6\xa9\x1a\x0a\xe9\x33\x04\x83\x84\x3b\x01\x06\xf1\x6f\x28\x1f\x23\x03\x45\x66\x2b\x4e\x01\x1d\x50\xe0\x58\xc0\x0f\x24\xd9\x7e\x2a\x8f\xe7\xb3\xde\x61\xef\x7f\xd0\xcb\x57\xcf\x1c\xd8\xe8\x1e\x42\x59\xef\x54\xa6\x9c\x41\x99\xdf\x32\x14\xa2\x61\x54\x22\x0a\x65\x54\x34\xa8\x30\x82\xac\x07\x3e\xe2\xa8\x9a\xc2\xea\x05\x4f\x53\xef\x29\xfe\x8f\x5d\xbc\x20\x4d\xa5\x1e\x1d\x31\x6c\x1f\x8f\x10\x24\xbf\xd4\x27\x88\x1f\xdb\xec\xf6\x25\x36\xb0\xdb\x5c\x66\xbd\xa7\x12\xd2\xb0\xd1\x4f\x19\x46\x43\x62\xa9\x95\x41\x2a\xd1\x3d\x86\x39\xc8\x9f\x03\xbf\xc4\x1f\x2a\xa4\x92\x6a\x3c\x34\x62\x80\x88\xde\x53\x0e\x67\xfa\xac\xdd\x8f\x8a\xc0\x44\x76\xa3\x99\x3f\x75\x5c\x0d\xbc\xfd\xa2\x81\xdd\x22\x00\xc5\xad\x0d\x59\x23\x6a\x68\xf4\xb8\xa3\xbd\x53\x59\xea\x8c\x6a\xd1\x62\x4f\x31\x90\x70\x8f\x72\xd5\x64\xcf\xe8\x4c\x6d\x36\xf2\x6d\xd9\xc7\xbc\x80\xeb\xe9\x91\xd7\x47\xbc\x90\x7e\x5f\xb4\xf1\x2e\x24\x3f\x12\x1e\xda\x85\x34\x7a\xc9\xf5\x90\x3d\x5c\xa0\xf7\x35\x25\x4a\x77\xc8\x8e\x5e\x78\x2b\xf6\x91\xcb\x77\x85\xbe\x4b\x4b\x9d\x75\x48\xb7\x54\x45\x77\x43\x39\xfc\x88\x1f\xec\x02\xb8\x22\x6d\x88\x77\x7c\xcb\x41\x27\x4a\x0f\xef\x24\x3d\x47\x19\xea\xf0\x7f\xd5\x3f\xb4\x1f\x6a\x33\x05\x75\x3b\x4f\xf5\xed\xfc\x62\x01\x64\x55\xff\x1a\x50\xf7\x6a\x91\x5e\x91\x92\x6e\xf4\x7c\xb5\x8a\x04\x4b\x35\xe3\xd3\x54\x54\x46\x90\xbe\xd6\xf7\xaa\x30\xb4\xea\xe0\x4c\xa8\xdf\x8e\xb2\xbd\x74\xb9\x94\x16\x35\x85\xe7\x3a\xa1\x27\x3d\xb8\x6b\x8b\x99\x6b\x27\xa4\x55\x23\x03\xb1\x03\xd8\x15\xb4\x9f\x55\x53\xf2\xa0\x95\x9e\x73\x3a\x42\x80\x45\x3e\x4f\x25\xb1\xe3\x2e\x02\x5d\xfc\xde\x82\xc5\x47\x47\xbf\x0a\x5a\x77\xa0\x05\x46\xc2\xdd\x82\xf8\xfe\xc8\x23\x14\x8e\x76\x09\xa0\xe6\x6c\x72\xdf\xde\xe5\xd6\x1e\x6b\xca\x00\xb0\x43\x73\x92\x37\x8b\x4c\x6e\xa3\xa4\x0b\xde\x32\xbc\xfe\xa9\xfc\x21\xd3\x53\x27\xfd\x4d\xb1\x5a\xab\x8d\x97\xd0\x80\x52\x82\x2d\xe0\x40\x84\xc4\x2d\xc0\xf0\x82\xf8\x33\x05\x0d\xa8\x86\x06\x05\xcf\x5c\x99\x7e\xeb\xe9\x02\x45\x84\x32\x28\x07\x32\x09\xe8\x88\xcd\x58\x3d\xe1\x0d\xfa\x01\xa3\xbf\xd6\x7d\x56\x3b\xa6\x33\x74\xbc\x56\x64\x00\x7a\xca\xc1\x03\x28\x80\xf6\x3b\xd0\xf9\x83\x58\xa5\xc3\xad\xe8\x17\x45\xd1\xcf\x1f\x01\x58\x65\x27\x60\x5d\xe3\x1b\x04\x4c\x52\x05\x20\x51\x4b\x8e\x89\x9b\x76\x85\xb4\xa3\xa1\x7a\x27\x08\xb5\x31\x8d\x0b\x0b\x00\xa1\x84\xc2\x3c\x50\x80\xe4\xfb\x22\x04\x09\x90\x41\x50\xee\x00\x02\x24\x3e\xb9\x0b\x98\xef\x2c\x23\xeb\xc4\x65\xc3\x00\x79\x9c\xbb\x19\xbc\xa3\xd9\xec\x84\x60\x32\xbd\x15\x26\x69\x4d\x6c\xc0\x54\xa4\x67\x29\x22\x25\x7f\x8a\xc8\x51\x98\x4c\xcf\x45\xe4\xf4\x71\x26\x6e\x35\x83\xba\xd6\x82\xac\x12\x81\x56\x5a\xaa\x08\xab\x19\xa0\x38\x4c\x46\x10\x08\x2d\xb8\x27\xf7\x64\x43\xab\xb6\x68\x12\x6a\x98\x84\x79\x06\xee\x0d\xcc\x6b\xb9\xee\x36\x48\xbe\x9e\xe2\x12\xf1\xca\xe0\xad\x79\xd8\xe0\xd2\x1c\x9e\xa7\x55\xb4\x69\x01\xe0\x16\xe0\x8f\xea\x55\x5a\x74\x35\x07\x4d\x65\xc4\x4d\x0f\xda\x40\xdd\x55\x11\x09\x80\x29\xa2\x06\xa8\x8c\xee\x66\x03\x90\x9f\x2a\x46\x34\x70\x9f\x76\x00\x07\xe4\x3d\xb6\xa0\xd7\x83\xd5\x9d\x85\x73\x16\xac\x6a\x4e\xae\xf4\xf0\xa3\x66\xc0\x72\x2f\xc3\x40\xf1\x2d\x80\xaa\xe4\x1d\xb7\x83\x5a\x0d\xc4\xd9\x7b\xd2\x04\x48\x01\xde\xf6\xc6\x00\x4c\x73\xba\xe9\x3f\xad\xcf\x1d\xdb\x70\x52\x9b\x02\xbe\x19\x05\xdd\xd2\xdf\x88\x74\x24\x66\xc2\xcf\x23\x4b\x02\xeb\x46\x4a\x0f\x6b\x32\x98\x5c\xf6\x89\x51\x55\xf9\x48\x78\xba\x99\xe8\x2d\xf8\x82\xd4\xde\x80\x43\x5b\xa6\xab\xbe\x2e\xab\x0e\x81\x2c\x2f\xb9\x48\x41\x87\x0b\x2b\x0f\xf0\xba\xb9\x26\x81\x8b\x69\x1f\xbe\xdc\xf6\x51\x3c\xa3\xb3\xeb\x7a\x01\xcd\x66\xd3\xaf\xd9\x4c\x9a\x45\xc9\xb3\x61\x2f\x02\xf0\x8a\xb5\x96\xf0\x98\xa1\xab\x14\xb7\xf9\x5a\x8b\x8d\x4c\x49\x95\xe2\x97\x54\x92\x24\x53\x52\xa5\x38\x25\x91\x74\xd5\xd6\xb5\xc3\x68\x80\xfe\x30\xd1\x17\xb3\x16\x77\xa1\x85\xbd\xc0\xb7\x47\xcb\x61\x66\xce\x4c\x4d\x0a\xa0\x37\xd0\x3b\x08\xb3\x7a\xb1\x40\x39\x97\xa7\xe6\x63\xec\xc5\xfc\xed\xef\x5a\x93\x4d\x90\x82\x62\x1c\x43\xb1\xdc\x6c\x3b\xff\xf0\x9a\x66\xc9\x5d\x70\x42\x8e\x57\x09\x9c\x6d\xda\xde\x48\xad\x28\xf0\x09\x57\x2b\xf8\x46\xcf\xe6\x91\xa0\x00\x2b\xf3\x72\x81\xa3\x8a\x3e\xab\x22\x81\x5b\xd1\x6b\x4d\xad\xfa\x96\xd6\x3e\xa8\x22\xb7\xb7\xa6\xe0\x62\x4b\x6b\x1f\x55\x91\xcd\x20\x84\xc6\xda\xd8\x54\x1e\xdf\x00\x1a\x65\xf1\x37\x8a\x65\x63\xf9\xbb\x5d\xef\x90\x33\xca\x42\x1e\x61\xda\x14\xfb\x50\x07\xda\x9d\x8f\xe5\x4e\x68\xdc\x71\xeb\xc4\x6f\x99\xf4\x3b\xca\x96\xce\xed\xff\x99\x9c\x34\x46\xaf\xab\x2c\xc3\x68\x27\x3b\x2c\xab\xc4\x24\x5b\x3a\x78\xae\x4a\xb8\x7d\xe4\xd5\x74\x78\x21\xfb\x19\x16\x59\xb3\x43\x5f\x2c\xbb\xec\x9e\x09\x66\xdf\xde\x8a\xbe\xfd\xbb\x5b\x7a\xa1\x8a\xa0\x0f\x87\x76\x7b\xab\xae\xd3\xb0\x40\x3b\xa3\xdd\x8e\x0a\xa0\x38\x35\x00\xc2\x74\xe7\xe5\x0f\xec\x2d\xfa\xf4\xe9\xb7\xe0\x96\xba\x90\x97\x03\x08\x1d\x66\x8b\x45\xbe\xaa\x51\xa4\x5c\x16\x8c\x3f\x6c\x08\x52\x48\x65\x13\x02\x65\x35\x16\x1e\x40\x4d\xd0\x16\x09\x76\xd1\xa9\x21\x0b\x4f\x41\xf8\x3a\xee\xe0\x9c\xc3\x2c\xb2\xf5\x02\x23\x2f\x65\xba\x89\x77\x7e\x9e\x0a\x53\x8d\xfe\x5b\x15\x13\xa9\x79\x71\x81\x5a\x2a\x19\x45\xff\xc5\x1a\xe9\xba\x29\x31\xc2\x9d\x2d\x27\x95\x54\xf0\x9f\x33\xe0\x3c\x2a\x87\x21\xd2\x04\x85\xa4\xdf\x7f\xcb\x8b\xcc\xe2\x8b\x82\xa4\xe8\xd4\xbb\xfb\x8d\x64\x65\xb1\xf5\xee\x37\x24\x7a\x88\x4a\xad\x45\x24\x1b\x72\xa9\xd4\xf5\x4f\x50\xa9\xaa\xa1\xb8\xee\xa2\x52\xd7\x76\xc6\x3c\xcb\x2f\xe7\x9a\x93\xe1\x98\x75\x94\x74\x38\x1e\x8d\x6e\xb3\xaf\x96\xb5\xfc\xa8\xd3\xb8\x3f\x75\xfe\xef\x88\x87\x0c\x88\x7e\xa4\xa4\x2e\x05\xb0\x76\xa3\xfc\xe6\xfd\xd3\xed\xae\x66\xde\xf2\x58\xa4\x37\x00\x16\x2b\xa6\xe1\x42\xbc\x7c\xff\x16\xa3\x08\xf6\xa5\x1f\x65\x04\xa1\x4f\x14\xca\x3f\xb1\x62\xfa\x1f\x50\xc0\x00\xb8\xa0\x79\x6d\xc8\x51\x27\x67\x72\x82\xbb\x4e\xed\xce\x95\x55\xe3\x9a\x72\xe8\x55\x54\xd9\x17\x9a\x0e\x77\x19\xa3\x35\x26\x7f\x08\x8a\xc0\xe0\x05\x69\x51\x17\x81\xae\x0d\xc1\xb1\x1d\x0a\x60\x71\xad\xda\x77\x5a\x54\x2b\x98\xa2\x5c\x41\x6a\x83\xd7\xfa\x3b\xfe\xdc\xe3\xc8\xdf\x26\x21\xc9\xd0\x31\xba\xf5\x7e\x4c\xba\x72\x77\x67\xa6\x34\xe3\x74\x73\xa3\x99\x29\xf4\x59\x28\x28\x2e\xc4\x3a\xb9\x5e\x61\xac\xf8\xe2\xf2\xb7\xec\x42\xde\xc6\xa8\xff\xc8\xee\xdd\x8a\xe6\x20\x5a\x01\x8a\x36\x12\x89\xfd\x7d\x7e\x7c\xd2\x09\xa7\xa3\xb3\x9b\x1b\xa4\x49\x09\x20\x46\x96\x1d\x63\x32\x9a\x4c\x9f\x5a\xc3\x52\x27\x52\xf1\x6f\x53\x63\xd7\x1c\x28\x75\x3a\x3d\xc3\x90\x6f\x0a\xb1\x88\x8b\x64\x21\x47\x7f\xd0\x1c\x4c\x27\x0b\x19\xe2\xb0\xbf\x3a\x48\x22\x25\xeb\x3c\x8c\x0e\x38\x1d\x91\x07\xab\xfe\xb7\x44\x10\xd7\x5f\xb3\xab\xf8\x42\xbf\x45\x2c\x36\x96\x19\x36\x46\x44\x9b\x3f\x5d\xc0\xf6\x15\x66\x98\x73\x0c\x50\x10\x6e\x0d\xef\x44\x6e\xef\x20\x82\xbe\xe7\x16\xb9\xb3\x12\x14\x48\x34\x5e\x07\xc8\x19\xc9\x19\xce\x50\xda\x5d\x95\xeb\x7a\x71\xf5\x09\xd1\x99\x0c\x93\x19\x5f\x7f\xf9\x32\x6f\x96\x0b\xe0\xa2\x11\x87\xf7\xe5\x70\x4e\xe7\x67\x78\x2f\x19\x5f\x28\x63\xf2\xee\x2d\xdd\xe4\xde\x4e\xb6\xc9\x09\xe3\x8d\x2b\x87\x56\xb7\x87\x56\x4a\xe2\x0d\xe1\x37\x42\x47\xd5\x4d\x9a\xeb\x33\x10\x5b\xbb\xc4\x07\x45\x64\x5c\x4f\xe6\x1f\x3d\x40\x5f\x61\x18\x0a\xf4\x0f\x19\x8c\xac\x66\x06\x44\xad\xbb\x77\xf3\xc2\xbb\x9b\x3d\xe9\x75\xf0\x6a\x03\x5e\xf9\xd1\x56\x3e\x3a\x78\x5b\xc6\x47\x47\x0f\x84\xb9\x58\xe3\xa3\xc0\x15\x2f\xfc\x0b\x39\x7e\xe4\xb3\xe2\x3b\x6b\x60\x74\x49\x47\xed\xbb\xdd\x30\xe7\xa8\x0a\x19\x60\xc9\x57\x55\xfe\x0d\x6f\x62\x7e\x36\x48\x83\x92\xce\x7a\x97\x0b\x9b\x17\x22\x52\xbc\x1b\xe1\xa0\x16\xf7\x66\x21\x22\x46\x21\x72\xd5\x27\xf9\x10\x95\x46\x6c\x59\x0e\x3e\xe4\x58\x8f\x9c\x7e\xce\x2d\x68\xce\x69\x1d\x50\x1c\x91\x9e\xb9\x41\x16\x46\x21\x19\x5b\x43\xac\xda\x66\xef\xda\xe2\x19\x85\x44\x6a\xea\x5a\x01\xe6\xf5\x12\xb8\x61\xb4\x89\xb9\xd0\xf7\x02\xaa\x37\x12\x46\x66\xe4\x18\x24\x44\xcd\x0a\x6d\xd4\xa4\xd0\x46\x4b\x22\xad\xdc\x45\x5a\x99\x44\x5a\x41\xfc\x62\x46\x98\x77\xe3\x92\xc0\x34\x30\x14\x3f\x0e\x6e\x88\x3f\xe0\xd4\x2e\x49\x7a\x91\x93\xb0\xaa\xf9\x69\xa4\x14\xf5\xa2\x83\x8a\x11\x53\x26\x11\xd3\x88\x11\x93\x7b\x30\x6b\xef\x60\xda\x90\x08\x87\xf3\x81\xe8\x10\xed\x4a\x50\x06\x5c\x32\x72\x4f\x5b\xa7\x70\x6b\x67\x15\xa3\x1d\x04\xb1\xc4\x21\xfc\x39\xc7\xaf\xab\xdb\xa5\xb1\x5d\x24\x70\xed\xe5\x78\xad\xfe\xcc\x83\x83\x2d\xc3\x0e\x51\xce\xbe\x1c\x57\x38\xa2\xdf\xb9\xee\xdb\x79\xb6\xe2\x1a\x22\x82\x01\x7c\x92\x95\x77\xa3\xad\xbb\x64\xbd\x42\x76\xe4\x4a\x86\x25\x83\x15\xdd\x46\x45\x1b\xf2\x89\x16\xcc\xa3\x9f\xca\xe9\xba\x46\x37\xb0\xd6\x60\xef\x5e\x99\x0f\xe7\x5f\x32\xd7\x47\x32\x50\xa5\xe3\xfb\x44\xd3\x7c\x9f\xe7\xd3\x39\x05\x52\x66\x11\x18\x0d\xdd\x76\xd5\xd8\xa6\xb0\x26\xd1\x3d\xa6\x87\xec\x2a\x70\x26\x8e\x53\xa5\x8a\xd2\x77\xf3\x84\x16\x1e\xa2\x4a\x3e\xbf\xd4\xc4\x29\x3f\xf5\xdf\x5e\x52\xd4\x1c\xe9\xc9\x1d\xa1\xa8\xd9\x39\x79\x9b\xa2\xd5\x8b\x2f\x95\x80\xee\x3f\x36\x13\x3d\xee\xb7\x65\xa6\x02\x17\x50\x2a\x5b\xf6\xe1\x2e\x7f\x30\xb2\xca\x63\xcc\x19\x9d\x17\x47\x7f\x4a\xa7\x5f\x01\x6d\x4c\x33\x5e\x00\x20\x84\x6e\x6e\xa2\x97\x14\x8f\x4c\xa7\x1c\xeb\x91\xc5\xd1\xe7\x22\x47\x92\x32\xbf\xc8\x01\xd0\x54\x81\xfd\x7d\x5d\x42\xed\x0f\xeb\x01\xb4\x9f\x4d\xfd\x59\xb9\x8b\x10\x96\x02\xee\xfc\x48\xa0\xd0\x26\x81\xcf\xe1\x77\x20\xba\x43\x12\x2e\x25\x42\x20\xa2\x44\x7e\x74\x35\xe2\x8a\x5a\x78\xc8\x36\x09\xc5\x67\x85\x9d\x59\xca\x34\xde\xf6\xb2\x00\x08\x7d\x59\x7e\x2f\xec\x1b\x05\x92\xf0\xa2\xe1\xa5\xb1\xd2\x39\xa5\x85\x7f\xfd\xd7\x33\x07\x07\x01\xae\x3d\x12\x5b\xc9\xa6\x20\x66\x0e\x21\x49\x20\x98\x1e\xfc\xdc\xa3\xc4\xce\xda\x9a\x0a\x6f\x6f\xc3\x8f\x70\x57\x35\xc0\xc3\xd4\xd1\x1f\xf2\xe2\x69\x09\x1c\x75\xc3\xfe\x02\xb3\xfe\xa9\x2d\xdb\xd9\x59\x39\xb0\xf3\x22\xd2\xa2\x9d\xdc\xd1\x5b\x78\xd3\x64\x4b\xe7\x71\x3b\xf0\x70\xe8\x89\x72\x5c\xc2\xaf\x25\xca\x91\x2f\x38\xbe\x14\x47\x69\x42\x6c\x97\xe1\xc8\x51\x85\xae\x21\x12\xd4\x60\xe3\xae\xfc\x26\xed\x78\x7d\xac\x45\x64\x0d\xb4\xde\xf5\xf2\xa1\x0e\x5c\xf1\x8d\x7e\x93\x4c\xed\x54\xbb\x71\x47\x0e\xa4\x85\x04\x52\xea\xd7\x22\x65\xa7\x96\xae\xa4\x76\x69\xa2\x9f\x2e\x24\x4c\x6c\xad\x55\x6b\xc0\xd9\x4e\xcc\xd2\x73\x27\x3e\x2d\x59\x68\x40\xcd\xc6\x78\x1b\xd6\xfe\xe1\x53\x55\xda\x0b\xc3\xd1\x01\xe4\xb9\x56\x7a\xad\x2c\x65\x7f\x12\xc6\x36\x1b\xdb\x39\xe8\x30\x43\x3b\xac\x4c\x0e\xc0\x5e\x38\x74\x32\xe2\xf6\x95\x86\xb9\xe1\xed\x7d\xa1\xe1\x56\x3a\x5c\x17\xf5\x3c\xbf\x68\x76\xaa\xcb\x47\x13\xab\xd3\x56\xcb\xf0\x04\x28\xd9\x4d\x37\x83\xdd\x5f\x7f\x31\xee\x12\x73\x8f\xad\xb2\xe7\xeb\xa6\x29\x3d\xf2\x99\xd3\x0e\xb5\x52\x76\x80\xb8\xb7\x81\x66\x63\xbf\x49\x04\xc8\xea\xd6\x70\x6a\xb8\x03\x0f\xb9\x93\x3a\x78\xc3\x04\x64\xde\xd3\xf2\x32\x2c\xee\xb6\x01\xb1\x2d\xb8\xf6\x99\x63\x47\xc7\xe7\xd6\xe7\x65\x97\x62\xbf\xff\xab\x68\x63\x10\x48\x7e\x22\x02\x78\x0a\x78\xe5\xc7\x21\xf6\xd8\xbb\x01\x5a\x96\xc2\xbf\x83\x72\x77\xa9\x5f\x9f\x0f\x6e\x76\xd0\x9f\xb0\x26\x11\xd4\xa0\xd8\x05\x39\xf5\x6c\xc2\x57\xe3\x18\x1f\x4d\xe4\x8a\xed\xb5\x98\x59\xc9\xff\x5a\x29\x4a\xdd\xa1\x1b\x7d\x98\xe0\x0f\xed\x6a\x28\xec\xa3\x53\x8a\xf0\x7f\xa8\x31\x7e\xab\x47\x27\xe4\xa6\xd6\x25\x6a\xb7\xe7\x96\xd3\xc2\x40\xd5\x49\xad\xf9\x87\xdb\x98\xd8\xcc\x28\xb8\x06\xcf\x16\x1f\x2a\x6b\x00\xa4\x5f\xb1\xfd\x45\x26\x44\xa5\xec\x4e\x88\xfc\x7e\xad\x44\xf7\xde\xf6\x1f\x65\xd4\x0b\x8c\x52\x37\xb2\xae\xf3\xba\xeb\x3a\xbf\xe5\xf1\x65\x1b\x1c\xab\x6e\x3a\x1e\x58\x82\x17\xf1\xcf\x3c\xb0\xe8\x2b\xf7\xff\x6b\x0f\x2c\x5b\x9f\x17\xee\xf0\x96\xd0\x7d\xac\x45\x17\xb3\x29\x6c\x73\xfb\xc6\x97\xc9\x37\x96\x4c\xfe\x38\x93\x84\x42\x6d\x74\xa9\x1a\x8d\x65\x34\x72\x09\x86\x95\x0b\xcb\xcc\x33\xd2\x8f\x31\xe6\x3b\xe8\xd0\x5a\x02\x5e\x12\x15\xb0\xd0\x91\x40\x91\x74\xb6\xbb\x48\x1a\x9b\x62\x49\x33\x8b\xda\xaa\xf6\x75\x08\x74\xc1\xcf\x48\xa1\xb3\x9d\xa4\xd0\x3b\xf4\x6f\x31\x09\x59\x17\x8b\x75\x57\x35\xad\x10\x2a\x80\x8c\xd1\x4f\x09\x94\xef\xdf\x59\xdd\x76\x0b\x62\xf1\x55\xbd\x5c\x2e\xe2\x67\x2e\x55\x7b\xa2\x51\xd7\x7d\xc8\x60\x5f\x11\xb6\x20\x00\x25\x0f\x59\x2c\x32\xb6\x6f\x02\xdc\x2f\x02\x42\x0c\x63\xaa\x24\xc7\xe1\x02\x77\x11\x05\xe0\xfd\xb4\xd3\x4d\x44\xcd\x73\xbb\xef\x6e\xbf\x94\x76\x97\x78\xde\x7a\x63\xd1\x46\x8f\xb7\x18\x60\x69\xbf\x1c\x8d\xc3\x0d\x64\x07\xfd\xe6\x38\xea\xf5\xc9\x8d\xc9\x20\x8a\x23\x60\x46\x8c\x5f\x10\x7d\x6b\x49\x9b\x2c\xcb\x0c\xd2\xb6\xdd\x0a\x51\x56\x41\x9d\xbf\x0e\xfb\xad\xba\xc3\x7e\x6b\xed\xa6\x4b\xde\x73\xd2\x36\xea\xda\x60\x64\x7f\x65\x92\xed\xc8\xed\x86\xd2\x4e\x1c\xf8\x16\xdc\x1b\xd1\x56\x16\x25\xe9\x34\xf0\x1d\xd2\xc2\x85\xcb\x1d\x44\xe4\xb8\x09\x1d\x8b\xa1\x6d\x85\xb2\xf2\xe8\xa8\x4d\x81\x75\x71\x00\x6c\xd0\xed\x0e\xc0\x58\xa4\xef\x3c\x86\xc6\x8c\x62\x91\x5d\x34\xfe\x18\x60\xd3\xeb\xb2\x18\xdc\x3a\x1a\x36\xc8\xb4\x47\x93\x0e\xb5\x31\xb2\xdd\x09\x17\x0c\x36\x8c\x25\x06\xc2\x9e\xc5\x73\x0a\xca\xea\x4c\xc4\x74\xc9\x9a\x48\x5d\x5d\x66\xc3\x72\x31\x3b\x88\x7a\xec\x6f\x78\x46\x66\x3c\x68\xbf\x12\x1d\x64\xa7\x64\x6f\x79\x66\x77\x0d\x65\xb9\x67\x65\xc1\xcf\xf5\x45\xab\xac\xe9\xde\x3c\x05\x3b\x23\x20\x71\xa8\xb5\x4b\xcb\x5b\x0a\x2c\xcb\x66\xe6\x16\x29\x14\xf3\x8b\x57\x0d\xa0\x04\x61\x7b\x34\x49\x1d\x4b\x36\x3d\x83\xa6\x34\xbf\xd5\x5b\x32\x71\xd4\xba\x9f\x35\x3b\x23\x70\xe1\xa5\x36\x7a\xcd\x94\x1f\xd8\x66\xd3\x02\xdb\xd8\xb5\x5b\x60\x4b\x3b\x0c\x89\x0c\x7f\xb7\xb6\xb0\x24\xd7\x07\xad\x06\xd0\x23\x82\xbd\x24\xd2\x46\xb7\xed\x1c\xc5\x66\x67\x26\x1a\x82\x4f\x49\xe9\x2c\xc6\x9d\x65\x9a\x40\xeb\x37\x72\x9a\x52\x88\x14\x5a\xb7\x90\xd3\x95\x32\xa2\x88\xfe\x5c\xd6\x0d\xa7\xcd\xe1\x17\x4a\xd9\x68\x75\x29\x45\xd9\x39\x28\x75\x34\x4e\x55\x67\xe0\x4c\x04\xa8\x18\x3d\x11\x25\x7c\x72\xa6\xe2\xd8\x5c\xa0\xb3\x3f\xbc\xce\x13\x52\xb7\x58\x87\xc4\x3c\xa2\xa6\xb2\xf6\x02\x19\xed\x39\x77\x2d\x4d\xb9\x5a\x9b\x7b\x07\x82\xb5\xe8\x95\x53\xb2\x02\x60\xda\x87\xc3\x61\x24\xa3\xe2\xfc\x1e\xb3\x2c\xd7\x6e\xe7\x2e\xc6\x5a\x96\x95\x73\x18\xd9\xd3\x1d\x64\xdb\x6f\xdd\xdf\x45\x8f\xdc\xf6\xd5\xa5\x6e\xa5\xec\xd6\xd8\x30\xc4\x8a\xe8\xa8\xd8\x1c\x99\x9f\x84\xe1\x64\x1b\xab\xa2\x67\x43\xfa\x60\x13\x8a\xb6\x9d\x67\x35\x47\xbb\xf1\x1d\xfa\xb9\x81\xba\x0b\x0c\x83\x6e\x7b\x99\x06\x74\x58\x51\x1a\x06\x40\x6c\x30\xf8\xb4\xa8\xda\x66\xd7\xa1\x68\xca\xfb\xfb\x08\x45\x18\xc4\xfe\xff\x26\xed\xda\x7a\xdb\x56\x8e\xf0\x5f\x91\x08\xd4\x20\x43\x4a\x91\x92\x53\xf7\x40\x2a\xa3\x16\xcd\x43\x5b\x20\xe9\x83\xcf\x41\x1f\x0c\x21\xa0\x25\xfa\x84\x80\x4c\x0a\x24\x95\xd8\xb0\xf5\xdf\x3b\x97\xbd\xef\x92\xb6\xd0\x3c\x44\x96\xb8\x97\xd9\xe5\xec\xee\xcc\xec\xcc\x37\x06\xe2\xb6\x91\x3b\xf7\xe6\x04\x74\x4d\x40\x36\x40\x2f\x50\x9c\x03\x4a\x2e\x54\x56\x04\x30\x76\x57\x4e\xb0\x36\x06\xec\xe9\x6c\x54\x19\xc1\xc8\xc2\x51\x2d\x33\xc1\xaf\x4b\x23\xc3\xb5\x18\x35\x8b\x2e\x31\xe6\xd0\x33\x86\xf1\x6c\x64\xc9\x5e\xc9\xcb\x91\xac\xac\x4f\x0f\x25\x67\x19\x9f\x2e\x87\x33\x90\x4f\x41\xfb\x82\xc1\x53\x0e\x83\x6f\xdf\xa8\xd1\x6f\xdf\x72\x4c\x5f\xd5\xf8\x53\x31\x8d\xcb\x89\x04\x55\x24\x22\xc3\xa3\x97\x38\x89\x05\x0c\xb2\x98\x90\xc8\x3d\x29\x3a\x2b\x99\xf0\x99\x45\x09\xba\x7d\x42\x4c\x66\x0b\xc4\xbe\x18\x87\xc8\x67\xcb\xe9\xba\x11\x28\x90\xc2\xac\xf1\x93\xd1\x4f\xff\x5b\xde\xdd\x10\x6f\xc3\xbe\x86\x90\xbb\x51\xaa\x36\x80\x1d\xc3\x9b\xe3\x9e\x93\x46\xef\x7f\x76\x91\xaa\x09\xab\x1c\xe5\xcd\x00\x38\x57\xc9\xa9\xb2\x4c\x2b\xb0\xae\x43\x20\x18\x23\x95\x0c\xc8\x08\xab\x9e\x58\xcd\x01\xe8\xe2\x7f\xdf\xfc\xe7\x2b\x86\x6f\x77\xc8\xa8\xfb\xa2\x2f\x90\x0d\xa8\xb1\x7a\xce\x2c\x8b\xb7\x65\xa0\xd7\x76\x28\x7f\xca\xc4\x44\x94\x60\x2b\x43\x76\x7f\xc6\x7b\x44\xc9\x03\xf6\xeb\x93\xdd\xd3\x4d\x23\xf5\xd3\x51\x46\xfd\xea\xfe\x29\x66\x9f\xd8\x32\x43\xc4\xe2\x12\xf6\x66\x32\xd8\x12\x5f\x9c\xe3\xca\x4a\x20\x08\x33\x5c\x48\x48\xa1\x6e\x45\x78\x41\x1f\xc7\xbd\x5a\xd5\xeb\x13\x0f\x91\x83\x26\xc7\x0d\x21\xf8\x1d\x6f\x4b\x74\x1f\xc3\x0f\xc4\xcf\x7b\xa6\x43\x11\xc1\xe6\x92\x15\xfd\x88\x2e\x6a\x81\x87\x1a\x86\xb5\xb5\x04\xde\x2a\x7e\x26\xe8\x8c\x32\xd3\x62\x3a\x7c\xc1\x63\x70\x85\x60\x5e\x91\x59\xb5\x31\xe0\xd5\xd6\xd1\xdf\x24\xa4\xc2\xa6\xce\xa3\x06\x64\xe5\x54\xfe\x00\x2b\x03\x7e\xfa\x81\xa6\x2d\x72\x25\xd1\x78\x0b\x28\x4c\x91\xfd\xab\xa5\xbc\x82\x36\xb8\xae\xc1\x0c\x9a\x98\x7c\xc6\x3a\x32\x52\xa4\xe3\x28\x9a\x28\xd9\x00\x01\xe2\x38\x5d\x05\xcb\xfc\xc0\x32\xa9\x2a\x23\x4e\xde\xd2\x02\xa4\xc5\xe1\x88\xd9\x62\xf1\x62\xde\xc1\x4b\x8b\x83\x37\x05\x18\x12\xa2\xe9\xb2\x41\x0f\xd0\xfe\x30\xfc\x90\xa7\xaa\xa4\x99\x81\xbf\xa7\x62\xda\x66\xcb\x95\x9e\x44\xf9\x84\x6e\xc2\x97\x62\x32\x45\x95\xd4\xaa\x62\x4c\x33\x3f\x11\x55\xfa\x4f\x25\x3e\x2f\x3f\xf5\xf0\x05\xed\x25\x8c\x7b\x6b\xda\xde\x4e\x96\x16\xe3\x5e\x66\x69\xd5\xe4\x30\x14\xc1\x74\x44\xf6\xba\x47\x58\xd6\x56\xa1\x89\x86\xb1\x67\x6d\xfc\xc6\x9d\x95\x13\xe3\xb7\x26\x3e\xc8\xd3\x9f\x60\x81\x6e\x2c\x6b\xab\x51\x48\x6f\x07\x12\xcb\x6a\xb0\x28\x4a\x16\x0c\x26\x73\x23\x2f\xd4\x60\x25\x80\x06\xe2\x2c\xea\x93\x90\x5d\x2d\xc1\x64\x4f\x77\xf0\xb0\xb8\xfa\x2d\x70\xc3\x59\xb4\x2e\x30\x72\xe3\x23\x26\xd3\x65\xc5\xc9\x4e\x41\xdc\x50\x36\x77\xf8\xc8\xa8\x66\x23\x99\x48\xb0\x38\x3a\x0e\x15\xfc\xdc\x6b\x4f\x6b\x10\x2b\x17\xe6\x86\xda\xaa\x71\x15\x9d\x84\xa2\x11\x8b\x9f\x84\x08\x2c\x96\xac\x4f\xa6\xd5\xae\x95\xf0\xd6\x1c\x3a\x36\x66\x49\xec\xaa\x9b\xde\xed\x20\x34\x13\x5a\x03\xf1\x28\x57\x1d\xd4\x46\x07\x2d\x4e\x13\xf3\xe2\x69\x7e\x8f\x58\x8b\xad\xdb\xcd\x9a\xa3\xb4\x6a\x82\x9c\xcf\x30\x8f\x39\xcc\x1b\x66\x85\x0c\x12\x20\x55\x02\x2f\x1d\x34\xdf\xfa\x89\xdc\x5c\x34\x65\xed\x76\x5d\x71\x67\x68\x24\x0c\xbe\xfa\x26\xae\xa4\x66\x41\x37\x6e\x42\xb4\x09\x74\x4a\x5a\xc4\xd0\xdb\x62\xdd\x22\x2f\x83\x35\x51\x7d\x08\xa4\x32\x15\xd3\x01\x1b\x90\x90\xd0\x81\xf9\xa4\x88\xee\xbc\x6b\xfa\x86\xd6\x13\xe2\x0a\xa1\x7d\xf1\x5b\xb3\x46\xd3\xd3\x26\x98\xf3\x07\x14\xa0\x78\x15\x20\x15\x0d\x19\x89\x9a\x00\xd4\xd0\x02\xd5\xd2\x1c\x79\xaa\xc2\xcc\x98\x45\x28\x8e\x34\xc0\x6e\xb8\xde\xac\x91\x05\xe7\xd8\xf2\x64\xa4\xeb\x09\x11\x69\x68\x0f\x1d\x9f\x6c\xd7\xbd\x7e\x61\xbd\x9c\x55\xa1\xb9\x29\xfa\x79\x6e\xec\xd7\xd8\xdb\xaf\xd1\xed\x71\x60\x51\x0b\x45\xca\x8a\x8b\xa4\x73\x56\x1c\xb2\xb8\xe1\x0d\xad\xb2\x40\x5d\xb5\x91\x94\x5b\xbf\x3b\x63\x73\x7a\x7d\xce\x4a\x19\x7d\x69\x50\x23\x7f\x42\xaa\x82\x03\x02\xe5\x53\x69\x81\x01\x43\x35\x92\x45\x85\xfc\xf5\x63\x95\xb9\xba\x12\x87\xe2\xc6\x3a\x1c\x09\xd3\xf6\x8f\xd0\x42\x78\xa5\x36\xbd\x3d\x0e\xdd\xa5\x4b\x6a\x6a\x65\xe8\x46\xf0\x68\x5b\x09\xef\xff\xcf\x60\x22\xcb\xf6\x7b\x39\x9c\x5b\x00\xec\x2e\xec\xa5\x88\x56\xc0\xe5\x87\x5f\x41\x48\xbf\xc5\x1c\x23\xb3\x65\xd6\xe5\x28\x40\x1f\xf0\x90\x04\xd1\x75\x6e\x16\xa7\x0d\xaf\x32\x65\xd7\x4e\x64\x38\x3c\xe5\xf5\xa5\x87\x6b\xcb\x9c\xec\xc4\xf6\x72\xf4\x29\xe8\x6a\x20\x21\x54\x2c\x94\x55\xca\x9b\xa0\x44\x53\x92\x08\x37\x6d\x30\xdc\x54\x40\xaa\x0f\xd1\x9b\x3b\xd2\x6f\xc5\x8b\x00\xb6\x36\x93\x34\x12\xc3\x0a\xe8\x88\x86\x6f\x31\x67\x75\x5b\x60\xf6\xc2\x4c\xb9\xca\x99\xf5\x0a\x24\x51\x90\x33\x43\x84\xdd\x22\x4d\xc3\xd5\x95\x37\x5d\xb8\xdb\xd9\x2c\x5c\x6d\x98\xdb\xb8\xee\x06\x0b\x32\x67\x5a\xbc\x77\x7a\xd5\x27\x6c\x88\xd1\xc6\x7d\x6c\x5d\x01\x1f\x81\x48\xc9\xd3\x98\xb4\x85\xcf\x40\x69\xc6\x5e\x84\x42\xed\xd1\x42\xad\x00\x9e\x8a\x12\x05\x57\x4d\xae\xd2\x6b\xfe\x60\xbf\x6e\x76\x8e\xce\x75\x1e\x3b\xd9\x4c\x5e\xa7\xba\x49\x16\xc9\xff\x92\x9c\xe5\x46\x89\xfb\xcc\x81\x95\x8c\x83\xde\x96\x37\xc6\xdf\xb8\x94\x19\x2d\x3a\x59\xd9\x3f\xe7\xb0\xd0\x57\xb1\xf1\x1b\x6e\x9b\x7e\x11\x96\x49\xdf\xe0\xc7\xe5\x62\x96\xf9\x6e\x5b\xbe\xd9\xdc\xf5\x12\x1e\x74\xda\x32\xe5\x5c\xd4\x96\xf2\xf6\xd2\x15\xd7\xb9\xe2\xe7\xc9\x92\x54\x4d\x25\xd6\x29\xb8\x23\xa4\x31\x01\xe3\x4a\xc2\x41\xbd\x0f\xc8\x31\xda\xb7\x07\x5f\x2b\xbb\x0c\x13\x6e\x1a\x8a\x26\x36\xb4\xa5\xd2\xe6\x25\xd3\x1f\x02\xdb\x81\x8a\xeb\x6f\xd0\xcd\xc1\xe0\x98\xab\x2b\xa1\x3b\xe1\x17\x2b\x4e\x9d\x34\x37\x65\x53\xce\x98\x53\xfd\x9e\x94\x39\xdb\x1b\x85\xf0\x90\x22\xff\x32\x79\x28\xa1\x68\xa1\xca\x55\x59\x91\x3c\xc7\xd3\xf6\xe5\xa5\x45\x64\x35\x92\x85\x2a\x4b\xec\x01\x89\x07\xe8\xd0\xd3\xd1\xe3\xe0\x0b\x3d\x78\xe1\x2f\x8a\xb6\xc2\xe8\x8c\x89\x50\x03\x04\xb2\x21\x31\x40\x1d\x02\x0e\x53\xda\x97\x64\xd3\x84\x85\x16\xab\xdb\x76\xa8\x5b\xa0\x1f\xb3\x46\xaf\x2e\x2a\xef\xd3\xa9\x99\x26\x24\x50\x1c\x3c\x81\xe2\x10\x56\x6f\x82\x43\x51\x8d\x04\xd5\x9b\x03\xef\x90\x5f\x64\xfc\x67\xf0\x60\x3f\xd0\xc1\x7e\x10\x07\xbb\xf8\x94\x02\xc1\xd0\x51\xee\x6c\xa7\xc7\xb7\x1e\xe5\x83\xde\xb5\x8e\x99\xd6\xb9\x41\xb6\xbc\xac\x86\x76\xe6\x71\x2f\x5a\x63\x67\x4e\x9e\x77\x39\x2d\x3c\x39\x31\xb1\x8c\xa7\xcb\x0e\xda\x69\xe8\xa0\x56\x48\x33\x47\x1f\x68\x55\x18\xa4\xd5\x4c\xc5\xbd\x64\x16\xd2\x4f\x78\x1b\x0c\x48\x1a\x1c\xa4\xa4\xf3\x68\xaa\xbd\xae\x90\xdb\xa4\x79\xd3\x38\xb6\x35\x9a\x4e\x15\x1c\x48\xe9\x86\xe6\xe4\x8d\x38\xdf\x39\x74\x32\x9a\x44\x59\xb4\xbc\x3e\x3e\x4e\x3e\xb7\x88\x98\x7f\x53\xd4\xdd\xe4\x4b\x53\x63\x0e\xb9\x10\x7a\x51\x7e\xfd\x4e\x35\x45\x82\xcc\x8e\x12\xb4\x18\xb7\x21\xb5\xc0\x17\xb9\x6c\xbf\x8d\x3b\x2b\xa4\xd3\x01\x08\x76\xb7\xd7\x4a\xc7\x43\xb3\x9b\xf7\xde\x2b\x52\x58\x9e\x3b\xaa\x14\xe9\x69\xaa\x61\x5b\x3c\x07\xad\xee\x82\x97\x6b\x2f\xae\x1d\xb4\xec\x90\x64\x8e\xb5\x8e\x03\xe5\x7d\xfa\x2c\x7a\x0e\x40\x4f\xb0\xde\xc8\x4a\xdc\x8d\xaf\x44\x6f\xc1\xe9\x98\x22\x83\xef\x60\x5d\xfd\x39\x73\xd8\xce\xba\xf3\x70\xd7\xda\xb8\x83\xb7\x2b\x05\x49\x3b\x1b\xe5\xd7\x64\x41\x04\x13\x4c\x6d\xa6\xcb\x55\xdc\x49\x93\xe6\x39\x9b\x2e\x12\xfe\x8e\x5f\xec\xdf\x87\xc4\x8b\x37\x7b\x68\xb8\x2b\x2c\x20\x4d\x88\x20\xe0\x8b\x65\x86\xc6\xe3\x55\xd2\xc2\x25\xbf\xfe\x7d\xbf\x0f\x31\xeb\xa0\x5c\x71\xce\xd0\xfc\xee\xec\xd5\xfc\x21\xbc\x11\x25\x67\x74\xe8\xd9\x85\x66\x77\xa7\xb0\x54\x55\xf5\x84\xf0\x5c\x66\x5e\x6d\x93\x44\x57\xcb\x00\x81\x62\x48\x82\x10\x81\x1a\xc1\x48\xc6\xd7\xce\xbb\xce\x3b\xef\xba\x71\x06\xef\xc6\x25\xf7\xc1\x13\x65\xd4\xe9\xc4\x3c\x6e\x1c\xd6\x7e\xb3\x2b\xae\x09\x6c\xec\x40\x44\x0d\x23\x43\xf5\xc1\x80\xb9\x61\x29\xd8\xf1\x11\x09\x41\x35\xa2\x40\x7e\xb9\x6e\x59\xf9\x1c\x69\x0a\xb0\x99\xbb\x57\xbf\x51\x0c\x2e\xa4\x23\x4a\x46\xb7\xfe\x43\xcc\xaf\x6d\xba\xff\xd0\x4e\x98\x6e\x97\x01\xc3\xaf\x27\x9d\x87\xf0\x26\xe5\x3e\x1b\x10\x94\x55\x8e\x18\x9d\x64\x64\xb9\xdd\x90\xf9\xc2\xfc\x65\xbd\x93\x3e\xc1\x88\x3c\x20\xfd\x7e\xfb\x6c\x47\x16\xa7\xbc\xdf\xf4\x1c\xd7\x47\x8e\xf8\x65\x60\xc3\x0e\xc8\x6f\x08\x11\xb1\x53\x6e\xc5\x62\x69\xc9\x55\xa5\x3a\x41\xe9\x5c\x75\x4e\x4a\x9f\xee\x5f\x7c\x25\x12\xe8\x6f\xa7\xdb\xe1\xb5\x57\x5a\x7d\xc7\x3b\xcf\xf6\x45\x95\xd5\x0b\xf3\x4c\xa1\x3b\xed\x5f\x69\x0f\x03\x1b\x6e\x94\x0e\x83\x3b\x14\x0d\xac\xb6\xef\x49\xfc\x61\xda\xcf\x79\xd0\x6a\x98\x6a\x8c\x01\x1a\x4d\x96\x09\xbc\x5f\xba\x0c\x6d\xc3\x56\x37\xe5\xe5\x6d\x90\x4f\x1d\x4d\xf1\x27\x35\x40\xf1\x66\x08\x18\x6c\xe0\xf5\x48\x4a\xb9\x94\x24\x57\x7c\xeb\x2d\x82\x47\x8c\x83\x4c\x71\xcb\xea\x51\x99\x3d\x0b\x13\xe0\x4a\x92\x87\xdb\xde\x66\xa7\x05\xd2\x58\x72\x9f\xe8\xc7\x99\x9b\xd5\xd0\x6b\x0d\x82\xaf\x52\x56\xcf\xd2\xd5\x0b\x47\x39\xcf\x6f\x59\x79\x29\x86\xe4\x12\x39\x0a\xc3\x74\x19\x2c\x26\xfa\x78\x5d\xc8\x39\x84\xfc\x49\x2c\xc3\x96\x21\xbe\xb8\x76\x2d\x36\x13\x0f\xc6\x83\x0c\x2a\x2c\x4e\xa0\x48\x58\x5d\x19\x70\x2b\x79\x83\xce\xf2\x66\x87\xfb\x91\xc3\xe6\x0d\x78\x84\xf2\xd4\x41\xb9\xea\xf2\xa3\xa2\x21\x0f\x72\x77\x57\x31\xd3\x4a\x19\x8c\xb4\x8a\x92\x75\x8b\x48\x77\x71\xa9\xb0\xe5\x17\x88\x56\x91\x15\x24\xd9\x49\x2e\x57\x99\x1d\x9c\x4c\x0c\x36\x9b\x15\xa6\x7f\xeb\xab\xb2\x45\xe1\xc9\x16\x05\x8b\xff\x5f\x2d\x37\x5b\x8e\xdc\x42\x9b\x17\xdd\x4b\x95\x7e\x15\xef\xf2\x23\xb8\xa5\x14\xa6\xdd\xde\xbb\xb4\x2b\x78\x81\x38\x5d\x2b\x96\x46\x5a\x37\xf8\x1f\x5f\x62\x2b\xe3\x39\xdd\xd3\x8f\x97\xa7\x09\x7b\xcd\xd8\x5e\x8c\x83\x10\xbc\xca\xc0\x03\x1c\xfb\x4b\x20\xb5\x98\xc7\xb3\x16\x97\xae\xeb\xf9\xef\xbf\xff\xeb\xb3\xef\x1a\x12\x3d\x8a\x7f\x33\xfa\xef\x17\xfc\xef\x49\x7e\x95\xff\x22\x75\xd5\xf5\xfe\xf6\xf1\x69\xfb\xfe\x8f\x80\x6b\xde\xf2\xfa\xdd\x97\xa2\xff\x3e\x6f\x0b\xd0\x5e\x1f\xe2\xe4\x65\x91\xd5\x79\xf4\x18\xc1\x06\x07\x07\xf5\xc7\xab\xfe\xe5\x57\x1d\x23\xd7\x37\x37\xb4\x29\xc4\xcb\x6b\xda\x9d\x6b\x0d\x0a\x91\xdb\x47\x26\xb0\xa3\x34\xda\xae\xe5\x5e\x7d\x2c\xf6\x08\x7f\x01\x52\x2f\x4c\xfd\x3f\x9b\x53\xdb\x81\xba\xf6\x21\x8b\x16\xe8\x12\xe1\x3e\xff\x52\xd5\xb0\x79\xe8\x12\x2a\x5a\x21\x45\x9f\x0a\xca\xb9\x65\xea\x9e\x5e\x56\x14\x95\xea\x3c\x24\xb6\x7c\xdc\x6e\x16\x2b\xf3\x2b\xec\x06\x0b\x5c\xf8\x5e\x46\x35\x8e\x95\x2c\x6f\x1b\xc4\x39\x8a\xaf\x53\x10\xbf\x50\x52\xdf\xf0\x87\x28\x9e\x2e\x57\x8b\x24\x79\x57\x63\x6a\xe3\x2e\x2d\x94\x31\x99\x9f\xbe\xab\xff\xda\x27\x05\x83\x5c\xe4\xb7\xea\xe9\x76\x8d\x81\xf4\xcf\x7c\xbb\xa1\xeb\x18\x79\x24\x76\x79\x14\x81\x74\x8a\xb9\x14\x81\xba\xfb\x7c\xba\x5c\x9f\x0c\x34\xcc\x42\x98\x2a\xbb\xf4\x84\xe9\x26\x64\x67\x9f\x30\xc1\x5c\x7c\x60\x93\xf4\x0e\x85\xe2\x85\x89\x4c\xb4\xc8\xf6\xb9\x6c\x65\xbd\xff\xc4\xb8\x44\x44\xc5\x43\x7e\xba\xfd\xbe\x5d\xdf\x43\x6d\xec\x2b\xeb\xd2\x1c\x71\x02\xd2\xfc\x41\xb5\x9d\x1d\xd3\x34\xeb\xa0\x87\x4d\x8c\x07\xfd\x71\x63\xf4\x83\xc8\x53\xfb\xd9\x72\x03\x27\xe9\x43\x8a\x76\x12\x98\x2f\x3d\x41\x09\x56\xce\x97\xc9\x4a\x54\x78\xc0\x33\x57\xfd\x8d\x44\xe2\x20\x13\x1c\x25\x28\xb2\xba\xad\x54\x36\x96\xe6\x35\x9e\xd2\xf0\x3d\x53\x7d\x26\x67\x39\xad\x98\xcd\x52\x64\xc5\xdf\x37\x3b\x7a\xad\xae\x7b\xfe\xae\xa8\x7f\x14\x5d\xc4\x60\xef\x78\xac\xa2\x93\xee\x23\x3c\xf8\xb0\xa7\x75\x66\x98\x79\xdc\xec\x2f\xc2\x29\x68\x7e\x0f\x55\xf0\x26\x1e\x5e\x56\xd1\x9d\xda\xf2\x37\xac\x5f\x26\x8c\xb3\x45\xd9\x69\x09\x40\xec\x4e\xda\x8e\x8c\x55\xcb\xee\x66\x43\xb4\x61\x74\x08\x81\x91\x61\xfc\xc8\xfc\x47\xd5\x55\x77\x15\xb0\xc1\x53\x1e\x7d\xaf\x40\xa6\xa4\xdb\x0a\x7e\xc6\x90\x5e\xd1\x72\xb1\x38\x3e\x46\x99\x6a\xef\xae\xd9\x3f\x61\xae\xc4\xb2\xde\x13\x38\x58\x5c\x6a\xd4\x5a\x13\x27\x4c\x36\xd3\xc0\xfe\x75\x7f\x68\x7e\xe6\x11\x93\x2c\x8f\xcb\x71\x02\x6b\x8f\x88\x3f\x21\x65\x66\xbf\x75\xb2\x96\xc9\x12\xcd\x7e\x95\x0b\x13\xc8\xf6\xd0\xe0\x57\xbe\x86\xc7\xdb\x62\x49\x6e\xd6\xcf\x28\x1f\xa3\x76\x14\x85\x2f\xe7\x0c\x73\x96\xac\xff\x17\x00\x00\xff\xff\xeb\xd0\xc3\x9d\x15\x51\x04\x00" func dist_bundle_js_bytes() ([]byte, error) { return bindata_read( @@ -86,12 +86,12 @@ func dist_bundle_js() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/bundle.js", size: 282901, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/bundle.js", size: 282901, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _dist_bundle_js_gz = "\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x00\x0e\x40\xf1\xbf\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xc4\xbd\x79\x77\xdc\x48\xf2\x20\xf6\xb7\xd7\x5f\x82\x55\xa3\x29\x01\x5d\xc9\x22\x29\x4d\xf7\x74\xa3\x94\xac\x9f\x44\x89\x12\xbb\x25\x52\xf7\x45\xb2\x39\x60\x15\xaa\x0a\x22\x0a\x28\x01\x09\x1e\x22\xb8\xaf\x7f\x7b\xef\xda\x5e\xdf\x7e\xf6\xda\xde\xfd\xf9\xd8\xf5\xed\xf5\xfd\x6c\xaf\xed\x7d\xcf\xf3\x49\xb6\xfd\x01\xfc\x15\x1c\x11\x79\x20\x81\x42\x51\xea\x99\xd9\xe7\xf7\x24\x56\x22\xef\x8c\x8c\x8c\x8c\x88\x8c\x8c\x6c\x8d\xf3\x78\x28\xc2\x24\x5e\x09\x1c\xc1\x62\x96\xba\x97\x26\x26\x71\x7c\x96\xb9\x97\xe1\xd8\x69\xc5\xfb\xfe\xa1\x0c\x09\x0a\x9d\xfa\xe9\x4a\xce\xdb\x3a\x6b\x9b\x73\x71\x31\x0f\x92\xf1\x4a\x1a\x7c\xcc\xc3\x34\xe8\x74\x54\xa0\x8f\x65\xb2\x4e\x27\x77\xd3\x40\xe4\x69\xbc\x92\x43\xa5\xad\x75\x17\xe3\x43\x1d\x17\xaa\x38\xac\x75\xc8\xe3\xe0\x6c\xe5\x41\x9a\x26\xa9\xd3\xde\xf2\xe3\x38\x11\x2b\xe3\x30\x1e\xad\xcc\x92\x51\x1e\x05\x2b\x37\xdb\x5d\xbf\xdb\xbe\xd9\x76\xfb\x62\x9a\x26\x67\x2b\xc3\xde\x30\x19\x05\xbc\xfd\x64\xef\xfe\xab\xc7\x0f\x8e\x76\xf7\x5e\x1e\x6d\xef\xbd\xda\xbd\xdf\x66\xc3\x2b\xac\x2f\xe2\xd8\x77\x7e\x19\x9c\xcf\x93\x54\x64\xde\xe5\xd5\x55\x1f\xc7\xb0\xbf\x7e\xd8\x1b\xfa\x51\xe4\x44\x3d\x95\xc4\xf4\x68\x9c\x40\x0e\x30\xe6\x94\x71\xe3\x70\x3f\x38\xec\xab\xae\x26\x4e\x3c\x88\xbd\xc0\xbd\x62\x11\x2b\x4b\x06\x4c\xc2\xee\x4a\xe5\xc2\x26\x75\xe2\xd5\x18\x46\x82\xd5\x85\x5f\x02\x2f\xe6\xf3\xf5\xbe\x7f\x27\xed\x45\x41\x3c\x11\xd3\xbe\xdf\xed\xba\x89\x93\x22\xd0\x4d\x17\xae\x9c\xcb\x0d\x6f\xdf\xee\x6d\x3b\xcf\x82\x95\x4c\xa4\xe1\x50\xb4\x09\x8a\x82\x07\x4e\x3b\x0d\x7c\xf8\x76\x59\x6c\x3e\x56\xd3\x24\x17\x41\x0a\x71\x29\x8f\x7b\xcf\xf1\x83\x25\x10\xba\x1f\x8c\xfd\x3c\x12\x14\xd1\x87\xcc\xbd\xb5\x30\x1d\x42\x2e\x0a\x0e\x93\xd9\xcc\x8f\x47\x6d\x39\x3f\x21\xa7\xc8\x2c\x19\x9e\x04\x58\xb9\x2f\xbf\x73\x11\x46\xf0\x95\x71\x5d\x64\x9e\xc4\x41\x2c\xb2\xb5\xbb\xf3\x79\xef\x43\x76\x0e\x69\xf9\x42\xda\x56\x12\xc7\xc1\x50\xa8\xf4\xe1\x62\xfa\xd4\xd7\x89\xd1\x42\xe2\x8b\x40\x88\x30\x9e\x64\x2a\xc3\x5c\x66\xf0\x09\x26\xd9\x1a\x0d\x14\xa2\xc7\x3c\x4a\x60\x9a\x5f\x88\x24\xf5\x27\x41\x2f\xcf\xc3\x51\x7f\x5c\x14\xce\xbc\x17\xfb\xa7\xe1\xc4\x17\x50\x6a\x28\xbb\x81\xad\xd4\xf3\xf2\x31\xf7\x7b\xaf\x5e\xed\xdc\x77\x5c\x97\x85\x3d\x80\xb6\xc9\x5d\xa2\x8b\x7b\xa9\xf1\xb8\x97\x05\xf1\xc8\x69\x63\x49\x48\x77\xaf\x74\x99\x00\xd1\xb9\x5d\x41\x30\x55\x04\x6a\xcb\x92\x28\xe8\x45\xc9\xc4\x09\xa0\x78\x7a\x1a\xa4\xdd\xb6\xb7\xd2\xee\x06\xbd\x59\x90\x65\xd0\x11\xa8\x86\x20\x3f\xe5\xa2\x37\x84\x69\x14\xc1\x83\x28\x98\x01\x0c\x9c\x94\x5d\xc6\xfe\x2c\xf0\xda\xfe\x7c\xde\x66\x73\x5f\x4c\xbd\xf6\x5a\x9b\x4d\x61\xb6\xa2\x20\xf5\xb2\x2b\xb6\xb4\x84\x19\x85\xce\x9c\x43\x67\x97\xe6\xce\x14\xac\xcb\xec\xd1\xb5\xd9\x85\x2f\xf2\xcc\xf4\xc8\x93\xc3\x2a\x0b\x0f\xaf\x2b\x3c\x84\x49\xaf\x17\x5d\xf3\x20\x16\x3a\x1c\x5d\x5f\x47\xc2\x2e\xad\xfe\xb9\xfd\xb8\x97\xe6\xb1\x33\x65\x71\xef\x51\x98\xc1\xac\x5e\x3c\x86\xf9\xc5\x09\xa8\xcc\x84\xe8\xa5\x30\x6b\x41\xea\xd4\xab\x0b\x58\x9c\x47\x91\xcb\x46\xc9\x30\xc7\x88\xde\x71\x32\xba\x80\xd9\xb8\x62\x97\x0b\x98\xe6\xdd\xda\xf8\x9a\x59\x8b\x05\xbe\xbf\x65\xcd\x2b\x01\x92\xbe\x63\x4b\x10\xdd\xbb\x75\x6b\xbd\x9e\x66\x2d\x12\x48\xbe\xc5\xae\x59\x06\x90\xfe\x0d\x53\xab\xd7\xbb\x75\x7b\x83\x95\x2b\x15\x3e\xa9\x28\x2d\x54\xef\xd6\x6f\xd6\x19\x51\x04\x6f\xe3\x3b\x68\xb0\x42\x1c\xbc\xdb\xeb\x57\x87\xec\x96\x4d\x61\x90\xbc\xb9\x97\x2d\x2b\x02\xf6\x89\x06\x6a\x36\x0a\x80\x54\x03\x31\x93\xbf\x3d\x7f\x36\x1a\xc8\xa0\xb3\x7f\xd8\xb0\x5e\x82\xde\xdd\x5c\x24\x51\x18\x9f\x04\x29\x4f\x1d\x00\xad\xd7\x4e\x8e\x3f\x20\x5e\x9a\x2a\xe3\x81\xd0\x94\x14\xb3\x78\x0b\x65\x1c\x31\x0d\x33\xbb\x72\x5c\x2b\x01\x37\x11\xc2\xbd\x0c\x7a\xaf\x60\xd4\x3d\x3f\xcb\xc2\x49\x2c\xf3\x0b\xf7\xaa\x6f\x7a\x31\x4f\x13\x91\x60\x7b\xfc\x12\xd7\xa3\x48\xf3\x21\x60\x8b\x17\xb0\x3c\x8d\x32\xaf\xb5\xce\x82\x99\x1f\x46\x18\x10\x67\xa1\x00\x18\x61\x10\xb6\xa9\x37\xb0\x2f\x25\x67\xf8\x81\xb4\x77\xfe\x34\x85\xb1\x9e\x53\x36\xc0\x3b\xc0\xb4\xc0\x3b\x4d\xc2\xd1\xca\x3a\x1b\x46\xd0\xf6\x2e\xa1\x37\x60\xb0\x98\x45\x4f\xfd\x14\x30\x5b\x27\xcf\x7c\x31\x9c\x56\xa3\x84\x3f\xb9\x97\x87\xd1\xa8\x8c\xc1\x21\x7b\x36\xde\xea\x7d\x45\x70\x1c\x51\x6f\x12\x88\x47\xa6\x66\x07\xa9\xbe\xe8\xcd\xf1\x03\xf2\x02\xb9\x5f\x07\x42\x0f\x93\x10\x42\xc0\x07\x8a\xaf\xb7\x97\xcd\xb0\x1f\xc2\x16\x43\x40\xcb\x60\xab\x0c\x0f\x81\x4e\x53\x65\x2f\x01\x1e\x0e\x52\x65\xf9\x15\x9c\x0b\x87\x76\xed\x76\x20\x97\x07\x4c\x11\xcf\xdd\xb6\x8f\xbf\x32\x8b\x3f\xc1\x21\x3a\x6e\xa7\xe3\x64\xbd\x30\xdb\x8a\x92\x0c\x30\xd3\x71\x07\x29\x7f\x02\xcb\xb9\x37\xf3\xcf\x9d\x74\x75\x83\xad\xbb\x5e\x0a\x6d\xb2\xa4\x37\xcf\xb3\xa9\x33\x74\xfb\x41\x04\xfb\x17\xd5\x1d\x8b\x50\x5c\xc8\xaa\x17\x93\xd7\x21\x3e\x95\x7d\x8d\xe4\xa0\x11\x28\xe1\xf8\xe2\x85\x48\x31\x9f\x2a\x11\xb9\x57\x54\xc2\x54\xa0\xb7\xe5\xa4\xf7\x21\x09\x81\x1c\xb7\x71\xfb\x36\x25\xbd\x06\xb2\xac\x21\xfa\xa4\x9c\x19\xc7\x05\x3a\x31\x8f\xfc\x61\x80\xeb\x01\xd3\x25\xb5\xa0\x2c\xcf\xa9\xd8\x6b\x3f\xa2\x14\xa8\xbe\x29\xcd\xb3\x71\x92\x18\x0c\x84\x27\x55\xa5\x6a\xde\x8e\x01\x76\x31\xaf\x46\x49\x36\x45\x62\xad\x44\x5d\x97\xb5\x11\xe1\xe2\x89\xb5\x4c\x34\x2f\x45\x75\xc6\x00\xa8\xd6\x86\x8e\x12\x66\x24\xc1\xa8\x9c\x47\xd8\xae\x00\xd5\xfd\x78\x88\xc5\x83\x1e\xe2\x0e\xcc\xa0\xa9\xa6\x27\x92\x17\xd4\x86\x23\x77\x9f\xd4\x60\xd9\x4b\x83\x9a\x80\x1e\x09\x4f\x7b\xc7\xf8\x05\x63\x32\x0c\x8a\x55\xf6\x8a\x55\xf0\xd2\xab\xad\x53\x85\xbb\xe5\x92\xd0\x75\x08\xd8\xa3\x17\x12\x89\x35\x0c\xac\x88\x5e\x59\x33\xec\x06\xd4\x96\x35\x63\x4b\x1a\xb3\x56\x5b\x43\x6b\x56\xaa\x6a\xce\x8a\xe9\xd9\xf8\x70\x49\xd4\x81\x0a\x61\x48\x11\x09\xfa\xa6\xa0\x21\x16\x14\xa5\x3e\x2a\x94\x82\x12\xac\x08\xd8\xb3\xd4\x28\x4a\x18\x2f\x19\x44\x49\x1f\x1a\xc6\x50\x26\xaa\x21\xdc\x8d\x87\xd3\x24\xb5\x26\xee\xb2\xa4\x5e\x54\xc2\x7c\x96\xa4\x4b\xd6\xa4\xbe\x2c\x0a\x26\x51\x5f\x7f\xca\x2e\x5f\xb1\x80\x96\xa2\x45\x75\x71\xc3\x90\x78\x43\x5d\x70\x62\x83\x1e\x29\x65\x05\x7c\xc1\x52\x04\x5c\x7e\x89\x41\x6b\x9e\x2f\x4d\x92\x1d\x81\x44\x9c\x5f\xfa\xc7\x00\x31\xd8\xae\x9e\x04\x62\x9a\x8c\x6c\xf0\x90\x40\xd0\xd6\xe9\xed\x2b\x26\x09\xbe\x67\xef\x63\x25\xd9\x44\xfc\x5f\x11\xae\xe8\x4d\xfd\x6c\xef\x2c\x7e\x9a\x26\xf3\x20\x15\x17\xd0\x51\x58\x83\xc1\x7e\x7c\x08\xdc\x7f\x5c\x72\xdd\x01\xf4\xe0\x5c\x00\xa3\xe0\x35\x8d\x51\x94\x7b\x08\x2c\x09\xab\x4f\x57\x48\x94\xcc\xf6\x92\x4a\x16\xba\x1f\x02\x05\xae\x35\xdb\xb6\x76\x9e\xb6\x3b\x80\x55\x6f\xed\x44\xf6\xd6\x69\x27\xf4\x80\xf1\x8b\x2e\x24\x6d\xf0\xd3\x09\x71\x29\x40\x7d\xa8\x15\x9f\x87\x56\xcb\x38\x09\x89\x1e\x8b\x6f\xd7\xc1\x43\xe6\xf7\xb2\x1c\x7a\x41\x93\xca\x53\x36\x02\x0a\x2f\x82\x95\x4a\x17\x58\x75\x0f\xf5\x61\xe8\x2c\x04\x90\x44\x51\x38\xcf\xc2\xcc\xab\xf3\x0a\x66\x6f\x95\x1b\xcd\xa6\x20\xc2\x86\xfc\x14\xe7\xf1\xa0\xdd\xeb\xb5\xbd\x98\x05\x1c\x58\xde\xfc\x58\xd2\x32\x07\x36\xbd\x55\xbd\x31\xb9\x5d\xa8\x1f\x40\x0e\x38\x19\x9c\xef\x8d\x6b\x53\x08\xd4\xeb\x6e\x9a\xfa\x17\xe5\xf8\x7a\x2a\xa3\x6b\xda\x55\x11\x48\x96\xcc\x8c\xc3\xde\x97\x72\xdd\xa5\x7e\xba\x19\xf7\x63\xd8\x87\xa0\x36\x9a\x6e\xa0\xa5\x25\x11\x95\x81\xd5\x8d\x2b\x96\xcd\xa3\x50\xdc\x8d\x47\x5b\xfe\x1c\xa2\x82\xc5\xae\xb4\x80\xbe\x46\xc9\xb1\x1f\xb9\x52\x22\xb5\xe4\xd7\xdf\x51\xe1\xe7\xc1\x24\x38\xff\xdd\xca\x2c\xcf\xc4\xca\xd4\x3f\x0d\x60\x77\x01\x39\x76\x72\x73\x65\x1c\xf9\x93\x95\x0c\xc5\xa8\xb2\x8f\xd0\x43\xd8\xa6\x13\x90\x02\x71\x03\x0f\xce\x83\x21\x6c\x4b\x7d\x37\x95\x7b\x99\x0d\xaf\x04\xf8\x5a\x1a\x25\x2c\x41\x95\x1c\x83\x54\xeb\x92\x44\x47\x09\x5d\xfc\x36\xc3\xd5\xab\x6f\xb1\x22\xac\x80\xd6\xb0\xda\x04\xb8\x9a\x6c\x89\xf0\xce\x1e\xb1\x64\xec\xf2\x6c\x1a\x8a\x20\x9b\xc3\xa6\x44\x23\xf2\xd6\x0e\xb2\xee\x1a\x6b\xc4\xd3\x65\x4c\x97\xdc\x38\x43\xe0\x68\x53\x6c\x8b\x57\x3f\x8b\xc2\xfa\x7e\xf9\xe4\x31\x00\xdf\xb0\x15\x4b\x77\x69\x21\xd3\xb9\xdc\x94\x35\xf5\xac\x16\x69\x2c\x51\x14\xed\x36\xb5\x70\x57\x54\x98\x00\x26\x8c\xf8\xaf\x76\x3c\xcc\x90\x39\x86\x14\xc4\xfb\x01\x10\x87\xb2\xb9\x5a\xf9\x05\x26\x42\x15\x87\x52\xa6\xb9\x6c\x91\x17\x58\xd6\x5a\x15\x8e\xb1\x06\xa2\x69\x39\x5b\x36\x4c\x1f\x13\x71\x53\x30\x1f\x40\x46\x5d\xea\xc2\x16\xae\xf4\xa5\x5d\x56\x7d\x04\x92\x84\xd9\xda\x0c\xb5\x1d\xfe\x68\x54\x2b\x64\x93\x52\x56\x72\x07\x94\x8b\x18\x03\x8a\xa9\xe1\x0c\xf0\x9f\x6a\x3c\x6a\x7d\x02\x33\x9a\x0e\xd2\x1e\xad\x13\x40\x44\x0f\x70\x3f\x03\xbc\xd7\xdf\xb0\x08\xa0\x3f\xd3\x70\x8c\x4c\x8b\xbb\xba\x01\x8b\x34\x24\xe2\xd3\xe9\xf8\x0a\xe5\x0d\xa0\xea\xe0\x56\xdd\x3f\x04\x09\x5e\xb2\x7d\x2b\x6d\x0d\xba\x34\x98\x25\xa7\xc1\xff\x2f\x03\xf2\xd5\x7a\x24\x7a\x68\xc6\x06\x83\x53\x3a\x35\x39\xbc\xfe\xea\x46\x0b\x78\x60\x1c\x25\x96\x04\x9e\x33\x67\x1b\x86\x8f\xfd\x05\x23\x9d\x2c\x4c\xf6\x52\xf4\xd4\xb5\xc8\x75\x01\xdb\xd3\x32\x2c\xa1\xbe\x61\x23\xdd\x1a\x8c\xba\xd8\xb0\xa1\xbc\x98\x21\xa0\x28\xc2\xb9\x1d\xbd\xca\x97\xe2\x5d\x49\x16\xac\xb5\xdc\x50\x6c\x49\x29\xd9\x6f\xcd\x7a\xd6\xf9\xa6\xc0\xe6\x5f\xa5\x9c\xc2\x14\xbb\x44\xfc\x2b\x41\x01\xe5\x88\x12\x9f\xb8\x18\xd0\x20\x51\x68\xdb\x6f\xdf\x69\x93\x9a\xaf\xbd\xd9\x66\xba\x26\xd3\x37\xa8\xab\x7d\x67\x0d\x33\x40\xf2\xa1\x25\x65\x54\xaa\xb6\xbb\x44\xfb\x86\x59\x98\x6a\xdf\x69\x4b\xe5\x5d\x50\x27\x05\xd0\xd1\xfd\xc3\x7e\x85\x71\x09\xdc\xa0\x89\x71\x11\x6a\x51\x74\x6f\xf2\xf6\xcd\x2e\x6e\x6b\xdd\x9b\xed\x9b\xe5\x90\x4a\xfc\xb8\xba\x82\x0d\x76\x81\x31\x5c\x42\xf9\x7f\x11\x8d\x57\xa3\x6e\xa0\x70\x92\x19\x55\x9b\x8c\x73\xa9\xe8\xb0\x07\x32\x24\x23\x30\x78\x96\x58\x25\x87\x2e\x2c\x49\x94\xc2\xb2\xc3\x8f\x80\x5d\x26\x8d\x9c\x41\x0e\x2a\x09\xec\xc0\x30\xc8\x32\x35\x28\x94\x74\xac\x32\x52\xf2\x41\x65\x9a\x26\xe3\x5a\x4a\xab\x51\x51\x6b\x03\xb8\x9c\x42\x43\x1e\xb0\xe4\x8a\x1c\xc8\xfc\x5b\x99\x5c\x1a\xb8\x31\xeb\x5d\x15\x97\x73\xb9\x0e\x53\xb5\xd1\x19\xb6\x1a\x93\x61\xdf\x49\xa1\x37\xbc\x7d\x74\x1c\xf9\xf1\x09\x2a\x66\x75\x0f\x74\x8d\x95\xa5\x61\x71\xfb\x86\xdd\x36\x13\x39\x10\x5d\xc2\xcd\x6e\x7b\x15\x56\x99\x87\x98\xbf\x30\xfa\xa6\x85\xa6\x70\x6b\x94\xbc\x54\x9c\xbd\x83\xd4\xbd\xfc\xac\xcc\x5a\x75\x07\xd2\xbc\x9e\x23\xb7\x3e\x23\x1b\x14\xc5\x6e\x3e\x3b\x06\xe1\xe8\xe9\xde\x8b\x9d\x97\x3b\xaf\x1f\x1c\xed\xec\x6e\xef\xec\xee\xbc\x7c\xa7\x90\xac\x51\x5e\x5b\x82\x69\x98\x57\x72\x17\x0b\xeb\x77\x6d\x7f\x7d\xf5\x3b\x7f\xf5\xd3\xdd\xd5\xf7\x87\x65\xd0\x3b\xfc\x6a\x0d\xd6\xc7\xda\xfe\x8f\x07\xd9\xc1\x7a\xfb\xe6\xe6\xc1\x1a\x3f\x38\x5f\xdf\x58\x3d\x38\xdf\xd8\x3e\x38\xff\xed\xf6\x21\xf0\x28\x31\x5f\x73\x06\x5e\x7b\xff\xc7\xf6\xe1\x57\x83\x76\x71\x73\xff\xc7\x9b\x10\xb8\x59\xc0\x6f\x9b\xdf\xd9\xfc\xdd\x41\x76\xd8\x75\xd7\x70\x96\x7b\x59\x92\xa7\x43\x20\x5b\x90\xff\xe0\x20\xfb\x8a\xe3\x9f\x76\x37\x36\xf1\xee\xa0\x6d\x10\x08\xd0\x19\xfa\xfa\xe0\x7c\xee\xec\x63\xfe\x36\x10\x01\xa7\x75\x7f\x6f\xeb\xe5\xbb\xa7\x0f\x5c\xf8\x92\x71\x50\x43\x57\x7f\xa4\xac\x5d\xb4\x99\x55\x1b\x24\xb8\x5f\xb5\x89\xaa\xd0\x47\x61\x8a\xdd\x71\xd6\xa0\x2d\xf8\x42\x55\xb0\x9d\xdf\xae\x35\x55\xc5\xb1\x97\x6b\x03\x53\x4f\x49\x82\x58\x7b\x12\xc2\x62\x87\xe5\x83\x90\xdd\x9a\xfa\x28\x1a\x05\xe9\x03\xd4\xb3\x84\x41\xa6\x18\x39\xa7\x13\x1f\x67\xf3\x7e\xd1\xf9\xd5\xc6\x37\xeb\xf0\x13\x09\x0c\x53\x70\x22\x83\xb7\xe0\xef\xc7\x3c\xa1\x8f\xdb\xbf\xa1\xbf\xdf\xf5\xdd\xb5\x49\xc8\x48\xc7\xd4\xac\x98\x62\x66\x1f\x35\xd3\x8a\x9c\x2d\xec\x99\x40\xce\x50\x16\xc0\x7d\x44\xf0\x54\xb3\xb9\x7a\x17\xf4\x41\xf4\x5a\xa7\x7d\x73\x7f\x03\xb6\x23\xb1\x7f\x1b\xb5\x52\xad\x96\xd8\xbf\x75\x88\xc7\x04\x15\x26\x58\x28\x26\xb8\x3f\x2c\x75\x27\xd4\x27\x5c\x02\xc0\xb7\xd3\x50\x2f\x76\x93\x51\x90\x39\x43\x54\xc8\x23\x85\x54\x82\x53\x08\x5b\xad\x8e\x72\xac\x15\xae\x34\xc0\x58\x08\xcf\xc0\x58\xee\xd2\xfe\xaf\xb8\x6a\xbd\x85\x5f\x01\x11\x4f\xee\x68\x79\x42\xeb\xa5\xaa\x9c\x75\x3f\xfa\x7c\xaf\xa2\xa6\x5e\xe9\xbd\x1e\x84\xac\x25\xe5\x9a\x39\x17\x94\x1e\xcc\xe2\xaa\xc9\x2e\x7a\xe5\x2e\x47\x05\x57\xcd\x8f\x39\x7f\x0a\x37\x93\x7e\xd2\xe5\xb7\xf4\xc4\xa4\xfb\x09\x4e\x0c\xfc\x74\x37\x0e\xfb\x7e\xa7\x13\x2f\x00\x0f\x7b\x2a\x21\x07\x50\xcb\x9a\x72\x94\x83\x70\xb2\x72\xa4\x86\x1a\x5a\xd0\xaf\x08\xdb\xa8\x74\xb6\x96\x5e\x85\xb0\xd8\x33\x76\x29\x90\xf8\x09\xa6\xf7\x17\xd4\x65\x3d\x4e\xce\x82\x74\xcb\xcf\x48\xa5\x29\x15\x93\x5e\x7a\x65\x14\x75\x65\x8f\x9a\x08\xe0\x62\x6b\xe5\x00\x54\x63\x65\x55\x7a\xf8\x5f\x54\x91\x81\x55\x59\x4d\x13\xc9\xc4\x2c\x4b\x08\x26\x95\x03\x06\xe5\x17\x6e\xd1\x6a\x5b\xf5\x74\x72\x45\xa9\xc2\x94\xc2\x77\xa9\x00\x05\x69\x0b\xfd\xb4\x66\xa0\xd6\xd5\xc6\xe1\xb0\x72\xfb\x6f\x9b\x19\x69\x6d\x98\x8e\x2d\x34\x6d\xf4\xce\xbf\x40\xc4\xbb\x62\x46\x0d\xbd\x2c\xa7\x6a\x7a\x71\x38\x66\x8a\xbf\x6c\x34\xd7\xf4\x5b\xea\xb4\x17\x5a\xd0\x73\xff\xc7\xd6\x8f\xb3\xa1\x6a\x5f\xa2\xaa\x5c\x82\x3a\xd7\x9d\x6e\xd4\x0e\x34\xa8\xe2\x20\x5d\xb6\x33\x3b\x3f\xc2\x56\x7a\x70\x76\xe8\xfe\x99\x73\x70\x76\xb9\xc1\x36\xbe\xbe\x72\x69\x57\x86\xbd\x6a\xff\x60\xb5\xef\x75\xf8\x41\xf7\xe0\x06\x3b\x38\x3b\xe8\x1d\x76\xff\xcc\xd5\x3b\xf2\x3e\x6c\xe0\xb0\x8d\x1f\xee\xaf\xf6\xba\x32\x08\xfb\xfa\x61\xd7\x73\x06\xad\x65\x49\x07\x6b\x07\x6b\x2e\xa4\x1f\x8c\xba\x07\x6b\x03\x17\xb7\x69\x8c\x19\xd0\xf6\x8d\x75\x9e\x9d\x41\x23\xf0\x95\x00\x4f\x60\x0a\x1e\xf4\x0e\x56\x0f\xbf\xb2\xbe\x57\x0f\xd7\x80\xcc\xad\x1d\xf4\xa0\x44\x18\xc3\xa0\x63\x3a\x18\xf4\xa3\xc2\x2c\x24\xf8\xc4\x0f\x5a\x17\x09\x48\xd2\x01\x66\x9b\xa7\x61\x16\x64\xc5\x7c\x9a\x88\x64\x92\xfa\xf3\xe9\x45\x01\x7c\xd7\x48\x66\xcf\x8a\x71\x92\xc7\x23\xaa\xa9\x08\x67\xb3\xe4\x38\x8c\xc2\x00\x82\xf1\x28\x47\x80\x42\xc1\x99\x1f\xfb\x13\xc2\x63\x2c\x87\x8c\x3b\xc6\x8a\x60\x38\x8d\x93\x28\x99\x5c\x14\xc3\x29\xb4\x20\x66\x7e\x56\xe0\x51\x62\x1e\x03\xea\x14\xa3\x30\x0d\xb0\x0f\x17\x45\x00\x2d\xc9\xea\xd1\x5c\x60\x4e\xf5\xa0\x1a\x3f\x14\x39\x30\x62\x33\x3f\x3d\x09\xf0\x34\xb0\xc8\x92\x28\x97\x3d\x3a\xf5\x65\x81\xac\x38\x06\xf6\xd3\x0f\x31\x90\x40\xda\xc7\x3c\x28\x8e\x25\xd3\x0f\x4d\x01\xdd\xc2\x0d\xab\x18\x46\x81\x1f\xcb\x40\x02\xcb\x03\x03\xc9\x6c\x8e\xc7\x82\xc5\x08\x64\xe6\x61\xea\x0b\xe8\x8d\x3f\x4b\xe2\x51\x56\xd0\xf8\xc3\x61\x56\x4c\x93\x68\x84\x67\x90\x45\x14\x4e\xa6\xd4\x3e\x6c\x59\x22\xc6\x9a\xe7\x11\xf0\x86\xd4\xa3\x1c\xf6\x36\x1a\x6b\x0a\x9d\xc0\x98\x53\xe8\x3c\x6c\x4a\x59\x01\x3d\x84\xca\x61\xe8\x7e\x1a\x50\x6f\xa0\x49\x3f\x86\xef\x34\x27\x60\x8f\x92\x19\xf5\x1b\x8f\x01\xb3\x60\x54\x8c\xa9\x19\x00\x76\x94\x20\xac\x8a\x89\x1f\x45\x01\x00\x67\x92\x87\xc0\x62\x53\x77\xc2\x91\x7f\x51\x9c\x84\x88\xb4\x71\x11\x07\x00\x7d\x3f\x2d\x92\x93\x30\xf6\xcf\xfc\x02\x80\x19\xce\xa1\xde\x14\x3a\xe0\x47\xf8\x7b\x1a\x06\x67\x59\x01\xb2\xf8\x49\x36\xf5\x0b\xa4\x07\x11\xa4\x63\x97\x93\x54\x14\xd9\x45\x26\x82\x19\xf4\x73\x12\xc4\xc3\x8b\x02\x58\xdd\x28\x04\xd4\x00\xfa\x92\xfa\xc5\x90\xd0\x02\xfa\x3c\x1e\x07\x01\xe2\xcb\x28\x81\x1e\xfb\x04\x85\x00\x0f\xc2\x83\x22\xc0\x91\x52\xf7\x61\xba\x8b\x71\x2e\x8e\x93\xa8\x38\xf1\xf3\x31\xf4\x2d\xca\xcf\x73\xe8\x3a\x0c\x30\x83\x49\x05\xb8\xfa\xd9\xb4\x98\xe5\x59\x90\xcf\x0a\xc0\x94\xe4\xc2\x97\xb8\x86\xbd\x9c\xfb\x61\x8a\x3f\xd4\xa7\x64\x18\x02\xb2\x12\x54\x2f\x0a\x68\x46\x24\x49\x01\xb8\x04\xd8\x87\x10\x3e\x0d\xa2\xe2\x34\xf4\x3f\xc0\x28\x4e\xc3\x08\xa4\x07\xf8\xc9\x10\x6d\x4e\x13\xea\xd9\x29\x54\x3c\x09\x0a\xc2\x6c\x89\x06\x08\x7d\x98\x53\x00\x98\x3f\x2f\xd0\xa4\x06\x47\x11\x0f\xa1\xf7\x48\x1d\x8a\x09\x4a\x20\x00\x59\xe8\x19\xe2\xf0\x24\x29\x60\x0e\x3f\xf8\x34\xd1\x6a\x39\x00\xfc\x12\x84\x5a\x12\x01\xac\x45\x82\x33\x20\x92\x93\x0b\xe8\x56\x92\x00\x94\xcf\x90\x84\x14\x67\x49\x7a\x02\x90\x0c\xd2\xa4\xf0\xd3\xb9\x5f\xf8\x59\xe8\x03\x44\x61\x16\x8f\xc3\x13\xc0\xc8\x88\xd0\xf2\xd3\x27\x04\x2f\xf4\x23\xca\x8f\xa1\x33\x09\xae\xca\x64\x5e\x8c\xfd\x74\x56\x8c\x43\x80\xd0\x24\x1c\xc3\xbc\xe7\x69\x0e\xd8\x3f\x4e\x8a\x0f\xc9\x71\x06\xd3\x7d\x16\x16\x27\x29\x20\x08\x88\x57\xf0\x27\x9c\x25\x05\x9e\x34\x14\xb0\x4a\xf2\x02\x17\x23\xfc\x01\xf0\xa0\x99\x41\x31\x47\xbc\x9d\x63\x2a\xe0\x94\x28\x3e\xce\x01\x36\x69\x08\x1d\x4c\xf3\x69\x5a\x64\xc1\x39\x74\x1e\xa4\x1d\x84\x57\x80\x7f\x12\xe8\x3f\xc0\xed\x0c\x97\xf3\x59\x78\x12\x16\x9f\x92\x38\xc0\x25\x05\xfd\x1e\xc1\x7f\xec\xf0\x31\xae\x23\x40\x88\x04\x31\x18\x97\x6a\x31\x49\x4e\xa1\x83\x02\xba\x36\x2b\x66\x00\xc5\x38\x10\x45\x12\x47\x45\x92\x4e\x70\xf9\x17\x73\x18\x1e\x76\x58\xc0\x74\xe5\x31\xb4\x01\xe1\xf3\xf3\xf3\xe2\xfc\xe2\x13\xcc\x4d\xe1\x8f\x00\x52\x85\x3f\x06\xcc\x2b\xfc\xb0\x80\xf9\xf6\x67\x85\x1f\x17\x3e\x00\xef\x23\xc0\x0f\xa0\x57\x40\x8b\x7e\x5e\xf8\x67\x85\x7f\x5e\xf8\x9f\xa0\x47\xc5\xf1\x71\x71\x0c\x5d\x82\xde\x8d\x8b\xe3\x49\x71\x3c\x85\xee\x15\xc7\x1f\x8a\xe3\x59\x71\x1c\xc3\xe2\x2f\x8e\xa1\xd3\x40\x05\x00\xe4\xa7\xc5\xf1\x59\x71\x0c\x28\x8d\xdd\x2f\x86\xc3\x62\x08\x78\x30\x2e\x86\xb0\xec\xa7\xc5\x30\x2c\x86\x27\x30\x05\xc5\x70\x56\x0c\x91\x14\xc2\x82\x2c\x86\x79\x31\x3c\x2d\x86\x67\xc5\xf0\xbc\x80\xb5\x30\xfc\x04\x74\xa1\x18\x7d\x28\x46\x27\xc5\x68\x06\x2b\xb5\x18\x7d\x2a\x82\x61\x01\x4b\x21\x00\xfc\x4f\x61\x09\x14\x30\xe6\x20\x87\x69\x2b\xc6\x1f\x8a\xf1\x49\x31\x86\x29\x4c\x8a\x71\x0a\xcb\xb6\x98\x1c\x17\x93\x51\x01\x88\x38\x19\x17\x93\x49\x31\xc1\x89\x05\x54\x2b\x26\xb3\x62\x12\x17\x93\x79\x31\xf9\x08\x54\xa6\x00\xca\x32\xc1\xe9\x2e\x26\x67\x05\x90\xc8\xe9\x49\x31\x9d\x15\xd3\xb8\x80\x99\x9a\x8a\x62\x0a\x48\x30\x2a\xc2\xa0\x00\x00\x03\x9c\x61\x69\x86\x49\x11\x7e\x2c\x60\xb1\x84\x59\x11\x8a\xe2\x43\x50\x7c\x98\x01\x8e\x14\x1f\xe6\x05\xe0\xd8\xc9\xa4\x38\x99\xc2\x94\x14\x27\xb3\xe2\x24\x2e\x4e\x20\x32\x2d\x4e\xce\x8a\x13\xa0\x18\x9f\x00\x77\x8a\xe8\xb8\x88\x86\x80\x3a\x45\x74\x52\x44\x69\x01\xb8\x1b\x09\x58\xa8\x45\x74\x5a\x44\xb8\x54\x8b\xd9\xb0\x98\x8d\x00\xad\x8a\xd9\xa4\x98\xc1\x72\x05\x14\x8b\x8a\x19\x4c\x31\xae\xe0\x02\xf0\x76\xf6\xb1\x98\xa5\x05\x90\x8c\x99\x80\xc5\x5c\xcc\x4e\x8b\xd9\x59\x31\x3b\x2f\x80\xc8\xcd\x3e\x01\x02\x16\xf1\x10\x70\xa1\x88\xc7\x05\xe0\x54\x1c\x16\x80\x12\x30\xfb\xf1\xbc\x88\xd3\x02\x70\x35\xfe\x54\x00\x02\xc1\xea\x98\x03\xa2\x8e\x8b\x39\x20\xcb\xb4\x98\x03\xaa\x46\xc5\x1c\xe2\x63\xc0\x9d\x02\x70\x73\x0e\x7b\xc8\x59\x31\xbf\x28\x3e\x22\x4d\x2b\x00\x9f\x80\xf8\xc1\x92\x48\xcf\x8a\x0c\xa8\xd8\x71\x91\x0d\x8b\x6c\x04\xc8\x5c\x64\x40\x7f\xa7\x40\xd7\x8a\xec\x43\x91\x9d\x14\x19\x10\x8e\x59\x91\xc5\xb0\x56\x8b\x0c\xb0\x1d\xc8\x49\x5e\x64\xa7\x45\x76\x0e\xb4\xae\xc8\x3e\x15\x62\x58\x08\xc0\xca\x71\x21\x26\x85\x98\x16\xe2\x43\x21\x4e\x0a\x11\x15\x62\x56\x88\x18\xd6\x73\x21\xe6\x40\x65\x0a\x21\x0a\x71\x5a\x88\xb3\x42\x7c\x2a\x72\xbf\xc8\x27\x45\x7e\x52\xe4\x59\x91\x5f\x14\xf9\x27\xd8\x79\x8a\xd3\x21\x50\xf9\xe2\x14\xe8\x4d\x58\x9c\x02\xf1\xc9\x8b\xb3\x71\x01\x94\xf6\x22\x28\x2e\x44\xf1\xc9\x2f\x3e\xcd\x8a\x4f\x67\xee\xc1\xf1\x1a\xf3\x61\xbb\x3e\x58\x35\x1b\x74\xb7\xf3\x67\xbf\x3a\x58\xfb\x35\xff\xcb\x47\x8e\x5b\xdc\xbc\xf1\xd5\xc1\xfe\xc1\xe1\xa0\xe5\xb1\x5e\x1f\xb6\xf1\xcf\xe4\x3b\x5c\x6b\x96\xd0\xdb\x4c\x0b\xd2\x96\xac\xdd\x66\x5a\xe6\x67\x89\x0e\x84\x4d\xd9\x94\xdc\xed\x94\xe2\x7b\x59\xa0\x26\xba\x3b\xbd\xc1\x1a\x09\xef\xe9\x17\xe7\x5c\xd2\xb6\x96\xf7\x41\xe6\xb4\x14\x10\xcb\x44\xfc\x21\xc8\x74\xf7\x02\x10\x05\x83\xa7\x78\x30\x36\x4c\x40\xe6\x8e\x94\x0d\x02\xc9\xf9\x3f\x3a\x3d\x77\x80\xfc\xd2\x1f\x74\x6c\x43\x4c\xe0\x6b\x1f\x37\x57\x3c\x37\x94\xc2\xcc\x93\x4a\x24\xaa\xd6\xc9\x6c\x61\xe1\x40\xb0\xb4\x21\x28\x0f\x36\xb4\x3d\x45\x59\xbb\x62\x31\x2d\xfb\x2c\x96\xb0\x90\x91\x0c\xce\x86\x2c\x62\x73\x59\xd3\x18\x24\x54\xa5\xef\xda\x02\x62\x8f\x8d\x4b\x63\x8b\x86\x02\x68\xec\x30\x96\xc5\xc8\x84\x0e\xad\x29\x62\x36\x96\x0d\x1a\x0d\xde\x18\xea\x43\x6e\xf7\x85\x48\xbb\xd3\xee\x18\x84\xf8\xb1\xfc\xd2\xe2\x69\x80\x22\x5e\x63\x9b\x35\x21\xd5\xee\x80\x52\x0a\xb0\x39\xcf\x8b\x62\xc8\xc6\x1c\xed\x7f\xe0\x0f\x19\x60\x74\x3a\x2d\xdb\x34\xa0\x28\x42\x1d\x23\xf7\xdc\xc2\xd7\xdf\xc8\xa9\x17\x45\xab\x61\x16\x7a\x61\x46\x61\x39\x78\x6c\x75\xee\x9a\x53\xcc\x3c\x8a\x8c\x85\x09\x15\x7b\xe4\x67\xaf\xe2\x63\x3f\xc2\x8d\x7d\xa4\x04\x23\x10\x11\x02\x9c\xf9\x4e\x07\xcd\x07\x94\xf2\x02\x0f\x63\x95\x0a\x60\x75\xc3\xc5\x2e\xbb\x80\x68\xa1\x1b\xd9\x36\x11\xbd\x07\xd8\x4d\xe7\x72\x56\x9a\x96\x80\xd4\x2d\xa5\x89\xf0\xaa\x34\xdb\x89\x5d\x54\x8f\xc2\x94\x31\x6a\x80\x8e\x33\x36\x5c\xb4\xe9\xb4\x2b\x7b\x29\xa1\x50\xaf\x4e\x01\xe7\x11\xd9\xf5\x79\x89\xaa\x16\xf5\xe7\x0a\x15\x46\x7c\x2e\x6b\x50\x1a\x86\xeb\xd7\x80\x4b\x1a\x25\x98\x80\x11\x75\x69\x54\xed\xd2\x55\xb5\x4b\xaf\xd2\x85\xd1\xc1\x4c\xc0\xdf\xb9\xaa\x1a\x32\x48\x0c\x68\xb5\x32\x13\x09\xed\x01\xfb\x77\x1a\xe8\x94\xf9\x67\x6c\x3e\x14\x82\x5d\x1a\xfc\xf3\xc6\xcc\x60\x9f\x37\x95\xb2\x97\x17\x5d\x5d\xb1\xeb\xe7\xb0\x41\x79\x1c\x10\x38\xee\x0a\x27\x28\x27\x93\x6c\xb8\xdc\x36\x1d\x77\x2b\x35\xb7\x1a\xaf\xb3\x76\xe0\xac\x4d\x5c\x52\x1f\xe9\x08\x17\x23\x12\x1e\xa3\x1a\x47\x56\x51\x14\xa4\x20\xea\x74\xd2\x32\x82\xac\xb9\x37\x13\x85\x78\xad\x75\x35\xa4\xd6\x86\x14\x4b\xab\x34\x62\x89\x34\x1a\xc6\xa7\x98\x63\x19\xe5\xda\x07\xf1\x52\x52\xae\xa9\x9f\x6d\x03\x66\x97\x19\x55\x86\x6b\x04\xc6\x35\x98\xb7\xf0\x05\x4c\xe3\x2c\xf8\x5c\x76\xaa\xff\x4d\x92\x8e\x50\x41\x76\x77\x0c\xa8\x57\x6b\xc8\x43\x4d\xf3\xe1\x57\x03\x5d\x01\xc8\x91\xd6\x12\x5c\x66\x08\x21\xf4\x52\x56\x99\x5f\xe9\xfe\xc0\xca\x53\xc7\xde\xb9\x42\xa6\xfb\xc0\x45\xef\x26\xe2\x11\x30\xf1\xba\xe9\xbd\xf4\x7e\x22\xe8\x60\x62\x79\xde\xbb\xe2\x71\xe0\x67\x62\x2f\x0e\x74\xef\xed\x02\x61\xb6\xb3\x00\xdf\x12\x4b\x61\x89\x0e\x5a\x1b\x20\xe8\x5f\xb1\x7a\xff\x1a\xb1\xca\x5a\x6f\x55\xc0\xba\x68\x70\x50\xd1\xb6\x29\xfa\xda\xfe\xe0\x9f\xfa\xd9\x10\xd0\x5e\x78\xed\x16\xe0\x5e\xa7\xd3\x3e\x3d\xb6\x23\xae\xd8\xe7\x00\x50\x3b\xa2\x51\x38\xe6\xb4\x02\x18\x63\xa7\x23\x35\x9b\x0d\xb8\xd1\x13\x20\x5e\x10\x98\xe9\xe0\xb2\x34\x0d\x69\xf7\xda\xb0\xe4\x9b\x9a\x5d\x84\x65\x63\xdb\x2b\x01\x34\x3b\x68\xe9\x96\x97\x63\x8d\xec\x42\xe0\x7a\xb0\x22\xd8\xf5\x53\xd1\x70\x68\xd3\x6a\x05\x6a\x78\xd7\xad\x11\xdd\x86\xa5\x09\x92\x0b\xef\x4f\x73\xa6\xf7\x59\x85\xa1\x65\x60\xb8\x4c\xd7\x66\x91\x52\x69\xbe\x60\x0e\xf3\x96\x57\x6b\x1d\x67\x35\xe6\xb1\x46\x4b\xdb\xd1\x82\x36\xcd\x82\xc4\xb5\x5a\x3a\x2c\x2c\x75\x8b\x54\xcf\xb2\x31\x50\xbe\x7a\xef\x17\xab\xc3\x5c\x22\xf1\xd4\x11\x79\xbd\xd0\x75\x40\x92\x79\xad\x61\xa9\x8d\xf1\x0f\x1d\x98\xda\x40\x95\xda\xb4\xb2\x9b\x2e\x53\x9e\xda\x99\x3e\x3f\xd4\xa9\x10\xf3\xcc\x5b\x5b\x53\xc5\x7a\x20\xfc\xae\xa9\x71\x2f\xab\xa9\x79\xfc\xed\x3f\x6b\x2c\x66\x81\x02\xf6\xdb\xeb\xc1\x00\x6b\x59\x6e\xab\x86\xe1\xa5\xde\x69\x25\xa1\x23\x95\x83\x83\xb5\x70\x61\xb7\xd6\x05\xe4\x76\xa1\x53\xa1\xb2\x39\x5e\x0e\x18\x5d\xaf\x9a\x86\x66\x25\x7c\xa1\x83\x4b\x0c\x0f\x20\x4b\xc5\x50\xa5\x91\x5b\x50\xc4\xba\xce\x5e\xd4\xa2\x4d\xa7\x8a\xc2\x29\x6b\xe7\x34\x11\x30\x0f\xed\xae\xb2\x4f\x5e\xc8\xcf\x5b\xeb\x64\x55\xb7\x74\x46\xab\xd6\x07\xc8\xfe\xb8\x8b\xdc\xfa\x5a\xc7\x9f\xcd\xfb\x6b\x13\xd6\xee\xb4\xdd\x6b\x26\xf5\x9a\xca\x96\x43\x00\x6d\x2f\xb9\xcd\x23\x55\xf3\xc8\xc9\xc5\xa3\x42\x56\x67\xa4\x6a\x25\x5f\x69\x4c\xa0\xcc\x81\xb6\xa9\x46\xbb\x9f\x97\x29\xac\x30\xe0\x9a\x5e\x44\x3e\x5a\xc2\xa1\x79\x4a\xa5\x44\xe3\xb9\x79\x55\x58\xa9\xe2\x19\x23\x5b\x8f\x6b\x3a\xfc\x05\x35\x36\xe2\xa3\xac\xb8\xa1\xd7\x0d\x15\xb6\xd7\x90\xa7\x6b\xe2\xf8\x08\x32\x81\xe2\x72\xd7\xd9\x2a\xf2\xde\x72\x59\xd1\x5d\x96\xab\x43\x76\xbb\x7a\xd9\xc3\xba\x03\x28\xed\x6a\xa1\x7f\x47\x52\x8b\xc9\xed\x8f\xa2\xb8\xbc\x92\xf3\x70\x34\xf3\xcf\x1f\x87\x19\x2c\xc9\x20\xd5\x79\xec\xa8\xa2\x90\xb7\x18\xae\x4c\xc5\xa9\xd5\xf3\xc5\x8b\x24\x41\x99\x31\xb1\x32\xc6\x64\x68\xd0\x98\x2d\xb4\xb2\xd5\xef\x90\xc0\xf6\xa9\x4e\x9b\xad\x02\xbe\x35\x17\xb2\x73\x08\xbe\xab\xf2\xb6\x49\x0c\x82\xfe\x03\x1c\xe7\x83\x99\x24\xc0\x18\x51\x5a\x9c\x6a\x80\xa8\xeb\x19\x95\xa4\x0a\x34\x4c\x86\x91\xbc\x65\xf7\xc4\x4e\xdc\xa8\x96\xcc\x82\x6a\xb2\x3d\xcd\x68\x32\x84\xc0\x00\x7e\x7b\x13\x58\x9e\x30\xdb\xf5\x77\x11\xb9\xa5\xd5\x29\x52\x26\x65\x75\x1a\x4b\x53\xd3\xe3\x60\xc5\x5f\x99\x83\x7c\x80\xe8\xb4\xa2\x40\x57\x5d\x82\xd5\x8e\x6a\xab\x2b\xbb\x43\x01\x8c\x9d\x2f\xb0\x80\x20\xe6\x26\x52\xc0\x35\xf2\xa5\x41\x89\xca\x27\x5a\x1c\x32\x75\xfd\x0d\xc1\x0b\xa8\xd8\xb2\xd3\x7b\x94\x04\x83\x71\x16\x63\x5d\xcd\x32\x57\x62\xf5\x69\x3b\xc1\x43\x70\x63\xf5\x0c\x72\x1d\x13\xf6\x95\x06\x02\x86\x02\x8e\xe8\xd7\x81\x74\xf3\x55\x3c\xf4\xf3\xc9\x54\xb0\x95\x3c\xce\xe6\xc1\x30\x1c\x87\xc1\x68\x45\x75\x75\x85\x5a\xec\xdd\x74\xaf\xe8\x32\x85\xdd\x8b\xfd\xe0\x90\xf9\xc0\x2f\x6b\x59\x67\x03\x21\x90\x62\x44\x76\x16\x92\x0c\xae\x7b\x64\xec\x02\x86\xc0\x08\xaf\x6c\x78\xd6\x45\x0e\xb7\x7f\x9c\x06\xfe\x49\x9f\x52\x6e\xd9\x29\xcc\x1e\x50\x25\xdb\xed\xa5\xd9\xac\x8f\x5b\xa6\x8c\x42\x36\x0f\x0d\x03\x12\x5e\xef\x14\xcb\x48\xd0\x25\x2b\x6a\x27\x41\x11\x3f\xe7\x1b\xfd\x64\x33\xef\xe7\xdd\xae\x9b\xed\xe7\xab\x1b\x87\x16\x6c\xf3\xc3\x7e\x6c\xdb\x9a\x67\xea\x86\x0d\x8a\x7d\x38\xf4\xcb\x3f\x55\x2b\x58\xcf\x90\xc7\x8a\x56\xa1\xe4\x39\xd4\x75\xe5\x7c\xdd\x14\x1d\x42\xde\x5a\x7f\x8c\xe8\x59\x41\x5f\x7f\x34\xd2\xf8\xcd\xab\x14\x0e\xf1\x38\xa1\xdb\xc9\x29\x70\xbd\x8b\x8b\x28\x52\xc5\xac\xb5\x64\xc8\x94\xfb\x25\x58\x5f\x41\x5d\x00\x83\xee\x87\x62\xe5\x71\x61\xc1\x52\x2d\xe3\xd1\x7a\x10\xef\x20\xea\x86\xdd\x41\x19\xf6\x44\xb5\x3e\x40\xc2\x41\x75\xc9\x40\x0c\x14\xa8\x46\x28\xbb\x0b\xd7\xab\xc5\xf3\xfd\x3a\x42\x8b\xc3\x85\x3c\x82\x2d\x36\x50\x5b\x90\xd8\xc4\x99\x9f\xc6\xc1\x48\x83\x13\x50\xc0\x59\x24\x2c\x78\x9b\xa1\x81\xf6\x79\x8b\x39\x59\xd2\xe9\x24\x9b\xeb\x0a\x44\x56\x33\xea\x16\x41\x82\x4a\xaa\xc6\x1e\x00\x6b\xc3\xf4\x5d\xda\x40\xce\xa0\x13\x27\xa3\xc0\x5d\xc1\x74\x3c\xff\x47\x52\x98\x85\xc7\x51\xb0\x62\x13\xf5\x95\x19\x6c\xae\xe9\xc5\x4a\x04\x6b\x66\x65\x14\x08\xd8\x37\x82\x51\x6f\xe5\xd7\xa3\x15\x0d\xfb\x6c\x05\x90\x08\xe3\x5e\x01\xc2\x07\xb2\x54\x9d\x4e\x3b\xee\x8a\x48\x80\xf8\xa0\x05\x08\xe4\x8a\x42\xc8\xd6\x6b\xd7\xa7\x4c\x13\x04\xd6\xb0\xe1\xe9\xbe\xa3\x64\x03\x54\xb2\xf2\xe9\xb8\x15\xcb\xdf\x2a\x86\x27\x31\x5f\x82\xf0\xb5\x6c\xc3\x80\x7f\x6e\x8f\x97\x8c\x86\x2e\x8f\xf7\x5f\x61\x05\x02\x6e\x27\x08\x5d\xd1\x7c\xd9\x84\x48\xe4\x1f\xb4\x86\x08\x65\x38\x10\x50\x73\xe5\x4c\xe7\x57\xc6\xf5\x3d\xea\x69\xec\x36\x6c\x4b\xd5\x9e\x36\x2c\x6d\xdc\xa0\x7c\x96\xfd\x31\x0b\xbc\x55\x5d\xe1\x75\xd4\x77\xad\x29\xe9\x37\x6f\x13\xe6\x9e\x25\xd0\xb1\xd5\x0d\x86\xb7\xf2\x44\x51\xc0\x66\x51\x2e\x72\xd2\xab\xe9\x61\xa0\x4a\x4e\x5d\xbe\x59\x58\xa1\x36\x35\xa9\x8e\xbe\x42\x50\xaa\x49\x64\xb2\x5c\x2a\x62\x4b\x5a\x9d\x71\xbf\x9f\xad\xae\x6e\xae\xf7\xf1\xfa\x4b\xbc\x9f\x1d\xca\xbe\x61\xc8\xf4\x07\xfa\x66\x7f\x4a\x8d\x61\xc2\x33\xb9\xc3\xe0\xbc\xaf\x1b\x9d\x9f\x04\x03\xda\xe7\xeb\x31\x0f\x1c\x1d\xe2\xeb\xac\x79\x54\x2e\x6c\x69\xca\xbc\x3d\x61\x1b\xee\x1f\x35\xc8\xe5\x2b\x44\xe6\xbe\x1b\x45\xcd\x6c\x95\x62\x68\x16\x66\xbc\x3e\xbf\xad\x6b\x7a\xa7\xf3\x22\x0b\x59\xdf\x04\x2b\x54\x19\x76\x86\x3a\xa5\xc5\xdb\xd2\x4b\xa7\xbc\xaf\x6e\xbd\x2e\x32\x15\x38\x8b\x82\xae\xb0\xd9\x7d\xae\x83\x46\x6a\xda\xac\xc5\x6d\x83\xc1\xba\xb2\xb9\x2c\x47\xbd\xbe\xea\x1c\x71\xc5\xfe\x37\x73\x49\xc4\x14\x2d\xa3\x2b\x12\x27\x71\x10\x7d\x73\x19\x79\x59\xe6\xfd\xd8\xc8\x32\xe5\x7d\xbc\x6b\x80\x56\x9d\xfe\x68\xf9\xac\x5b\x96\xfe\x56\x35\x0b\xbb\xcf\x20\x5d\xdc\x6a\xeb\x5b\xe8\xc2\x06\xaa\x59\x18\x6f\xff\x10\xfb\xa3\x7b\xb1\x95\xe4\xb1\x68\xa2\x57\x86\x0a\xf2\xa0\xec\x88\x09\xee\x0b\xec\x85\xfd\xe9\x0e\x36\x3c\xfb\x5b\x81\xc8\x5b\xbf\x92\x22\xdd\x6f\xae\x15\xe9\xae\xf4\xb5\x45\x2d\xec\x5c\x5e\xf5\x53\xe0\x52\xce\xc5\xcb\x70\x78\xc2\x17\xa4\xf8\x76\x1e\xcb\x8b\xfc\x23\x40\x29\xb5\x65\x9d\x29\xcb\x76\xf9\x8b\x5b\xe2\xce\x6c\x16\x8c\x42\xbc\x2e\x2a\xbe\xa4\xc4\x93\x5c\x90\x69\xd2\xde\xb1\xf4\xf2\x00\x04\xf2\x0b\x4a\xa1\xbd\xc6\x13\xe9\x19\xc3\xc4\xc1\xae\x47\x9b\xba\xc6\x1a\x5c\x36\x81\x5e\x94\x0d\xb2\x77\x43\x97\x51\x0f\xa0\x2e\x3a\xef\x1f\x12\x7f\xa7\x98\x1a\x6e\xdc\x3f\x54\xbd\x43\xb4\x47\xe1\x29\x9e\x89\x11\x8b\x5b\x1f\x8a\xb3\x00\xc1\x54\x23\x44\x3f\x2d\xc9\x62\xd0\x83\x15\xf0\xc0\x07\xa9\xc1\xee\x64\x80\x9e\x10\xca\x7b\x0a\x61\x2f\x91\xb5\xa2\x7f\x0b\xbc\x27\x11\x1e\xe7\x22\x40\xcb\x3d\xe0\x32\x2b\x83\x33\x07\x32\x89\xbe\xc3\x45\x59\x9d\xf6\x45\x90\xb5\x59\x3b\x4e\xda\xe6\xa6\x20\xea\x89\x35\xc6\x0d\x9c\x25\x60\x74\xda\xca\x05\x49\x7b\xc1\x37\x0e\x9e\x02\xc8\x13\x69\x84\x15\x08\x62\x9c\xcb\x4a\x60\x0f\xa1\x4b\x9e\x1c\x4f\x14\xdb\xea\xbc\x74\x55\x00\x56\x49\xf5\xc4\xc8\x17\x3e\x2a\x24\x7a\x99\x48\x50\x5b\x32\xf7\x27\xbe\x04\x14\xd3\xfd\xdf\x5c\x77\xf5\xc9\x54\x6a\x2e\x7f\x41\x06\xc0\x6c\x54\x60\x55\x87\xac\x46\xc3\x16\xb1\xc3\xa9\xb6\xce\xda\x5f\xb5\xd1\xc3\x84\x5d\x1c\xaf\x17\x86\xb3\x20\xc9\xf1\x70\x65\x1d\x1a\xa0\x5e\x88\x50\x44\x80\xf2\xc7\xc0\x30\x64\xb8\xbd\xa4\x3d\x15\x44\x36\x28\xed\x05\xf1\x29\x12\xbe\xb4\x07\x44\xf9\x94\xcc\xad\x89\x09\xc3\x08\x4b\xda\x88\x29\x1a\x98\x2e\x0a\x8c\xc7\xf4\x5b\x63\x5b\xca\xa8\xca\xee\x84\xd1\x24\x77\x63\xe0\x18\xc6\x05\xec\xab\xbd\x24\x17\xae\x99\xaa\x71\xea\xbc\x2b\x61\xb6\x82\x6e\x93\x94\xfd\x1a\xac\x25\x54\x22\xf5\x86\x67\x23\xbb\x16\xa3\x35\xa2\xb4\xe9\x28\x4c\xbf\xa8\x0d\xca\xd9\xd4\x82\x24\x3b\x5f\x2f\xba\x0d\xa9\xe0\xb6\xbd\x30\x6c\x5d\x90\xba\x4b\x1b\xb4\xec\x63\x49\x44\x18\xbc\x41\x80\xd8\x44\x4b\x7a\x13\x58\x94\x56\x5c\x14\x16\x99\xb0\x95\x3c\x66\x1f\x26\xa1\x5c\xa0\x96\xa4\x95\x36\xe7\x86\x5d\x51\xbb\x4c\x58\xdd\xd0\x2b\x61\xbd\xa2\x75\x92\xbd\xc7\x8a\x5a\xd6\xd5\xe0\x99\xdc\xbe\xb4\xbd\x7d\xca\x1d\xe8\xcf\xba\x0b\xec\x5d\x52\x5e\x2d\xee\x76\xd3\x3b\x49\x5f\xde\x2c\x4e\x2b\x37\x8b\xf5\x75\x7d\x68\xd4\x56\x5d\x31\xeb\x2c\x56\xd5\x81\x2d\xe0\x1a\x4b\xf1\xec\xaa\x1f\xaf\xae\xf6\x5d\xba\xa6\x8c\x7f\x7a\xa7\x7e\x94\x9b\xcb\x40\xcd\x4a\xad\x05\x17\x11\xc1\x20\xf0\xe4\xda\x0c\x06\xed\xb6\x17\x74\xdb\xed\xb2\x60\x56\xd1\x4c\xa2\x0e\x71\x0b\xa4\xa7\xbb\xc2\x81\x55\x61\x32\xe5\xb5\x1b\xf4\xc8\xd4\xa6\xf6\xa8\xe3\x3b\xc8\xa8\x99\x03\x36\xa3\x8c\x04\x46\x60\x73\x75\xa3\x6f\x5d\xbd\x32\x75\x0e\xeb\x75\x9a\xea\x60\xc8\xbf\xb4\xb2\xa8\x72\x3a\x87\xf0\x1b\xa6\x21\x9a\xb6\xfa\xe4\x2b\x48\x06\xdd\xa2\x50\x67\x80\xab\xaa\xf6\xb2\x82\x79\xc3\x08\x71\x5e\x4d\x35\x21\x2f\x2b\x02\x06\x3f\xb1\xc7\xee\xf7\xb5\x1f\x95\xd4\x49\x60\x96\x58\x48\x0e\x04\x00\x0b\x0c\x33\x99\x19\x6b\x92\x65\x3d\x18\x5b\x13\xf1\x48\xe0\x9d\x61\x93\x34\xb5\x92\x5e\x57\x93\x46\xd6\xbc\x1f\x1c\xb4\xbb\x1f\xab\xc9\x33\x8d\xcd\x25\xda\x06\xa5\x68\x12\x0f\x50\x2a\xf1\x1c\x21\x11\xb9\x1f\x0f\x92\xd5\x55\xaf\xdb\x4d\xee\xa4\x6a\x44\x21\x60\x5d\x42\xbb\x62\x08\x6b\xc1\xf8\x6d\x4b\xae\x16\x91\xf9\xd4\x46\x24\xd8\x01\x16\x74\xb1\xb0\x26\xad\xec\x13\x2b\xfb\xc6\x37\xeb\x9b\xa8\x22\x0c\x36\xf9\x77\x9d\xce\xc6\x6d\xf8\x28\x8a\xdb\xb7\x38\xfe\x40\x1a\xfd\x7e\xfd\x5b\x15\xf8\x66\xe3\xeb\x6f\x29\x00\xb9\xbf\xdd\xf8\xee\x16\xec\x29\xdf\xde\x5a\xbf\x45\x65\xbe\xbd\xa5\x4a\x41\xe0\xb6\x0e\x7c\xa7\x02\xdf\xfe\x56\x56\x78\xeb\xd6\xb7\xb2\x82\x6f\xbe\xbe\xf5\x5b\x4c\xb4\x10\xfd\xe2\x5a\x44\x97\xd2\x1c\x5d\x62\x22\x94\x57\x0b\x93\x58\x6d\xe9\x4a\xe0\x0d\x4c\x3d\xc0\xef\x90\x97\xb7\x93\xc3\xb2\xf6\x07\xb5\xda\xa1\xea\x0a\xf9\x80\xaa\xe1\xdb\x97\xf5\x13\x21\x51\x68\x85\xc4\x84\xe5\x5c\x0c\x84\x93\xb1\x94\x05\xae\x97\xf5\x51\x4a\x43\x77\x39\x20\xa6\xc7\x3c\x67\x3e\xb4\x1b\x1e\x72\xa3\x10\x5b\xf1\xcb\x76\xb7\xaa\x5e\x83\x48\x22\xb5\x16\xaf\xb8\x13\x77\x3a\x13\xa7\xb2\xfa\x05\xde\xc9\x32\x6c\x72\x59\xd5\x71\xb5\x2a\x53\x8b\xc0\x35\xfb\x85\x75\x9c\x5b\x53\xff\xa6\x8a\xaf\xcf\xa9\x7a\xfd\x25\x94\xf6\x1b\x51\xab\xd3\x69\xdd\xc8\xe4\xaf\x13\xd8\xea\xde\x89\xd4\x08\x57\xe2\x8c\x53\x1c\x62\x52\x82\x4c\xea\x4f\x03\xd6\x3e\x3a\x82\xfe\x85\xf1\xd1\x51\x1b\x2a\xaa\xc4\x9f\xa5\xfe\x7c\x1e\x8c\x30\x45\x17\xbe\x8b\x47\x15\x86\x59\x82\x1d\x11\x37\xb2\xb2\xaf\x66\x9f\x93\x02\x40\x59\x83\xd2\xa7\x43\x94\x72\x15\x06\x51\xb0\x57\xec\x6b\x61\x5e\xf7\x01\x2f\xb6\xd5\x16\xc4\x17\x55\x05\xa4\x5c\xc7\xc2\x96\x0c\x31\x1b\xe6\x13\xd8\x2a\x12\x34\x20\x72\x5d\x47\x8e\xc3\x08\xa8\x16\xd5\xd6\x32\x39\x91\x90\x01\x4f\x1b\xd4\x2b\x14\xfe\x49\xa0\x6b\x78\x91\xe9\x58\x32\x93\x57\x39\xcb\x1e\xdf\xa8\x9e\xf5\x59\x7d\xd4\x17\xac\x2b\xed\x30\x2d\x29\xea\xea\x98\x34\x25\x9c\x38\xf5\x51\x5b\x1e\x63\xec\x81\x07\x83\x1b\x64\x4b\x41\xfd\x4d\xcd\xe8\x6d\x50\xc8\x68\x0b\x0a\x8b\x80\xa1\x2c\x16\x4c\x16\xa0\x44\x19\x6c\xf8\x08\x6c\x57\x58\xed\xda\x40\x5a\x84\x1b\x65\x31\x10\xc3\xb2\xb1\x2e\x5b\xc2\x2e\x10\xf2\x2e\xf8\x42\xeb\x1a\xa4\x25\x64\x40\x64\x36\x63\x85\xa5\x1b\xd4\xa6\x74\x5d\x6a\xe4\x03\x7d\x61\x38\x89\x51\x7f\x6e\x8a\x7c\x05\x65\x1a\xf8\x85\x58\xd4\x27\xcf\x40\x5f\xf2\x18\xd2\x57\x94\x5c\x73\x7a\x41\x3c\x8b\x9d\x45\x7c\x74\xfb\xd6\x7d\x65\x3d\x0d\x31\x5f\xdf\x14\x30\xbf\x17\x68\x50\x68\xc8\x5b\x75\xfa\xa5\x0f\x29\xbc\xa0\x21\xe8\xe2\x61\x10\x8f\x80\xf6\x85\xab\x09\xcb\x9a\xa6\x2d\xe7\x47\x99\xe3\x37\xe0\x29\xba\x2a\x8b\x07\xa1\x97\x00\x70\xa2\x26\xbc\x9b\xf3\x68\x10\x19\x31\x99\x8d\x61\x69\x4c\x91\xc6\x06\x74\x46\xd2\xf7\x91\x74\xe5\x9b\x63\xa0\xb6\xc3\x2e\xf0\x9b\x9a\xba\x8d\x10\xda\x33\xa0\xbd\x43\x24\xc7\xa3\x3b\x73\x45\x8e\x4f\x79\xb4\x3f\x3a\x64\x13\x7e\xda\xd3\xad\xb0\x0b\x3e\x71\x66\x6c\x08\x94\x99\x3d\x80\x78\xdc\xf2\x10\x7c\x0f\x38\xbf\xe7\xce\xf8\x85\x51\xc4\xb5\x2e\x68\xd6\x21\x7e\xdb\xc5\x2b\x46\x61\x9c\xc3\xd4\x49\xbd\x1a\x4c\xcf\x55\x36\xc8\x60\x07\x9e\xee\x8f\xbb\xdd\x43\x3e\xd3\xb4\x67\x5a\xce\xdb\x23\x61\xce\x65\x8f\x50\xa2\x02\x0c\xb8\xbc\x2a\x93\x5f\x8b\xba\x6f\x85\xa9\x2f\xa9\x66\x45\x6d\xa2\x8a\x56\x48\xef\x1b\xab\x28\xd0\x43\xd2\xa3\x00\x35\x44\xa6\xf1\xc8\x5b\x5e\xec\x53\x73\xb1\x16\xed\xe7\x59\x79\x70\x65\x4a\x33\x9b\x86\x7e\x14\x36\xe3\x56\x2f\xef\xd4\x9b\xe5\xda\x07\x8a\xa9\xe0\x9d\xb0\x04\xd3\x41\x60\x66\x99\x66\x91\x8a\x63\x61\x7e\x39\xc5\xb3\xf3\xad\xcc\x91\x8e\x1d\x41\xfc\xf3\x70\x81\x4d\xb3\x2b\xdc\xb9\x94\x02\x4a\x4a\x94\xa8\x62\x29\xeb\x7f\x28\xaa\x3c\x3a\xd6\x06\x78\xbd\xc0\x63\x03\x0b\xb5\x17\x02\x91\x18\xc4\x28\x81\x13\xd4\x91\x62\x60\x60\x0a\x35\x1a\x82\x36\x58\xf7\x6c\xa6\xe9\x99\xd5\x7d\xd3\xdb\xfe\x22\x07\x4f\xb5\x07\x78\x32\x84\xb5\x83\xb8\x89\x74\x50\xc8\xda\x01\x2c\x2d\x4b\x80\xb9\x51\xe9\x71\x95\x51\x27\xa0\x90\xbb\xb0\x6d\xdf\x49\x61\x7b\x56\x6c\x8c\xd0\xf2\x45\xc3\x6e\xfd\x5e\x7c\x19\xf3\x4f\x0c\x10\x8b\x61\x7a\x5b\xe8\x83\xae\xef\x36\x50\x9d\xef\x17\xea\xaa\x31\xfd\x5f\x52\x49\x50\xf7\xe7\xd5\xd4\x21\x92\xc1\x5a\x56\x7d\xe5\xb1\xad\x39\x30\x2c\xf9\x8c\xeb\x6b\x5c\x64\xfb\xd4\x9d\x68\x82\x98\x40\xbf\x2d\x0c\x97\x98\xa3\x78\x3f\xdf\xba\xc3\x5d\x12\xdc\xcf\xb6\x41\x53\xa2\x5b\x48\xc8\x0f\x59\xd9\xfd\xd2\x07\x70\x29\x3c\xc7\xd7\xb0\x75\x50\xf5\xd3\x4c\xf2\x76\x7d\xad\xcf\x42\xd4\xee\x27\x9b\x68\x93\x9d\xf2\xc4\x74\xd2\xda\x95\xea\xfe\x25\xeb\x55\xbe\x68\xac\x32\xa5\xe3\xb9\x25\x55\xfa\x8a\x4d\x62\xa9\x2e\x43\xb0\xac\xa0\x24\xf4\x28\xa4\xdb\xf2\x01\x01\x10\x81\x90\xdc\x09\xfb\x2e\x30\x0c\x0e\x0c\x1e\x6f\x9e\x27\x16\x0c\x2c\xb9\x2f\x5b\xa8\xbd\x5e\x71\xa2\x2a\x5e\x5d\xc5\x8a\x13\x5c\xec\x9f\xaf\x36\xff\x62\x14\x6b\xc0\xb0\x75\x8d\x61\xd6\x3a\x1f\x56\xcc\x47\x1b\xb5\x18\x03\xe1\x59\x48\x1e\x59\x03\x5b\x28\xd4\xb2\x54\x1f\x9a\xc6\xa6\xc0\x89\x82\x9c\x6f\x2d\xdc\x79\xed\x0a\x46\x90\xa3\x3e\x81\x9c\x7a\xeb\x0d\x7d\x8a\x37\x17\xd0\xa7\xab\xd9\xf4\xd4\xf4\xa4\xe5\x48\x69\x26\xaa\x4e\x00\x82\x7d\x1f\xc5\x91\x18\x84\x11\x74\x94\xcd\x7c\x79\xda\xe4\xe4\x28\x8f\x0c\xf0\x6f\xe6\x65\xb0\x80\x33\x5c\x14\x4d\xfd\xce\x8a\xc2\x97\xce\x6c\xd0\x92\x0d\xdd\x74\xe7\xee\xd5\xe2\x4a\x1f\x7f\x76\xcd\x9c\xc1\x1c\xbb\x24\x9b\xab\x28\x1f\x97\x51\x28\x97\x51\x68\xe4\x27\xa4\x6f\xfd\x64\xe0\x64\x9c\x5c\x2a\x6c\x47\x89\x0f\x92\x94\x0b\x42\x13\xac\xb2\xe7\x29\x0a\x55\x00\xbc\xfd\xec\xd0\x3b\x72\x3d\x5f\x12\xc3\xec\xb0\x41\x92\x9a\x1a\x98\xc6\x24\x77\x09\xe0\x74\x2f\xaf\x6c\xad\x10\x09\x74\x71\x4d\x1f\xa4\x64\xe9\x18\xc4\xb8\xbe\xd8\x0f\xb1\xfa\xd0\x54\x6f\x4d\xd9\xa8\x79\xc0\xa2\x86\x77\x0a\xd5\x69\x54\x88\xc6\x7c\x0e\x92\x0a\x4e\xcd\x13\x16\x34\xc1\x71\x56\xbf\x8c\xa3\xb0\x47\x9b\x68\x5b\xa7\xd2\xe9\xa0\x69\xbe\x40\xbe\x3d\x47\x61\x68\xf0\x5e\xd7\xe4\x95\x2a\xa5\x3d\xdf\x72\xde\x9b\x0e\x5e\x21\x0d\xf1\x1a\x55\x6f\x83\x47\x90\xd6\x6d\xb7\x5d\xef\x83\x0c\xe0\xf1\x5d\xa9\x40\x30\x28\x2f\x2f\xd2\xa8\xc9\x53\x37\x66\x60\xee\x92\x01\x39\x20\x66\x09\x6c\xac\x64\xdc\xd7\x88\x5a\x46\xe3\x42\xa8\x4e\xdb\x66\x29\x0d\x4a\x57\x5b\xc4\xd4\x62\x72\x4e\xdc\x58\xc6\x1f\xe0\xe0\x58\xcb\x28\xeb\x68\x0f\x55\xb6\x2e\x97\xca\x39\xbd\x16\x16\xf1\xfa\xca\x90\xf3\x67\x58\x7e\xd8\xe2\xef\x3b\x1d\xf8\xfb\x09\xed\x9b\xa2\xa2\x48\x4c\x5b\xdb\x02\xf8\xc6\xc1\x31\x6a\x38\x87\x30\x4c\x2f\x81\xc5\x79\x79\x45\x3a\x21\xbe\x95\x3a\xd1\xe0\xf2\xca\xab\xb4\x49\xa8\x95\x31\x58\xa5\x01\x9e\xad\x03\x7a\xe1\x8e\x03\x38\x0a\x21\x54\x09\x94\x48\x36\xe7\xa1\x46\x88\x39\xd2\x33\xd4\xce\xec\xcf\x0f\x51\x93\xa1\x31\x16\x3e\xcb\x53\x04\xad\x29\x57\x8e\xd3\x00\xef\x9d\x7c\xf0\x5e\x78\x4f\x63\x17\x9a\x34\x7a\x59\x04\xec\x65\x86\xe8\x74\x8a\x1f\xd2\xd6\x2b\xa0\x99\xb8\x02\x96\xc9\x92\x54\x2d\xda\x84\x77\x4a\x0c\xfa\x94\x74\xc9\xf2\x88\xf8\xd0\x77\x5e\x97\x87\x77\x99\xad\x07\x0e\x94\x65\xc1\x11\xfb\x88\x0e\xee\x52\x34\xca\xb7\x31\xe2\xa2\xe2\x93\xc9\x66\xef\x98\x3e\xac\x29\x69\x99\x72\xb1\x29\x35\x28\x13\x74\x51\x9b\x71\x9f\xf3\x04\xdd\x1a\xa3\x3a\x51\x1d\x31\xf0\x5b\xeb\xeb\x9d\xce\x3d\x64\xcf\x40\x6e\x30\x2b\x2b\x87\x09\xf4\xf9\x43\x01\x85\x50\x48\x06\x7a\xa4\xc5\x83\x6e\x37\x34\x1b\x5e\x44\x0b\x97\x26\xb1\xd3\xc1\xb3\x8e\xa8\x5c\xab\x73\x3e\x34\xd3\x21\x68\x3a\x20\xd5\xe2\xf1\xd3\xaa\x8f\x62\x1f\x28\x6f\xe4\xde\x59\xc7\xeb\x34\x3a\x61\x71\xf7\x7c\xb0\x14\x02\x34\xf8\xb3\xb4\x34\x48\x5b\x79\x2a\xf3\xd6\x69\xd1\x09\xe2\x36\x11\xa2\x18\x19\xac\x04\x55\x49\x38\xd5\xcb\x19\xac\xad\x5f\xd0\xe8\x8b\x85\x46\x65\x7b\x8a\x9d\x4b\xe5\xe6\x98\x5e\xd3\xda\x71\xa5\x35\xb3\x7b\xca\xa1\x5b\x47\x0a\x84\x9e\xe6\xac\xb4\x85\xbc\x1d\xc5\x5d\xa1\x3b\xad\x52\xb7\x74\x3d\x43\x50\x7a\x22\x5d\xf7\xba\xa8\xbf\x67\xeb\x9b\xd2\xf5\xf2\x6a\xbc\x99\x40\x64\x82\xfe\x47\x53\xde\x44\xbe\xd2\xa2\x00\x4e\x67\x90\x78\xdd\x54\x16\x24\x46\xaa\x0b\x6c\x0f\x52\xfc\x4d\x64\xed\xd3\xcd\xcd\xcd\x75\x16\xc3\x5f\xb2\x59\x8b\x49\x41\x88\xa2\x9c\x68\x18\xf8\xf3\xca\xc0\xf7\x0f\xaf\x1d\xb8\x1e\xad\xf1\xaa\x13\xd4\x06\x7e\x54\x1f\xb8\x61\x6b\xaa\xb5\xc5\x2c\x2c\x05\x44\xf5\x3d\x70\x40\x12\xc7\xd7\x2d\x58\x6b\xc3\x55\x6e\xc7\xa1\x76\x8b\xd7\x3c\xb3\x6a\x2f\x59\x05\x27\x55\x27\x20\x25\x3f\x07\x6b\x0f\xbe\x33\xc9\x2b\x97\xac\x43\x6e\xf4\xc8\xa7\x40\x74\x3b\x1d\xc0\xa1\x5c\x5b\x34\x00\x14\x81\x20\xe7\xc0\x0a\x6c\x85\xf0\xe3\xc2\x60\x21\x2a\xe7\xd0\x66\x4e\x7b\x8d\x7e\x1f\x84\xe4\xfb\xdc\x9e\x4e\x6d\x15\xd1\xe5\x11\x34\x37\xbc\x13\xf5\xdd\x0c\x58\x48\xe4\x27\x80\xfa\xca\x85\x86\x1b\xb5\x8e\x34\x4b\xcc\xa2\x66\x4f\xcc\xe6\xd8\xb4\x70\xf0\x98\x97\x68\x67\x49\x73\x71\x29\x95\x1a\xff\x10\xf7\x74\x62\x04\x13\x60\x19\x80\x80\x27\xae\xf4\xc1\x2d\x6d\x65\x16\xa7\xfd\x65\x43\x7b\xb2\xa9\x44\x36\x15\x96\x87\x0b\x21\xd2\x13\xc5\x7b\x25\x8a\xf2\x08\x7a\x14\x04\x78\xae\xf4\x33\x0d\xed\x55\xaf\x2c\xa9\x71\xbe\x0d\x2d\x02\xfb\xb4\x31\x4b\x90\x5b\x59\x5e\x54\xb3\xbc\x6c\xc8\xb2\x7b\x3d\xd7\xb2\x54\x7c\x22\xfe\xe5\x65\x48\x0c\xe0\xe7\xc4\xa7\xfb\x35\x16\x86\x66\xa8\xc1\x9c\x0e\x55\x49\x95\x8d\xc2\x47\x1e\x11\x50\x9c\xd8\x42\x6f\xe9\x2a\xd3\x2c\x5a\x02\x6c\xb8\x34\x19\x47\xde\x1a\xa5\x1b\x54\xac\xa7\x87\x3c\x1c\x84\x6a\xb7\xc2\x63\x40\xef\x08\xd6\x87\xc5\x17\xee\x54\x78\x17\xa9\x90\xb6\x4f\xff\xd6\x5b\xf2\xec\x61\x0d\x62\x37\xd6\x84\xf2\xd3\xac\x77\x4b\x54\x78\xa9\xee\x2f\xb0\x64\x2d\xee\x97\x87\x29\xf2\xc3\x4a\xcb\xec\xb4\x4c\x1f\xc1\x07\x3a\x20\x06\x78\xae\x8a\x97\xc8\xf0\x24\xd3\x3b\x91\xbd\xdc\x89\x4d\x47\xcb\x11\x9c\x34\x73\x5f\x92\x57\x62\xc4\x33\xd1\x8e\xf9\x11\xd6\xe0\xc7\x3e\x1a\xbe\x56\x78\x22\xe0\x88\x3e\x0d\x86\xfc\xbd\x27\x59\x22\x60\x72\x1e\x13\xe7\x05\x45\x21\x6b\x64\xb2\x0a\x64\x9f\x20\x6b\x04\x59\x23\x99\x35\xc7\xac\xc2\x55\xcb\x7c\x8e\xcc\xd5\x7b\x7c\xbe\x05\x7f\xa6\xf8\x45\x77\x99\xa7\x9d\x0e\x3e\x27\xd4\x9a\x1b\x7e\x89\x0e\x8f\xd9\x50\x16\x1b\xf1\xf9\x72\x85\x3e\x9b\xf1\xb1\xa5\x8d\xaa\xa5\x62\xed\xa3\xa2\x98\x99\xdb\xd3\xce\x08\x10\x48\x29\x41\x81\x26\xce\x06\xc2\x7c\x09\x03\x1e\xda\x0a\xa7\x96\x31\xf8\x35\x0c\xdb\x69\x49\x3c\x4e\x0d\xc3\x76\x5a\x65\xd8\xf0\x53\xf4\x17\x98\x35\x21\x87\x37\xe1\x4e\x36\x18\xa7\xde\x28\x75\x6b\xd3\x64\xb1\x79\xc9\xdc\xa1\x72\xf4\x3b\x29\xa7\xf6\xae\x35\xb5\x1a\xcf\x0d\xe3\x83\xdc\xb5\x44\x1a\x3d\x96\xd0\xf4\x5b\xd1\xf2\x56\x02\x0b\xd7\x47\x5a\x2e\x19\x1f\xa4\x3f\x03\x7c\xe9\x08\x71\x6b\x1f\x25\xc0\x43\xaf\x55\xc2\x9e\x1e\x8a\x2a\x01\x83\x95\x61\x45\xba\x0e\xb5\x1f\x60\xae\x7e\x59\x9f\x2b\x49\x7c\x59\x4b\xae\xee\x7b\x6b\xb6\x2b\x3f\x64\x73\x7a\xd1\xa9\x3f\x84\x45\x9a\x38\x11\x9b\x43\x1e\xef\x88\x35\x6d\xd5\xe8\x11\x70\xc8\x61\x51\xce\x59\x04\x70\x6a\xad\x2b\x6b\xd5\xa1\xe9\x56\x69\x36\x6e\xc0\xf4\xf8\x97\xec\xc7\xda\xb7\x9d\xfa\xae\x6d\xc6\xaf\x6c\x73\x19\x64\xe8\xe9\x51\x8e\x12\xe2\x1b\xc0\x81\x18\x61\x0c\x3d\x1e\x26\x74\xc4\x87\x49\x4f\x52\xa7\x14\x22\x1a\x2c\x98\x0c\x71\x4a\xd0\x48\x02\x0a\xd9\x68\x9f\xba\x57\xd6\xab\x53\xdb\x78\x5d\x41\x4a\xc4\xb1\x32\x24\x20\x8d\x0d\x90\x5d\x79\x44\x0d\xcc\x31\x09\xbb\xd4\x66\x7f\x79\x9b\x0a\x81\x48\x12\x28\x07\xf9\xa1\xb6\x79\xa0\xb5\xed\xc0\x94\x8e\x6b\x3d\xc6\x8b\xe4\xa8\xaa\xc4\x0b\xbf\xde\x75\xb9\x76\xc8\x9b\x02\x9a\xf4\xd1\x99\x49\x6b\xdd\x6e\x73\xbb\x01\x95\xcf\xc8\x78\xde\xe6\x25\xf0\xca\xaf\xa4\x29\x6a\x50\x4e\xa8\xe5\x1d\x51\xce\xa4\x60\xfa\x95\xb3\x53\xcc\xaa\x99\x6f\x58\xbd\x29\xad\x63\x69\x00\x8d\xa1\x7b\x52\x34\xf3\xd9\xb6\xa2\x9c\x6e\x5f\x33\x35\xfe\x21\x9d\x3e\x48\x56\x05\xf5\x20\x19\xe2\x64\xd4\xc8\x40\x0e\xc9\x27\xe4\x10\x95\xd8\xad\x10\x08\x77\x53\x96\xa2\x68\xc9\x4c\x9c\x0f\x07\xf8\x37\xf7\x72\x74\x08\x6d\x14\x25\x43\x97\xee\x6f\x19\x88\xdc\x5b\xa0\xdb\x1a\x01\x32\x43\x75\xf0\xe8\x18\xf7\xda\xcc\x10\x1f\x34\xfb\x35\x2f\xb3\x21\xc3\x27\x8f\xaf\x7d\x48\xd0\xdc\x16\xe9\xb5\x22\x5a\x6b\x43\x96\xa3\x86\x0b\xc5\x58\x3c\x4d\x69\xea\x78\xd4\x07\xfa\x0b\x74\x3e\x67\xcd\xac\xdd\x63\x62\xed\x80\xec\xdf\x40\x67\x9c\x83\xa1\x37\xc4\x83\xb1\x21\xee\xc8\xde\x7b\x8b\xfb\x83\x1c\xf0\x0b\x39\xb6\xf1\x2f\x26\x51\x6e\x10\x96\xe7\xc8\xeb\x68\x97\x9d\xb9\x21\x90\x91\xcb\xe6\x03\xea\x3c\x08\xd5\xd0\x4f\x09\x04\xcf\x21\xe9\x6c\x80\x57\xbf\xa0\x2d\x84\xa6\x79\xdd\x21\xb2\x76\xbd\x47\x36\x9a\x97\x98\x51\xc1\x4a\xdc\x46\x8f\x3c\x3a\xa7\xb6\x0e\x5a\xaa\xfe\xe2\x4b\x56\x67\x6c\x09\x44\x42\x5a\xf1\xa4\x6a\xf1\x29\x7c\xb5\x54\x50\x42\xdb\x89\x84\xb4\xb3\x3f\x47\x4e\x45\x73\x47\x61\x7f\x66\xd6\x75\x88\x3e\xc0\xcd\x63\x36\xd6\x99\x4d\xed\x56\x7a\x77\x98\x39\x7b\x99\xe3\x7e\xe5\x88\xd5\xa0\x8b\x7e\x2d\xca\x73\x9a\xca\xca\xd1\x55\x55\x29\x1b\xb1\x2e\x31\x88\x02\xb0\x02\x40\x0a\xc6\x23\x06\x54\x94\x4a\x4e\xa1\x42\xe0\x3e\x36\xb1\x63\xa5\x31\x00\xd7\x70\x03\x29\x4b\x48\x61\x49\x90\x9b\x91\x55\xa1\xa4\x2c\xe1\x56\x8d\x3e\xcb\xf7\x6c\x80\x77\x91\x52\x96\x2d\x9e\x29\x29\x4b\x6c\xa2\xe0\x16\x43\x2d\x28\x67\x09\x29\x67\x55\x08\x5e\xe2\x1a\x1b\x2c\x34\xc0\x02\x02\xd9\x2d\x4f\x5f\x2c\x7e\xf2\x87\x26\x13\xdc\xeb\x45\x4e\x4d\xeb\x59\x2b\x06\x60\xb4\x5a\x16\x38\xde\x55\xb0\x81\xb8\x5f\xd2\x40\x54\xe4\xa2\x14\x95\x11\x19\xce\x73\x48\x5a\x08\xa9\x98\xb8\x97\xd1\x5b\x4b\xb0\xdd\xe4\x08\xf6\x87\x40\x45\x10\xd1\x3d\x87\x14\x11\x68\xf3\x01\x2b\x64\x68\x69\x23\x4a\xbd\x66\x24\xd7\xe8\x9c\xec\x42\x22\xd2\x41\x7b\xc4\x2b\xf9\x0b\xca\x89\xb1\x25\x37\x29\x22\x90\xef\x8f\x91\x1a\xcf\x6d\x1d\x05\x4c\x52\x2e\x97\xd5\x1c\x3a\x55\x55\x58\xc0\xb2\x66\x73\x52\x58\x38\x78\x86\x84\xba\xdd\x86\xbc\x86\x77\x1f\x5a\x67\x68\x9f\x95\x0f\x16\x8f\x3e\xd4\x36\xd5\x70\xec\xf1\xac\xaa\x9d\xe8\x57\x9e\x33\x9a\xc8\xd7\x46\x34\xbf\xb6\xa0\x0c\x11\xcd\x8a\x59\x04\x23\xca\x23\xb0\x05\xcf\x33\xe3\x8c\xd7\x47\x43\xcf\x0c\x11\xd5\xef\x61\xf3\x2a\xc1\xef\xe1\x49\xdd\xdd\x74\x82\xab\x62\xf1\xec\xe0\x46\x6d\x69\xe0\xfb\x5b\x96\x44\x42\x26\xca\x0b\xf7\x59\xd1\x56\x5f\xda\x11\xed\x64\x9b\x80\xeb\x04\x2b\x3c\xab\x31\x5d\x4c\xbb\x09\xa0\x3b\xea\xb6\x48\x05\xe5\xc4\x03\xb1\xc9\x7d\x4f\x6c\xfa\xf8\xcc\x56\xd8\xdd\xf0\x12\x1e\x96\x24\x42\x05\xde\xca\xce\xec\xe1\xd3\x02\x65\x17\xdf\x5a\xd2\x3c\xac\x55\xfb\xa9\x14\xe9\x05\xb8\x26\x41\x91\xf4\x00\xa8\xdb\xa8\xd4\x25\x4f\xc1\x9a\xab\x03\xfa\xe3\x24\xdd\xd0\x5d\xbb\x45\xa7\xf2\x0e\xf2\x6d\x4a\x61\xca\xe9\xca\xa8\xef\x4a\x26\x3f\x2a\x8a\x54\x9e\x8a\xcf\x79\x36\xc0\x2d\xaf\x6a\xaf\x69\x54\x89\xb0\x09\xa4\x38\xd4\x21\x0c\x75\xd8\x9f\x0f\x12\x9e\xc3\x58\x43\x9e\xeb\x21\x1e\x65\x30\x55\xf7\x33\x6b\x78\x46\x49\xbd\x54\x3b\xa9\x8a\xee\xf9\x34\x19\x4d\xa3\x2a\x55\xc6\xea\x76\x67\x6c\xae\x73\xd6\x77\x0b\xfb\xd1\x1b\x25\x60\x00\xb0\xf5\xdd\xcd\x85\xdc\x15\xaa\x52\x96\x90\xba\x2c\x59\xea\x37\xcd\xa5\x2c\xcd\x4d\xb5\x1c\x22\xa2\x2c\xf9\xf5\xb2\x92\xc8\x18\x2c\x29\x4b\x5c\x5d\xbd\x98\x95\x5b\xdd\xfe\xb2\xdf\x19\xb2\x4e\x74\xed\x0d\xd4\x37\x1b\x96\x6d\x3c\x1a\xa4\x8b\x0a\x8f\xb8\xa6\x1b\x78\x9e\x95\xf7\xd6\x53\x28\xad\xd5\x48\xa2\xe4\x60\x50\x80\xef\x66\x2e\x89\x11\x59\xdf\xcd\x91\x19\x22\x21\x42\xd1\x45\x32\x5a\xcc\xf7\xe3\xfd\xe4\xf0\x50\x6a\x9b\x28\x81\x54\x28\x90\x19\xb5\x70\x10\x0b\x3f\x9a\xa6\xe4\xd6\x01\x70\x43\x17\x2b\x07\x39\xda\x32\xcf\xee\x67\x82\xfd\xcc\x30\x3e\x2f\xfb\x39\xc4\x7e\xfa\xdd\xdc\x25\xbd\xb1\xdf\x77\x87\xfa\xb8\xc7\x2c\xb1\x08\xb6\xf6\x6e\x37\xbb\x93\x63\x62\xd4\xcd\x70\x18\x99\x19\x06\x91\x25\x8c\xc7\xc3\x22\x2a\x69\x75\xd9\x22\xaa\x71\x5a\xd9\xfa\xeb\xf8\xa5\xa4\x3c\xd8\x18\x5c\x75\xec\x90\xf2\xd3\x14\x75\xfc\xec\xb6\xcb\x80\x09\x8b\x5d\xb7\x26\xe6\x59\x87\x56\x04\x61\xb5\xa4\x49\xe6\x0a\x60\x8d\xe5\x0c\xb7\x00\x7a\x00\x2a\x56\x7b\xc2\x03\x6c\xcf\x62\xa8\x63\x6c\x1a\xf3\x0a\xbc\xd1\x4a\x9f\xa4\xa1\x2d\x37\x60\xeb\xf8\x3a\x6d\x62\xbd\xb4\xd4\xb4\x70\xa3\x38\xb6\xee\x0b\xaf\x93\xa4\x74\x0b\x8d\xc2\x95\x3a\xb7\xf2\x08\x9e\xd8\xbc\xdd\xe9\x1c\xa5\xce\xd2\xab\xd2\xd6\xc7\xed\x43\xe9\xff\x0c\xe8\x15\x15\x6b\x50\x29\x95\x99\xc5\xea\x2d\x29\xa8\xa6\x1c\x68\x4c\x19\xbf\xba\x2a\x56\x2b\x4d\x88\xd5\xd5\x43\xf6\xb5\xba\xeb\x24\x36\x6f\x7d\xb6\xde\x8d\x43\x3a\x41\xaf\x54\x79\x58\xa1\xca\x84\xe1\xc2\x6c\x07\x65\x4e\x54\xab\x82\x0c\x08\x13\x11\xda\x0f\x11\x5b\x90\x4e\xd2\x86\x8b\x40\x4a\x30\xc2\xad\xac\x62\x39\x39\x48\xbd\xc0\x6d\x5a\xf3\x72\xdc\x7e\xea\x34\x9e\x98\x87\x8d\xb3\xb9\xb8\xe9\x1f\xf9\x4e\xee\xa3\xb8\x45\xc6\x5f\x66\x71\xb5\xdb\xb4\xfb\x23\xdb\xc6\x11\x7f\xe4\xb9\x41\x23\xde\xf8\xd7\xe2\xcd\x07\x5c\xa0\xe6\x0e\x18\x3d\x81\xdc\x30\x18\x5d\xef\x1e\x5e\x8c\x1c\xc4\x9e\xb0\xea\xcf\xae\x5f\x58\x09\xa1\x56\xac\x94\xf1\x30\x67\x64\x51\xa4\xce\x9e\x4e\x91\xe9\xf3\x15\xf7\x4b\x3b\x7d\x08\x1b\xdf\x0c\x58\x58\xa9\x14\x6a\x21\x08\x42\xb5\x0a\x5d\xad\x64\x23\xe5\x5a\x2c\x0f\x24\x41\xfe\xbb\x1b\x5a\xe7\x2b\x81\x93\x43\xff\x76\xe8\xc8\xa5\x9f\x72\x63\x46\x3e\x93\x7d\x10\x36\x2d\xce\xd3\xaa\x28\xa8\x3d\x11\x96\x46\x05\x4e\x39\x1f\x5b\x8b\x4b\xec\x98\x6f\xb1\x73\xa4\x5f\x5b\x6e\xff\x18\xc9\xe6\xf9\xfe\xb1\x7d\x4d\xff\x98\x96\x1d\x9e\x7a\x9c\x73\x20\xea\xe7\x52\xf3\xc1\x42\x8a\x10\x18\x81\x7b\x89\xcb\x46\x45\x71\x2a\x47\xf6\x9c\x47\x3d\x72\x75\x82\x8e\xa2\x83\x94\x1d\xf1\x0b\xc8\xf5\x9c\x86\xba\xb5\xca\x8f\x0c\xd5\xdc\xdc\x92\x05\xce\x80\x19\xb8\x81\x47\xf3\xd2\x60\x72\x0f\x09\xee\x70\x75\x0b\x29\xed\x53\x3e\x02\x31\x8c\xa2\x5f\x40\x10\x03\x20\x8d\xee\x40\xf0\x5c\xc6\x9e\xe8\xd8\xf3\xbe\x28\x20\xbc\xeb\xdd\x67\xa2\xc3\xff\xb2\x33\x1a\xdc\xf7\x76\x5d\x36\x43\xc3\x27\xfc\x7e\x52\xbc\x04\x60\xfe\x25\x6c\xef\x2e\x37\x40\xdb\x61\x4f\xd9\x09\x7b\xc1\xce\x00\x68\x7b\x06\x43\xee\xda\xfd\xe7\xcf\xd9\xdd\x2b\x5a\x08\x8f\xf9\x18\xd1\x66\x5a\x3a\xb5\x94\x0e\x6c\x1e\xef\x3f\x38\xa4\xb7\x0f\x00\x22\x2f\x10\x22\x19\xc0\x03\x24\xe3\xfc\xce\x79\xf9\xfc\x93\x0e\x82\x04\xce\x16\x16\x60\x34\x98\x14\x05\xe1\x78\xb9\x0e\x1f\xb3\x73\xb9\xfe\x80\xd5\xef\x9c\xb0\x31\xfc\x7d\xc2\xa6\xf0\xf7\x25\x1b\xc1\xdf\xa7\x6c\x06\x7f\xf7\xd8\x29\xfc\x7d\xc1\x26\xbc\x05\x8d\x50\x0d\xec\x01\x37\x77\x45\x2c\xbb\xdd\x61\x5a\xe5\x50\x03\x4b\x33\x25\x78\x17\x68\xf7\x26\x5e\x09\x6e\x1d\x67\xa5\x5e\x44\xbd\x50\x04\x1c\xf4\xaa\x79\x78\xd2\x7a\xd6\x6f\xa5\xed\xc5\x78\x9e\x7f\xea\x03\x5a\x66\x99\x93\xac\x99\x07\xfd\x5c\xe3\x7f\x26\xb1\x98\x82\x28\x2d\x59\xd0\x92\x50\x39\x35\xe3\xa3\x6c\x11\x49\x73\x8c\x1f\x96\xb4\x23\x42\x84\xcd\xba\x43\xdc\x70\xf3\x3b\xc3\xbe\x1b\x01\xcb\xc9\x53\xed\x53\x42\xea\x3c\x20\x0e\xf7\xff\x12\x95\xbb\xa5\x54\xb8\x30\x03\xc9\xc0\x2f\x41\x1f\xaa\x69\x66\x91\x9c\x81\x90\x60\xef\x57\xe9\xa0\x25\x9d\xcc\x17\xd6\xa0\x51\x78\x76\x5e\x92\xce\x38\xaf\x6a\xf0\x97\x9e\x98\x4b\x2d\x0c\x3e\x29\x66\x9f\xbe\x0e\x35\x12\xef\x16\xf7\xf1\xa0\x32\x91\xf4\x87\x0d\x57\x51\x53\x53\x32\xed\xa2\x73\x5f\x0b\x89\x29\x48\x88\x49\x5f\x67\xbd\x92\xe2\x20\x76\xe3\x11\xa9\xf6\xa7\x7c\xbf\xec\x31\x6a\x55\xa9\xd7\xb4\xd4\xc7\x9d\xce\x18\x0f\x6e\x51\xe6\x7b\x99\x3a\x53\x36\xc6\x17\xa9\xa6\xb8\x9d\x66\xf0\xf3\x1d\xa0\x3a\xfe\x55\x68\x90\x0d\x72\x10\xce\x8d\xe0\x00\x2b\x37\x5b\x1d\xc2\xca\x45\x31\x1e\x84\x9b\x27\xae\xd4\xd3\xc3\xa4\x4c\x51\xe5\x39\x25\x9f\x25\xb4\x43\x8e\x50\xc2\xd8\xa5\x53\x0a\x58\x9c\xbb\x50\x62\xba\xff\x1b\x7d\xb1\x75\x90\xa7\xc6\x4c\x60\x0a\x02\xae\xfd\x45\x40\x9a\xc1\x5a\xdc\xce\xbc\xd7\x66\x29\xce\x9c\x11\xa4\x59\x66\x44\x69\x5d\x45\x26\xd5\x63\xc4\xb9\x05\x25\xe7\x26\x4a\x9c\x6a\x11\xb0\xf3\x16\x1f\xe2\x7d\x03\xa0\xf9\xc3\xcd\xbc\xa6\xd3\x46\x65\x9e\x62\xe3\x2e\xe5\xda\x44\x9b\x21\x5c\x9c\xfb\x12\x7a\x11\x3f\x62\x29\x29\xc5\x92\x41\xea\x8c\x01\xb2\x40\xd6\x52\x67\xce\xc6\x44\x15\x1a\xb5\x68\x28\x98\x27\x86\x31\x9b\x82\xcc\x34\xc5\x83\x74\x07\x6b\x9d\x1e\xb2\x16\x54\x06\xd4\x64\x0e\x9b\xca\x18\x78\x1f\xaa\x4b\x0f\x8a\x2e\x5b\x10\x38\x97\xe7\xd1\x5a\xef\x96\x45\x0d\xa6\x86\x1a\xd4\x24\x9d\x1f\x3c\xfa\x79\xa7\x44\x8a\x6e\xc0\x81\x36\x48\x31\xe3\xa1\x67\xa4\x03\x74\xaa\x0e\xfd\xa7\x5f\xbc\xb7\xac\x2e\x8e\x62\x94\x0a\xca\x22\x6f\x4d\x91\x16\xef\x06\x03\x98\xea\xae\xf0\xf0\x46\xcf\x40\x1f\x8a\x79\x56\x03\xdf\xcb\xb6\x85\x30\xa5\xa0\x42\xbc\xb7\xb6\x68\x5a\x37\x5a\x32\xbb\x52\xef\x8e\x6f\x5a\x9b\x09\x26\x0b\x38\x94\x46\x2d\x82\x07\x73\x0c\x13\xd9\x4a\xaa\x93\x4b\x13\x0a\x73\x49\xc7\x16\x63\x33\xc7\x53\x9e\xed\x8f\x0f\x81\xe8\x96\x67\x49\x53\x79\x7e\x24\xd3\xd1\x5a\x1c\xa6\xe9\x94\x66\xab\x3f\x52\x08\x30\x22\x04\x38\x65\x33\xc4\xdf\xd4\x99\xb1\x53\x08\x34\x23\xc0\x88\xb2\xcf\x3a\x9d\x19\x4c\xdf\x29\x4e\x1f\xe6\x36\x53\x4c\x87\x18\xa3\xb2\xab\x73\xa0\x06\x73\x5e\x79\x41\x96\xf3\xa9\xcc\xa6\xbc\xe4\xe2\x9b\x9e\xf6\x73\xae\x17\x78\x8f\xad\xfc\xc6\xce\x4f\x5a\xfc\x02\x88\x92\x5d\x4b\x28\xef\x70\xd5\xa2\xd0\x97\xa9\xd3\xc0\xc9\x4e\x3a\x9d\x49\x4d\x0b\xd3\x90\x0b\xda\xb8\xb0\x73\x5d\xb8\xd7\x9d\xc6\xcc\x6a\x9b\x54\x3c\x78\x91\x79\x4f\x33\x64\x1b\xf1\x84\x7c\x99\xca\xce\x26\xb8\xea\xb3\xef\x38\xf1\x20\xd9\xcc\xbd\x7c\x33\x01\xd2\x82\xe6\x89\x30\x2b\xf8\x13\x22\x07\x97\xf0\x1c\x35\x1e\xa8\xe0\xb4\xf4\x83\xa7\xe4\x80\xa0\xb4\x22\x91\xee\xa3\x8f\xfd\xe1\x49\x51\x3c\xf1\x0d\xe1\xe7\x78\x0a\xf3\xc4\x1f\xcc\x62\x2f\x61\xe9\x20\x51\x85\x3c\x6b\x47\x98\x54\x6a\x0a\xb9\xb9\xd8\x58\x14\xcf\xcc\x56\x1a\x72\x64\x14\x9f\x41\x0d\x5e\xc8\x82\x41\xa8\xeb\xb1\x7a\x74\xb1\x54\x46\x1d\xc4\xe5\x16\xb1\x68\x70\x48\xa6\x0b\x59\xf8\xc9\x68\x32\x42\xba\x9e\x20\x17\x79\x1b\x6f\x58\xe0\x95\x50\xee\x5b\x2e\xa7\x28\xf6\x39\xbe\xb5\xd1\xf6\xc4\x6a\x35\x09\x2f\x5e\x40\x2c\x5e\xc6\x10\x2c\xe8\xfa\x6e\x3d\x51\x95\x0b\x48\x56\x66\x62\xb5\xd4\x2e\x5c\xd2\x5d\x0f\x2f\x60\xf8\x98\xb2\xcd\x72\x93\xf9\x9d\xb9\x5d\x6e\x04\x3e\xe9\x91\xd9\xc2\x41\xdb\x6f\x05\xa0\xd8\x82\x95\x3c\x6c\x2b\x95\x43\x60\x02\x34\xde\xf4\x72\xd4\xbb\xb8\xda\x07\x2c\x3d\xa0\x3b\xcf\x05\x7d\xc3\x6f\x45\xb7\xbd\x55\xe9\x8d\xbd\x56\x16\xcd\x25\x2d\xf5\x9d\x8d\xda\xd2\xc6\xfe\xa3\x0f\xf5\xc2\x18\xec\xeb\x73\x0b\xac\x97\x5d\xbf\x9a\x20\xa1\x08\x70\x6a\xa8\x1f\x69\x59\xfa\x4d\x54\x99\x18\x86\xd4\xe9\xea\xe4\x44\xc8\xf4\x50\xfd\xfa\xea\x37\x53\xbf\xb9\xfa\x1d\xaa\xdf\x48\xfd\xce\xd5\xef\x58\x78\xda\x6c\xea\x38\x1f\x8f\xcb\x57\xc6\x65\x3b\xf1\x00\xba\x92\x00\x7e\x33\x48\xbf\x10\xc1\xde\x78\x9c\x05\xc2\xdc\xf0\x71\x35\xad\xaf\x51\x6f\x59\x58\xf7\xf1\x7b\x4f\x61\xa7\x8c\xd5\x7e\xef\x8f\x44\xf9\x1c\x5c\xd8\x8b\xfc\x4c\xec\xa8\x39\x33\xe1\x06\xc3\x90\x73\x33\x5b\x31\x39\x31\xa7\x7b\xe9\xc0\x18\xb5\x60\xce\x31\x13\xbe\x06\x95\x0d\xe4\x3e\xe5\xc9\xa8\xfb\x01\x3e\x34\x23\x4f\xf0\xcd\x02\x7f\xef\x6b\x5b\x86\xbe\x55\x90\x0e\x03\x5b\x67\x42\xfa\xd8\xa5\xf7\x92\x29\xea\xbe\x89\x29\x8a\x5d\x34\x74\x60\xdb\x19\x9d\xbf\x36\x19\xf1\x3d\xaf\x4a\x94\x01\x47\x3f\x9d\xe6\x88\xe4\x6e\x86\xbe\xd3\x37\x57\x37\x00\x75\x7f\xbd\xc1\x39\x3a\xc1\xda\xb4\x0e\xf8\x8e\x52\x4b\x9b\xd9\xda\x0b\x2b\x2e\xe8\x2a\xf6\xbc\xa2\xaa\x5a\x4e\x5d\x39\x32\x4b\x87\x75\x86\x07\xbd\x74\xce\x24\xf0\x10\x53\xde\x4a\xb2\x2e\xb3\xa4\x12\x8f\xcb\x13\x91\x10\x4f\x6d\xc5\x21\xaf\x38\x50\x3c\xb3\x5d\x38\x2e\x78\x66\xc4\x6b\xbc\xf6\x60\xee\x66\x9b\x76\xe1\x27\xb6\xf8\x1e\x28\xd7\x80\xe4\x81\x11\x19\x81\xcd\x75\x4f\x99\xec\x5a\x06\x53\x69\x45\xe1\x8f\xdc\x67\x4a\x0f\x04\x22\xed\x2b\x70\x37\x38\x29\x76\x80\xca\x81\x58\x07\x6c\x69\x58\xf8\xc5\x5e\xf1\x02\xcd\xd3\x3b\x27\xb8\x5f\xa5\x9d\x13\xd2\x45\x77\x76\xe4\xd7\x0e\x72\x00\xce\x10\x6d\xe5\xdd\xfd\xdf\xe2\xf1\x09\x88\xd8\xf4\xf1\x2d\x72\x6f\x80\x37\x9b\x1c\xb2\xa6\x9b\x3e\x9e\x44\xf9\x18\xe2\x3b\xc8\x26\x27\x9b\x1c\xc0\x81\xea\x79\xe8\xf1\xce\x26\xda\x95\x01\x37\x8e\xd6\x6c\xfa\x72\xd9\x1d\xae\xb0\x0a\x18\x67\x63\x1b\x82\xa6\x9f\x9d\x27\x74\xf8\x78\x0b\x55\x7d\xb7\xa0\xdf\x05\x74\xe7\x09\x30\xcb\x7b\xda\x78\x05\x5f\x3a\xac\xf1\x11\xb7\xd1\xb6\xfb\xf6\x21\x9f\x0d\x02\xe4\x19\x46\x4c\x00\x4f\xec\x7a\x20\x1d\x8f\x5c\x16\x40\x18\x52\x2e\x1c\xcc\xc2\xde\x50\x34\xa5\x6b\xf4\xc3\x2a\xbf\x06\x4e\x05\xda\xc5\xca\x20\x88\x7f\xa0\x88\xd0\x95\x7d\x63\x55\xf6\x8d\xae\xec\xeb\xb2\x32\x48\x77\x51\xbc\x44\x18\x8d\xa8\xfb\xbf\x3d\xe4\x54\x00\x16\x01\x82\x16\x62\xbe\xd5\xbc\x3f\x06\x07\x02\xfe\x78\xb0\x2f\xe0\x07\xc3\x0f\xc8\xa9\x93\xbf\x3b\xa4\x02\xdf\x21\x04\x50\x6e\x40\x5a\x2d\x4d\x1f\x70\x42\x79\x62\x1f\x69\xef\xa9\x09\x0f\x94\x2d\xe9\xf2\x73\xa3\xcb\xab\x8a\x49\x59\x28\x8f\xb9\xc3\x15\xc9\xbe\x38\x89\xd6\xbd\xba\x0d\x67\xa7\x4f\x2b\x68\x85\x6e\x70\x94\x4e\xe8\x7a\xf3\x4b\x27\xa6\x73\xc5\xda\x79\xe8\x0b\xad\x62\x5b\xb8\xd8\x84\x3a\xaf\xcc\x18\x28\x90\x63\x35\x4e\xd7\x58\xfb\xa9\x75\x26\x4c\x47\x4f\xe4\x32\x02\xcf\x80\xf1\x2a\x07\xf6\xdd\x3b\x6a\x30\xeb\xdb\xa5\x05\xa4\x0e\x2e\x0d\xc5\x23\x96\xef\x94\x9c\x84\x96\x56\x59\x2d\xfe\x1e\xc4\x78\x6b\x43\xb4\xf9\x39\x57\x5e\x8c\xa9\x30\x87\x0d\x5b\x1b\x3e\x56\xe1\xc4\xd5\xcb\xd5\x75\x02\xb4\x0c\x74\x48\xf3\xb8\xb8\x6a\x66\x75\x81\x90\x56\x0c\x57\x4a\x53\xbf\xd4\xbe\x84\x14\xf3\xb7\x44\x5f\x2b\x67\x06\x29\x4a\x1a\x86\xaa\x95\x64\xdf\xc7\xb5\xa9\x88\x9c\x43\x96\x6b\x45\x11\xf6\xe2\x24\x7e\x00\x64\xea\x6e\x3a\xc9\x3a\x9d\x2d\xa2\x2e\x5a\x6f\x4f\x36\x89\x99\x41\x20\x20\x13\x28\xbc\x39\xf2\x2c\x7e\xc8\x90\xbc\x97\x9d\x1c\xba\xe5\x99\xe7\xd0\xa0\x94\x75\x8c\xb0\x63\xd3\x36\x7d\x3d\x62\xff\xd0\x43\x82\xa9\x77\xc8\x81\xbc\xc8\x17\x78\x1f\xd1\x65\x87\x97\xf8\x95\x3b\xe5\x27\x76\x0d\x95\x9c\x96\x39\x57\x85\x82\x56\xf8\x6e\xd8\xe7\xd4\x05\x60\x4f\xdd\x57\xb7\x2f\xf6\xd2\xa5\x60\x75\xf7\x9c\x21\x0e\x56\xae\xf1\x5a\x2d\x3c\x36\x5b\x8e\xe0\xb0\xe5\x9b\x1d\x48\x5d\xf9\x10\xe8\x82\x0a\xb8\x3b\x3c\xda\xdf\x60\x1b\xf6\x21\x6b\xed\xb0\x73\x5d\x9f\x9b\xa0\x8e\x06\xb5\x42\x68\x92\x43\xa7\x9a\xca\x5d\xc1\x47\xb9\xc2\xd2\x2e\x2f\x59\x3b\xcb\xac\xf2\x55\x05\x15\xf4\x7d\xb4\xea\x3d\x00\xe2\x81\x69\x1e\xcb\x8b\x69\xa1\xbc\x98\x16\x12\x0d\x90\xe6\x9b\x4d\x24\xe0\x43\x6a\x29\x9c\x02\xac\x69\xf1\xe0\x01\xea\x0d\x8c\xde\xdd\x3e\x84\x08\x88\x60\x93\xe6\x96\x6c\x57\x60\x59\x54\x2c\x71\x2f\x50\x65\x7c\x66\x1d\x13\xb0\xd6\x06\x6b\xad\x33\xa8\xcf\x86\xf5\x76\x9d\x23\xb4\xcd\xed\x35\x2f\x31\x70\x1a\xa7\x81\x4e\x2e\x36\x5c\x46\x50\x5c\xdf\x44\x73\x0b\x00\x30\x3a\x1e\x2b\xcd\x83\xfe\x04\xd5\x0b\x9e\xae\xd2\x64\xaf\xeb\xa6\x96\x34\xf6\xe8\xba\xc6\x24\xb7\x25\x9b\x54\x8f\x9a\x0b\x54\x98\xa3\xe8\x7e\x9b\xa8\xa1\xbc\xff\x49\xd7\x13\x02\xcb\x73\x84\x6a\x32\xed\x6e\x58\x60\x7b\xfd\x0b\x9a\x92\x6c\xd0\xea\xc6\x42\x9b\x74\x68\x28\x5b\xd5\x77\x01\xab\xad\xda\x1a\xcb\x37\x96\xc6\x52\xb1\xc8\x0d\xb0\x4c\x06\x78\x59\x49\x73\x45\x2d\x8b\x8a\x1a\xf8\x12\xdd\x45\xcc\x4d\x5c\x66\x5d\x57\xa8\x82\xf2\x53\x6d\x7c\xd2\xc0\x66\xe1\x82\x73\x65\x30\xda\xf5\x90\x05\xc5\xeb\xbc\x0f\x7d\xbc\x0e\x84\x0d\xd3\xf3\x4b\xea\xfe\xa1\x42\xa3\x06\xb8\xdb\xc3\x66\x56\xda\xcb\x7c\x01\x56\xd6\x40\x26\xc8\xfc\x2b\x1d\xc8\x9b\x08\x55\x60\x3d\xb4\x25\xb6\x86\xaa\x84\x2c\xd5\x5a\xaf\x16\x7b\xf6\xa5\x38\xb4\xba\xd1\x68\xb4\x11\xbb\xe8\xe6\x20\x1e\x00\x29\x4c\xbb\x31\x83\xda\xd1\x64\xc9\x7a\xfd\x48\xd1\x22\x69\x11\xe2\x6a\xd3\x0d\xad\x76\x46\x7b\x8f\x01\xfe\xf5\x3d\xbf\x05\x7f\xdd\x41\xe8\x95\x2e\xa9\xb4\x1f\x2a\xcb\xb0\xc4\x86\x29\xad\x6b\x7b\x41\xbc\xad\xd2\x32\x74\x36\x22\xc9\xe5\x82\x06\x1d\xad\x1b\x81\x2e\x4f\xe4\x59\x55\xc8\x79\x52\xa1\x9d\x96\xce\x1d\x69\x28\x52\xb8\x4c\x52\xb8\xcc\x25\x1b\x3a\x73\x8b\x4c\x5d\x5c\x82\xcd\x52\xd7\xbd\xc9\x37\x6e\xa9\xdb\x55\x10\x09\x7c\xc2\x95\x75\xc3\x5b\x9b\x4c\xae\xa3\xc9\xa4\xbc\xcb\x31\xc8\x4b\x4a\x3e\xc7\x6e\x8d\x79\x8a\xa7\xbb\xc6\xd8\x89\xae\x74\xd0\x9d\x39\xbc\xd0\xc1\x9c\xf1\xe0\xa1\x70\x50\x7f\xea\x85\x0e\xea\x53\xdd\x3b\xeb\xca\x23\x26\x8f\xfb\xab\xab\xc2\xe8\xe9\x52\xa2\xff\x63\xc7\x99\x62\x89\xa9\x2c\x81\x9b\x82\x2a\x54\x1a\x3d\x5d\xa1\x96\xdb\x8c\x69\xae\x43\x7a\x1e\xe6\x96\x5d\xc9\x67\xd1\x2c\xa0\xa3\x5c\x1b\xd3\xbf\xff\x05\x38\x26\xa9\x4a\xb3\x81\x50\xec\x26\xdc\xa9\x22\x1b\xb0\x95\x64\x22\x97\xa2\x5f\xff\xee\x86\x8d\x77\x89\xc2\x39\x44\x79\x55\xb1\xf2\xe4\xb4\x80\x7c\xa1\x27\x3d\x3b\x0d\x12\x44\xbe\x26\xa7\x67\x64\x3f\x2d\x55\xde\x89\xa2\x02\x74\xe9\xd4\xca\x96\x34\x90\x80\x20\x31\x1e\x46\xea\x27\xf7\xf8\x70\x4f\xcb\x70\x44\x46\x4c\x2a\xf7\xf9\x75\xc0\x5b\xc2\xcf\xb4\x69\x3f\x16\xc8\xaf\x55\x0d\x96\xaa\x28\x4b\x17\x69\x58\x88\xa7\x93\xe4\x30\xac\x34\xa4\x44\x6f\xb3\x0d\x57\xb1\x84\xf5\xd6\x00\x99\x76\x92\xb7\x9e\x85\xcd\x1b\x99\x1d\xdb\x01\x50\xf2\x19\x1a\x2d\x2f\xbd\x2c\x21\xd4\xc6\x87\x40\x2a\x7d\x08\xa4\xca\x87\x80\x5a\x54\x2e\x2b\x7b\x0d\xc4\x17\xbd\xe4\x02\xf4\x9b\xae\xc6\xa4\x76\xe7\xb7\xeb\x74\x21\x49\xbe\x88\x01\xf8\x82\x4d\x4b\x4e\x4b\xaa\x78\x00\xba\x98\x55\x21\xa7\x61\x52\xdf\x20\x4f\xf1\xd8\xba\xd4\x95\xca\x93\x70\x7d\x66\xa8\xa8\xa2\xa7\x8c\xd1\x12\x3a\xcf\xae\xc0\xd7\xff\x43\x2a\x24\x2a\x5f\xab\x93\x8c\xc8\xcb\x03\xfe\x2f\x83\xc8\x17\x70\x5c\x4b\xd8\xa0\xfc\x4f\xd0\xc0\x22\xcf\xd5\xd8\xd4\xf0\xba\xa6\xfe\x38\x8e\xab\xca\x6f\x45\xbf\xa0\xa1\x3f\x9c\xdf\xaa\x9e\x11\xcf\x93\xd2\x0c\xed\x5d\xec\x2c\xf2\xd2\x36\xb2\x8c\x6b\xc8\x12\x2e\x76\x31\x2c\xbb\xd8\x3e\x4e\x12\x7c\xf1\xba\x72\xc5\x5d\x5e\x41\x10\xd2\xaa\x03\x50\x5d\xcd\x4e\xea\x4a\xb3\x02\xbc\xeb\x0f\x3c\x88\xba\xbb\x85\xa6\x1e\x9a\x9a\xe2\xf6\x3d\x8b\xa5\x31\x52\x8b\x2b\x0e\xcf\x27\xe4\x43\x33\x0f\xa8\x11\x89\x19\x6c\xb4\x03\xf4\x00\x07\xb3\x4d\xf6\xc2\xf6\xde\x3e\x4d\x1a\x04\x1d\x27\x28\xc5\xdc\x4e\x07\xda\x21\x1f\x22\xdf\xe3\x51\x1f\xd9\x3f\xa7\xea\x66\x87\xda\xbd\x71\xcb\xe3\x94\xe5\x51\x6c\xdd\x7d\xb0\x35\x91\x33\x9b\x54\xd0\xed\xea\x8f\x36\x50\x2b\xab\xef\x34\xf9\xd3\x0a\x47\x12\x6f\xd2\xc1\x45\x4c\xbe\x2a\x50\xef\x30\xf4\x85\x73\xa1\x6e\x7e\x7b\xb1\xd1\x9c\x0e\x00\x3c\x69\x15\xcf\x27\xd5\xce\x2c\xf0\x34\xe4\xd0\x06\xd0\x29\x20\x67\x3e\x78\xcf\xa4\xd2\x17\x6d\xa3\x91\x38\x95\xeb\xe5\xc9\x82\xd5\x76\x85\x7a\x93\x7e\x09\x1b\x45\x5f\xa2\xb0\x14\x51\xa1\x00\x3b\x98\x4b\xca\xfd\xfd\x43\xb7\xa6\x7b\x92\xde\x60\x48\x71\x43\x7a\x28\x4f\x8a\x9f\x21\x14\x01\xf9\x13\x5f\xf5\x68\x10\x41\x1f\x24\x96\xfa\xda\x36\xad\xb2\xdd\xc4\xad\x57\x8e\x27\xcc\x4a\xd4\x6c\x87\x7e\xd9\x34\xa8\x5c\x0c\x39\xbe\x26\x9f\xa5\x3e\xb7\xd6\x18\xf4\x85\xfc\x8d\x59\x9a\x6b\x2b\x55\x2a\x14\xc8\x49\x91\xb2\xae\xae\xb9\xb3\xb3\xca\x1d\x55\xd1\x99\xe9\xf7\x5f\x2b\x6a\x24\xe3\xc7\xe2\x2e\x3a\xf1\x00\xc8\x85\x15\xcf\x77\x89\x27\x80\x33\x95\xa0\x45\xf3\x85\xd4\x4e\x35\xdb\x60\xdd\x59\x9e\xa5\xa5\x4e\x96\x7a\x38\x33\x1c\x40\x55\x79\xe2\xd4\x5d\x9b\x95\x26\x3b\x15\x7f\x6c\xf2\x54\x07\x95\x2b\x69\x70\x1a\xa4\x59\x03\x28\xd4\xd3\x1b\x62\x9a\xe6\x15\x2f\xb8\xe6\xd8\xdc\x94\xbc\xb2\xc0\xf6\xc4\x02\xb7\x0d\xe8\x8a\xc3\xd6\x97\x56\xa6\x67\xf1\x82\xef\xbc\x45\xff\x6c\x96\x62\x35\xb9\x9e\x81\xc5\x9b\x54\xf2\xd1\x28\xd2\x64\xb9\x8c\x2e\xb3\x7c\x8e\x0d\x7a\xfa\x05\xdb\x1d\xf9\x69\xa1\x57\xcb\x48\xe1\x65\x39\x71\x41\x99\x0e\xa8\xe5\x22\xc3\x3b\x58\x14\xad\x60\x4d\x36\xb9\xc6\xd2\x8e\x21\xef\x92\xbe\x2c\xc5\x1b\x23\xe5\x5b\x8f\xd8\x31\x60\x02\xbd\x89\xde\x6a\xe1\x83\x9e\x63\x2c\x75\xb7\xb5\xfe\x53\x6d\x83\x20\xf6\x8e\xf5\x31\x48\x93\x11\xb9\x68\x36\x57\x57\x9c\x92\xd9\xf3\x60\x78\x44\x64\x2c\xfd\x6d\x63\x73\x22\xf6\x9e\x9b\x53\x17\xab\xfc\x42\xf1\xfb\xb6\x83\x62\xe9\x9d\x4f\x55\x64\x54\x06\x86\xf0\xc3\x50\x07\xb8\xbd\x97\x7a\x64\xbb\x66\xe5\x31\xe0\x81\xbd\x0f\xed\x2c\x10\x8d\xc5\x02\x5b\x76\x81\x93\xa4\x72\xb6\x45\xbd\x7b\x45\xdb\x8f\xa5\xb0\xac\x55\xda\x7c\x80\xda\x78\x19\xa8\xd3\x91\xe0\x51\x4e\xc8\x3c\x3a\xee\x7f\x1f\x6b\xe0\x5a\x2a\xcb\x3f\xbe\x0d\xe5\x9c\xcc\xdb\x5a\xd6\xc6\xab\xda\x58\x25\x38\x2a\x3b\xe8\x2d\x3b\xff\x87\xc6\x99\x8e\x63\xef\xf1\x17\xcd\xf4\x76\xb5\x39\xaa\xed\x51\x0d\xb4\xf7\x16\x58\x64\xd9\x88\x1f\x7b\x9f\x4c\x23\x98\x87\x9a\x49\xd9\x6f\x80\x76\xb1\xfa\xee\x79\xe7\x76\x15\x09\x1e\x2d\xa9\x34\xfb\x85\x95\x56\x10\xe5\xf5\x2f\x47\x7b\xeb\x24\xc1\xf2\x83\xd5\x12\xea\xdb\xa6\x9c\x6f\xec\x55\xd1\xc4\x57\x5f\x2a\x9a\xd6\xaf\x99\x3c\x9a\xa5\xb2\x0e\x2b\xe5\x4d\xec\x48\x71\x1a\x57\x8c\x1c\xf9\xa7\xc4\xb6\xf3\xd3\x86\x9b\x20\x7a\x4b\x7e\x5c\xde\x6e\x4b\x0c\x2d\xb3\x76\x76\x2a\x69\x9a\x5d\xee\x53\xad\xc2\xc3\x29\x78\x53\x47\x04\xec\x89\x2d\x3a\x6c\x24\xce\x0e\x7d\x6f\x01\x5c\x50\xf2\x46\x3d\x46\xc3\x39\xf3\xc7\x2f\x21\xef\xe8\x66\x0c\x2d\xa3\x54\xaa\xa5\xb2\x6b\x9c\xa0\x3c\xf6\x7e\xf8\xe7\x42\x06\xdf\x7d\x56\x78\xf6\xe5\x71\xf5\x80\x6e\xf5\x59\x9e\x1b\x16\xc4\x52\x69\x01\x69\x63\x4f\xdd\x2a\x88\xee\x25\x28\x47\x0e\x97\xda\x8b\xb7\x27\x54\x0a\xa3\xbd\xc2\x4b\x19\x6d\xb7\x1e\xbd\x90\x18\x82\x44\x6e\x5f\x14\x7d\x68\xc1\xd6\xa0\x7a\xdf\x78\x15\x92\x17\x0e\xe8\x50\x9a\x4e\x78\x85\xb9\x58\x80\xc6\x95\x10\xad\xae\xd5\x36\xb3\x99\x67\x48\x6c\xf4\xce\x2a\xc7\x9d\xd2\xb8\xd3\x6b\x3d\x56\x94\x38\x95\x54\xd0\x09\x11\x07\xf9\x60\x29\x10\xa8\x63\xa8\x23\x0f\x84\x2e\x88\x90\x0e\x2d\x62\x1b\x0e\xa9\x02\x40\x5c\x07\xc0\xdc\x02\xc0\xb3\x2a\x35\xda\x6d\x22\xf4\x37\x54\x9e\xe6\x6b\x57\x4b\x13\x9a\x6d\x5f\xf1\x6e\x5f\x40\x0e\xd6\x8c\x64\x10\xf0\x63\x40\x4a\xde\xa5\x53\xb1\xf5\x12\x16\xba\x57\xab\xab\xc1\x9d\x8d\xc1\x92\xf7\xaa\xb4\x5f\x1b\x4b\x65\x5a\xdf\xec\x96\x62\x56\xa0\xb5\x0c\xa2\x9c\x38\x75\x00\xb6\x8e\xb6\xe9\x64\xf5\x7b\x22\x2f\xac\xd7\xfe\xd8\x38\xff\xde\x16\x38\xfa\x7f\x12\x28\xa5\x06\x4a\xe9\xd2\x3b\x5c\x00\x16\x20\x6f\x68\x1e\xd3\x0c\x18\x39\x4e\x66\x5f\x19\xf9\xbe\x22\x1a\x3d\xa1\x9b\x7b\x35\x02\xbf\x79\x4b\x2f\xdd\xda\x0e\x08\x08\x7d\x01\x22\xde\xf7\x89\x6d\x3a\xef\xf6\xe3\x82\xef\x1a\xa5\xaa\xb4\x89\x13\xf2\xd2\x5b\xa9\x32\xb4\xde\xf2\x94\xbe\xf0\x16\x1a\xdd\x18\x34\xb2\xa3\xde\xc3\x9a\xd1\x88\xa8\xbc\xad\xf0\xa4\x78\xf9\x87\x0c\x41\x84\xd7\x0e\x41\xd0\xa5\xf8\xea\x10\xe2\x50\xe3\x54\x33\x32\xa9\x49\x23\x00\x3c\x6d\x44\x18\x85\x35\x66\x67\xaa\x5c\x40\x88\x2b\x3d\xb2\x1d\x4a\xa7\xbf\xa0\xe1\x17\xbf\xbc\xe1\x74\x69\xc3\x89\x69\xb8\xec\x0b\x0a\xeb\x9d\x4e\x9e\x39\x63\x97\xe5\x14\xc8\xd1\x14\x77\xcc\x61\xeb\xb4\x4a\x3a\x46\xf2\x5d\x75\x9e\x65\x8e\xbb\x1a\x91\xf9\xcc\xfa\x26\xa7\x5b\xe0\x30\x7d\xba\xb0\xea\xfd\xb4\xaf\x2a\x51\x76\xb5\xcf\xe4\xe5\x69\x7d\xc5\x07\x4f\x04\xd8\xb8\x28\xd0\xe5\x4c\xc6\xe7\x72\xe0\xea\xaa\xda\x98\x8f\x32\x27\xa9\x28\x5d\xc2\x4a\x37\x55\xc5\xce\x69\x51\xcc\x5a\x4a\x15\xf7\xa5\x2d\x94\x2a\x4b\x47\x79\x14\x2c\xb1\x29\x92\x75\xcc\x49\x0a\x65\x53\x7e\x8a\xe6\xdc\x20\xb4\x4c\xd0\x2d\x0d\x39\x70\x92\x30\x98\x74\x3a\xad\xb1\xf4\x79\x02\xb5\x4f\xa0\x81\x11\x37\xd3\x36\x5b\x75\xa2\xd5\x11\xee\x0d\x00\x1c\x72\x44\x36\xeb\xfb\x03\x27\x27\xf7\x39\x04\x21\xb4\xd5\x89\x6a\x3d\x75\x3d\xec\x67\x8e\x23\x0f\x6d\xdb\x34\xbf\xd3\x19\x0f\xc6\x9c\x06\xee\x41\x5f\xf0\x1c\x00\x6f\xc7\x28\x18\xe1\xed\xac\x98\xfc\xe1\xe1\xdb\x8a\xd5\x1a\x59\xcb\x2f\x8a\x3a\x00\xd8\x90\xb8\x25\xba\x6e\x44\x57\x08\xc6\x6c\x0a\xdd\x59\x87\x01\xc2\xea\x3c\x55\xd6\xf4\x5f\x44\xd3\xe8\x0a\x8a\xd2\x75\xd2\xbb\x79\xad\x75\x6d\xc7\x0c\xb5\x40\x55\x1b\x72\x3a\xc9\x0e\x0e\xfa\x38\x21\xb3\x10\x1f\x5f\xbf\x81\xd6\xda\x33\xff\xfc\x8d\x1f\x0a\x34\x56\x86\x11\x20\x89\x8e\x7b\x2a\x8e\xae\x21\xb8\xd0\x9b\xb6\x50\x0f\x2a\x53\xae\x41\xdc\xd3\xdf\xde\x69\x69\x83\xd0\x1b\xa2\x5a\x00\x2f\x4f\x58\xe6\x08\xa1\x4d\x9f\xc8\x0b\xe2\x06\xb3\xb5\x67\x16\x1e\x84\x95\xdd\x52\x79\x4c\xb4\x49\x8c\xa5\x8f\x0e\x17\x0f\x4a\x98\xa8\xdc\xca\x29\xbd\x44\x2e\x10\xf7\x15\xfb\x70\xe5\x4a\x9e\xae\x60\x6b\x2f\x43\x77\x99\x13\x46\xab\x8e\xd2\xca\x06\xd5\x89\xf4\xc2\x4c\xe3\x1e\x41\xaa\x2e\x01\x2c\x85\xcc\x53\x3e\x47\x9b\x5a\x6a\x46\x4b\x03\x7e\xfd\x90\xe4\x79\x2a\xcc\xf2\x3f\xf7\x51\x89\xeb\x47\x45\x6e\x39\xbe\x70\x4c\xc3\xf0\x3a\xe6\x26\x80\x55\xd4\x78\xb1\x47\x2c\x61\x6e\xac\xee\x2a\x03\x77\xe8\xc1\x70\x1a\xa0\x93\x82\xa5\x2c\x4c\xfd\x20\x2d\x25\x47\xe3\xa5\xbf\xa0\x14\x1f\x5c\x77\x12\x7d\x1d\x31\x58\x32\x6c\x93\x3b\xc3\xdc\x2c\x44\xcb\xf7\x52\xf1\x48\xdd\x20\x7d\xd7\x30\xec\x6d\x51\x9f\xec\x97\x76\x42\xf5\x28\xc7\x2f\x71\xfb\xb9\x30\xbf\xad\x25\x5d\xb3\xe0\x3d\xb7\x17\x1b\x71\x4e\xf6\xa2\x19\x87\x25\x3f\x5e\xd3\x61\x03\xd9\xc0\xdb\x9e\xe3\xda\xe6\x6d\xb3\x1e\xbb\x6a\xb3\xab\xea\xe0\x3f\x5b\xe5\xf4\x9a\x2a\xef\x37\x55\x39\xb2\xaa\x6c\xe4\x5b\x2a\x55\xec\x5c\xc7\x3b\xce\xfe\x28\xb8\x5b\xd6\xc7\x36\xe0\x2b\xd7\x47\x4f\xcd\x46\x2e\x11\xb2\x85\xa2\xc9\x2f\x20\xdd\x1a\x81\x68\x53\x1b\xa0\x07\x19\x4f\x53\xe9\x94\xb7\x15\x91\x96\x34\xb7\xd5\x32\x54\x1b\xa4\x8f\xa4\x4e\x92\x31\xd9\x10\x65\x90\xcf\xee\x09\x9d\x1b\xe8\x31\x7c\x28\x8a\x8e\x57\x15\xe1\x4b\xe7\xe4\x09\x53\xbc\xc8\x3d\x1b\x70\x93\x2a\x29\x2e\x0d\xaf\xf7\x40\x02\x64\xc4\xc6\x29\x74\x40\x9f\x53\xfb\xb6\xf3\xff\x8b\xb0\x54\x84\x28\xb5\xd2\x1f\x7e\x6e\x84\xfe\x6e\x1a\xcd\x2b\xdf\xc7\xfa\x98\x52\x7b\x40\xb6\xba\xf0\xc0\x4c\x8a\xe9\x7f\xb3\x6a\x4b\x29\xac\x74\x2d\xf8\x6e\xaf\x55\xcd\x96\x85\x88\xa7\xa4\xde\xd4\x62\x8c\x51\x86\x2b\xe5\x6f\x69\x3d\xca\xf9\xa7\xea\x93\x4d\xc7\xf6\x8a\x0c\x68\x6f\x2e\x0a\xfa\xdd\x28\x0a\xf9\x46\x8f\x5d\xfa\x87\x6a\xe9\x73\xbb\xf4\x62\xee\x77\xd5\xdc\xcf\x2b\x6d\x75\x3a\x1b\xf4\x86\x20\x3e\xec\x8c\x2f\xf9\x76\x3a\xf5\x0a\x8c\xbe\xb7\xad\x9e\x69\x6c\xa3\xa2\xb7\x5a\xe7\x91\x5e\x42\x35\x87\x77\xeb\xfd\xea\xd5\x93\xba\x3a\x5c\x19\x92\x92\x7a\x99\x4e\xb3\xf0\x47\x76\x00\xbd\x57\xaa\x97\x6c\x5d\x77\xd0\x12\x5e\xab\x59\xb9\x72\x66\x61\x12\xbd\x99\x7a\x2d\x2a\xdc\x46\x1f\x43\x9d\x0e\x99\xca\xd3\x4f\xe9\x9e\x8c\xbc\x4a\xaa\x13\xd6\x78\xa0\x8e\xd0\xf5\x1c\x36\xa9\x37\x93\x81\xf6\x4d\xe9\x7a\xad\x96\xa5\x9f\x7a\xb2\x38\x1f\x8b\xca\x75\x7d\x87\xaf\x3a\x57\x0f\xab\x70\x7d\x69\xd5\xd4\x30\xae\xda\xc3\x5f\x7b\x16\x2a\x5e\xe3\x88\x1c\xf8\xb5\xea\x2b\x62\xd5\x5a\x9e\x5a\x00\x55\xd6\x78\x74\xb9\xcf\x76\x9e\xfa\xa5\x70\xde\x40\xfb\x17\x65\x8e\x91\xa0\x79\x52\x66\xbc\x13\x02\xec\x33\x03\x7b\xe3\x7a\x2f\x23\xd7\x7b\x7e\xe5\xb2\x91\xef\x1a\xcf\x7b\xd2\x57\x89\x2b\x7d\x81\x84\xae\x74\x41\x82\x16\x4c\x74\x30\x88\xe7\x83\x87\x8c\xdc\x82\x50\xed\xe6\xa6\xb9\xf4\xc0\x85\x2c\xb4\x4d\x00\x5e\xd8\xd3\xb4\x13\xd2\x3c\xd1\x15\x4a\xeb\x44\xc1\xce\xa2\xf5\x3d\x40\x7d\xed\x29\x7b\x36\x48\x32\x79\x65\xa5\xbc\xe8\xe2\x7a\x0a\x89\xd5\x65\x16\x44\x6b\x1b\xc6\xf7\x17\xeb\xb5\x6f\x72\xec\xd8\xd3\xbe\x70\x0d\xa4\x89\x22\xbc\xad\xd6\x7f\x72\x3d\x45\xf8\xbe\x9a\xfb\xae\xdd\x5c\xc3\x29\xd0\x62\x05\xa2\x86\x33\x8f\x17\xdb\xb3\x00\x3f\x40\xc0\xbf\x2d\xb3\x3b\x9d\x0f\x62\xbf\x2c\x7f\x58\x2d\xfc\xca\x6e\xbe\xe9\xfd\x06\x4b\xef\x6f\x61\xf8\x35\x7a\x58\xf5\x9a\xd5\xfe\x61\xdd\x08\x7c\xdb\xee\x27\xb9\x85\x7f\x5b\xd3\x6e\xdc\xab\x6d\xd5\x1f\x32\xfb\xe8\x78\x89\x16\x6b\x40\xaf\x3d\xa4\x8c\x16\x8a\xeb\x59\x22\xfc\xa3\x66\xc2\xa8\xfc\xe5\x0b\xbc\xaf\xb0\xc8\x3d\x0a\x65\x08\x1f\xbb\xec\xfb\xcc\xdc\xc9\xb6\x37\x9d\xd7\x8b\x7b\xd7\xc2\x61\xd2\xd3\xb8\x6a\x9c\xf3\xe6\x0b\xca\xbc\xa8\x95\xf9\x54\x2b\xf3\xcb\xf5\xd4\xe5\x69\x0f\x6b\x72\x93\xfc\x71\xb1\x53\xa6\x04\x7b\xd9\x50\xe0\x87\x3f\x65\x8f\x94\x93\x66\x4b\x75\xfe\x05\xdd\xa9\x38\x68\x7e\x68\x23\xd4\x6e\x13\x42\x3d\xab\x32\x49\x80\xb5\xa5\x3b\xd7\xea\x69\xe9\x8d\xcf\xe9\x99\x6a\xb7\x53\xe5\x35\xec\x92\x2c\x33\x5f\xde\xda\x49\xad\xe7\x39\x12\xf9\xbc\x21\xde\x9f\xef\x0b\xd3\xb4\xcf\x72\x77\xe0\xef\xe7\x87\xda\x24\xd3\xc3\x0f\x8e\xaf\x74\x50\xc0\xf8\x42\xb1\x24\xf4\xb7\xcd\x98\xbc\x7f\xd8\xdf\x93\xdb\xb6\x13\x70\xba\x4e\xe1\xd6\xf7\x7c\x81\x0c\x5c\x6d\xc7\x7f\x95\x35\xdd\x1d\xe9\x74\x50\x97\xd0\xb7\xaf\xfa\xd8\x77\x68\x96\xfb\xa6\x8e\xc9\x79\xbb\xf6\x4d\x43\x6f\xdc\x86\x52\x5f\x8f\x3e\xd6\x36\xe5\xe5\x5d\xa1\x3c\x17\xa6\xdd\x76\xdb\xb4\x91\xc9\xc7\x52\xe4\xb5\x14\x64\xdb\x01\x77\xaa\x97\xbe\xd1\xe5\x48\x52\xb9\xec\x03\xfb\x16\x5e\x7e\x51\xb0\xd3\xab\xd6\xb2\x1b\x7c\x5f\x23\x22\xe5\x15\x28\x7b\xcd\x3d\x6d\x3a\x4a\x49\xd5\xeb\x44\xf4\x75\xe5\xda\xea\xc0\xef\x4d\xad\x0b\xb3\x20\xfd\x50\x35\xeb\xbc\x95\x0c\xdc\x60\xe5\x45\x67\x22\xef\x4a\x47\xc7\x74\x3b\xec\x22\x76\xd4\xb5\xa0\x52\xab\x65\xaf\x82\xa7\xbf\xf0\xfc\x30\xf0\x9b\x2e\x9a\xe4\x0b\x17\x8f\xb4\xa3\x42\x61\xd9\xfd\xc4\xf4\xac\x12\x9e\xb5\xec\x87\x0c\x2d\xbc\x0f\x1b\xec\x7c\x84\x5f\x3f\x6b\x50\xfb\xf4\xe5\x95\xd7\xc4\xd0\x0f\x68\x04\x25\x15\xf0\x68\xd8\x9f\xb5\x48\xf5\xab\x53\x6a\x1f\xfe\x18\x87\x27\x8d\x97\xb1\xa4\xf0\x02\xe4\x23\xc4\xa3\xa7\x54\x6f\x82\xf6\x2e\x91\xfa\x8d\xc7\xc2\xe4\xdb\x35\x50\x9a\x3b\xeb\x44\x58\x39\xe6\x42\x87\x16\xea\xf5\x32\x63\x28\x55\xb9\xf4\x1c\xf3\x64\xa0\x4e\xc6\x41\x94\x0c\x71\x3f\x84\xed\x0c\xfa\x81\xb7\xf3\x43\xcb\x97\x93\x72\xe7\x5f\xe2\xa9\x93\x34\xbc\x62\x52\xf5\xda\x29\xfd\x97\x2e\x3e\x13\x91\x58\xef\x25\x4b\xff\x94\xea\xdd\x95\x52\xd7\xb7\x90\xa3\x4e\x33\x7d\x7f\x39\x25\xac\xe8\xdc\xd5\x2c\xb0\x44\x8b\x9e\xa5\xd3\x6d\x54\xb3\x26\xc0\xe6\x6a\xb1\xd2\x7a\x0e\x0a\x2f\xe7\xb1\x80\x6f\xb8\xde\x62\xaa\x20\x0b\x43\x41\xf2\x39\x5d\xc7\xa4\x67\xae\x04\x47\xc2\x83\xa2\x26\x9e\x91\xd1\xc1\xf4\x00\x22\xb1\x96\x75\x3c\xe5\x91\xc7\x55\x31\x30\xd6\xbf\x06\xc9\x48\xfc\x7a\x43\x4f\x08\xba\x8c\xd5\xcb\x0b\xef\x6f\x76\x43\xe9\x40\xd6\xf2\x54\xdb\xde\x08\x56\xdb\x5d\xc7\x09\xf1\xf9\x1e\xa3\xc6\x43\xff\xee\xc2\x2c\xc0\x37\xf5\x8d\x2a\xb3\x61\x18\x70\xb2\xfc\x21\x9b\x46\xf5\xa0\xf3\xba\xdb\x13\xc9\xab\xf9\x3c\x48\xb7\x7c\xb4\x85\xea\x06\xca\x57\x90\xad\x4a\xcd\x97\x55\x92\x06\xa4\x8c\x71\xf6\x04\x1b\x5b\xf9\x87\x66\x5a\x54\x66\xd1\xe5\xca\x7b\xd1\xe2\xb9\x7f\xcc\x1b\xdd\x3f\xa2\x17\x34\x3a\xe3\x2f\xdf\x09\x01\x42\xb3\x5a\xde\xe2\xdc\xc4\x9b\xcd\x55\x23\x23\x98\x4c\x4b\x4b\xd6\xdc\xe9\x07\x86\xd3\x1e\x94\xfd\x9f\xa0\x13\x11\xfb\xed\xaf\x79\x73\xe1\xdd\xa6\xc2\x2f\x04\x6b\x1f\x1c\xdc\xe8\xb4\x2b\x35\x8c\x17\x60\x80\x9e\x55\x6a\x20\x40\xfd\xe1\xa2\xa3\x27\xc5\xf4\x25\x1c\x30\x20\x75\xd7\x6e\xc1\x16\x35\x44\x15\x23\x08\x45\x78\x83\xcf\x52\xf3\x0c\x53\xa7\xdd\x66\x19\xf9\x03\x34\x3e\x9e\x42\x98\xc4\xae\x05\x88\x69\x9d\xee\x95\xe3\x31\x6e\xa8\x6c\x59\x66\xb4\x3c\x7f\xd0\x35\x25\x2c\xb5\xd8\x02\x5d\x5d\x30\x5a\x07\xa2\x96\xd5\x10\xf3\xd4\xb7\x4f\x07\x01\x3b\xe8\xbd\x06\x03\x29\xb6\x41\xef\xcd\x07\x75\xd0\xc4\xfd\x51\xb2\x22\x7e\x7d\x4b\x7a\x24\xa6\xcc\x00\x1b\x81\xce\x4e\x03\xf8\xee\x9f\x4d\xc3\x28\xb0\x9c\x54\x58\x70\x98\x2c\x19\x97\xfd\x20\x4d\x0d\xe3\x4a\x0b\x39\xcb\x03\x42\x13\xb2\x5d\xf8\x4e\xcd\x57\x89\x08\x66\x80\x1e\x22\x78\x11\x08\x01\x72\x12\x3d\x16\x7d\xa4\xfd\x90\x10\xed\x50\x7e\xeb\x98\xe9\xc6\x3c\x76\xe0\xdf\xe5\x15\x3a\x38\xc0\x4b\xca\x2c\x8a\x95\x1a\x19\xdd\xc8\x95\xc9\x71\x2f\x9c\xe1\x5d\xdb\x0c\xf2\xe8\x20\xe6\x95\xee\x75\x72\xbc\x5c\xff\x10\xbd\xa1\x0f\xf1\xc8\x0b\x1f\x5b\x45\x57\x1b\x22\x48\xe7\x09\x76\xa8\x28\x9e\x02\xb6\x73\x7c\xe8\x73\xa5\xcb\x57\x6e\xb6\xd9\x8c\xff\xe0\x3b\x4e\xdc\x0b\xb2\xa1\x3f\xa7\x74\x57\x39\x84\xe8\xb6\x8b\x76\x77\x6c\x7f\x38\x63\x60\x9a\xce\xc5\xe0\x39\x50\xfd\x6a\x36\xac\x00\x8d\x17\x54\x13\x56\xda\x8d\x36\x6b\x4f\xda\x74\xee\xb3\xb6\xf6\xab\x15\x19\xff\xea\xf9\x63\x0e\x85\xda\xe6\x4b\x1f\x05\x99\x08\xaf\x1d\x25\x23\x3f\x9b\x96\xa0\xa4\x94\x6c\xbf\xdd\x5d\xe9\x76\x5f\x89\x6e\xfb\xb0\xed\x76\xdb\x07\x71\xbb\x5f\x2e\xc6\x59\xd5\x17\x26\xba\xed\x41\x26\x56\x4f\xb9\x74\x1d\x01\x4b\x69\x0a\xc8\xa2\x56\x0c\x3e\x62\x60\xca\xef\x08\x36\x92\x47\x6f\x21\x6a\x5f\x21\x5b\xfb\xe6\x4a\xf7\x20\x3e\x3a\x0a\x9c\x76\x37\xee\xb6\x5d\xfc\xba\x09\xa3\xf1\xe9\x89\x0d\x9d\xa7\x0f\xdd\xe8\xfa\xdd\x76\x1f\xb3\x2a\xc0\xd2\xae\xe0\x98\x2a\x1c\xe7\xe8\x48\xac\xf0\x15\xa8\x07\x38\x4b\xd7\x5d\xe1\x9c\x58\x90\x95\xc1\xca\xcd\x9b\x2b\xde\x0a\xa4\x9a\xca\xe7\x3c\xef\x1a\x52\x87\xd7\xb7\x4d\x23\x7d\x79\x12\x87\xfe\x95\xd3\xd0\x3f\x8e\x82\x3e\x9e\x53\xc2\x7c\x9e\x85\x62\xba\xe2\x24\xc7\x1f\xdc\x95\x4b\xec\xcc\x14\x41\x73\x05\x21\x74\x9c\xe0\x64\x83\xa9\x19\xe3\x14\x08\x16\x10\xab\x69\x39\xea\x11\xc4\xdc\xd8\x68\x97\x11\x33\x8a\xe8\x53\x59\xc3\x1b\x41\xc7\x1d\x68\x0c\x15\x42\x08\x78\xd5\x8e\x33\x19\xb4\xdb\xf4\xfc\xdc\x4a\x51\x50\x07\x60\x8c\xf8\x20\x1f\x36\xdd\x6d\x63\x77\x61\x64\x6c\x05\xc1\x02\x50\xb9\x09\x25\xc2\x41\x1b\xbf\x03\xf8\x3e\x52\x58\x07\x35\x40\x6e\xe8\x26\xa5\x60\x15\x77\xd3\xd4\xbf\x28\x79\x8f\xde\x87\x24\x8c\xa1\xce\x92\x44\xa7\x21\xbe\xa0\xbc\x72\xb9\xa2\x00\x0e\xc5\x94\xd4\x62\xf8\x33\x68\xce\x5d\x41\x18\x78\x6d\xd9\x1d\x00\x8a\xde\x64\x8f\xe6\x00\x1e\x09\xce\x0b\x7e\xe6\xdb\x8f\xa2\xa9\x2c\xaf\x7d\x67\xc8\x4e\x4d\x09\x00\xa9\x6b\x84\xec\x08\x5d\xaa\x02\xc9\xba\x50\xf8\xca\xa7\xec\x49\xe8\x5c\xe8\xa3\xb1\x0b\x4d\x7f\x2e\x2c\x3d\x72\x8d\x33\xd4\x2a\x37\x45\xf6\xdc\x81\xb4\x9a\x4b\x6b\xf7\xbc\x35\x9a\xe2\x0b\xf2\x0c\xdf\x7e\xef\xa2\x6b\x72\xda\x51\x99\x4e\xcb\x89\x96\xb2\x21\xfd\xa0\xd3\x79\x7b\x27\xda\x5a\xd2\xae\xa1\xeb\xa6\x89\xe6\x0e\x60\xc3\x1e\xb5\x80\x8c\x47\xa5\xea\xe3\xcf\x56\x7d\xfd\x98\xd6\xcd\x80\xca\x98\xa1\x6e\x89\xa2\x2d\xe5\xf5\x35\xbc\x9e\xc5\xe9\xdd\x05\xfe\xeb\xb1\xe6\xee\x40\xbc\x41\xee\x97\x9e\x05\xd6\x9c\x56\x3b\x0b\x80\xa9\xf2\xb5\x3f\x2d\x7a\xcf\x57\x45\x78\x61\x9f\x8e\x49\x70\xd5\xc9\x44\xb3\x08\xd1\xf4\x99\x8e\x49\x92\x59\x98\x65\x28\x28\x50\x3a\x48\x8e\x3d\x1d\x83\x2e\xa7\xa4\x9b\x76\xc9\xe6\x59\x3b\x1a\x6c\xf2\x8b\x77\xed\xa4\xe0\x9d\xae\xda\xda\xd2\x8d\xcd\xac\xbc\xd0\xa7\x6e\x6b\x1a\xc8\x64\x6e\xc9\xb5\xea\x8b\x34\x2b\x79\x37\xc1\xd8\x93\x90\xde\x2d\xc0\x26\x55\xfe\x0c\x28\x70\xe0\xa7\xe8\x6d\x4a\x8d\x9d\x0c\x03\xaa\xf5\xa1\xb8\x15\xf6\x26\x51\x72\xec\x47\xf4\x7a\x0e\xec\x04\xa1\xf6\x06\xe4\x68\x77\x40\x21\x0a\xbb\xb8\x98\x81\x8a\xe3\xfb\x0f\xa5\x63\xa0\xf5\xfe\x90\x87\x32\xd3\xdc\xed\xbb\xe8\xd7\x8d\x18\xb2\x7e\xce\x73\xd3\x8e\xec\x71\x34\xc8\x3c\x58\x35\x57\xfa\x8e\x64\xc9\xba\xc1\xf6\xe6\xb6\xb8\x72\x1a\x46\x6e\xf2\xad\xad\x36\x84\x4e\x92\x33\x1b\xc7\xae\x72\x5c\xca\x9c\x00\x00\xeb\xcc\xa2\x99\x6f\xbb\x68\xe2\xdb\x4e\x05\x3b\xaf\x60\xd8\xd1\x67\x19\x99\xca\x86\x1d\xf4\x66\x3e\xf9\x8a\x2a\x8a\x13\x54\x07\xd8\x97\x65\xce\xa8\x1f\x22\xbd\xa8\x9f\xf9\x1d\x2d\x5e\xf7\x19\xfa\xca\xe3\x94\xca\xfa\x24\x94\x36\xa2\x28\x8b\x3d\x42\xd5\x84\x75\x40\xf8\xe4\x0b\xbb\x48\x07\x4c\x4f\xc9\xbd\xc5\xac\x2e\x12\xbc\xb4\x61\xb4\x48\xf5\x02\xab\xb9\xbd\x0a\x38\x2d\xd5\xbf\x1d\xff\x2a\x76\xd4\x79\x97\x2d\x9a\xbd\xf0\x2b\xea\x2c\xfd\xda\xe8\x29\xd9\x59\x56\x72\xee\x9a\x31\x95\x32\x99\x26\x28\xb4\x72\x95\xb7\x11\x7d\xb8\x00\x92\x96\xb9\x15\xb2\x1b\x4b\x37\x4a\x0e\xbe\x0d\xa6\xdd\xfb\xbb\x84\xc9\x2d\xd4\x1f\xe0\xc1\x1f\x0a\x5f\xf2\x52\x8d\x7c\x20\x8a\xca\x48\x0d\xac\xbe\x49\x06\xbb\xb8\xf2\x46\x42\x07\x29\x6c\x58\xbe\x16\xa5\xce\x52\x7d\xeb\x2c\xb5\x4d\x57\x4c\x94\x81\x8b\xe3\xa3\xd9\x00\x46\xb8\xda\x7f\x78\x86\x3e\x50\x69\x00\x11\xc7\x77\x5e\xd0\xf0\x68\x3f\x42\xe7\x32\xd1\x21\x9f\xa3\x35\x96\xed\x20\x19\x23\x1b\x0e\x89\x6b\xc6\x09\x31\xaf\x5e\x6f\x21\x5b\x3a\x64\x13\x35\xe5\x5d\xb8\x85\x62\xae\xc6\xa5\xf6\x55\x14\x54\x24\x2f\x5c\x4f\x71\xa5\x8a\x8a\xac\xc7\x3c\xb2\x91\xc9\x3c\xcb\x68\x44\x3e\xb5\x00\x2b\x05\xef\x9b\x97\x77\xa2\x80\xbb\x52\x16\xda\xfb\xf6\x4d\x19\x63\x2c\x6b\x9e\x71\x48\x2c\xeb\x02\x26\xcc\x13\x6e\x09\x20\x36\x50\x8d\xa6\xd7\x72\xef\xfb\xb6\xf7\xfb\x23\x9e\x66\xb5\x37\xe7\x77\x30\x83\x75\x8c\x61\xe3\xa3\x7e\xe1\xd6\x3a\xb7\x68\xc4\xf8\xfa\x13\x33\x5a\x47\x63\xe1\xff\xe3\xcf\xea\x17\x8c\x9c\x5f\x4a\x11\x1b\x4a\x78\xd0\x87\xdc\x0b\xf2\x7f\x5d\x3f\x8b\x6e\x5a\x33\x07\xc5\x7d\x77\x0d\xef\x93\x03\x51\x40\x8b\xd6\xc6\xc7\x54\x50\xca\x29\x5d\x83\x59\x67\x23\xf6\x22\x22\xf7\x66\x1b\x9b\x4a\x78\x32\x6e\x22\xd4\xbd\x50\xd5\x2a\x54\x8e\x8a\x06\xb6\x9b\xa9\x37\x3a\x8c\xf2\x6e\x43\xb6\x19\xf4\xdd\xdd\x6c\x33\x1d\xa0\x6a\x98\xe3\x13\x3a\x1e\xbd\xa3\xb3\xa8\x58\xfb\xe0\x97\x87\x2d\xdd\xae\x30\x4e\x60\x31\xba\x2b\xae\x02\x80\xec\x5b\xd1\x03\x09\xdf\xcf\x23\x91\x39\x3f\x88\xde\x1e\x1d\x29\x3a\x00\x3d\x06\x29\xf3\x70\x78\x02\xb1\xec\x31\x9e\x89\xfc\x20\x85\xe4\x6d\x1f\x36\x2a\x62\x01\xd9\x3d\x0c\xde\x07\xfe\x9f\x3d\xc2\xd0\x83\x34\x4d\x52\xf6\x1a\x83\xdb\xaa\x07\xec\x0d\x7e\x3d\xf1\x81\x57\xfe\x84\xa1\x5d\x3a\x09\x63\x1f\x31\x2c\x9b\x62\x3f\x60\xf8\x79\x30\x79\x70\x3e\x67\xef\x30\xfc\x82\x8e\xaf\xd8\x43\x0c\xe3\x79\xb6\xac\xf6\x19\xfa\xc9\x29\xd7\x26\xbb\xe1\xf3\x8f\xf6\xf7\x5b\x9f\x3b\x6f\xb1\xc8\x19\x6c\x5e\xc9\x19\xa0\xc2\x5b\xbf\x37\x4a\x86\x84\xdd\xec\xbd\xcf\x5f\x5b\xb9\x7b\x22\x51\xad\x7c\xef\x73\xc0\x4a\xcd\x59\xc0\xb0\x33\x7e\xc3\x47\xc3\xa1\xbd\xb3\xf8\x69\x9a\xcc\x83\x54\x5c\x30\x91\xe1\xed\x6e\x4a\x31\x05\xd3\x0c\xda\x3a\x62\x49\x86\x1b\x73\xfb\xc7\x76\x77\xee\x3b\x71\x56\xf2\xe9\x6b\x3a\x67\x61\xf8\x57\xb7\xf7\xd5\xc0\x19\xf0\x83\x83\x03\xc7\x2d\x56\x60\x62\x57\x7a\x5d\x15\x71\xe8\xae\x4d\x90\xaf\x87\x1c\xb8\x9b\xdf\x80\x9e\x84\x19\xdf\x05\xd6\x21\xd3\xd0\xbe\x47\x1e\x07\x51\xed\x97\x31\x9f\xd2\xe0\x6f\x98\x75\x3a\xa4\x19\xcc\x50\x5f\x44\x7b\x30\xe4\xf0\x33\x96\x65\xfc\x8d\xdf\x1b\x06\x61\xc4\x72\xac\x62\x18\x01\xc7\xf1\x32\x9c\x05\x49\x2e\xd8\x90\x12\xc7\x51\x02\x70\x8d\xa8\x2a\xf8\x0b\xd0\x9c\x04\xe2\xa9\x06\xd1\xde\x18\x7d\xb7\x65\x6c\x9e\xf1\x67\xf2\x35\x29\x36\x26\x08\xcc\x15\x54\x76\x32\xd4\xfd\x07\x29\x4a\x3a\x6c\x4a\xb5\x4c\xb1\x25\x10\xab\xa1\xe4\x34\x63\x23\xfc\xca\x02\xa1\x5b\x9d\x51\x4d\xd2\x1e\x80\x9d\x52\x81\x53\xcc\xf2\x0a\xa4\x85\x6f\x69\x88\x50\xee\x34\x63\x13\x4a\x9a\x60\xd2\x9b\xc0\x3f\x79\xe2\xcf\x21\x7e\x92\xb1\x8b\xcc\xb6\x0b\xc3\x1d\x5c\x22\x36\x64\xc6\xa3\x0a\x52\xc5\x7d\xf3\x1b\x5d\x91\x50\x3e\x32\x85\xa3\xe0\xb3\x01\x0b\x77\x1d\x56\x10\x24\xa9\x8d\x3d\x05\x42\x65\x94\x11\x80\xf2\x0f\xa8\x61\xf8\x0b\x88\x86\x84\x55\x56\xf4\x20\x63\x5b\x94\xb0\x45\x30\x1a\xa6\x01\x20\x3c\xc4\x6f\x65\xec\x18\xfb\x18\x66\xdb\x61\x1c\xc2\x1a\x38\xa7\x5c\xe7\x94\xeb\x24\xb8\xc0\x37\x80\xce\x33\xf6\x9c\x60\x3d\xf3\xcf\xd9\x91\x0c\x85\x31\x3b\xa3\x9c\xf0\xf7\x9e\xdf\x8b\x09\x57\xcf\x32\xf6\x84\x22\xe1\xef\x27\xdf\xd4\x89\x06\x0e\x19\x7b\x89\xcd\x90\xba\x71\x07\x50\x79\x8f\xaa\x49\x7d\xc0\xf2\x19\x7b\x4a\xd9\x77\x1f\x3c\xbc\xfb\x72\xe7\xf5\x83\xa3\x9d\xdd\xed\x9d\xdd\x9d\x97\xef\xd8\x0b\x8a\x7f\xba\xf7\x62\xa7\x1a\xbf\x4b\x85\xe7\xc9\x99\x73\x8b\xdd\xbe\x85\xaf\xd3\xde\x87\x66\x33\xf8\xdd\xc1\x5f\x7a\x44\xe7\x24\xe3\x17\xd9\xe0\x22\xeb\xdd\x7b\xf7\xf2\xc1\x8b\xa3\xa7\x0f\x9e\x1f\x3d\x78\xfc\xe0\xc9\x83\xdd\x97\xde\x3a\xbb\x6b\x55\xf0\xf5\x6d\xac\xe0\x71\xc6\x27\x0a\x0b\x61\x92\x5e\x65\xa5\xc7\x31\x54\x46\xb7\xac\x29\x7b\x95\x59\x1e\x26\x79\x0b\x4f\xe6\x7b\x6f\xc2\xf8\xf9\x4b\x5a\xe1\x30\x56\xed\x38\xf2\xb9\xcb\x54\x5e\xf2\x33\xc9\x17\x4e\xb4\x61\x2d\xa3\xcb\xca\x3e\x22\x01\xe4\x04\x48\xf0\x0d\x34\x82\x79\xab\xe7\xe7\xbe\x5a\xf8\xdb\xa9\x3f\xc1\x5f\xc7\x35\xe6\x31\x25\x57\xa7\x4a\xb6\x36\xae\x54\x3d\xd6\x79\x16\x6f\x8d\xb3\xba\xcc\xba\xe1\x56\xca\x56\x72\xaf\xc3\x8e\x49\xb7\x1d\x16\xf5\x4b\xfc\x52\x0a\xd2\xde\x16\x30\x37\x4a\x0f\xe3\x1d\x0b\x66\x69\x7e\xbc\x73\xc1\xb4\xd6\x00\xc4\x6d\xa6\x54\x47\xde\xe5\x11\xba\x82\x25\xb2\xfb\xa1\x82\xfd\xe5\xd1\x89\x53\x22\xb1\x49\x97\x7b\x8d\xf4\x86\x79\x29\xac\x53\xb5\x58\x2b\xdd\x71\x61\xf4\x2b\x29\xe8\xfd\xbc\x54\xc5\x04\x66\x23\xb8\xc2\x95\xb1\x9d\xf1\xc7\x59\xf9\x7c\xa1\xcd\x3e\x3e\xce\xc8\x50\x92\xa4\xdc\xe0\xca\xdb\xf3\xfb\x3e\x3a\x06\xfd\x3e\x26\xda\x74\x6a\x97\x2a\xfd\xc6\xa2\x77\xd4\xc7\xda\x93\x2d\x20\x1b\x29\x0a\x4f\x32\x97\x7c\x96\xc5\x5f\x9d\xa0\x27\x63\xb5\x6c\x85\x14\xad\xcc\x79\x12\xc4\x5e\xa0\x1d\xf6\x3a\xde\xe5\x0c\xa9\x6d\x15\x17\x50\x5c\x79\xe2\xd5\x42\xde\xd4\x91\x45\x4e\xb1\x48\x8a\x12\x92\x2e\x70\xaa\x5c\x92\xe2\xb5\x34\x0f\x18\x6f\x69\xac\x4e\xf0\xb9\x97\xf1\xad\x0c\x49\x58\xa5\xef\x9a\x52\x40\xd9\x77\x28\xaf\x94\xa5\xd8\xa3\x1a\x78\x6c\xe0\xa0\xcd\x29\x66\xde\xf1\xd9\xeb\xca\x14\x4a\x0b\x60\xf4\xfe\x6e\x6c\x1f\xca\x09\x2c\xf5\x95\x64\x1f\x1f\xf2\x0f\xab\x4e\xb2\x2a\xd4\x41\x52\xc2\xc2\xcd\x75\x9a\xe3\x6e\x37\xd8\xe4\xaf\x8c\x0a\x56\x8a\x70\x41\x59\xe3\x76\x46\x75\xd1\x24\xbe\xc9\x78\x9c\x3a\xf6\x24\x92\x0e\xdc\x9c\x89\xc6\xee\x00\xaa\xc3\xbb\xf9\xf4\x12\xe0\x06\x30\x95\x9f\x3e\x5f\x84\xcc\x83\xd5\x6b\xac\xb2\x20\x32\x6a\x2e\xfb\xd8\x5c\x94\xce\x46\x21\xf9\x87\x8c\x67\xa9\x93\xc6\x2e\x7b\x47\xa1\x84\xcc\x16\xd8\xc3\x65\xa5\x06\xeb\xde\x86\x69\xe7\x6a\xf1\x76\xd3\xfe\x3e\x9a\x27\x62\xc3\xcf\x32\x7e\x06\x18\xb8\x90\x83\x66\xfd\x9e\xef\xe2\x8c\xe0\x96\x04\xa8\xcd\x6e\x64\xfc\x81\x9d\xf7\x7a\x0b\x18\xdb\x7c\xe6\x23\x19\xc0\xf4\x25\x09\x01\x7c\x7f\x1e\xf2\x86\x5a\x96\xda\xe6\xb5\xde\x67\xda\xa2\x48\xe2\xdc\xdb\x8c\x3f\x69\xec\x49\x93\x0f\x59\x62\x1d\xaf\xfa\x78\x0e\xb8\x76\xbe\x86\xf6\x76\xf8\xf8\xef\x4b\xdc\x4f\xc9\x0b\xd5\xcb\xc6\xce\x54\x2c\x9e\x54\xb3\xef\x33\x1e\x55\x31\x57\x79\x20\xaa\xf8\xc9\xac\x7a\xb4\xc4\x05\x4c\x12\xc5\xde\x18\x56\x2f\xee\xbe\x52\x6b\x1e\xd1\x69\x00\x32\x0d\x96\x1f\x9a\x78\x10\x70\xbc\xb0\x12\x65\xd4\x6e\xec\x91\x87\xce\x2b\xf8\x61\xdf\x67\x3c\x4d\x9d\x39\xa0\x40\x90\xf3\xf3\x85\x5e\x04\xae\x6e\xcc\x36\x20\x88\xeb\xa7\x54\x4b\x1c\x4e\x57\x4d\x09\x8a\xa2\xc9\x48\x17\x66\x94\xa6\x18\xb0\x98\xdc\x6a\x7a\xd2\xa7\xe4\x79\x26\x2d\x8f\xae\xbc\xfb\x29\x13\x39\x76\x72\x1b\x8f\x71\x72\x1e\x2e\xa2\xa6\x39\x5e\x07\xba\x9f\x3c\x4e\xce\xf4\x69\x1d\x48\x03\xf8\x0a\xdd\xd2\xc3\x3c\x61\x0e\xf3\x3c\x41\x46\x02\xd7\xd5\x4e\x75\xb5\x57\xa5\x26\xb6\xd6\x10\x4c\xe4\xb7\x2d\xfe\x32\x73\xee\x8a\x6e\x7b\xfd\x5b\xf2\x5c\x3a\xf3\x79\x73\x4d\xcd\xfe\x2a\x81\x02\x79\xf2\x05\x4a\x7c\x79\x32\xe0\x0f\x48\x89\x22\xcf\x85\x00\xb5\x9f\x94\x2a\x9a\x8d\x6f\xbc\x0d\xd4\x10\x48\xe4\x49\x3e\xdf\xe7\xa3\x25\x7d\x66\xe1\xe7\xcb\xae\x28\xcd\xf3\x97\x00\xd1\x7a\x46\xcb\xb6\x22\xf9\x80\xce\x65\xad\x07\x8f\x26\xd5\xb4\x78\x49\x9a\x8d\x71\x7c\xc2\x1e\x59\x75\xec\xb7\x47\x41\x14\x88\xa0\x7d\xc8\x5f\x8b\x4a\x0a\xd2\x15\xfe\xa6\x16\x07\x82\x04\xff\x54\x8b\x83\x1d\x88\x7f\x14\xec\x9d\x1d\x87\x84\x8d\x3f\x03\xce\x5c\x5d\x2a\xe0\x8f\x04\xca\xe3\x63\xe0\x10\xf8\x8d\x04\x83\xe9\x05\x7f\x4b\x81\x2c\x0b\x27\x31\xff\x3e\xc3\xb0\xe0\x7b\x18\x77\x1c\x80\x30\x11\xf0\xf7\x14\x06\xf1\x87\x7f\xaf\x43\x77\x61\x8a\x83\x50\x7d\xfc\x10\x5c\x70\x81\x1f\xda\x5b\x3f\x7f\xe2\x33\x21\x55\x24\xfc\x41\x42\xc1\x3c\x3e\xe1\x8f\x53\x0c\x02\x8f\xe6\x0f\x05\x7f\x25\x3f\xc8\x15\x88\xe0\x2f\xa9\x40\x92\xc7\xe2\xde\x05\x7f\x83\x7d\x90\xfc\x16\xbf\x47\xf5\xe6\x29\x74\x33\x36\x41\xf2\x76\xcf\x53\xfc\x1e\x05\xc7\x50\x6a\x18\xf0\x44\x7e\x49\x89\x93\x3f\x52\x5f\x30\xcc\x50\x06\x23\xff\x82\xfb\x14\x0c\x51\xde\x09\xb0\xcc\x07\xec\x03\xba\xdd\xe7\xdb\x3a\x24\xab\xbe\x57\xf9\x7c\x83\x27\x8c\xfc\x91\x8e\x93\x9f\xaf\xf1\x73\x1c\x02\x1c\xde\xa8\x10\xc2\x74\x17\x47\x3b\x06\xd6\x4b\x04\x31\x7f\x97\x96\x1f\xf7\x83\x60\xce\x1f\xca\x88\xe4\x8c\x67\xa1\x0a\xc9\xf6\x72\xfa\x4c\xd2\x07\x30\x47\xfc\x6e\x52\x7e\xc8\xe4\xc7\x2a\x66\x27\xe6\x9f\x42\x1d\x94\x49\x1f\xd5\x37\x88\x95\xfc\x87\x32\x2c\x13\xdf\x51\x84\x5a\x0b\x19\x7f\x88\x9f\x93\x34\xc9\xe7\x00\xe4\x4f\x08\x64\xd2\xc7\xc2\xc7\x47\xf9\x11\x8a\xd0\x8f\xf8\x8d\x94\x3e\x04\xba\x4a\xa1\x92\xfc\xad\x8c\x39\x05\xf1\x8c\xdf\x08\x65\x38\x39\x09\xf8\x2b\xec\x17\x8a\x24\x3c\xc8\x55\x68\x07\x5d\x07\x33\xbc\x2d\x30\xe7\x1f\x12\x19\x78\x8d\x44\x3d\xe3\xef\x65\x3c\x30\xba\xf0\xf1\xd4\x2f\x3f\xb4\x3c\xcc\x5f\x50\x64\x30\x4b\xc2\x4f\x01\x1f\x52\xf6\x20\x9d\x04\x5c\x60\xed\xb3\xf0\x1c\xd0\x69\x17\xb3\xc4\xc1\x04\x71\x23\xc2\x1c\xc9\x2c\x14\xfc\x7b\x0a\xe1\x94\xce\x31\x34\xf7\x43\x14\xa3\x7d\x0a\xa6\x34\xa8\x71\x58\x7e\x48\xe0\x4c\x4d\x0c\x8d\xf1\x21\x82\x00\xf5\x12\x5c\x50\xb9\x28\x87\xe0\x36\x8e\x40\x0b\xa6\xfc\xc4\xb7\xbe\xf6\xc6\xfc\x2e\x7d\x23\xb5\x0b\x12\x15\xba\x0b\x04\x1b\xc3\x20\x46\x41\xbf\x1f\x63\x06\xc0\xe3\x74\xc2\x47\x21\x05\x91\xf7\xe5\xaf\x29\x07\x0c\xf3\x14\xf8\x63\x19\xce\x00\x9d\x31\x94\x4d\x41\x1a\x07\xec\xfa\x44\x1f\x48\x84\x78\x42\x41\x60\xdb\x61\x9e\xde\x95\x61\x5c\x81\x0f\xe9\x73\x0e\x2d\x8c\xf8\x0c\x1b\xc0\xa7\x20\x78\x96\xa8\x90\xc2\xad\xca\xa7\x44\xde\xa1\x8e\x93\x9f\x91\xfc\x9c\xf3\x2d\x0a\x4c\x81\x7c\x08\x88\x3e\x0d\xe5\x57\xce\x8f\x29\x3e\x44\x99\xe9\x15\x8e\x49\x24\x24\xc5\xf2\x0f\x94\x23\x79\x1a\xc1\x4a\x97\x8c\x3d\xdf\xa6\x28\x18\x7f\x06\x98\x38\xe3\x29\x66\xcf\x63\x84\xf0\x3c\x91\xc1\x8f\x7c\x2c\x43\x9f\xc2\x39\x9f\x62\xf0\x54\x22\x48\xe2\x9b\x30\xa0\x51\x88\x5f\x67\x53\x58\xaa\xfc\x19\x66\xc2\xd3\x4e\x10\xf7\xf9\x8c\x3e\x52\xe8\xed\x04\x9b\x3a\x07\x52\x7a\x8a\x51\x58\xdb\x44\x05\x54\x5f\x2e\x88\x5c\x01\x41\xa2\x35\x47\x8b\x6c\x98\x44\x11\x26\x11\x6e\x22\x2d\x4a\xb2\x40\xa6\x04\x66\xed\x05\xd5\x85\x17\x9c\xc3\xfa\x1d\x49\xca\x88\x97\xf7\x01\xf5\x02\x49\xe1\x66\x01\x74\x69\xa4\x16\x56\x62\xb5\x99\x05\xd4\xc8\xae\x84\x6b\x18\xc9\xc9\xc5\xb1\xe7\x01\x8e\x7e\xd7\x77\x04\x0a\x36\x48\x6a\x51\xac\x13\xfc\x8c\x08\x20\xc8\x9e\x11\xee\x41\x20\x36\xd1\xe7\x3c\x14\x7e\x84\x8b\x21\xa3\x64\xf4\x32\xcd\x2f\x42\x1d\x24\x9a\xf2\x40\x51\x41\xa0\x8b\x3c\xc7\x5c\xd0\xd7\xec\x0d\xc0\x8a\x0f\xe9\x8b\x44\x44\x1e\x95\x61\xa9\x12\xe3\x73\x8a\x81\x25\x0d\xcb\x8e\xc8\x0b\xd2\xf7\xfb\x3a\x24\xcf\x7a\x3e\xa5\xea\x13\x29\xfc\xeb\x50\x7d\x3c\xf6\x01\x5b\x77\x12\xeb\x4b\xe6\xfe\x98\x5a\x51\x58\xe2\x8d\x2e\xf1\x86\x66\xf1\x44\x16\x49\xa1\xf4\x0f\x98\x15\xf7\xb0\x67\x44\x4d\x46\x20\x06\x87\xb0\xc0\xf6\x7c\xa2\x2d\xc3\x28\x1f\x21\x89\x48\x98\x79\xb6\x85\x3f\x23\x12\x84\x5a\x69\x29\x34\xf3\xad\x50\x45\x20\x1e\xde\xa0\xb9\xc9\xee\x49\x93\x2d\x7e\x2c\xd3\x50\x83\xc8\xcf\x65\x58\x5d\x50\xe1\xcf\xd5\x27\xc0\xfc\x82\x1f\xa9\x8f\x8f\x39\x50\x88\x33\xf5\x81\x3a\x03\xfe\x44\x7e\x48\x6d\x09\x7f\x2b\xab\xd7\xca\x47\xfe\x52\xa6\x3e\x41\xf2\xc5\x9f\xca\x8f\x5d\x7f\x97\xbf\xd0\x41\x11\xc2\xd2\xde\x55\x5f\x48\x20\xee\xeb\x30\xf2\xdc\x7c\x47\x7e\x29\x2c\xdd\x93\x5f\xf6\x22\x7a\x2f\x1b\x54\x53\x75\x22\x33\x48\xb5\x1f\xbf\x2b\xbf\x90\xeb\x1f\xc9\xd1\x3f\x96\x31\xaf\xb4\x49\x15\x7f\x15\x12\x35\x3e\xf6\x8f\x09\x99\x52\x44\x26\x3c\x61\xe3\xef\x53\x15\x52\x67\x6d\xfc\xfb\x94\xc8\xf0\x39\xff\x21\x23\x12\x0b\x9b\x16\x06\xe2\x64\x2b\x89\xc7\x40\x7e\x04\xbf\x4f\x04\x37\x81\x3d\x72\x47\x86\xce\x40\x74\x24\xca\x39\xe2\x63\x49\x61\x47\x8f\x83\x31\xd0\x53\xf5\x21\x57\xce\x48\x11\x5f\xd2\x2d\xf1\x99\x2f\x69\x22\xaa\x45\x7c\x49\x14\x47\x39\xd0\xb6\x7b\x89\x09\xcb\x62\x8f\x64\xc4\x1c\xf6\x7e\x7e\x2a\x33\x66\xb0\xa1\xf3\x98\xc2\x79\xbc\x13\x43\xc7\x04\xac\x48\xfe\x1c\x97\x19\x2e\x8d\x8f\xb4\xe0\x62\x20\x66\x34\xd8\x24\x27\x12\x39\x0b\xf8\x0f\x9a\x58\x06\x0a\x9d\xc3\x32\xa2\xc4\x5a\x9f\x22\xf1\x8d\x1c\x2a\x1e\xe6\xfa\x53\x2e\xa2\x09\x91\x3b\xa5\x79\xe1\x17\xf4\x95\x86\x33\xe0\x65\x55\x88\xc6\xbe\xa5\xbf\xe4\x28\x8e\xe5\x27\xa0\x0b\x3f\x97\xf4\x4f\x2d\xc3\xe7\xbe\x21\x03\x3b\x23\xfe\x81\x28\x5c\x92\x02\x05\x39\xc2\x20\x70\x4f\x72\x2d\xfa\xf1\x85\xec\x3d\x3a\xcc\x05\xac\x50\x6b\x61\x04\xfc\x21\xce\x88\xe4\x06\xa2\x51\x24\xe1\x87\xc1\x54\x42\x6e\x8a\x3b\xc1\x0f\x69\xb9\x8a\xf4\x22\x22\xac\xba\xa7\x08\xcf\x82\xb2\xa0\x34\x42\x7e\x1a\xdb\xe9\xf2\xad\x6a\x8b\x49\x4d\x0f\xd1\x98\x1b\x4f\x07\x62\x64\xb6\x03\x14\xff\xd1\xf4\x11\x40\xe6\x03\x88\x02\xfe\x46\x6d\x98\x9a\x25\x95\xb1\x0d\x42\x63\xf5\x6c\x4b\x7b\x71\x0c\x06\x0d\x1e\xdc\x4a\x9d\xd0\x9b\x04\xcf\xf1\xa0\x65\xef\x4d\x52\x71\x8a\x07\x22\xb7\xe8\xbd\x7e\xf0\xfc\xc5\xce\xde\x2e\x3f\x63\xef\x85\xb3\xdf\x46\xce\xb4\xcd\xda\x8a\x41\x85\x10\xb1\x8e\xfa\x57\x3e\x98\xc4\xda\x8a\x25\x28\x43\x32\xe1\xb0\xe2\xf3\x05\x7d\x1b\x56\x1c\x33\xa0\xa6\x81\x1a\x91\x6c\x1f\x94\x06\x36\x07\xfe\x9a\x2d\xb5\x52\x41\x69\xf4\x26\x38\xdf\x46\xbf\x7c\x9c\x3f\xea\x5b\x72\x01\xba\x4e\xb4\xb2\x97\x2f\x09\xe3\x10\xd5\xdb\x02\xf4\xa2\xd4\xd1\x91\x6c\x90\x7c\xce\x65\x14\xa1\x77\xa4\x0c\xa1\xe8\xd4\x62\xc8\x61\xa2\x3e\x3a\xaa\x94\xe6\x78\x94\x58\x14\x29\x5a\xfb\x1e\x1d\x8d\xc2\xf4\xe8\xe8\xce\x3a\xcb\xd4\xb1\xa0\xae\xc2\xa3\x17\xb9\xe8\xf5\x62\xec\xa7\x27\xe8\xbd\x2e\x3d\x78\x7a\xc6\x4a\x0e\x7a\xc9\x78\xdb\x47\x47\xed\x6e\xd0\x6d\x6f\x21\x67\x0f\x61\xbc\x18\xde\x6d\x4b\x08\x2d\x05\x00\x1a\x8d\xeb\xd7\x5c\xe5\x9b\x07\xc3\x8c\x1c\xd9\xa1\x1e\x54\xd9\x49\xda\x90\x41\xdd\x55\x52\x19\x9c\x86\x1f\x3e\x6a\xdf\xa7\x97\xed\xc5\xe0\x48\xba\x63\xf0\xc2\x6e\x4a\xda\x2c\x7d\xf5\x0c\x0a\x9e\x86\xc1\x99\x04\x9f\xf5\x45\xa0\xf3\x15\x3c\x90\xd0\x78\xa9\x84\x01\x08\x91\x49\x09\xb2\x41\x5b\x3d\xbd\x85\xc7\x8f\x96\xaf\x49\x56\x19\x5d\x57\xe5\x6a\x3c\xf7\xa5\xb1\x18\xd7\x84\x00\x0a\x48\xb3\x5c\x15\x36\xd6\xa4\x90\x8c\x57\x81\xde\x5c\x61\x7a\x48\xa9\x56\x95\x25\xf6\xc2\x66\x0c\x33\x88\x3b\xc2\xb2\x19\xa4\xd9\x05\x61\xd9\x1e\xe8\xd2\xa9\xab\x74\x01\xe0\x0e\x12\xb4\x5e\xa2\xe8\x52\x40\xb7\xab\x24\x0d\x68\x19\x39\xdf\x65\x2d\x13\x7a\x51\xcb\xd0\xa8\x6c\xfc\x17\xb5\x6c\x9a\x23\x5e\x1e\x1a\x23\x66\x72\xd9\xca\x1c\xe8\xb5\xec\xc9\xb5\x0c\xab\x74\xf0\x2a\xf6\x1e\xc5\xcb\x17\xea\x42\x9b\xe4\xbf\x11\x9b\xad\xca\xfc\x52\xe0\x6d\xee\xaa\x12\x1c\x9d\x3d\xbf\x3a\xd3\x96\xa4\xd9\xd0\xdd\xd2\xe8\xea\x54\xaa\x5d\x6e\x2b\x67\x98\xaa\x36\xcb\x22\xd2\x36\xcc\xc7\xd7\x93\x62\xde\x0a\x54\x34\x22\x6c\xa5\x4d\x25\x9f\x34\x22\xd5\x17\x34\x65\xdf\xf7\x08\xd4\x77\xbd\x09\x29\xd3\x54\x5b\x08\xcc\x95\x89\x75\x8f\x8e\xd6\x95\xb7\x86\xf5\x4d\xbd\x1f\x68\xe9\xc5\x59\x0d\x94\x93\x4f\x04\x4f\x79\xfd\xae\xe9\x4e\x97\xd6\x3c\xc9\xa3\x7a\xf4\x6e\x12\x97\x22\xbd\xb3\x2a\x5c\x2f\xa6\x8a\xe9\x14\x1e\xef\x29\x54\xfa\xa9\x25\x9c\x25\xb3\x46\xcd\xaf\xc3\xd8\x60\xc3\xb4\x8a\x55\x6e\x44\x18\xcb\x60\xbc\x68\x15\xf2\xb5\x1f\x9d\x81\x47\x2b\xae\xc0\xf5\xe6\xde\x58\x93\xea\x2f\xf4\xc2\x5a\xd9\x62\x17\xbd\x54\x2c\xb8\x1b\xf5\x2d\x0f\x1f\x59\xcd\x4e\x84\xe5\xbc\xd5\x5a\xe2\x54\x15\xdf\xf0\xad\xb8\x5f\xc5\x77\x39\x3b\x9d\x56\x4e\xaf\x66\x43\xc0\xd8\xa2\x45\xf8\xaa\x0d\x2a\x6a\xf1\x5d\x45\xfd\xec\x66\x65\xcb\xa5\x49\x9a\x57\x96\x83\x9c\x36\xcb\xf7\xaf\x31\x08\x89\x99\x8f\xa6\xcb\xfa\x51\x70\xe0\x1e\xd4\xbb\xba\x37\x90\xb4\x6b\x3b\xb0\x68\x90\x7a\x96\xcb\x57\x36\x35\xce\x34\xc6\x50\x5e\xba\x93\x46\xb3\xb0\xa2\x98\x56\xad\x59\xa8\xfc\x88\x57\x62\xd1\x46\xb6\x62\x07\x83\x04\x7d\x64\xdb\xbd\x1c\x27\xd2\xf0\x65\x7f\x7e\x68\x4c\x5e\x44\x49\xc4\xa5\xbf\x59\x7c\xc5\xe0\xca\x9e\x7a\x62\x4e\xe6\x25\x75\x91\x2e\x95\x81\xbc\xa0\xb9\x2a\xf2\x11\xb4\x29\x62\x33\xf0\x93\x4d\xc3\x31\xa6\x21\xd7\x89\x3f\x74\x48\xdd\xc6\xa7\x99\x64\x4a\x95\xcf\x90\xf0\x7b\xe6\xa3\x4f\x84\x54\x22\x0c\xd6\x53\x60\xe9\x42\x15\x31\x78\x13\xb8\x03\x20\xce\x73\xa0\x57\xd8\xa3\x36\x4b\x64\x01\xec\x45\x01\x7d\x28\xea\xb9\x2b\x58\x16\x2c\x60\x99\xe5\x34\xc6\x18\x7c\x00\x42\x54\x71\x0b\x96\x50\xe9\xc8\xc2\x78\x24\x56\x6b\x12\x37\x9a\x26\x53\x1b\x33\xeb\xc8\xb9\x2d\x50\x47\x92\x69\x6f\xd4\xc8\x10\x6d\x54\x3c\x10\x95\x68\x6a\x8e\xc7\xa2\xc2\x61\x4a\x25\xe3\x79\x95\xed\x04\x92\x8b\x5a\xa1\xe7\xd5\x58\x60\xe0\x40\x14\x39\xaa\x46\xea\xb6\xce\xaa\xd1\xda\xc8\x82\x3f\xa9\x65\xcf\xd1\xa3\x9b\x9d\xef\xfb\x17\xc0\x72\x8a\x7a\x37\x41\xb4\x5a\x88\xe3\x2f\xeb\xbd\x94\xaa\x08\x3b\x0e\xb6\x9e\x4a\x1e\x62\xe8\xed\x08\x22\x20\x55\x1e\x3b\x58\xa8\x45\x92\xe6\xea\x80\x50\x0b\x51\x1d\x38\xd6\xf3\x97\xc8\x9e\xeb\x88\x9d\xf1\xf6\xed\xde\xad\xde\x7a\x9b\x3d\xe1\x1b\xec\x25\xbf\xc5\xf6\xf8\x6f\xd8\x53\xfe\x2d\x7b\xc1\x37\xbe\x61\xbb\xfc\xf6\x2d\x76\x9f\x7f\xf3\x1b\xb6\xc3\x37\x6e\x7d\xcb\x4e\xf8\xad\xaf\xbf\x61\x77\xf9\xed\x75\xf6\x98\xb7\x7b\xbd\x5e\x9b\xbd\xe2\x1b\x5f\xaf\xb3\x0f\x98\x7b\x9b\xaf\xb3\x7b\x50\xcd\x23\xa8\xe6\x35\x6f\x83\x08\x0b\x1d\x0c\x46\x2b\xbe\x39\x88\x6c\xb3\x37\xc8\x1b\x4a\x6b\xff\x23\x8b\xb3\x46\x1e\xf1\x13\x6f\xef\x4b\x65\xca\x8a\x11\xf7\x0f\xdb\xec\xa3\x1d\x0d\xa4\x19\xa2\x7e\x28\xa3\x94\xe8\x0f\x91\xef\xca\x48\x54\x00\x40\xcc\xc3\x32\x86\xa4\x7b\x88\x7a\x56\x46\x69\xa9\x1e\x62\x6f\x94\xb1\x4f\xfc\x39\x44\xbc\x2d\x23\xa4\xe8\x0e\x71\xef\xcb\x38\x29\xad\x43\xdc\xf7\x65\x9c\x94\xd9\x21\x2e\x10\x65\xe4\x8b\x00\x73\x09\x3b\x86\xd0\x0b\x22\x63\x2b\x52\x99\xa5\x40\x6c\x2a\x6a\xa3\x95\x56\x3a\x90\x92\x58\x29\x64\x9a\x72\xfb\x96\x06\x47\x58\x4f\x52\x56\x2b\x90\xe4\x5b\x49\x3b\xda\x2c\x06\xe2\xb3\x6a\xfc\xc6\x37\x3a\x21\xaf\x26\x94\x8d\x0c\xad\x84\xd2\xc2\x06\x12\xa2\x7a\xc2\x56\x04\xd2\x9f\xd2\x51\x40\xfa\xbc\x96\x5e\xb6\x35\xae\xa5\x94\x8d\x81\x2c\xbd\x76\x70\x8c\xd6\xfe\x07\x78\xbf\xe2\x66\x7f\x6d\xc2\x46\x14\xe7\xa8\x48\x17\x6f\x52\x1c\x74\x21\x7e\x06\xf1\x10\x1b\x1c\x38\xbd\xaf\x06\x07\x6e\x81\xe5\xc4\x81\xeb\x42\xea\x41\x2c\x8b\x9e\x42\x96\x0e\xd0\x48\xe8\x57\x11\x89\x62\x22\x8a\x8f\x79\x22\x8a\x5f\xdd\xfe\xae\xf8\xd5\x77\xdf\xb8\x98\x65\x02\x59\xf6\x3b\x77\x36\xdb\x37\x7f\x77\x08\x9f\x17\x40\x45\x68\x42\x9d\x53\xa1\x8c\xa4\x5d\xf6\xc0\x44\x4e\xca\xc8\x2d\x28\x78\xe7\xd7\xab\xce\xfe\x41\x76\xf0\xe2\xb0\x3b\x70\x7f\xbd\x09\xe5\x8f\x29\xb6\x16\x79\x4e\x91\xbc\x16\xfb\x1c\xc7\x75\xe3\xe0\xd2\xd9\xff\xf1\xe0\xe0\xea\xf0\x2b\xe8\xe7\xc1\x41\x4f\x7d\xb8\x5f\xb9\x07\x57\x90\xe9\x08\x33\x9d\x7d\x75\x63\x8d\x9d\x41\xe8\xc7\x83\xec\x2b\xbd\xa4\xf6\x57\x0e\xe2\x83\xf4\x40\x1c\x76\x0f\xce\xd6\xd8\x13\x4c\x5d\xdf\x3f\x7f\x7b\xb8\xc6\x5e\x52\x4e\x0d\xe0\x5e\x77\xb0\x55\x9e\x42\x1d\x1c\x42\x55\x7b\x38\xe6\x83\xf3\xe1\xfa\xea\xc1\xf9\xe8\x1b\xf8\xff\x2d\x06\x02\xf8\x3f\x86\xc0\x18\x62\xc6\x18\x33\x1e\x23\x44\x9e\x22\x98\x6f\xfc\xe8\xae\xb1\x17\x58\xac\xf7\x55\x77\xf0\xe3\x8d\xcb\x2b\xc7\x2d\xf6\x0f\x0e\x0f\xd6\x0e\x0e\x30\xd3\xae\x81\xd0\x8b\x12\x42\xf7\x69\xe2\x70\xa7\x38\x38\x5e\x63\x3b\x58\xfa\x26\xf5\x39\xbf\xb5\x7e\xeb\x5b\xfa\xfb\x9d\x2c\x7e\x22\x16\x77\xa7\xf6\xfe\xdd\xd5\xf7\x07\xb2\x97\xd4\x4d\xd9\x4f\xec\x28\x2e\x2d\x48\xf7\x57\x3f\x1d\xc8\x3e\x53\xa7\x65\xaf\xa9\xdb\xdd\xb6\xde\xd2\x54\xaf\x40\x8c\xba\xbc\xc5\xae\x9c\x01\x47\xf1\x54\x74\xdb\x6e\x41\x72\xea\xa0\x8d\x1f\x32\xdc\x2d\xf6\xd7\x57\xbf\x83\xb2\x74\x95\x09\x35\x1d\x77\xa1\x95\x95\x7f\xe1\x5f\x3c\x18\xff\xdf\x7f\xf1\xff\xfe\x93\x7f\x5a\xef\xfa\x3f\xfb\x7b\x3f\xfd\xb3\xbf\xf8\xbb\x3f\xff\xf4\xd3\xcf\x3f\xfd\xf9\xcf\x3f\xfd\x95\x9f\x7f\xfa\xab\x3f\xff\xf4\xd7\x7e\xfe\xe9\xaf\xff\xfc\xd3\xdf\xf8\xf9\xa7\xbf\xf9\xf3\x4f\x7f\xeb\xe7\x9f\xfe\xf6\xcf\x3f\xfd\x9d\x9f\x7f\xfa\xc7\x3f\xff\xf9\x3f\xf8\x7f\x7e\xfa\xa9\xcd\x1e\x0b\xbe\xdf\x26\x54\x87\x36\xac\x55\x0e\x5f\x48\xb9\xe0\x87\xc8\x15\xfc\xda\x0b\x5d\x7f\xaa\xc5\x8d\x9f\x86\xaa\xb6\xcd\xda\x96\x61\xb5\xc6\xe4\x47\x59\x1e\xed\x26\xe1\x47\x92\x34\x08\x48\x3a\x06\x01\x09\x1e\x08\x00\xc1\xc2\xbf\xd2\x3c\x8a\xb5\x8f\x50\x6d\x62\x59\xfa\xc1\xa7\x36\x81\x84\xa0\xd6\x93\x4a\x25\x0a\x69\xfc\x90\xd7\x31\x16\x7a\xf0\x61\xec\x2d\x21\x5c\x52\x0d\xfd\x61\x53\x0a\x15\x57\xf6\xdc\xa2\x08\xf0\xa5\x48\x24\x4a\x73\x64\x8f\x89\x51\xc6\xd4\x0b\xd8\xa9\x57\x74\x8d\xfc\x03\xd9\x88\x7d\x10\xfb\x89\x38\xe4\xf0\x13\xca\x1f\x5f\xfe\x64\xf2\x27\x97\x3f\x43\xf9\x13\xc9\x9f\xb9\xfc\x19\xc3\x4f\x0b\xb6\x33\xb1\xff\x89\xbe\x3f\xd2\xdf\x54\x26\xfe\x40\x7f\xdf\xd1\xdf\x87\xf4\xf7\x19\xfd\xbd\x41\x7f\xdf\xd2\xdf\xf7\xf4\xf7\x7b\xfa\x1b\xc8\x62\x42\xfe\xc4\x58\xb5\xb4\x78\xd8\xa6\x6e\x6e\x53\x23\xdb\xd4\xc8\xb6\x6c\x64\x9b\x1a\xd9\xa6\x46\xb6\xe5\x28\xb6\xe5\x28\xb6\xe5\x28\xb6\xe5\x28\xb6\xe5\x28\xb6\xa9\xd5\x6d\x6a\x75\x9b\x5a\xdd\x96\xcd\x6d\xcb\xe1\x6d\xcb\xe1\x6d\xcb\xe1\x6d\x9b\xe1\x6d\x53\xff\xb7\xa9\xff\xdb\xd4\xff\x6d\xd9\xdb\xed\x4a\x37\xef\x41\x37\xb5\xe3\xb0\xd6\x06\x53\x8e\xc0\xbc\x75\x66\xdc\x85\xb5\x36\xae\xd8\x23\xc8\xd5\xfe\xfd\x4f\xc0\x8f\xde\x85\x49\xf9\xfd\x9f\xeb\xc0\x5f\xd1\x81\xbf\xaa\x03\x7f\x4d\x07\xfe\xba\x0e\xfc\x05\x04\x7c\x0c\xfc\x47\x3a\xf0\x1f\xeb\xc0\x7f\xa2\x03\xff\xa9\x0e\xfc\x43\x1d\xf8\x9b\x10\xd8\xc2\xc0\x7f\x06\x81\x21\x06\xfe\x35\x08\xdc\xc7\xc0\x7f\x07\x01\xd4\xfe\xfd\xfe\x6f\x41\xe0\x01\x06\xfe\xb6\x0e\xfc\x1d\x1d\xf8\x97\x74\xe0\x3f\x87\x00\x22\xef\xef\xff\x0b\x1d\xf8\x2f\x75\xe0\xbf\xd2\x81\x7f\x19\x02\x3b\x18\xf8\x57\x74\xe0\xef\xea\xc0\xbf\xaa\x03\xff\x35\x04\x42\x0c\xfc\x37\x3a\xf0\xdf\xea\xc0\x3f\xd6\x81\x7f\x1d\x02\xbb\x18\xf8\xef\x21\x80\x2b\xf6\xf7\xff\x06\x04\xf6\x30\xf0\x6f\xea\xc0\xbf\xa5\x03\xff\xb6\x0e\xfc\x3b\x3a\xf0\xef\xea\xc0\xff\x80\x17\xf0\x30\xf0\x3f\xea\xc0\xff\xa4\x03\xff\xb3\x0e\xfc\x2f\x3a\xf0\xbf\xea\xc0\xbf\x07\x81\x57\x18\xf8\x7b\x3a\xf0\xef\xeb\xc0\x7f\xa0\x03\xff\x1b\x04\x72\x0c\xfc\xef\x3a\xf0\x4f\x74\xe0\xff\xd0\x81\xff\x10\x02\xef\x30\xf0\x7f\x42\x00\x97\xe5\xef\xff\xa9\x0e\xfc\x0d\x9c\x53\x02\xd9\x3f\xc2\x79\xa2\xd0\xdf\x87\xd0\x4b\xa4\x38\xbf\xff\xbf\x48\x5c\xc1\xd0\x3f\x80\x50\x96\xb5\xaf\xd8\x6b\xc4\x9b\x0e\x7c\x75\x80\x08\xf4\x21\xe9\x0e\x86\x23\x81\xc1\x4d\x0c\x4e\x30\x78\xb3\x7d\x13\x82\xb8\x5d\x63\xfc\x4d\x8c\x87\x6d\x1b\xc3\xbf\xa3\xf0\x77\xdf\xf4\xa1\xae\x37\x54\x17\xd5\x03\x91\x90\x48\xf5\x78\x50\x25\x93\xf5\x78\x50\x25\xd3\xf5\x78\x50\x29\x53\xf5\x78\x50\x27\x53\xf5\x78\x50\xe7\x15\xfb\x84\x75\x19\x86\xd5\x43\xc7\x7c\x44\x26\x21\x74\xc5\x3e\x62\xe2\xc1\x01\x64\x85\x3f\xb2\x3f\x58\x9e\xee\x1d\xe2\xac\x1e\xa0\x1e\x09\x89\x9d\xdc\x21\x10\x6e\xf4\xab\x22\xbe\x53\x11\xdf\x41\x3b\x3f\x08\xfe\x09\x56\xab\x54\x5a\x48\xa2\x76\xd8\xe9\xc8\x40\x8b\x73\x12\xb5\x3a\x1d\x12\xb8\x94\x09\xfa\x40\xfe\x92\xd0\xc5\xde\xd9\xc5\xe3\x43\xb2\x3d\x6a\xc5\x96\x61\x58\xcc\x1e\xda\x59\x04\x64\x11\x28\xd8\x59\x59\x04\x7b\x26\xf8\x3b\x88\x7d\x28\x2a\xde\xbf\xca\xc7\xc5\xfb\xad\x67\xa2\x28\x9e\x09\x75\x71\x0c\xfa\xf5\x0c\xb2\x3e\x13\x3d\xd3\x4f\xf5\x0d\xd2\xc8\x98\xbe\x40\xfc\x86\x91\x3d\x13\x52\x4f\x70\x43\xf0\x87\x54\x7f\x2f\x38\x27\x13\x54\xce\xa9\xc1\x77\x82\xbd\x05\x5e\xc1\x71\xfb\x0d\xf6\x56\x52\xa5\xd3\xd0\x23\x99\xd0\xf3\x67\xa3\x4e\xa7\x0c\x0f\xf0\x9e\xc1\x11\x7f\x2b\x98\x8c\x6b\xb8\xdf\xf9\x16\xc4\x7b\xd7\x93\x23\x1d\xdc\x10\x03\xc7\xea\xd0\x5b\xe1\x52\x69\x48\x96\xbf\xaa\xb6\x2b\xb7\xf4\x52\xea\xda\x1f\xac\x49\xeb\x24\xe1\x33\x90\x3f\x5e\x53\x0e\x84\xd0\x00\xff\x34\xa6\x4a\x78\xea\x19\xbe\x44\xf5\xd9\xe5\xd5\x21\xfb\xc6\xdb\xaf\xdb\x34\x95\x16\xd0\xa4\xe2\xbb\x06\x7e\x16\x88\x14\x64\xf6\xdb\x69\xe0\x0f\x51\xfd\x90\xb8\xde\x02\x78\xd1\xbe\x4c\x43\x25\x71\x02\x47\x65\x46\xf7\x55\xbd\x9d\x78\x2c\xcf\x44\x13\x27\xed\x3d\xc7\x78\x60\x8d\x08\x1a\x4d\xf6\xb8\xd2\x88\x07\xb6\xf7\x2c\x73\x2e\x47\x61\x06\x92\xde\x05\x9a\x5e\x03\xc1\x54\xf5\x80\x5c\x90\x26\x73\x44\xc3\xcc\xbb\x9c\xfa\xf1\x28\x0a\x5e\x0c\x53\x90\x8c\xbd\xa0\xf7\x54\xa7\x90\x0d\x0b\x64\x0c\x80\xef\x19\xdd\xc3\x53\xd7\x17\xa8\x90\xb7\x73\x48\x6b\x46\x9d\xe7\xee\x68\x44\x56\x1d\x7e\xf4\x28\x40\x75\x5f\x53\xd6\x40\x9e\x08\x2f\xcd\x40\xe7\xaf\x1f\xf3\x30\x0d\x46\x4c\x9d\xc3\x05\xe9\x17\xe5\x0e\xd5\xd8\x1e\x63\x6f\x83\x49\x18\xdf\x4b\x84\x48\x66\x7b\xe3\x31\xf0\x44\x4d\x5d\x49\xe2\x1d\xab\xc8\xe2\xc8\x71\x48\xb0\xcd\xbe\x98\x87\x31\xf4\xe1\x3e\xf4\x1c\xed\x5f\xaa\x35\xc1\x62\x66\x61\x66\xd7\x83\x1b\xb3\x9d\x05\x1d\x9a\x30\x34\xe2\x90\x00\x7e\x21\xa0\x8e\xff\x8f\xbc\x77\xed\x8a\x1b\xc9\x12\x45\xbf\xcf\xaf\x00\xcd\x1c\x4a\x6a\xa2\xd2\xa4\xed\xb2\xab\x94\x25\xb3\x30\x50\x5d\xdc\xb1\x8d\xc7\xe0\xae\x99\x43\xd1\x94\xc8\x54\x82\xc6\x99\x52\xb6\xa4\x84\x62\x80\xff\x7e\xf7\xde\xf1\x7e\x28\x49\x57\xf7\x9c\x3b\x67\xdd\xe5\x65\x52\x8a\x97\x22\x76\x44\xec\xd8\xb1\x9f\x28\x07\x6d\x7f\xaa\x9b\x3d\xd4\x08\xfb\xdc\x16\x0d\xcf\x6b\x43\xbd\x1c\xe3\x34\xd2\xec\x99\x99\x5c\x85\xfe\x91\x5d\x15\xdd\x01\xd7\xbe\xc2\xbc\x36\xf5\x36\x9f\x3d\xbb\x46\xf6\x63\xff\xf8\x0e\x8e\xdf\x0f\x26\xe5\x8d\x50\x87\x76\xc0\x64\x35\xe1\x0f\x1d\x28\x95\x75\x07\x3b\xfc\x6e\xe7\x91\x46\x70\xc4\x05\x13\x54\x3a\xf5\xae\x20\x84\x83\x71\xb9\xe2\x5f\x7b\x2d\xee\xae\xc8\x4b\x8d\x3c\x67\x21\x3d\x7b\x0e\x37\x17\xbf\xaa\xbb\x7c\x03\xad\x7b\x2b\xbc\xff\x23\xac\xca\x90\xe0\x47\xe9\x7e\x6c\x96\xba\x2e\x67\x93\xa6\x50\x7e\x96\xa8\x0c\x1a\xf6\xc4\x70\x3d\xea\x92\x67\x46\x51\x6b\xab\xa8\x18\x77\xf7\x7c\x5d\x1c\x4f\xf7\x45\x4b\xe9\x8a\xd6\x5b\x02\x35\xda\x21\x88\xfe\xf2\xc0\x10\x4c\x20\x05\x92\xc5\x9f\xa0\xd8\x3d\xb5\xd3\x0e\xab\x49\x5a\x85\x67\x17\xe5\xb8\xd0\x2b\x3e\x89\xa7\xf5\x42\x36\x09\x10\xba\x29\xeb\x65\x1b\xca\x70\x10\x48\x2f\xbe\xe8\x44\x87\xc5\x0d\x46\xb6\x50\x8a\x46\x05\xcd\xfb\xc8\x48\x83\xa8\x82\x5e\xfc\x52\xce\x66\x9f\x0a\x00\xdf\x4d\xe1\xac\x7f\xed\x77\x13\xb1\x24\x79\x52\xe2\xad\x6d\x66\x64\xe5\xe3\x8c\x0c\x55\x9e\xfd\xd4\x50\x49\x1d\x56\xc7\x1d\xd8\xa8\xf2\x92\xb2\x66\xb7\x49\x0b\x7f\xfd\x09\x79\x6a\xd1\xb7\xae\x74\x53\x6e\x4e\x56\xef\xd6\x7e\x8b\x5c\x46\x00\x78\x8e\xf6\x50\x5c\x99\xca\x06\x9d\x4a\xff\xa9\xa9\xe7\x6a\x7a\xe2\x0e\x55\x5c\xf5\x2b\x97\x4b\x29\xc8\x1e\x94\x93\xcf\x8b\x89\xb5\x21\x51\x24\xdf\xbb\xd4\x08\xac\x4e\x9a\xa0\x9f\x7a\x3e\x8f\x59\x6e\x0f\xec\x99\x7d\x8f\xf2\x6b\x13\x21\xa0\xe1\x3e\x29\xe0\xcb\xb5\xcf\x95\x57\x43\xfb\xcb\xf4\x9d\x4e\xb7\xd4\x58\x1d\x7e\x1b\x93\xba\x68\x37\xaa\xba\x83\x87\x8d\xbc\xba\x83\xda\xd5\xd5\x06\xb9\xf5\xa8\xab\xd9\x1d\xfc\x29\x36\xa8\x99\x41\xe4\x40\xc4\xeb\x90\x0d\xf6\x7b\x6f\xbb\x09\x99\xf0\x14\x0a\xa9\x2c\x1c\x34\x60\xd8\x0f\x70\x74\xc4\x40\xd7\xcc\x4a\xb5\xc7\xfd\xbd\x15\x00\x52\x60\xa3\x05\x4a\xc9\xb9\x5c\x76\xc5\x69\xdd\x01\x6e\x75\x7b\xd6\x23\x61\x0b\x60\x9e\x3f\xf5\x4f\x3a\x61\x6f\xdd\x8f\x9e\x36\x57\x8e\xbf\x95\xb5\x1f\xcd\x6d\x7e\x50\xdf\x56\x7d\xcd\xb5\x08\xeb\x81\x07\x85\x1f\x8d\x4c\x17\x8e\x8f\x2c\xb8\x06\x03\xd8\x82\xd0\x31\x99\x52\xc6\xc5\x33\xfb\x73\xd6\xc6\x46\x37\x42\x2b\xb2\xff\x84\xce\xf8\xab\xed\x15\x25\x58\x2d\x8e\x87\xfc\x77\xf4\xdc\xf0\xad\x5f\xd4\xdd\xf9\x68\x37\x64\x9f\x28\xab\x26\x18\x03\x4a\x07\xbe\xef\x37\x9a\x9b\x63\xae\xfb\xcf\x1f\xd6\x66\xfa\xac\x2a\xfb\xcb\x8d\x9c\x3d\xe1\x1f\x35\xb9\x77\xd4\xb4\xfe\xca\x2f\xfa\xd6\x79\xcf\x0c\xc3\x7a\x97\x04\xe0\xcf\x41\x8a\xc7\xc6\x5e\x26\x55\x14\x3f\xb9\x4a\x85\xec\xdd\xaa\x84\xc2\x9d\x06\x0a\xe9\x15\x0c\x5d\x98\xe7\x55\x7e\x25\x4a\x88\x43\xac\xf5\xf1\x05\x8d\xc0\x3a\xe9\xb6\xb6\x4c\x3e\x5f\xdc\x57\x8c\x9f\x3d\x9c\x24\x02\x12\x46\xf3\xfa\xcc\x4b\x57\x61\x00\xdf\x3e\x39\x83\xa7\x2b\x42\xce\x00\xcc\x9a\xc4\x9b\x37\xcd\xd6\x97\x76\x9c\x2f\xa1\x78\x97\x85\x09\x51\x39\x2d\x21\xc8\xc9\x58\xa3\xe1\x03\xa4\x50\x7e\x4d\xdf\xac\xb1\x1b\xbe\xed\xa7\xd4\xcc\xac\x95\x97\x88\x51\x27\x45\xb3\x7c\x6e\x42\x54\x84\x07\x16\x8f\x84\x02\x88\x9b\x00\xb7\xc9\x6b\x3a\x04\x2f\x97\x80\x65\xf5\x10\x4e\xba\xbb\x59\x11\xa2\xec\x9f\x24\x41\xeb\x9b\xa2\x41\x25\xec\x7f\x4f\xa3\xeb\x72\x32\x29\xaa\x48\x25\xfd\x47\x1a\xf1\x39\x8a\x1e\xc5\x07\x79\x1d\xe7\x63\x4a\xdb\xe6\xfe\xb6\x9c\x74\xd7\x69\x34\xdc\xd9\xf9\x5f\x11\x13\x9f\xd6\x08\xa1\x48\xb6\xa3\xc5\xef\xd8\x96\x73\xab\xe0\x3b\x3d\xd0\x7b\x81\x03\xd2\x55\xf0\xdc\x8d\x2e\x67\xf5\xf8\x0b\x72\x77\xe0\x08\xc6\xd6\x61\xd3\x4f\x8a\xc6\xbd\x24\x74\x26\x2e\xf6\x10\xce\x9f\xfa\x70\x15\xc6\x9d\xee\x3f\xdc\xbe\xed\x69\x13\x10\x56\xd2\xdf\x64\x93\x85\x5a\xe4\x86\x4d\xab\x3a\xc9\x56\x7c\x8d\x47\x67\xf6\xcf\x40\x63\xcf\xa1\x6f\xcd\xc1\xa2\x26\xfb\x91\xc3\x1b\x52\xd5\xe6\x30\x43\xf7\x39\xf2\x3e\x77\xaf\xef\x92\x66\x27\x65\xe2\x6e\x28\x11\xed\x97\x01\x35\xca\xd5\x82\xeb\x11\xe5\x97\xb8\x48\xa8\x78\x68\xad\xc6\x78\x69\x14\x1b\x9d\x0a\x85\x30\xf3\xa3\xd9\x31\xfe\x85\x79\x5d\x77\xd7\x6a\x48\xbf\x90\xde\x4d\x23\xbf\x56\xfb\x15\xba\x7a\x71\xb2\xc8\xc7\xba\x8c\xee\x91\xb1\x98\x63\x6e\x91\xe7\xd5\xbe\xa4\x9d\xbd\x4e\x03\x5c\xeb\xd6\xa9\x6e\xaf\xf3\xe8\x91\xad\x5c\xc8\x06\x68\x7b\xae\xdd\xdc\x62\x19\x35\x35\xd4\x4c\x13\x1b\x8a\xb8\x40\xe9\xf0\x87\x9d\xc7\x73\xf6\xda\xe6\x47\x19\x86\xe3\x74\x1d\xd7\xfc\xa3\x8a\xf3\xaf\xbe\x5f\x51\x5e\x06\x32\x13\x2e\x52\x6a\x74\xbb\x4c\x4e\xbc\x3a\xc7\x5f\x06\xc6\xdc\x91\x9a\xb1\x67\xf5\x39\x5c\x2e\x28\x9a\x7d\x69\x6a\x34\x11\x85\xbd\xb5\xd5\xc4\x70\xc8\x94\x32\x90\x02\x8c\x45\xfa\xcc\xe1\xbc\xac\x67\xb3\xf2\xf2\xd9\x6d\xde\x54\x28\xde\xc2\x55\x6d\x65\x94\x15\xd9\xcc\x63\x38\x0b\xa0\x74\xee\x11\x92\xe5\xb8\x4d\xe1\xd3\xb3\x12\x2f\x22\xfe\x05\x4f\x90\x41\x06\x87\x4b\x23\x56\x62\x93\xa0\xee\x4b\x08\x67\xd4\xd8\xcf\xe8\x7f\xb5\x1b\x62\xef\xb6\x1b\x79\x53\x90\x0b\x8f\x06\xce\x9d\xa2\xd9\x00\x44\x3a\x2d\xaf\x96\x4d\x4e\xc0\xa2\x5b\x01\x2c\xdd\x8d\xf6\xba\x5e\xce\x26\x74\x75\xb8\x2c\x36\x78\xbb\xc5\x24\x62\xe2\xfc\x51\xf2\x5d\xb3\x4b\xd0\x83\x91\x9e\x98\x12\x26\x26\x38\xe6\x74\xf8\x7a\x87\x05\xc0\x94\x0e\xbf\xff\x01\x66\xf2\x07\x77\x26\x85\x3b\xee\x3e\x00\x3a\x40\x3f\xfc\xbd\x18\x2f\xb1\xf2\x61\x75\x53\x36\x75\xc5\xa3\x86\x60\xe0\x2f\x38\xd3\x61\x5d\x23\x86\x11\x5e\x9d\x86\x0c\x4d\x77\x4c\x68\x21\xab\x33\xda\xcf\x2b\x1c\xf6\xb2\x2d\x36\x7e\x2e\x5b\x18\xe3\x1d\x99\xf8\x6c\x08\xfb\xa0\x8d\x7c\x03\x9a\xc1\x49\x95\xd8\x33\x1b\x32\xce\x4e\x1d\x5c\x1b\xe5\x63\x1b\x1c\xb5\x0d\x8e\x60\x37\xd3\x57\x2f\x59\x2f\xc8\x00\x34\xc3\x9d\x5e\xd8\x0c\x9e\x29\x8e\x19\xc1\xe4\x7e\xcc\xcd\x18\x04\xe3\x73\x9e\x7f\x29\x3e\xc2\x11\x96\x56\xc4\xf0\x33\x99\x89\x98\xf5\x33\xee\x73\x3f\x8b\xac\xac\x88\x88\x3e\xad\x03\xd9\xc2\x63\x0c\x9a\x31\x04\x72\xaf\xea\xb7\x08\x5d\x2f\xe3\x91\xa9\xce\xf4\xd9\x24\x8b\x35\x86\xfd\x1f\xc8\xc2\xd2\x47\xac\xee\xef\xba\xb5\xb1\xb0\xaa\x6d\x0d\xc9\x6d\xc1\xaa\x6a\x96\x54\xd5\xcd\x21\xaf\xac\x6d\x14\x54\x95\x05\x44\x5c\x22\x59\x56\xe1\xd9\xce\xb2\x69\x70\xd9\x98\x93\x9b\x0e\x9f\xe3\x4a\x18\x7e\xc5\x4a\xc0\xa3\x79\xff\x7f\xee\x72\x80\x9b\xc5\xbe\xd1\xc5\x00\x01\xa5\xba\xeb\x61\x1f\x99\x43\x66\xc2\xb1\x9b\x9d\xe8\xd1\x04\x6b\x62\x4e\x5f\x4d\x6b\xb0\x5e\x6d\x33\xb7\xaf\x05\x13\x1e\x5e\x03\x46\x66\x5f\x7d\x01\x31\xaf\x2a\x4f\xef\xa9\xf5\xb8\xd6\xea\x79\xbe\x06\x8e\xe5\x3a\x1b\xc2\x6c\xdb\xc2\xb3\x80\x4e\x55\x8b\xe8\xef\x24\xbe\x9f\xe6\xb3\xf6\xae\x6f\x43\xa2\x03\xb4\x5d\x83\x39\xf5\x23\x3a\xbd\xfd\xe6\xcd\xc6\x3c\xbf\xa3\xf3\xe5\x3a\xbf\x29\x00\xa9\x46\xdf\x6c\x77\xdb\xdf\x44\x1b\x78\xa4\x7d\xa3\xe3\xfa\x32\x52\x5f\x36\xb1\xa8\x22\x13\x58\x6f\x6f\xd3\x57\x78\x92\x0c\x5f\x3c\x4d\x14\x70\x8d\x5b\x38\x9f\xc5\x79\x9a\x37\xf9\xbc\xcd\x04\x8d\xfa\xb7\x25\x5a\x2f\x56\x3e\xb5\x31\x7c\xb9\x1a\x80\xfe\xb1\xe4\x42\xb3\xf6\xb7\x6a\x89\x1a\x8b\x74\x2a\x73\xe2\x91\x74\x15\x73\x17\x93\xc3\x6e\xf9\x84\x65\xf6\xba\x83\x62\x01\x2b\xab\xf6\x76\x5a\x2b\x4a\xec\x4b\x76\x5e\x7f\x51\xf3\x6b\x2d\xe4\xe7\xe4\x20\xd7\xdc\x9c\x01\xe4\xf1\x74\xa5\xa7\x77\xb4\xdd\x86\x8d\x39\xcd\xac\x01\x57\x7e\x8e\xc9\x1d\xe0\x79\xf2\xb8\x0e\x93\xf2\x62\x49\xdc\x5c\x1b\x06\xf1\x13\x1c\xdf\xb5\xeb\x22\xb7\xf6\x73\x35\x0f\x7e\x59\x0e\xa1\x6f\x06\x14\x27\x98\x72\x79\x12\x8f\xa9\x00\x5f\x08\x7e\xfa\x1f\xf4\x09\xc5\xf6\x39\x2b\xcf\x13\x9a\x1f\x9d\xdd\xc7\x7c\x0c\xcf\x87\xe4\x86\x0a\xc1\x2b\xce\xf2\x27\xa3\x40\x8f\x54\x42\x9f\x71\xf6\xea\x0d\xf6\x56\xdf\x0a\x76\x2b\x21\xe0\x15\xc6\xb5\x44\xb0\xd3\x77\x58\x83\x5e\xcb\x31\x3c\xa7\xba\x6d\x30\xba\xac\x94\x28\x7f\x27\x9f\x50\x26\x1e\xcc\x03\x78\x90\xad\x8f\x47\xbe\x7b\x1a\x8f\xb8\x8e\x90\xd0\x4b\x78\x09\xc9\x68\x7c\x0a\x9b\x62\xdc\x71\x9f\x24\x35\x06\x6a\x28\x4d\xf7\xab\x32\xaa\xa0\x30\x17\x2b\x06\xdc\xcc\x83\x04\x26\x30\xaa\x51\x3e\xb0\x6e\x05\x5b\x5b\x4e\x42\x3c\xe5\xcc\xa1\xeb\xec\x1e\x3d\x8b\xa5\x53\x72\x30\xc6\xa0\xf7\x75\x23\xee\x9f\x6f\x0b\x40\xb1\x65\xdd\xa4\x9b\x9b\xd3\x41\x28\xe3\x71\x94\x67\x59\x36\xa3\x4f\xef\xc6\xd7\x83\x5b\x58\xe3\xa7\xc6\x09\x07\x28\x7e\x0a\x48\x92\x4d\x05\x7e\x84\x07\x42\x8d\x09\xa5\x74\xd7\x19\xff\x79\x78\x98\x0e\xa6\x0d\x7a\x15\x8a\xfe\x14\x25\x29\x34\x24\x66\x0b\xf2\xe5\xbc\x05\x1a\x57\x99\x5b\x5b\xea\xd1\x2b\xe5\x55\x44\x0e\xd9\x3a\x55\xb1\x1c\x87\xd0\x24\xe3\xfe\x75\xa8\xa7\xd1\x33\x0a\x0f\x10\xeb\x9e\x23\xd8\xd0\x05\xe1\x66\x96\x2d\x09\x12\xfc\x79\x4c\xcf\x7c\x7a\xe6\x99\x5d\x7c\xb4\x40\x03\xf1\xcb\xb6\x9e\xc1\xea\x8d\xe7\xe8\x24\x76\x9e\x2d\xc8\xad\x78\x0c\x94\x54\x92\x40\xaf\x09\x3e\x8b\x01\x00\x7d\x4e\x96\xf6\x50\x8c\x3b\xbb\x12\x59\x13\x86\xb0\x1f\x8b\x2f\xc6\x3c\x75\x3b\x43\x08\x8e\xae\x39\xbc\xb9\x2f\xb9\x05\xfa\x09\x68\x60\x9d\x7e\x54\x69\xa2\x34\xec\xef\xad\xad\x3d\x81\x85\xe9\x37\xee\x8c\x9a\x09\x1f\xb5\x7c\x95\x9e\x3f\x62\x73\xab\xb6\xf1\xb7\x43\x18\xac\xf9\x41\xe5\x4b\xb9\x48\xd8\x37\xa7\xd7\xc5\x46\x55\xb4\xa8\x64\x4f\xf8\x60\x03\xbf\xbb\x01\xf7\xca\x68\xa3\x6c\x37\xc8\x5b\x75\x75\x05\x78\xa3\xe0\x69\xd4\x4a\x81\xd7\x4b\xb8\x31\x97\x70\xe9\x84\x04\xd8\xbf\xba\xd6\x37\x02\x32\xac\x60\x7c\x46\xa4\x6b\x9e\x1b\xee\x3e\x2d\xbe\xd6\xd1\x4e\x09\xd4\xe8\x19\x5f\x78\xf2\x6d\xce\x78\xd2\x39\xfb\xe6\x3f\xea\xe5\xc6\x58\x5f\xd7\xf0\xfb\x98\xc3\x3b\x81\x97\xdc\x39\xac\x75\x48\xce\x2b\x12\x75\x51\xd7\xbf\x61\x62\xae\x99\x6a\x28\xbb\x49\x8c\x59\xd8\x85\x2f\x75\x2c\xfa\xf1\x43\xdd\xfd\x04\x68\x9e\xe3\x37\x20\x57\x96\xad\xa2\x55\xc4\x70\x7e\xe4\x59\x70\x76\xcb\xbe\xa1\xd2\x93\x51\x8b\x45\xd8\x43\x8b\xd0\xb1\x7b\xe4\x7e\x64\x01\x20\xf3\x5b\x9d\x2a\xf6\x5a\x4f\xb7\x54\xeb\xb2\x5c\x94\x30\xa7\x2b\xd9\x0d\x3f\x68\x52\x1c\xe8\xd2\x1a\xa8\x50\xab\xf8\xba\x71\x4e\x8c\x4a\x4f\x0f\xd3\xfe\xc4\x1a\xa3\x0c\xf4\x29\x3c\x48\xb3\x1f\x6a\x8c\xf1\x0d\x3f\xb6\x50\xbd\xc8\x68\xf6\x06\x3d\xe9\xdd\x18\x5e\x7c\xe5\xc5\x4e\x18\xd2\x9d\x29\xbb\xb2\x5c\xcb\x5d\xe5\x76\x29\x2c\x05\x24\x74\x75\xf9\x17\xc4\xc3\xf2\x68\x42\xdc\x11\x17\x99\x74\x52\x95\xa0\x4b\x69\x32\x05\x43\xa3\x24\x66\xb8\xb6\xa5\x58\x66\x05\xba\xf6\xba\x17\x9c\x34\x5c\x83\xe8\x6a\x4d\x73\x75\x10\x31\x14\x1a\x53\x19\xb4\x29\xc7\x05\x85\xf1\xf2\xf0\x10\xc2\x0c\xaa\x1d\x71\xf8\x87\xd0\x7e\xb6\xb9\x59\x04\x33\x98\x50\x06\x74\x10\x75\xe1\x63\xe5\x40\x41\x42\xcc\x6e\x51\x4c\x34\x25\x4b\xa8\x54\x20\x9e\x1e\xc5\xc1\xa7\x49\xe7\xb6\x9f\xd9\xb3\xe4\x64\xb3\xa2\xc6\xda\x67\xe6\x42\x89\x28\x5e\x89\x53\xc0\xda\x2f\x11\x46\x32\x71\x4b\x7c\x12\x47\x34\x05\xc9\xa0\xcc\x65\x57\xce\xda\x67\x78\xb1\x8c\xcc\xdb\xc7\x3d\xa7\x46\xa8\xa5\x16\x87\x44\xfa\x69\x4a\x3b\xa5\x66\x94\x03\x34\x08\x27\x37\xfa\x7a\x99\x3e\x7f\xc1\x56\xf5\x31\x7d\xfe\x1d\xeb\xe9\x61\xfa\xfc\x15\xb3\xfb\x97\xbe\x78\x15\xa6\x64\x7c\xee\xd1\xab\xd5\x64\x0c\x77\xa1\x27\xa3\xb7\xf3\x10\xd1\x7c\x11\xd2\x02\xc5\x4d\x2f\x5f\x6c\xbf\x7a\xe8\xda\x8e\x6f\x37\x94\x09\xc8\x47\xa0\x1a\x3c\x13\x5e\x25\x63\xa1\xd3\xa6\x31\x8e\x18\xc5\x0b\xde\xac\xc9\xb9\x46\xa0\xce\x46\x78\xb1\x3e\x26\x21\xde\xab\xb9\x68\xea\xaf\xe4\x10\x96\xe6\x22\x00\xe2\xf4\x17\x62\xee\xf1\xaf\x7e\xac\xf9\x82\xc6\x68\x2d\x06\xe7\x16\x26\xa7\x6e\x26\x76\x11\x5f\xf2\xc7\x05\x0b\x82\xa9\x08\xc4\x82\x9f\x98\xdd\x4b\x91\x99\x95\x8c\xe6\x94\x65\x9c\x18\x4a\x08\xc1\x8f\x58\x72\x93\xbf\xe3\x5b\xdc\x5b\x86\xab\x7d\xe4\xdd\xb6\x1a\x79\x18\x58\x4a\x19\x72\x5e\xe2\x04\xc9\x5d\x93\x9b\xca\x3f\xb3\x71\x29\x0a\xb8\x0c\xd5\xaf\xb8\xdb\x09\xc1\xf4\x53\x5a\x3c\xb8\xa6\x03\xd5\x3a\x7d\xdb\x0a\xc8\x68\xd1\x69\xab\x21\xbf\x62\x32\xc2\x5d\xd7\x3b\xce\x11\xd1\x95\x66\x83\x72\x76\x3c\xfe\xcc\xc0\x9b\x40\x53\x54\x66\xe0\x6b\x9e\xc0\x6d\x8b\x1d\xa6\x8e\xb8\xcc\xac\x5e\x9e\xe9\x8b\xd7\xec\xef\x66\x37\x7b\x42\x98\x75\xd9\xcd\xc8\x00\xe0\x6a\x0b\x3d\x5c\x46\x5d\x80\x23\xd3\x95\x45\x3e\x0a\xac\xf3\x44\x21\xbc\x99\xac\x2c\xf2\x6f\x78\x67\x09\x94\x00\xa2\x79\x8c\x0e\x95\x7a\x98\x93\x36\xab\x3a\x7c\x49\xb6\x3b\x1b\x1b\x77\xec\x80\xa2\x6a\x5f\x55\x5e\x5e\x54\x56\x83\xfe\xaa\x2f\x63\x0d\xd5\x00\x01\xe4\x2b\xaa\x63\x79\x51\x99\x83\x6a\xed\xba\x54\x1c\xab\x2a\x50\xae\xc3\x9c\x97\x85\x25\x83\x7c\x1d\xce\xe5\x13\x72\x3e\xe3\xac\xe8\x3f\x45\xe4\x71\x66\x86\x0a\x6d\x44\x6b\x32\xfc\xab\x92\x11\x72\x13\xb5\x18\xfd\xff\x26\x70\x66\x89\xd7\x0e\x5f\xf5\x29\x28\x8f\x4c\x87\xb2\xfc\xfb\xdb\x13\xa1\x35\x57\x71\x12\x73\x7f\x3f\xb6\x3e\x15\x03\x94\x93\xbb\x2b\x57\x2b\x9d\xe5\x42\xe7\xcd\xde\xa6\x2b\xeb\xf0\x83\x5f\x06\xd4\x49\x1e\x43\x5b\xf8\xc9\x8f\x62\xa9\x47\x7f\x5f\xfb\xf5\xca\xf8\xde\x92\x44\x73\xd6\x84\xf5\xd5\xbe\x55\xec\x56\xe5\xcc\x8c\xbe\xd5\x5b\xaa\x7a\xad\x79\xdd\xc7\xc0\x3f\x59\x96\x39\xdd\x4f\x2d\x84\x2e\x48\x21\xbc\x1b\x34\xb1\xd7\x57\xc6\xfd\x0f\xf3\xe0\x4b\x70\x58\xc6\x6e\x97\xe0\xd3\x49\x90\x05\xeb\xcc\x64\xfe\x34\x7e\x5d\x55\x44\x4d\xce\xea\x42\x34\x0f\xab\x8a\x70\x70\xfb\x25\x14\x58\xbd\xac\x75\x58\xc5\xce\x58\xe5\x21\x6c\xa4\xf9\xa3\x75\x0a\xf1\xd4\xd0\x88\x03\xad\xd1\x35\xcc\x1b\xb7\x57\x90\x26\xd0\x1d\xbb\x53\xea\xdf\xf8\x24\xca\xe1\xf3\x8b\x98\x78\xb3\xcf\xf4\x65\x88\x41\xe9\x13\xfa\x4f\x31\x2a\x3d\xd9\xb9\x8b\x1d\x8d\xeb\x25\xdf\x00\xf9\x25\x7c\x1f\xae\x31\x6d\xcd\xa3\xcd\x48\x56\x71\x07\xf4\x61\xa7\x65\x4c\x41\x1a\xbb\x47\xa6\xa1\xaf\x53\xa3\xc6\xf4\x54\xcc\xee\xe9\x63\xb6\x5e\x83\x26\x20\x8d\x9e\x48\xe5\x32\xb3\x73\xe8\x0a\x7b\xef\xed\xf1\xa7\xd3\x88\xc4\xb0\xfc\x13\x61\x19\x2c\x55\x23\xaf\xe9\xf2\x7e\x8f\x8e\xd7\xe1\xba\xe6\x15\xd7\xde\x6f\xb0\xf3\xc2\x51\xa0\xe9\xdc\xb9\x32\x9c\x1b\xa9\xe4\x92\x88\x44\xd8\xb1\x8d\xd9\xc3\xa4\xc0\xc0\x62\x32\x14\x59\x15\x62\x43\x62\xb4\x86\x50\x06\x06\xb3\x3b\xab\xcf\x19\xea\xda\x06\xb2\x05\xd3\xfd\xc7\x17\x5b\x5b\x78\xb8\xf3\x50\x0e\x79\x72\x5f\xc0\x1f\xe1\x38\x1f\xa5\xc6\x18\x57\xa0\xc6\x43\xb8\x73\x25\xdb\x86\xab\x20\x1c\x6a\xa9\x86\xca\x5d\x15\x19\x85\x9b\x15\xa3\xad\xfb\x47\xeb\xf3\x6b\x69\xac\x7e\x72\x5c\x53\x7f\x90\xf9\xe6\xe5\xc9\x61\xbe\x7c\x62\x98\x4d\x32\x2a\xb9\x8f\x31\x5b\x2e\x67\x2e\xbd\x74\xf8\xe2\xa9\xcd\xf2\xbc\x47\x99\xe2\xfe\xe3\xe7\x93\x9f\x53\xe1\x5f\xe7\xd3\xe1\xc7\x77\x7b\xfb\x87\x69\x24\xe4\xb5\x11\xfb\x78\xfc\x31\x25\x17\x3c\xe6\xf6\x15\x62\xc1\xe7\x2b\xa4\xf2\x83\x67\xc2\x51\xd0\xb3\x77\xf5\x98\x94\x6d\xf6\xf8\x3b\xa7\x9f\x43\xb7\x07\xe7\x26\xd3\xc2\x7d\x89\xc7\xf0\x18\xe7\x18\x32\x7b\x40\x1d\x15\xcf\xb2\xa3\x42\x11\x45\x6a\xea\x52\x68\x8f\xd1\x25\x40\xe2\xcb\x48\xd6\x82\x01\x14\xbb\x6e\xb9\x62\xf0\x3b\x2b\x06\x77\x49\xb0\x81\x90\x50\xb9\x7f\x3c\xe9\x73\xbc\x3c\x3c\xef\x91\x31\x3f\x31\xd2\xe4\x3e\xdc\x81\x00\xb0\x3d\xe9\x6e\x58\x06\x0b\x3d\xdd\x37\x75\x9c\x14\xa2\x72\xa5\xaf\xd5\x0a\x6b\x42\x8b\x7f\xc3\xc8\x53\x74\x9b\xa2\xdb\x2d\xc3\xb8\x90\x0e\x94\x5a\xd8\xab\x31\x22\x06\xea\x01\x49\xc6\xd9\x58\xb1\x88\x44\x82\xe0\x7d\xf9\x22\x59\x54\x8a\x73\x74\xa8\xbc\x01\xa4\xdf\x33\xbb\xf7\x96\x34\x0b\x41\xe3\x89\xa7\xcd\x73\x40\x6d\xf1\x1d\x32\x30\xb9\x5c\x76\x5d\x5d\x59\x94\xb0\x72\xb2\xb6\x09\xeb\x62\x5e\x74\xf9\xbf\x16\x77\x18\x5a\x25\x9f\x75\xe2\x69\xdc\x35\x33\xf1\x48\x6e\xa0\xe0\x39\x11\x91\xdb\x0c\xf8\x3b\x94\xeb\xf8\x77\x49\xae\xf6\x9f\x21\xad\x98\x9a\x0f\x70\xb7\xbe\x92\xf3\xb5\x14\x89\xa4\x69\xac\x98\x7c\xf6\xfc\xcd\xb2\x7a\xc5\xfc\xbd\x2b\xab\x2f\x7a\xde\x5a\xb6\xb4\x66\x2e\xa7\x13\x79\x5f\x29\x82\x8e\xc5\x24\x5a\xca\x2f\x75\x30\x99\x53\x72\x90\xc5\x6d\x5c\x19\xd1\x6d\xfa\xb5\xae\xf6\x81\x1a\xfe\x02\x09\x08\xdf\x75\x8c\x18\xdd\xbe\x44\x3c\x01\x35\x82\xf9\xa2\xe1\x0d\x7a\x72\x56\x8a\x1a\x3f\xb2\xb4\xad\xa9\x24\x39\xa9\xf3\x93\xd1\x91\x20\xdb\x6c\x88\x6d\x5d\x71\xe6\x35\x94\xc3\xb8\x84\x38\xa7\x13\xd9\xc7\x02\x15\x6c\x8b\x09\x66\xec\x60\x19\x11\x88\x9e\x6c\x52\x90\xe9\xc2\xcb\xa1\x16\xac\xb0\x80\xb2\xb4\xa6\x4c\x65\xfb\xda\xd4\x04\x97\xf4\xaf\x4e\xe1\x24\x38\xa7\xde\x6d\xed\x2e\xfb\xa2\xa0\x14\xba\xbe\xba\x6d\x4e\x6b\x2a\xb8\x3a\x7a\xd5\x85\xab\x77\xec\x28\x07\x23\x73\xff\x2c\x94\x81\x7e\x2e\x24\x8f\x5d\xde\x67\xbf\xba\x6f\x6e\xeb\xce\x22\xe0\xdf\x40\xc1\x41\x9f\x5a\x38\xc6\x0f\xbd\x37\xad\x1b\xd8\xfd\xb5\x52\x7b\x12\x20\x85\x59\x72\xb4\xa2\x4d\x80\x90\x26\x33\x5f\x5b\x06\x9f\x9e\x12\xb4\x9e\x6e\x4d\x9a\xc1\x14\x17\xd0\x57\xfd\x4e\x6c\xdc\x35\x13\xb8\xcb\xd8\xc9\xe9\x70\x27\x80\xb9\xf4\xce\x4e\x87\xaf\xd7\x94\xca\x33\x1b\xad\xa4\xc3\x97\xdf\x23\xde\xf3\x04\xf5\xff\x8d\x47\x82\xcd\xb3\xff\x9f\x7f\x26\x78\xdc\xff\xff\x46\xd8\x28\x3a\xac\x07\x2c\x02\x10\x02\x2c\x44\x9a\xab\x37\x40\xb4\xea\xd9\x00\x09\x82\xe8\x1f\x03\x88\x7e\xae\xe6\x1f\x03\x04\xbf\xf4\x18\x4a\x30\x74\xca\xad\x04\xcf\x57\x2f\x19\x1f\x1e\x30\x82\xb0\x92\x47\x4d\x76\xf8\xeb\xdb\xcb\x37\x28\xaf\xb2\x00\x9b\xaf\x0f\x58\x77\xe4\xe9\xf3\xef\x6d\x60\x7b\xfc\xba\x5e\x60\x9b\xed\xbc\x47\xc8\x10\xc0\x9f\x04\xa3\xfc\xb2\x09\x4d\x1f\x47\x5a\xec\xc7\xb0\xea\x52\xec\xe0\xaf\x5a\x40\xc1\xef\x17\x60\x1b\x7b\x90\xde\xb5\x5b\x5f\xa9\x2a\x83\xf6\x6a\xf4\x6d\xcc\x54\x83\x83\x3e\x17\xe7\x92\x90\xe8\xd8\x42\x71\xbb\x05\x31\xd1\x3c\x7a\x02\x6b\x56\xb2\x5c\x33\x17\x81\x9c\x61\x63\x20\x80\x76\x28\x14\xb7\x08\x32\xb5\x78\x33\x1b\x6d\x6f\xcf\xe8\xf2\x06\x44\xd5\xd9\xec\x1c\xc8\xa8\x3a\x6e\x25\x4f\xaa\xb5\x25\xf8\xad\xa3\xb8\x80\x1f\x60\xdc\x67\xfa\x52\xc5\x05\x97\x1c\x3e\xe1\x29\x34\x6e\x81\x34\x23\x37\xab\xd9\xb1\x25\x82\x6e\x63\xce\x64\x40\xfe\x95\x0c\xcd\x17\xb7\xd0\x47\x6c\x55\xf9\x3a\x85\x43\xcf\xaf\xd8\xa9\x8a\xbb\x4d\xdc\x89\x2a\x69\x15\x2c\x5b\x99\x65\x2b\x55\x16\x45\x57\xa6\xb4\x3d\xcc\x87\xf5\x6c\x3f\x30\x08\x2f\x72\x65\x37\xb3\x8c\xb8\xb1\x2b\x98\xbb\xb9\x9c\x48\x56\xe3\x3c\xf4\xb3\x9c\x51\x82\x8a\xed\xe9\xc6\x8c\x39\xcb\x4c\xad\x1c\xa0\x69\x77\x60\x0a\x97\x72\xfa\x66\x6f\xc6\x30\x7d\xe3\x84\x66\x6f\x79\x36\x86\x45\x7d\xd6\x62\xdf\x2a\xf8\x71\xfb\x06\xa3\xc4\x8e\x6c\x6d\x95\x71\x8e\x31\x90\x0d\xbe\x76\x6b\x6a\x1b\x5c\x4a\x2d\x05\xb9\xf0\x8a\x47\x69\x59\x78\x86\x0e\x61\x61\xf1\x88\xbb\xdc\xc3\xc3\x47\x62\x13\xb4\x16\x6e\x79\x78\x38\x01\x02\x1d\x1a\xba\xc6\x3f\x1f\x38\xc3\xe8\x80\x7e\x46\x5e\xa8\xcb\x66\x77\x1c\x6f\x2e\x1e\x1e\x22\x74\x0f\x0b\xc9\xb0\x95\x8b\xea\x66\xf0\xe1\xf8\xe0\xf0\xe2\xf0\xc3\x5f\xb8\xce\x88\x61\x66\x82\x12\xc2\x7c\x83\x4b\x54\x37\x64\x3f\x70\xba\x48\x3c\xb8\x51\x68\xc1\xd5\xc6\x65\x31\xce\xa5\xbe\x8f\x30\x63\x41\x66\x82\xb4\x56\xf9\x52\x2c\x3a\xac\xd8\xde\x55\x63\x6e\xec\x8e\x05\x85\x1d\xed\xc6\xe7\x4f\xef\xa2\x24\x9d\xc5\x0b\xe4\xdf\x54\x45\x31\x69\xa1\x79\xa2\x7c\x79\x97\x0c\x7d\xa2\xff\xd5\x3a\x32\x4a\xd4\x1f\x69\x60\x12\xe6\x0f\x0f\xa7\x28\xdf\x8c\x9b\xec\x86\x43\xf0\x08\xa6\xee\x09\x4c\x45\xa6\x57\x42\x5e\x0c\x87\xfb\xb2\xaa\xa4\x9f\x09\x34\x2d\x9a\x7d\x04\xa4\x05\x09\x9a\x23\x62\xe2\xaf\x0f\x30\x6d\x1f\x0c\xc6\xd6\xfb\x44\x80\x1f\xf9\xc3\x68\x4f\xbb\x37\x9b\xf9\x2c\x7a\x8e\xee\xc2\xad\x4b\xad\x50\x4b\x7f\x46\x73\x00\x6d\xdd\x21\x23\x1d\xc6\xc3\x13\x69\x21\x70\x6e\x21\x7f\x3d\x3b\x7f\x64\xf9\x64\xe2\x76\x03\xd6\x9f\x5a\x77\xfb\x82\x72\xf4\xda\x92\x76\xc7\x02\xc1\x20\xf3\xc5\x74\x04\xac\xf8\xe8\xca\x02\x23\xf0\x15\x3e\x5a\x0b\x18\x72\x90\xaa\x5b\xa8\xcc\x26\x95\x61\x9b\xa2\x25\x49\x1d\x05\x89\x0a\xc9\xd1\x6b\xeb\xe3\x1e\xb4\x02\x80\x62\xc7\x32\x8a\x10\x97\x88\xc1\xd7\x14\xd2\x92\x29\xc9\x0a\x03\x18\xe2\x47\x22\x46\x3d\xb6\x25\x0d\x49\x03\xc8\x4f\xab\x10\x16\x9c\xf3\x66\xf0\xf4\x4c\x58\xa2\x7b\xec\x19\x20\x84\x6f\x3e\x57\x68\xa7\xb8\xd1\xd5\x1b\x18\x23\x47\x68\x5c\x91\x82\x5c\x86\x0a\x72\x6f\xbe\x21\x3e\x1c\xdc\x9b\x49\xd8\x23\x06\xcd\x47\xc0\x3b\x7b\x2c\x02\x7b\x08\x7c\xdb\x60\x44\xa1\x95\x26\x38\x46\x87\x1c\xbb\x1d\x89\xa9\x1a\xd8\x69\x93\xdd\xe8\x9f\xa3\xed\x1a\xed\x1c\x57\x9a\xe3\xcc\x62\x89\x54\x94\xf7\xaa\xc6\xdb\xa3\x66\x0b\x7c\xb3\x7b\x48\x24\xb2\x82\x3a\xb8\x1d\xfb\xb0\xab\xac\x31\xe2\x1a\x3d\x50\x91\xd6\x56\xfd\x84\xb1\xcf\x5a\x7d\x33\x1a\xe8\xed\x1a\xd3\x5f\x0f\x75\x2f\x68\x36\x24\x5d\xa8\xaf\xd3\x07\x5e\xbb\xff\xf3\xb7\xe2\xc4\x79\x03\x17\x7f\x9c\x9c\x9b\xdd\x18\x40\x40\xee\x37\xe0\xd2\x99\xc6\x63\x32\x20\x94\xb6\x49\x1b\xb7\x79\xbb\xc1\xc9\xce\x89\x89\x86\x9b\x02\xf5\x40\xab\x5a\xa2\xe3\x6b\xae\x4b\x12\x51\xf4\x16\xc9\xb9\xd8\x23\xf6\x7f\x31\xa8\x2b\x7a\xb2\x83\x86\xc2\xa2\xf7\x8f\x10\xdf\xb3\xc9\xe7\x8a\xb7\x35\xd9\x20\x64\x08\xbf\x7a\x01\x6c\x6e\x70\xde\x74\xba\x11\x6d\xe3\x16\x31\xcd\x36\xdf\x63\x5c\x19\x33\xe1\x62\xb7\x17\xf0\x78\x69\x57\x32\x3a\x29\x1d\xa4\x95\x21\x5c\xb7\xf0\x2e\x50\x8f\x68\x38\xf4\x64\x0f\x87\x77\xbc\x90\x65\x25\x8f\x74\xff\x1a\xe3\xb6\xf9\x68\x0b\x4f\x0b\xe2\x77\x17\x42\x2d\x96\x6b\x1d\x3f\x32\x99\x61\x2e\xc0\xea\x29\xcc\x2e\xfc\xf6\x08\x22\xac\x16\xd1\x0f\x2a\x44\x2c\x78\x7a\x01\x31\x80\x52\x8d\xad\xad\x2a\x43\xad\x4b\x64\x23\x0b\xee\x4d\x48\x8d\x09\xe3\x07\x18\xd1\x62\xe6\xbc\x9b\xc9\x68\x1c\x73\xf2\xb0\x64\xdf\x7c\x10\xf3\xbe\x21\xe2\xed\x69\x3d\xdf\xc1\xc6\x7b\x00\xeb\x46\xbb\x84\x05\x72\x07\x0b\x93\xf4\x37\x05\x22\x22\x31\x14\x21\xa2\x0d\x24\x9c\x6e\xf9\x2a\xaa\xb0\x9c\xb0\x4e\x6d\x01\x43\x91\x50\x84\x8b\x48\x29\x28\xf2\xbd\x20\x59\x96\x6c\x06\xe4\xae\xc4\xce\x0f\x0f\x40\xc0\x5c\x67\x92\xc3\x42\xd4\xce\x24\x13\xec\x15\x7a\x9b\x67\xa5\x59\xf6\x06\x5e\x8d\xb2\x57\xf0\xaa\xca\x8e\x16\x62\x4f\xec\xc6\xcb\x6c\xd1\xaf\xc4\xb6\x99\xc7\x73\xe8\xe0\x35\xbb\x61\x13\x76\x85\x6a\x9e\xb3\x6c\xbe\xb2\xf8\xc2\x2a\x0e\xbb\x6b\x89\x84\x17\xd4\xe2\x63\xba\x23\xe5\xe7\xdf\x25\x7b\x25\x68\x23\x86\xfa\x48\xa3\x0f\xd9\x1d\x55\x38\xcc\x64\x24\x51\xd9\xe5\x6f\x25\x05\x99\x8c\xee\x48\x19\x3f\x5e\xb2\x43\xad\xb9\x6a\xc4\x70\x79\x78\xb8\x33\x05\x3a\xbb\x07\xdc\xf1\xe0\x11\xa0\x9d\x3b\x61\x7e\x75\x07\x3b\x21\x9e\x41\x7f\xaf\xac\x16\xcc\x92\x8c\xdf\xe5\x0b\xc6\xa5\x01\x70\x69\x51\xf7\x97\x52\xc9\xf3\x99\x20\x37\xe7\xf2\x96\x73\x23\xae\x36\x57\x8f\x09\xfd\x03\x5c\xbb\xb4\x55\xd9\x66\xf1\xa6\xe0\xa9\x09\x42\x89\x09\x22\x0a\xf1\x4c\x3e\xc3\x88\x84\x77\x1b\x0d\xcf\x02\x2c\x73\x60\xc4\xbd\xe1\x37\x2c\xb8\x5e\x1c\x0d\x8c\x8d\x0a\x1d\x07\x92\x09\x76\x01\x52\x52\x9c\xa0\xa9\xac\xf1\xcb\xd2\x7b\x9c\xc8\xb2\x84\x5d\x69\x61\x78\x65\xa4\x3f\xd7\x59\x83\x98\x20\x40\xf5\x1e\xe9\xcd\xdc\x48\x75\xe4\x06\x29\x10\xbe\xf7\xdf\x01\x66\x2c\x2a\xb4\x58\x08\x24\xc6\xb2\x13\x36\xbe\x50\xfc\x45\x01\x0b\x74\xad\x6b\x53\x31\x74\x5a\xd1\xb3\x79\x4e\x98\x5d\xf1\x54\x94\xa4\xdd\x11\x20\xea\xc5\x57\x10\x8d\x8d\x08\x2c\xe9\x8f\x26\x94\xbe\xf6\x80\xd0\xd7\x99\xbc\xc1\x5f\xc1\xb2\x3a\xb4\x78\x22\x8a\x57\xf6\x49\x30\x82\x7a\x94\x22\x2c\xcb\xb8\xa5\xe3\xe5\x70\x2d\x1b\xb9\x55\x95\x6c\xa3\x35\xb3\xe4\x1f\x31\x81\x73\xbb\x6b\x99\x42\x89\xc4\xfe\x7e\x72\x55\x91\x9e\x5c\xa7\xa7\xdc\x78\x6e\xb5\x03\x42\xa9\xe1\x92\x5d\xaf\xe5\x73\xce\xf5\x07\x06\xf5\xd6\x30\x92\x3b\x1a\xe0\x62\x13\x2a\x66\x72\x45\x04\x7a\xd1\x18\x8a\xae\x8a\xaf\x15\x50\xe3\xd1\x5a\x76\x12\x2c\x3d\xe6\x67\xa6\x36\xce\x48\xf3\x1f\x30\xec\xda\x63\x3f\x8c\x9d\x23\x17\x95\x70\xab\x7e\x06\x7c\x68\xfe\xe2\x1d\x45\xf8\x16\xbb\x4b\xc7\x98\x4d\x69\xc0\x1b\xcc\x74\x69\xbb\xa6\xaa\x1d\xf9\x37\x1a\x39\x10\x44\x70\xc6\xc5\x46\xa4\x26\xec\x88\x04\x71\x4b\x93\xc7\x36\xee\x73\x4c\x31\xeb\xd7\x9a\x5e\x7c\xa5\xd6\xf4\x94\x33\x42\xfb\xa5\xdc\xd7\xbc\x80\x54\xff\x6d\x9f\x1d\xcd\x4b\x9c\x97\xb7\x40\x29\xb5\x45\x23\x27\x1a\x4a\x4e\x78\x49\x49\xa5\xb6\xcf\x7e\xce\xdb\xeb\x77\x9a\x66\x9d\x7b\xf9\x9c\xdc\x34\x8a\xdc\xb8\x45\x3e\x71\xf4\x68\x14\xb9\xe2\x45\xb4\x7c\x42\xec\x55\xc8\xba\xe3\x59\xb4\xb6\x75\xea\xa1\x48\x95\x6e\x5b\x20\x69\x5f\x73\x7f\x29\x61\xb0\xd2\x42\x80\x5d\xf2\xe2\x88\x28\x8c\x64\x68\xe7\x77\x9e\xa1\x31\x2d\xa4\x7d\xf2\x15\xfb\x2e\x5c\x0d\x1b\x76\xcb\x53\x7e\x56\xf4\xf6\x7b\x9e\xb0\x4f\x08\x7c\x26\xc7\x7a\x6a\x6a\x04\xb6\xcb\x05\xb1\x38\x75\xa5\xe3\x80\xc2\xe0\xc7\x6c\xb1\x3b\x49\xd1\xfa\xe4\x04\x9e\xae\x69\x61\x1a\xec\xd1\xd6\xf2\x54\x0c\xd5\x2f\x60\x01\x8f\x8b\x16\xba\x99\x70\x65\x0c\xab\x0b\xe9\x6b\x66\x74\x33\xfd\x81\x05\x21\x9f\x0e\x87\x2c\xa4\x06\x65\xeb\x75\x68\x78\xa7\x43\xb2\x94\xd0\x33\x92\x0e\xc9\x3e\xc2\x9a\xb8\x74\x88\x9c\x6b\x13\xb6\xe9\x90\xbe\xbf\x42\x81\x81\xad\xb3\x50\xd3\xe7\xd4\x5b\x77\x36\xd3\x17\x94\xdc\xb3\x7a\xd3\x17\xcf\xd9\xca\xb5\x9b\xbe\x78\xc1\x56\xae\xdc\xf4\xc5\xcb\x90\x6a\x58\xdf\xec\xa6\x2f\xbe\x67\x72\x6e\xd2\x97\x61\xf9\xda\xd7\xab\x87\xaf\x70\xe0\xf2\x62\xc7\xf7\x25\x5d\x0d\x4c\x0d\x8a\xa7\x8c\x78\xaa\x01\xca\xeb\xbd\x52\x24\xc4\xc7\x5c\x4b\xf4\xf6\xa4\xc1\x4f\x35\x90\xcb\x67\x95\xe5\x0f\x94\x0a\xb6\x66\xb4\x62\x1c\xaa\xe1\x62\x5a\xfe\x53\x0d\xcc\x49\x7f\x02\x9d\x41\x61\x7b\x0d\x3c\x8d\xde\x70\x4c\xd6\xaa\x78\x1a\xdd\x55\x83\xf0\x32\x5e\x1b\x2b\x57\x03\xe9\x91\xee\xb4\x5e\xf4\xd5\x0e\x14\x31\x47\xe8\x62\x2b\x98\x4b\x85\x04\x5c\x74\xec\x01\x9d\xa4\x2f\xbe\xb8\x4d\x0a\x8b\xa0\x7f\xd8\x71\x03\x75\x53\x22\xc7\xc8\x62\xc2\x34\x76\xe6\xdd\xc2\x70\x5b\x94\x03\x0f\x32\x99\x63\xaf\x3e\x54\x25\x84\xd8\x3d\x62\xa1\xc8\x14\x65\x7f\x05\x0e\x59\x0d\xc0\xf4\xf9\x73\xb6\x62\xc3\xf8\xf6\x64\xb4\x53\xd2\xe7\x2f\xff\x4e\x33\x33\x6f\x1b\xa4\xcf\x5f\x87\xd2\x4d\xe9\x9f\x0b\xe5\xf4\xf9\x0f\xff\x27\xb0\xa1\x9e\xbf\xf4\xc5\x77\x88\x84\x3c\x55\xbc\xa0\x0a\x94\x88\x0b\x89\xca\x8d\x9e\x3d\x67\x50\x25\x8a\x6a\x3f\x3c\xd8\xd6\xd6\xc8\xdd\x2e\x78\xac\x73\xf4\xa0\xe6\xea\x41\x39\xba\x73\xa6\xe8\xf0\x85\xa7\x25\x67\x74\x53\x7d\x73\x52\x8c\xeb\x49\xf1\xf9\xd3\x51\x2c\x94\xe3\x24\x38\x06\xa8\xe4\x31\xc0\xa0\x7f\x5d\x1c\xfd\x73\x94\x9c\x0d\xcf\x1f\x1e\x30\x50\xac\xd1\x75\x49\x9f\x22\x5f\x48\x04\xb3\x7c\x16\x65\xdc\x87\x31\x10\x96\x1d\xd0\xa8\xbb\x9b\x3b\x69\xbc\x50\xec\x30\xc8\xdf\x2e\x38\xe7\xce\x14\x3c\xa2\x1c\x29\xcb\x5a\xc1\x2f\x8a\x25\xa3\x61\x3b\x1b\x4a\x21\xd2\xbd\xd0\x80\x17\xc1\x7c\x8b\xc7\xd1\x38\x68\x6d\xce\x1d\xd5\x99\x42\x3a\x34\x26\x23\xfd\xa2\x38\x7f\x78\x68\x51\x47\x91\x64\xe8\x74\x43\x25\xfb\x50\xa5\x18\xd6\x4f\x5f\x4a\x2d\x31\x8d\x5d\xc6\x9c\xbb\xb2\x39\x04\x62\xf6\xde\xbb\x6c\x5b\x97\x85\xb1\x34\xd6\x65\xd0\x11\x36\x7b\x78\x90\xa0\x86\x6a\xe4\x65\x50\xd6\xda\xed\x49\x8f\xa3\x6b\x58\xd8\x63\xfa\x42\xc4\x4a\x84\x9e\xd4\xa5\xcc\xbb\x0e\x20\x40\xa5\xe3\xa8\xae\xac\x72\x48\x82\x6f\xee\xd0\xf5\xdd\xbf\x3d\xdb\x3d\xcc\xc6\x7e\x48\x54\xcd\xce\x41\xbe\xde\x63\xc2\x76\xc8\x8c\x5d\x3a\xa5\x96\x83\xe0\x8d\x07\xc7\x11\xc8\x5a\x31\x14\xa3\x74\x78\x28\xc8\xed\x45\x48\x5a\x5d\xcf\xc5\xaa\x61\xde\xf2\x85\xfa\x59\x51\xc9\xd5\x6d\xc8\x77\xbc\xfa\x42\xc1\xd5\x6b\x42\x2e\x5a\x37\x5d\xf2\x9e\xb6\xdd\x8c\x16\xae\x53\xe3\xeb\x6d\x14\x41\x98\x5f\xc6\x7e\xdb\x8c\x10\xea\xf5\xf1\x47\xb6\x94\xee\xdc\x1c\x03\x82\xb4\x62\x32\x8a\xa3\x7f\x39\x8d\x7e\x34\xf1\xdc\x9b\xc8\xd2\x60\x5d\x08\xd5\x02\xeb\x8c\x79\x4a\xa1\xf6\xc5\x2a\x6f\x46\x6b\xa0\x8a\x27\x00\xe2\xa2\xbb\xbe\x1d\x1d\xf6\x1f\xe1\xee\xe8\x9a\x76\x74\x49\x1b\x59\x1b\x31\xad\xdc\xbe\xb9\xb7\x7d\x51\xa4\x88\xc1\x66\x87\xb0\x91\x9f\xd8\xbe\xad\xda\xbe\xcb\x3f\xb2\x75\x61\xe6\x89\x45\x10\xb1\xba\x77\xe3\x1a\x65\x10\xd7\xac\xb7\x69\xe1\x9e\xb4\xe6\xa6\x6d\xbd\x4d\xdb\xd7\xfd\xe0\x8e\x35\x7b\x17\xdc\xac\x6e\xf7\x83\x1b\xd5\x71\x63\x88\xf9\xc2\xbb\x2f\xe7\xf2\x3e\xb2\x28\x62\xd6\xae\x61\xb9\x3e\x06\x18\xcd\x38\xec\xf3\x9e\x6d\xec\xb4\x2e\x8a\x3c\xf5\x01\x6c\x54\x6c\x7e\xb1\x47\x73\xda\x90\x5f\xb9\x1b\x6d\xba\xc2\xd9\x90\xe3\x3f\xb4\x21\xfb\x9d\x80\x0d\x02\x24\x7b\xe3\xad\xef\x1a\xb6\x57\xcf\x0c\xcc\x14\x59\xff\x24\x72\xec\x43\x88\x01\xe4\xd6\x84\x01\xe7\x9a\x53\xad\x82\xa3\x43\x7e\x39\x70\xac\x43\x70\x0c\xd1\x74\x08\xbe\x35\xbc\x2a\x05\x62\x0e\xa1\xda\x50\x85\x0e\xda\x38\x75\x20\x24\xbb\x4d\xac\x54\x5a\x98\x84\x04\xfa\xe2\xd6\x8a\xab\x40\x20\x02\x6d\xc6\x6a\x6d\xc8\xe4\x5e\x07\x46\x9e\x39\x89\x4b\xc8\x62\xaf\x57\x3a\x51\xe0\x2e\x14\x48\xd0\xb8\x31\x53\x76\xe3\x80\xc5\xc8\x45\x82\x98\x98\xdc\x0c\xe2\xad\x4d\x63\xab\x5d\x54\x7e\x42\x2c\x06\xdd\x8c\xe2\xb3\xbf\x3e\xdb\xfd\xe7\xf3\xed\x24\x4a\xd2\xe8\x4f\x44\xaf\xa9\x7c\x8c\xf2\x9c\xe3\x9d\x35\xc2\x48\xa4\x54\xe2\xd7\x5f\xe1\x34\x83\xe1\xce\x90\x49\x79\xcf\xc5\x70\x3c\xd4\xb5\x08\x48\x19\xfd\x15\xbd\xee\x45\xff\x82\xd1\x14\x91\xb9\xa7\x14\x8f\x00\x4a\x52\xf4\x8f\x95\xd7\xf2\xa5\xf0\xb7\x96\xd2\x89\xdf\x10\x25\x83\x79\xd1\x5c\x15\x5c\x11\xf2\x6f\x1c\x93\x3f\x4b\x63\x8c\x96\xb9\xf7\xed\xff\xbe\xf8\x97\x73\xf1\xb4\xf3\xed\x0f\xf0\xf2\xa7\xe4\xe1\xec\x4f\x83\x38\xf9\x15\x83\x79\xfe\xba\xfd\x70\xff\xf8\xd7\x7f\xc1\x88\x9c\x6d\x7f\x9d\xdd\xf3\x3f\x9d\xed\x9e\xef\x62\x45\x2c\xb9\xcc\x9e\xfd\x8a\xff\x76\x1f\xf0\xcf\xaf\xcf\xe8\x07\xd2\xc7\x90\xbe\x1b\x0f\xb6\x93\x67\x40\x87\xdc\x3f\x22\xc9\xe7\xb9\x45\x09\x69\x79\xe0\xb3\xa1\x88\xf5\xc8\x2c\x25\xb3\xd4\xdf\xe1\x4d\x86\x55\x00\x12\x9d\x10\x86\x36\x03\x01\x70\x1e\x41\xbc\x4e\x8c\xcb\x85\x10\x9d\x6a\xe5\xf2\x66\xb5\x2b\x26\x72\xc3\x81\x93\x58\x9f\x75\xdb\xc3\x73\x38\x1c\x4a\x74\xf7\xaf\xb5\x30\x5c\xf7\x06\x59\x47\x22\x4b\x11\xd0\x5e\x71\x9b\xd5\x6a\x33\xe2\x66\x91\x47\x32\xb4\xe5\x42\x6b\x53\xb1\x88\x58\xb4\x1b\xc1\x29\x54\x0a\x31\xe2\xb7\xc3\x24\x69\x84\x60\xb7\x3b\x2b\xcf\xd9\x37\xef\x85\x6f\xa7\xe8\x9b\xed\x92\xdc\x33\x2a\xd7\x4e\xe8\x5f\x89\x0b\x7a\xbf\xd9\x2e\x20\xeb\x1b\x6d\x0f\x56\xaa\x06\x77\x18\x34\x29\x04\xb8\xd8\xa0\x80\x4d\x14\x51\x8f\x73\x79\x23\xe1\x9d\xc9\x48\xc8\xeb\x78\xb2\xc2\x4a\xbb\x71\x4e\xb5\xcf\xaa\xed\xed\x73\x26\x3b\x98\xb3\x48\xf6\x8e\xea\x6f\xfc\xf3\x06\xb9\x96\x0c\xf4\x0c\xdd\x1e\xd1\x78\xf2\xc7\x44\x81\x66\xc9\xe0\xa6\x93\xa8\x09\x77\xac\x85\x8d\x28\x63\x7c\x9a\xc7\x89\x21\x3a\x20\xe9\x71\x0b\x64\x0f\x5c\xb9\xa0\x09\x53\xeb\x27\xb4\xc8\xf4\x7c\x8c\x19\xde\xcf\x98\x52\xb2\x09\x2c\xb0\x4a\xfb\xfa\x92\x4a\x43\xa3\x8a\xdb\x71\xec\xd6\x31\x9c\x73\x49\x5a\x49\x19\x7f\x29\x54\x83\xcb\x29\x06\x40\xbf\x87\xb3\x00\xa0\xde\x62\xec\x20\xad\x72\xb3\xbb\x70\xb5\x92\x28\x10\xad\x22\x15\xb5\xa3\xc3\x26\xc1\x23\x58\xab\x1e\x05\x86\xe2\x5d\x1e\x1f\x99\x52\x4c\x5a\x3d\xf2\x67\x7f\xfd\xf5\xd9\x9f\x9e\x09\x98\xa3\x8f\x34\x67\xe8\x7e\x05\x28\xff\x2f\xbc\xc2\x76\xe7\x11\xd0\x7f\x6b\xd3\x17\x70\xbc\x58\xb8\x28\x7d\xf9\x62\xa5\x47\x8b\x17\xab\xdd\x8a\x2b\x5d\x55\xed\xb7\x04\x8e\x46\xa5\x39\x28\xfc\x97\x2c\x84\x62\x84\xe7\x10\xfa\xfe\x77\x49\x79\x2d\xf2\xab\xe2\xdf\x79\x24\x85\x87\x07\x19\xc8\x76\x20\x1f\x04\x8b\x41\x28\x57\xbe\x2b\xa6\x1d\xbb\x33\x6b\xfe\xc7\x9a\x35\x31\x18\xc8\x3f\xd8\xf7\xcd\xe8\x9f\x9c\x43\xf0\xef\x74\x21\xf2\x62\x95\xbf\x06\xc5\x99\xe0\xcc\xb5\xba\x19\x2c\xdb\xa2\xd9\xbb\x82\x86\x47\xd2\x4d\x10\xad\x35\xe9\x26\x28\xda\xab\x26\x0d\x2a\x26\x3c\x1f\x44\xc9\xd6\x56\x5f\xee\xcb\xc1\x4e\x94\x3c\x3c\xb8\xd9\xef\xeb\xcb\x72\x56\x6c\x9c\xe4\x53\xe8\x23\x2f\xb0\x69\x15\xd8\xbf\x6e\xea\x79\x11\xca\xe1\x2e\x56\xda\x8d\x8f\xd7\x14\x68\x60\xd7\xa6\x64\xb7\xb6\x22\x45\x29\x47\x65\xb5\x61\xe7\xe2\x5e\xf4\x8c\x17\x5f\x78\x2a\xe3\xba\x08\xe7\xe4\x02\x34\x25\x2b\x92\x9e\xd3\x97\x08\xcf\x97\xab\x3c\x80\x2b\x4c\xa0\xa8\xcd\x67\x84\xa4\x6c\x1f\x56\xaa\x14\xe9\x6a\x40\x36\x2a\x98\xd3\x77\x78\xe1\xf4\x25\x71\x24\x75\x63\xe9\x4b\xf4\xbc\xf1\x72\x95\xc7\x69\x41\x09\xa0\x21\xeb\xa4\x98\x95\xf3\x12\xce\x07\x8a\x8f\x3a\x21\x41\xea\x77\x8c\x04\xe4\xef\x30\x03\x85\x2b\xea\x0c\xe1\x29\xc3\xe2\x05\x1c\x8f\x1c\xa1\xfe\x25\x9f\x2d\x8b\x36\x73\xd6\x8c\x50\x9a\x6e\xf0\x5c\x47\x43\x6d\xce\xf1\x42\xe7\x6f\xe2\x63\x6c\xf8\x6c\x47\x78\xa8\x32\x9b\xde\xe5\x5e\x84\x53\x37\x1d\xcd\x36\x76\x80\x4e\x91\x36\xc7\xa3\xfc\x4d\x39\xda\xde\x2e\xf9\xa0\x80\x8e\xc5\xa3\x62\x99\xd1\x0a\xd2\x8e\x10\xa3\xf3\x0c\xe6\xde\x78\x87\xd7\xd4\xc9\xde\x1e\x22\x0d\x40\x15\x97\x49\x73\x56\x0d\x38\x96\x8d\xdb\x04\x72\x23\xad\xb6\x39\xce\x74\x96\x3a\x2a\x97\x09\xf2\x50\xbc\x8c\xe5\xf6\x10\x9d\xa2\x9e\x8d\xcf\xb3\xc6\xd5\x5a\x1f\x27\xbb\x67\xe7\xd2\x4b\x2e\x16\x49\xe4\xcb\x2c\x49\x67\x8a\xb4\x6b\xe0\xee\xc0\x01\xcc\x4d\xa9\x2c\x00\x23\x11\x8a\x84\x8b\xb4\x1d\x90\xf4\x4b\xa7\x62\xb7\x71\x75\x7f\x0a\x56\xf0\x88\xe3\x8b\xce\xce\xf1\x14\xa8\x93\x12\x89\x5b\x3c\xed\x65\x0f\xcc\x8f\x48\x15\x46\x3d\xea\x3c\x8b\xce\xa8\xe2\xd9\xce\x39\xec\x1a\xde\xc8\x99\x72\xa4\x3f\x3c\xdf\xad\xc5\x98\x87\xda\xbd\x3e\xdc\xc7\x6b\xa0\x0f\x65\xe4\x6f\xa0\x9f\x87\x3b\x78\x85\x8d\xa2\xed\x76\xb4\x59\xb6\x1f\xf2\x0f\x31\x3a\xb9\xac\x61\xcf\xe6\x5b\x5b\xcb\x8c\x7e\xda\x37\xd9\x0e\xfc\xfd\x11\xc0\xa9\x17\xdf\x6e\xcc\x3b\x7c\xd6\x22\x28\x03\x5d\x4d\xcb\xb3\x3c\x9c\x25\x21\x59\x2a\x48\xfe\x6b\x71\xd7\x86\xe0\x58\x48\x3d\xd8\x67\x7f\x05\x2a\x1e\x09\x5d\xa0\x7a\x9f\x01\x94\x9e\xc5\xbf\x9e\xc9\x84\x5f\xcf\x13\xa0\x59\x71\x05\x16\x80\x57\xf1\x84\xc7\x19\x10\x76\x6e\xca\x65\x82\x3b\xdb\x39\x52\x1b\x72\x91\x9e\x9d\x8f\xf0\x1d\x06\xc9\xaf\x05\x94\xa9\x0c\x0c\x96\x40\x0c\x72\x32\x29\x03\xe2\xa9\x94\x9f\x01\x38\x2d\x7f\xc4\x15\x06\xfb\x72\x94\x6c\x6f\x2f\xd9\x3a\xdf\x34\x8e\xe4\xb3\x87\x5f\x91\x0a\x07\x22\x26\x41\x4e\xad\xf1\x65\xe9\x3a\x51\x75\x08\xe6\x7a\xbb\x10\xf3\x99\xf3\x6d\x02\x94\xc7\x39\xe9\xbc\x9a\x00\x6e\x85\xfb\x9f\x47\xc3\xa0\xdf\xa1\x88\x61\xc9\x11\xd9\xc1\x3d\x93\xf1\x27\x23\xba\xad\x0e\x25\x2c\xd6\x2e\x2c\x53\x41\x19\x33\x03\x4b\x64\x9e\xba\x96\x91\x09\x4d\x93\x06\x0f\x5d\x97\x8c\xf4\x64\xd7\x78\x81\x2b\xb4\xc6\x39\x1d\x07\x63\x16\xf1\x38\x95\x76\xab\x90\xb1\x2b\x7e\xa9\x12\xaa\xe5\x74\xc6\x52\x0c\xd5\x32\x16\xaa\xf9\x02\xf5\xf5\x0b\x73\x71\x59\xa8\x21\x07\x0b\xba\x09\x69\xe3\x24\xa8\x55\x53\xfb\x20\x2a\x76\x2d\xd4\x4c\x13\x92\x16\x84\x0a\x60\xfd\x8a\xd5\xf3\x05\xf6\x42\x5c\x23\xcb\x0e\xb0\x58\x26\x79\x42\xa3\xe5\x9b\x16\xd0\x6a\x9b\x08\x94\x97\xc3\xbe\x03\x04\x67\xec\x1f\x20\x87\x6b\x34\x6e\xe9\x60\xfd\xc3\x4e\xa5\x9b\x64\x5c\xb2\x99\xda\x6e\x15\x05\xbb\x02\xfa\x22\x46\xaf\xc9\xda\xf1\x19\x92\x7a\x78\x2a\xf5\x7b\xb2\x5f\x71\x2a\x29\x2a\x79\x07\xcf\x1d\x75\xd2\xd9\x9b\xb9\xe6\xae\xe0\x60\x4d\xbc\x5d\x4e\xa7\x45\xc3\x1d\xfe\xa0\x72\xb0\xf0\xd9\x04\x50\x30\x15\x8a\x0f\xe0\xf4\x17\x05\x8e\x4e\x8e\x55\x19\xb9\x5e\xc9\xfe\x21\xc2\x4b\xbb\x07\x60\x58\xca\xee\x14\x62\x1a\x9a\xf1\x15\x79\xe5\x2f\xee\x33\xc5\xda\xd1\x94\x7b\x07\x3b\x2b\x33\x38\xda\x3a\xa7\x48\xce\xc5\x25\x14\x10\x06\x6e\xa4\x15\xdb\x66\xa3\x54\x2b\xc1\x9e\xda\x62\x9d\xa9\x1d\x19\x07\xc1\x66\x3d\x10\x50\x76\x2f\x74\x00\x46\x03\xe6\x71\x41\xd3\xcf\x48\xf3\xde\x4d\xdd\x46\x0c\x32\x46\x94\x01\xf9\x26\x06\xee\xc3\x13\xf6\x6d\x38\x34\x52\x63\x2f\xef\x1a\x7b\x39\x35\xd2\x81\x58\x12\x5d\xcf\xfc\x39\x50\x79\xbb\xea\x29\x6d\xe4\xd3\x48\xb9\x91\x45\x38\x8b\xa8\xd7\x9b\xc6\x9c\xca\xc5\xa0\x6f\xc1\x12\xdc\xa5\x0b\xee\x1c\xc0\xdd\x02\x3c\x05\xb8\xdb\x37\x39\x80\x3b\xe7\xe0\x5e\x66\x78\x4c\x8d\x6a\x74\x79\x20\xcf\x5d\x13\x76\x4b\x20\x5e\x00\x1c\x0a\x62\x35\x77\x49\x5d\x05\x77\xd0\x8b\x90\xb6\x06\xe1\x9b\xd3\xda\x23\x16\x34\x2d\xd6\xe1\xfe\xaf\xa0\x93\x8d\xb6\x39\x6c\xde\x54\xd0\xc9\x2a\x09\xc5\x1d\x47\xd3\x3a\xbc\xc3\xc2\x4f\x46\xce\xcf\x74\xec\x27\x26\x36\xbe\x8f\xf4\x95\x37\xd2\x8d\x22\x08\x52\x95\xed\x2d\xb1\x82\x1f\x41\x88\xaa\xce\x3a\xb4\x9f\x67\xe1\x16\xd4\xca\x2f\xb2\xb3\x42\x11\x52\x80\x8e\x7c\x09\xef\xa6\xc3\x98\xe0\x26\x4d\x0e\xac\xf0\x88\x1d\x69\x7a\xd5\x9c\xd4\x0e\x6f\x63\x3b\x80\x38\x1b\x09\xaf\xf2\x4d\x0d\xf0\xaa\xa5\xef\xf7\x06\x7d\x00\xb5\x59\x87\x73\x5b\x20\x1d\x82\x7f\x76\x25\x56\xc4\x17\xd6\x02\xc1\x29\x67\xb5\x40\xc0\x71\x52\xd1\x9a\x21\xf2\xbc\xe3\x48\x83\x0c\x74\x60\x9c\xe5\xdb\x78\x90\x6f\xa0\xc2\x16\x77\xb6\x63\x5c\xc2\xd1\x9d\x90\x44\xbd\x81\xc3\xf8\xe9\xb5\x0d\x33\x46\xbb\xf1\xec\x5c\x70\x2a\x3a\xc3\xdb\x2b\xa7\x91\xd1\x05\xac\xa2\x35\xcf\x1a\xda\x35\x9d\x12\xe4\xb8\x13\x60\x04\xf0\xe2\x44\x27\x12\xf0\x85\x4b\xc0\x87\x97\x5e\x79\xae\xdd\x31\x23\x3f\x49\xb1\x85\x1f\x39\x29\x65\xef\x3d\x9a\x3f\xde\x7e\x1b\xbc\x20\x2c\x33\x0c\xa4\x30\xc2\x8d\x96\xe9\x03\x8a\xf6\x5d\x97\x58\xd3\x23\x09\x8a\x2c\xc0\x48\x39\xe3\x40\x14\x1c\x5a\xa2\x85\x3d\x5a\x4c\x1e\x36\x5c\xd5\x0e\x45\x00\xfa\x40\x0a\xb4\xb9\xf1\x04\x75\xb4\xbb\x39\x4c\xc9\xa9\x8b\xe1\x92\x14\x55\x17\x4c\x0f\xa5\xb2\xf9\xbe\x74\x12\x27\xf0\x5b\xec\x4b\x4f\x02\x12\x91\x9f\x57\xe8\x32\x2c\x8e\x91\x71\x14\x4f\xeb\xf1\xb2\xc5\x08\xa3\xd2\x5b\xe8\x53\x8e\x5e\x85\x1f\x8c\x65\x57\xff\x84\x55\xd1\x49\x89\x54\xb0\xd5\xb1\x4a\x43\x1e\x23\xf5\x97\xd2\xe1\x77\xa8\x09\xf2\xd2\x93\x33\x58\x9d\x0c\xf0\x23\xc4\xfd\x1d\xe9\x5f\xc5\xa0\x14\x0b\x5e\x83\x12\xae\x2f\xbe\x70\xa2\x18\xdc\x14\x4d\x00\x0e\x40\xf1\xbf\x5b\xa2\x07\x33\x75\x5d\x51\x69\x70\x7f\x82\x8b\xcb\x8f\xd9\xf0\x79\x50\xb3\x24\xb6\xbc\xea\x68\x57\x3b\xc2\xff\x0e\x22\x20\x5d\x04\x27\x87\x17\x31\xd4\x4d\x06\xcf\x48\xd6\xb7\x5f\x13\x51\xd2\x19\xde\x09\x28\x1d\x29\xfa\x9c\xf8\x2c\x5a\xdc\xda\xc3\x10\x92\x1e\x24\x4f\xee\xaa\xee\xba\xe8\xca\xf1\x51\xb5\x58\x76\xd4\x8a\x76\xc2\x0d\xbb\xe5\x78\x4a\x5a\x16\xb9\x66\x20\x01\x58\x4e\x8b\xdf\x45\x51\xc5\x0b\xc1\xbe\x47\x92\x89\xf5\x1e\x27\x07\xb2\xe4\x3b\xa0\x8e\x98\x2e\xbe\x2f\x9e\xb3\x85\x70\x88\x49\xa6\x2b\xfb\xd7\x79\xb3\x8f\x33\x3d\x4b\xd8\x14\xce\xba\xae\x5e\xbc\x2b\x6e\x8a\x19\x0f\x3c\x74\x9d\xdd\x5f\x16\xb0\x53\x0b\xea\x5b\x7a\xbf\x80\x7b\x4b\x31\x81\xcd\x54\xc2\xd4\x92\x00\x88\xb3\xfc\xef\x2f\x97\x97\x97\xb3\x62\x92\x2e\xe3\xfb\xba\x7a\x6b\x54\x21\x55\x6b\xe8\x7f\xbe\x00\xf8\x07\x0a\xec\xf3\x0c\x51\xee\x11\x99\x19\xa8\xfb\x5d\x8d\x4b\xb4\xd9\xc7\x88\x18\x0b\xc2\xab\x9c\x1d\x78\x58\x4d\x18\xa5\xc1\xa4\x7c\x6c\x8a\xb6\xe5\x6f\x08\x0d\x6a\x8d\xbf\x7e\xcc\xdb\xae\x40\x5d\xfc\x09\xb7\x41\x99\xa3\x78\xfb\x26\xbb\x27\x77\x3a\xdc\x90\xe1\x5a\x32\xa4\x79\x74\x4b\xd7\x97\x9b\x3c\x2e\xc8\xf0\x3e\x11\x4e\xc1\x0a\xe1\x14\xcc\xea\x40\xca\x71\x55\x3d\xb8\xbd\x2e\xc7\xd7\x58\x7e\x09\x28\x77\x26\x50\xee\x68\x8e\xa7\x62\x9e\x2d\x4c\xf7\x60\x76\x97\x53\xa8\x82\x57\xd4\x49\xde\xe5\x14\x20\x61\xb1\xb5\x35\x97\xd5\x79\x2d\x61\x10\x9b\xf2\x44\x72\xd3\x76\x1f\xea\x13\x8d\x3b\xe5\x83\xf6\x3e\xa8\x3a\x2c\xba\x0a\xcb\xa5\x81\xdb\x04\x9c\xaf\x93\xe0\x7a\x10\xc5\x92\xc4\x6b\xc9\x9e\x0f\xf8\x1e\xef\xfc\x23\x52\xf2\x1c\x35\x4e\x64\xff\xf3\x6c\x82\xc9\x82\xa4\xba\xc9\x08\xb7\x7c\x44\x7a\x6f\x12\x5f\x0f\x8c\xa5\x45\x30\x97\x27\xc6\x0d\xb5\x97\xe5\x72\xfe\xca\x41\x3e\x86\x65\xbc\x9c\x01\xf5\x7f\x7a\x5b\x7f\xc4\x45\x78\x20\x8c\x6e\xe0\xb2\x74\x93\xb0\x1b\xdb\x7b\xda\x0d\x47\x53\xce\x4e\x4d\xbf\x23\xcd\x39\x6f\x9f\xa6\xaf\x48\xfd\xad\x9f\xf7\x1a\xde\xa3\xe9\x90\xeb\xd5\xf1\x2d\x9a\x0e\x5f\xbf\x46\x44\xe8\x89\x2e\xfb\x10\xa1\xc5\x8e\xdf\xee\x34\xaf\x1f\x40\xfc\x19\x23\x95\xee\xc3\x28\xe3\x04\x72\xda\xe5\x25\x27\x3c\xe3\xa1\x74\x11\x09\xc8\x7d\xb6\x9c\x57\xfb\x84\xd6\x61\x85\x4d\x67\xc5\xef\xf2\xf7\xcf\x4d\x7d\x2b\x9f\x4f\xae\xa1\xde\x17\x7a\xab\xab\xee\x17\x1e\x66\x17\xde\x66\x70\x66\xed\xcf\xf2\xf9\x42\xbe\xfc\xac\xb2\x00\x2e\xe3\xb2\xbb\xa3\xc7\x06\x8d\x30\xe8\x01\x36\x7e\x85\x77\x39\x76\x5b\x22\x93\x16\x9f\xfe\x8b\x02\xca\xd2\x53\x5d\xcf\xe9\x1b\xe5\x6c\x76\xac\xab\x43\xa7\xeb\x2f\x85\x4e\x40\xb6\xe2\x59\xf4\x4b\x71\xf9\xa5\x44\x99\xd8\xbc\x85\x3f\xef\xeb\xff\x82\xbf\xc7\xd1\xf9\xc8\x24\x0f\x9a\x24\xa8\x00\x53\xfb\xa9\x08\xc3\x33\xb4\x47\x83\x1b\x18\xd0\x76\xb0\xeb\x65\x90\x13\xb8\x3b\xa3\x20\xfe\xaa\x41\x65\xcc\xd4\x78\x3e\x9a\xe7\x57\x05\xf6\x4f\x27\x29\x17\x79\x56\xea\x27\x40\x45\x79\x67\xa7\xed\xd7\x33\x8c\xf1\x03\x63\xb9\xe4\xd0\xb9\xe7\xbf\xbf\x50\x38\x63\x2c\x4a\xaf\x3c\xec\xb1\x7a\x75\x6b\xf1\x28\xd0\xb2\x2e\x7f\x73\x5a\xe0\x89\x4e\x3b\x3c\xd1\x6d\x0d\x85\x1b\xb2\x2d\x7c\x76\x5a\xc2\x24\xa7\x1d\x4c\x72\x5b\x21\x37\x95\xb2\x19\x7a\x71\xda\xf9\xa4\xe3\x39\xdb\x69\x6e\x4b\x18\x5b\xfd\x5e\x3d\x3a\xad\x40\x8a\xd3\xc6\x29\x62\x14\xd9\x02\x2e\xd3\xf4\x1e\xff\xaa\x52\xf8\xf2\x17\x2e\xf1\xf0\x17\x32\x95\x44\xa9\x98\xb7\x8e\x31\xe7\xa7\x7c\x5e\xce\x68\xe9\x21\x1b\xe5\xbe\x6c\x3f\x57\x65\x37\x03\x24\xf8\x81\x58\x01\x69\xc3\xda\x6b\x40\x18\x68\x22\x24\x59\x71\x40\x25\xa2\x09\x03\x20\x8d\xb4\x74\x1d\xc2\xe3\xfe\xf6\x84\x5b\x7d\xd4\xd8\xfe\xc9\x89\x6c\x53\x8b\x0a\x7a\x28\x81\x3a\x8b\xb9\xae\x04\x1c\xa6\x28\xe3\xa3\xb1\xe3\xc9\x8a\xf1\x96\x31\x63\x82\xca\x4f\x0d\x46\xaf\xc7\x1c\x62\x12\xc1\x8d\x42\x52\x1e\xd7\x77\x8b\xeb\xa2\x42\x87\x8f\x46\x3d\x41\x7b\xcc\x8b\x79\x4d\x2d\x22\x02\x39\xae\x66\x5c\xe7\x8b\x7f\x4e\x9b\x28\xe5\x21\x27\xde\xe4\x0b\x2d\x21\x2e\xf0\xb8\x6d\x7f\x9a\xd5\x39\x8c\xb0\x31\xc9\x10\xce\xf9\x47\x84\xdf\x2b\x44\xc3\x1e\x0d\x64\x75\xd4\x68\x45\xe6\x17\xa4\xf1\xe6\xf8\x56\x1d\xcb\xa0\x1f\xef\xf3\xe6\xcb\x72\xf1\x53\xcd\xf7\x4f\x1b\x90\x13\x1b\xb7\x79\xf2\x5b\x52\x24\x14\x40\xc3\x73\x33\x23\xb5\x08\xf0\x16\x2c\x58\xb4\x0d\xde\x8c\xb7\xb3\x16\x72\xb7\xa3\x34\x62\xf0\x8c\x82\xde\x06\xde\x46\x91\xf6\x98\x23\xe2\x32\xa0\xc5\x1a\xc1\x39\xd4\x1b\xad\xa5\x50\xf0\x11\x6a\x16\x43\xbf\xef\x9b\x32\x91\x77\xd0\x3a\x2e\x19\x89\xdc\xe9\xb6\x3c\x25\x48\x64\xd2\xf6\x7a\x09\xb3\x91\x34\x90\x9b\xe5\x9a\xa7\xdf\xc2\x15\x68\xc5\x52\xc5\x8b\x12\x3a\xb1\x49\x64\x37\xc6\xe4\x9a\x25\x21\x71\x86\x90\x88\x6c\x50\x9b\x51\xf4\xf8\x18\xd0\xca\xb2\x56\x6b\xfa\xf2\xd5\x53\xe7\xa1\xbf\x50\xd3\xe1\x4b\x3a\x45\x43\x2b\x15\xf2\x48\x47\x29\xb0\x4e\xd3\xe1\x2b\x3a\x94\xfd\x65\x0a\x07\x2a\x55\x72\x0c\x5f\x5e\x7a\xc2\xce\xfe\x9b\x06\x0f\x4b\x81\xb7\x3a\x44\xe0\xad\xe1\x61\xe5\x42\xb8\xc7\xe7\x69\xa6\xba\x12\x27\x4e\xc8\xbf\x8c\xf6\xb6\xec\x3a\xd0\x14\xfb\xce\x90\x01\x8f\x6a\xdb\x0b\x73\x51\xfd\x6d\x59\x2c\xc3\x71\x32\x74\x87\x9c\x77\x32\x9a\x77\xfa\x67\xbf\x9a\x25\x64\x2d\x75\x99\xb7\x8b\x4a\xde\x0c\xaa\x0e\x74\xe5\xf4\x6e\xcf\x0c\xc1\x61\xd9\x53\xea\xa6\x58\xe7\x7c\x6f\xc4\x45\x2d\x80\x09\xc4\x1d\x9d\xe4\x7f\x42\x82\xe5\x76\xa4\x17\xbe\x7a\xcb\xfa\xac\xac\x6a\x7b\x3b\xc1\x4d\x2a\xec\xdc\x88\x69\xa5\x3e\xb6\xc3\x3a\xf5\x48\x91\xb7\x61\x53\xfa\xe1\x4a\xd6\x98\x60\xb8\x56\xc8\x3b\xb6\x57\x9f\x5a\xe5\xbe\x8e\xc9\x5a\x1c\x57\x00\x1a\x64\xd7\xa8\x23\xe6\xa9\xab\x05\xbc\x24\xda\x8b\x26\x7d\x4d\xa6\x2b\x9e\x94\xfe\xa5\x27\x8d\xee\xa5\x0c\x15\xf7\xe2\xe4\xf0\xdd\xe1\xfe\x29\xd7\x05\xa9\x80\x28\xc7\x2d\xf3\xf0\x10\x1d\x7d\xf8\xf8\xd9\x49\xc5\x9b\x72\x39\x2b\x78\x22\x2e\xc1\xa0\xa6\xf1\xef\x06\xf9\x7d\x3a\xe0\x4a\xe5\xec\x23\x86\x5f\x3f\x5c\x4d\x62\x77\x09\xbb\x1c\x5c\xd2\x8b\x88\x00\xd3\xa2\x97\x69\xd7\x76\xe1\x6e\x20\xd6\x3d\xbf\x55\xe1\xa2\xbc\x1b\x08\xb3\x38\x4a\xfa\x37\xcc\x8c\x13\xcf\x75\xd8\x71\x06\xfd\xc8\x3a\x76\xec\xea\xf1\x4b\xc5\xf7\x26\x31\x3d\x83\x41\x05\xc0\x95\xc7\x83\x49\xd1\x53\x98\x1d\xf3\xb5\xf0\x51\x98\x37\xa8\xba\xad\x1b\x37\x17\x00\xf6\x9e\x2e\x35\x54\x77\xb7\x92\x31\x71\x55\x8d\xa5\xac\xa1\x8a\x12\xb3\x64\x37\xce\x51\x56\x1b\x73\x89\xa6\xca\x7b\x3b\x5b\xc2\x39\x93\x9b\x43\x1c\xdb\x43\x3c\x81\x09\xba\x41\xb4\xc8\x3e\x48\x56\x14\x4c\x8a\x71\x50\x1c\x14\xed\xb8\x29\x17\xb0\x54\x6d\x1e\x92\x81\x5e\xa2\x1b\x4e\x01\x48\xb9\x22\x67\x42\xa9\x93\xe6\x58\x16\x60\x5f\x12\x1f\xa4\x0b\x51\x4c\x42\x6b\x61\xf4\x75\x26\x40\x3b\x29\x66\x45\x57\x6c\x1c\x8b\x9e\x7a\x90\xf6\xdb\xb0\x21\x0e\xa3\xa4\x9f\x0f\x2e\xfc\x17\xd2\x0d\x0d\xef\x20\x2d\x57\xd9\x18\x85\xb7\x57\xfa\x60\x6d\x33\x96\x44\x04\x95\x1d\xa1\x22\xf7\x09\xf4\xed\x04\x80\x28\x18\x64\xaa\xd9\x69\xdf\xb4\xd2\x7d\x2d\x30\xab\xd7\x7d\xb3\x3a\x43\x0f\xae\xe1\x59\x9d\x99\xb3\x3a\x31\xd5\xaf\x36\x45\xb9\x13\x00\x1b\x65\xf3\xd5\xb4\xb5\xa5\x72\xe0\xf6\xfd\x79\x61\xbf\x1f\xd4\xb7\xd5\xc3\xc3\xe6\xf1\xc3\x83\x00\x33\x7c\xed\x44\x2a\x53\xc0\x28\x25\xf0\x3f\x1a\x5f\x9d\x1b\xc8\x21\x88\x05\xe2\x08\xb6\xe8\xf8\xcb\x65\xfd\xbb\x46\x05\x80\x31\x9a\x7c\x52\xd6\x3a\xc5\x68\xf1\xa6\x77\x43\xa0\x57\x5a\x0d\x39\x9c\x96\xab\x1e\x06\xd8\x9d\xc9\x00\x9b\x2d\xaf\xca\xea\xe7\xe5\xa5\xb6\xe5\x0e\x30\xc6\xf6\x57\x92\xc3\x97\xd2\x02\x3b\x1f\x77\x02\xdb\x68\xf3\x6d\x75\x15\x97\x9c\xb2\x4f\xd2\xde\x9b\x12\x4e\xb8\x65\x6e\x31\xd1\x96\xdc\x65\xab\x98\x2d\x62\x45\x69\x9b\x6e\xc9\x5f\x7b\x9f\x5d\x39\xac\xaf\x53\x0c\xea\x4e\x8e\x84\x9e\xe6\x7a\xdd\x22\x53\x4b\xb8\x1d\x72\x19\x5e\x46\xde\x6a\x5e\x97\x5a\x69\xcc\x40\x48\x4c\xcf\x05\xd3\xcb\x94\xe9\xb5\xcd\xcc\xe5\xc4\xf4\x5a\x63\xa1\x05\x89\x3c\xb1\x15\xfb\x94\x1d\x64\x9b\xc3\xd1\xbe\x49\xe1\xc7\x07\xd9\x27\x5c\x53\xb4\xcd\x91\x59\xb4\x82\xc7\x98\x04\x94\xe9\xb0\xcc\x9b\xef\x13\xe9\xbf\xcf\x6b\xfe\x08\x9b\x2f\x71\x20\x7f\xb8\xf5\x1f\x44\xeb\x5f\x28\xf8\x4e\xc0\x85\xc5\x07\x44\xb0\xda\x8e\x3e\x21\xda\xde\xba\x5b\x9c\xa0\x9e\x0b\x20\x64\xf4\xb5\x61\x1a\xdc\x23\x0f\x7e\xcf\xe2\x1b\x9e\xae\xe2\x1b\x36\x92\x6f\x58\x32\xe2\x1c\x22\x7b\x62\xf7\x60\xb7\xcc\xda\x34\xcf\x96\xe9\x05\xbe\x1e\xc1\xeb\x34\x05\x3a\x1f\x63\xd2\x5e\x27\xe9\x9c\xcb\xb8\x4a\x0c\x8f\x5a\x4a\x41\x6f\x29\xe2\x15\x73\xf6\x23\x25\xce\xc2\x87\xf7\xd8\x60\x9b\x3d\x71\x86\xcf\x12\x36\x7b\x7c\xcc\xf1\x74\xe2\xad\x5b\xf7\x80\xbd\xa7\x59\x66\x6a\x67\xa7\xaf\x76\xfe\x28\x23\xcd\xda\xd3\xe9\x90\xdb\xdc\x3a\x5b\x3a\x1d\xbe\xe0\x24\x94\xbb\xa3\x81\x92\x12\xce\x00\xbc\x0d\x0d\x59\x2f\x3c\x66\xdc\x77\x9e\x22\x5f\xe0\xb2\xbe\x43\xb2\x12\x6e\x84\x80\x9d\xfb\x54\xd7\x1d\xe7\x6c\xf9\x2b\x09\x88\x55\x4f\x1c\x82\xdf\xf1\xd4\xf6\x56\x90\x76\x0e\xe3\xf6\xca\xe1\xa8\x9e\x74\x79\x23\x39\xbd\x30\xa3\x63\x27\x67\x14\xac\x84\x6c\xd8\x50\x15\x48\x0f\x57\x10\x51\xfc\x42\x75\x78\x96\x1b\x3c\xdb\x3a\x1f\xae\x0c\x94\x83\x51\xf9\x00\xe8\xc8\x32\x46\x3e\x80\x17\x9c\x2b\x34\x5c\x42\x50\xa9\xd4\x3e\xa5\x90\xc8\x52\x6c\xa9\x1a\x4b\x46\x56\x79\xfc\x94\xec\xae\x2a\x03\x35\x27\x76\x31\xce\xe1\xd6\x49\xef\xe1\x22\x5a\x50\x5d\x9d\x86\x28\x36\x95\xfe\x66\x1d\xde\x3a\xba\x48\x32\x69\x53\x79\x45\x80\x35\x21\x83\xf9\xb4\x38\x0d\x0a\xaf\x66\x63\x8a\x36\x28\x5f\xd5\x35\x8c\x4a\xd1\xed\x57\xf9\xac\xc1\x35\x1b\x27\x3a\x12\x6b\xe0\x20\x6d\x7b\x0f\xcc\xe5\xca\x03\x73\x6c\x1c\x98\xb4\x2d\x54\x87\x74\x2c\x56\xb5\xc9\xcc\x75\x23\x8e\x50\x11\x91\x55\x74\x92\x7c\x7a\x54\xdd\xde\x18\xc9\x76\x72\x2d\x30\xb5\x0f\xcb\xeb\xec\xec\x07\x36\x7c\xc1\x9e\xbf\x66\x2f\x9e\x9f\xb3\x49\xf6\xfc\xf9\x0f\x6c\x8e\xce\x59\x0d\x09\x95\xf7\x19\x25\xa8\x62\x37\xd9\x26\xc6\x2f\xef\xc3\xf4\x5b\x5b\x3d\xc7\x48\x4f\xc6\x8f\xd9\x70\xc8\xae\xb2\xdc\x39\xc0\xef\xf8\x99\x76\x28\x24\xa1\x7a\xa7\x3c\x7d\x9e\x4f\xe9\xcc\xb6\x6b\xb9\xe7\x7a\xa0\xcc\xea\xf3\x5d\x2d\x3e\x16\xd8\xbe\xcc\x5c\xe8\xcc\x5a\xce\x4c\xef\x19\x66\x2f\xea\x73\xe1\x0d\xca\xc4\x1c\x5f\x3f\x38\x5e\xef\xa9\xe1\x51\xa9\x3f\x3a\x40\xaa\xfc\x0f\x18\xa2\x40\x5b\x5f\x3f\x46\x51\xf1\xa9\x41\xf2\x62\x7f\x74\x94\xbc\xf6\x1f\x1c\xe6\xe3\xa8\x34\x54\x12\xc4\x4e\xcc\xfc\x23\x48\xe1\x23\x7e\x3b\x78\x78\x50\x09\x67\x8b\x38\x01\x70\x39\xcd\x1c\xa0\x24\xad\xd7\x8f\x16\xc7\x49\x4c\x7b\xf0\x32\x50\x1b\x7f\x65\x55\xe6\x20\x34\xa9\x32\x1c\xaa\x02\x70\xd2\xd6\x51\x5c\x6e\x85\xb2\x19\x59\xa5\xfa\xb6\x4b\xb8\xe2\xd8\xbe\x45\x55\x1d\xae\xa2\xaa\x72\xb6\x14\x74\x11\x5b\x20\x41\x34\xdf\x1d\x93\x71\x58\x7a\xb7\x8b\x67\xcc\x32\x21\xbf\xe5\xee\xb9\x97\xa4\x4d\x4f\x26\x2d\xc6\x84\xdd\x40\xce\xdd\xc3\xc3\x18\x0e\x11\x3f\x1b\x3e\x91\x79\x4d\x6e\x6d\xdd\x41\x9d\x45\x76\x27\xe1\x1a\x27\x02\xc9\x40\x5f\xc8\xab\x64\x09\xc4\x1c\x2c\x2f\xde\xdd\x69\x36\x33\x28\xb6\x31\x8d\x43\x02\x07\xae\x82\xf1\x94\x4b\x39\xe1\xea\xdc\xae\x26\xdc\xa6\x80\x80\x6d\xa6\xed\xfe\x3f\x5a\xbe\x19\x3a\x39\xd2\xe1\x8e\x4d\x9d\x79\x18\x1d\xe8\x37\xfa\x62\xcf\xb9\x91\x0e\x5f\x7d\xe7\xd3\x64\x9e\x32\xe9\x0a\x01\x29\x5d\xd0\x81\x36\x68\x8b\xa6\xe3\x3a\x03\xb4\x9a\xc8\x2f\x21\xaa\x9f\xb4\x67\x95\x88\xa3\x2c\x04\xa3\x92\x61\x7b\x40\x5c\x68\x23\x72\x04\x8e\xef\x3d\x9c\xf3\x25\x79\x90\xe2\x3b\x55\x3a\xfc\xca\x9f\x38\xfd\x5a\x8f\xdb\x8b\x3a\x9a\xe8\xe9\x23\x8b\x3a\x5d\x03\xaf\xd7\xcb\x5d\x7b\x6c\x70\xdd\xd6\x05\xb2\xee\xd1\xe1\x07\x23\x5f\x74\x54\x0c\xa6\x65\xd3\x72\xd7\x56\xa3\xa4\x50\x2e\x1e\xe1\x35\x36\xf3\xe8\x36\xa0\x95\x6f\x07\x80\x36\x8a\xe6\x40\xe9\x77\xc8\x13\x11\xda\xcb\x17\x88\xb0\x78\x0b\xd2\x37\x0f\x0e\x8d\x34\x7a\x3a\x52\xe9\x11\x62\x17\xc5\xad\x9f\xdd\x7d\xe2\x1a\x6b\x58\x06\x9d\xa1\x72\x51\x4c\x8a\xa2\xfd\xd5\x45\x18\x8f\x35\x66\x80\x2e\x6d\x98\xe0\xf9\x09\x42\x3f\x30\x6a\xee\x6f\x64\xc9\x8f\xe8\x31\xff\x99\x65\x3b\xa3\x9c\xa2\x28\x8c\x66\xdb\xdb\x28\x43\xc9\x89\x5b\x81\xa2\x91\xc1\xfb\xe3\xbf\x1c\x5e\x1c\xfe\xfb\xd1\xc9\xe9\xd1\x87\x3f\x3f\x3c\x18\x39\x9f\x0e\x29\x0f\x7d\xde\x73\xe0\x2c\x80\x14\x40\x55\x06\xa2\xe2\x81\x76\xc9\x51\x15\x1a\xfa\x85\xfd\x36\xd7\xce\x02\xbd\xd9\xca\xcc\xa3\x83\x11\xed\xb4\x65\xb6\x24\x8d\xf6\xe5\xd9\xf5\x79\x86\x7f\x88\xe5\x8e\x0f\x50\x3e\x9b\x42\x5f\xc7\x94\x22\x7c\x99\x4c\xf9\xc2\xe3\x3a\x10\x06\xa0\xd0\x7d\x21\x87\x0f\xea\x39\xd2\x35\x4e\x0e\x7b\x0e\xc3\x9c\xff\x28\xfd\x87\x8c\xe6\x30\xd4\xf1\xd9\xfc\xdc\xec\xa4\xb9\x04\x30\x4f\x6b\x3b\xde\x08\x18\xdd\x9c\x8f\x6e\xa0\xa2\xa0\xae\x39\x34\x04\x89\x5d\x0e\x8e\x3e\x9c\x1c\x7e\x3a\xbd\x78\xbf\xf7\xe9\x5f\x3f\x7f\x4c\xab\xd8\x04\x00\x9b\x9c\xe5\x83\x39\xf5\x8c\xe0\x73\xce\x90\x6e\xa2\x47\x4b\xd3\xc3\x81\xb8\xdb\xca\xf2\x4c\x03\xee\xfc\xcc\x80\x77\x7f\x7b\xa7\x87\xff\x7e\x7a\xb1\x7f\xfc\xe1\xf4\xf0\xc3\x29\x20\x67\xab\xb9\xdc\xdc\x27\x4e\x3d\x63\x7e\xd3\xa0\xec\x4a\x6c\xf6\xf4\xbb\xef\xd8\xea\xad\x0e\x18\x6d\x1d\x7c\xe5\xb1\xee\xbf\xf3\xbc\x82\xac\xa1\xd4\x11\x17\x5b\x5d\x42\x11\x90\x0d\xe9\x92\x6d\x35\x78\xff\xfe\xf3\xc9\xe9\xc5\xe7\x93\xc3\x8b\xbd\xd3\xd3\x4f\x47\x6f\x3f\x9f\x1e\xa6\x43\xa6\x12\x3f\x7e\x3a\xfe\x08\xf3\xf8\x1f\xe9\x73\xf6\xf3\xde\xc9\xc5\xc9\x11\x06\x75\xf8\xe9\xa7\xc3\xfd\xd3\x93\xf4\x25\x25\xbd\x3d\x3e\x7e\x77\xb8\xf7\xe1\xe2\x2f\x7b\xef\x3e\x1f\xa6\xdf\x53\xda\x87\xcf\xef\x0f\x3f\x1d\xed\x8b\xb4\xe1\x2b\x4a\xfc\x78\x7c\x72\x74\x7a\x84\x50\xb4\x72\x5f\xf2\x2a\x00\xde\x4f\xef\x8e\xf7\x0e\x0e\x0f\x9c\x16\xe1\x70\xe0\x66\xd1\x40\xd2\x4b\xee\x32\x0f\x58\x13\x34\xe1\x15\x45\xca\x82\xfb\x7b\xc6\xd8\x16\x50\x71\xaf\x03\x38\x5d\x2e\x3b\xe2\x50\xf2\x9c\x96\xe7\x7c\x34\x18\xbf\x3c\x63\xc9\x33\xde\x2f\x3b\xa2\xea\xde\x17\xdd\x75\x3d\xa1\x2c\x40\x6b\x65\xbb\xbf\x6c\xbb\x7a\xae\x1a\xdc\xda\xca\x07\x17\x5e\xea\x4f\xa2\x67\x52\x30\xe6\xd7\xd3\xdb\x69\xcc\xc5\xb5\xf7\x4d\xbc\x99\x43\x39\x38\xfb\xab\x49\xde\x4c\xb0\x43\xbe\x11\x18\xfa\xe1\xb0\xcb\xa0\x78\x15\xee\x90\x9c\x3f\x33\x86\x75\xff\xae\xbe\x95\x8a\x3b\x23\xc2\x5f\x44\x00\xb4\x6d\x09\x54\xa9\x55\x71\x76\x9e\x8d\x81\x54\xf3\xbf\x21\x30\x58\x09\x4d\x8f\xfa\xab\x2f\xb0\x3a\x65\x5b\xd0\xc5\xfe\x2c\x78\x18\xcf\x70\xe6\x4c\xb4\x69\x00\x1e\x93\xdb\x80\xc5\x5b\x0b\x19\xa9\xf8\x88\x3d\x1f\x58\x63\x19\xa8\x81\x11\x54\x52\x65\x8f\x3f\xcd\x3a\x3e\x86\x39\x00\x1f\x6e\x85\xaa\x2f\x58\xbd\x8a\xa7\xac\x1e\xf8\xcb\x1f\x41\x2c\xca\xcb\x96\x03\xc5\xe5\xc6\xc0\xd2\xd0\x8d\x93\x72\x52\x1c\x4e\xa7\xb0\x4c\x5b\x5d\xd8\xdd\x31\xa2\xec\x5b\x6e\x6b\x40\x84\xac\x5d\xd8\x5a\xf9\xa2\xf4\x07\x38\x51\x61\x8f\x07\x4a\x5b\xfb\x48\x94\xe6\x5a\x44\x37\x45\x7f\xad\xf0\x36\x14\xd5\x8f\x6f\x8a\x66\x56\xe7\x93\x62\xd2\xdf\xc9\xbe\x9d\x8a\x1e\x5c\x36\x83\xa0\x7e\x78\xd8\x0c\x81\x14\x2b\x84\xd2\xa9\xb8\x07\x53\x6a\x7e\x33\x04\xc0\x6d\x91\xec\x8c\x59\x26\xf7\x8e\x09\xee\xec\x64\x8c\x26\x2c\x9c\xee\x8f\x0e\xf4\x22\xb8\xf8\xb0\xf7\xfe\x30\x8d\x90\x3a\xfe\x96\xcc\x9e\xcb\x49\xc4\xec\x8d\x97\xde\x93\xa3\xa8\xd0\xde\x10\x59\xd6\xd2\x97\xc5\x8d\x65\x2f\x92\xec\x95\x8d\x89\x2e\x0c\x8d\x34\x59\x1f\x93\x6c\x18\x89\x14\x73\x90\x22\xc9\x04\x8c\x48\x0a\xad\x13\x91\x15\x86\x17\x66\xae\xc0\x73\x29\x6a\xea\xbb\xb9\x16\x82\xd6\xf6\x24\x3b\xa3\xee\xc7\xd5\x48\x53\x90\x25\x1d\x50\x17\x82\xd4\x5c\x59\xfe\xac\x3b\xe7\xac\xee\x42\x86\xa1\xda\xdc\x79\x54\xcc\x34\x23\x40\x9a\x54\xa6\x51\x40\x0c\x98\x94\xb1\x26\x43\xbf\x1c\xca\xa9\xc2\xc3\x43\x4c\x7e\x3a\xd0\x26\x19\x6e\xa9\x88\xac\x31\xad\xd2\xfa\x46\x8e\xb7\x67\x58\xa8\x68\x89\x52\xc1\x1f\xfe\x28\xfd\x7a\xa0\x72\x5f\xed\xea\x73\x05\xcf\xfa\xd5\xea\xf6\x3d\x0a\x9c\xc2\xf7\x06\x46\x3b\x72\xf7\x48\x71\xbe\xb5\xb5\x29\x73\xac\x6d\x82\x39\xdc\xb2\x16\x85\x1b\x4d\x2f\x0a\xc1\x72\xc3\x37\xb2\x89\x9e\x2d\x85\x85\x78\x6c\x51\x93\xde\x30\x0e\x59\xad\xcd\x52\xb4\xe3\x7c\x41\x04\x3b\x4c\x87\xf0\x95\xa9\xaf\x4a\x21\x85\xb1\xdc\x53\x18\x2b\x43\x0a\x63\xa8\x03\xb0\xfd\x4d\x16\x7d\x83\x5a\x63\xad\xa7\xd4\x75\x74\x10\xf2\x5d\x91\xc7\xcd\xc0\xdb\xfd\xc9\x36\x6f\x0b\x9a\x62\x4e\x2b\x3d\xeb\x87\x02\x64\xaf\x3e\xc1\xd1\xbe\xc8\x2d\x03\x70\xe3\x26\x88\xd4\x8a\xed\x38\x05\x8d\x88\xbc\x43\xd4\x58\x9d\x81\xa9\x5e\x73\x8e\x76\x76\xeb\xb8\x4c\xd2\x1c\xfe\xc0\x40\x3b\x3e\x50\xd5\xac\xb7\xd9\xd0\xd6\x4a\xac\xb0\xdd\x28\x82\x6a\x85\xae\x96\x7a\xda\x6a\x41\x00\x09\x4b\xcb\xa7\x40\xd4\x85\x40\x04\x7b\xe9\xde\x80\x87\x43\x0c\xf0\xfd\x5f\x26\x28\xb3\xaa\x8d\xd8\xec\x31\x7e\x33\x11\x01\x9d\x50\x9b\xc0\xed\x1f\x41\xdc\x88\x6e\xee\x1d\x5e\xf0\xdd\x02\x25\x72\x1a\x0e\x81\xf9\xe8\xce\x59\x14\x6d\xd7\x96\xfd\x7b\xe3\xd1\x38\xd0\xc9\xc6\x3d\xd6\x3a\xb4\x8e\x8f\xb6\xc9\x08\x0c\xe5\x7f\x35\x46\xaf\xc1\x97\x1a\x4e\x26\xae\x31\x17\x98\x0a\x92\xd6\xf1\xc9\xa8\x77\xe5\x4d\xcd\xcc\x4e\x9d\x3e\x77\xbc\x7f\xc4\x47\x0c\x81\xe1\xeb\xd7\xf1\xca\x49\xaa\x56\x4c\x52\x95\xe0\x47\xb8\x40\xff\x69\xc8\xbb\x43\x0b\x02\xdf\x0a\x92\x15\x82\x3b\x13\xab\xa6\xe7\x14\x88\xb5\xf2\x02\x49\x32\x7b\x27\xa9\x3e\xc7\xcb\x3e\x4d\x11\x3c\x96\x4f\x4d\x51\x68\x66\xac\xbb\x63\x2b\xee\x8e\x06\x82\x4c\xbf\x23\x3e\x59\x10\x3d\xa6\x43\x9e\xb9\xb6\x9e\xe2\x77\x6b\x5b\x44\x99\x6e\x7c\x0c\x55\x7f\x66\xb8\x46\x21\xf3\x41\x03\xad\xf7\xaa\x11\x1b\x1e\xd7\x88\xc7\x81\xde\xf1\x39\xe6\xd4\x08\xbe\x98\x2f\xba\x3b\x79\x7e\x5b\xec\x2f\x5e\xf2\x97\x26\x5f\xf4\x71\xbd\x9e\xfd\x35\xfe\xf1\xec\xaf\x1b\xbf\x3e\x7b\x73\x8e\x3e\xc0\xc6\x19\xa7\xd2\x38\xeb\xe3\x5b\xea\x6f\x84\x9e\xc1\x7a\x78\x21\xb6\xdb\xc6\xd8\xd0\x25\xd6\x57\xb2\x4e\x7a\x16\xdb\x19\x2d\x7e\xd4\x91\x36\x91\xd9\x11\xe3\xc5\x07\xb9\xd5\x95\x7a\xca\x51\xa6\xde\xa1\xf7\x36\x36\xc3\x93\x1f\xff\x10\x7f\x06\x1f\xf0\x9a\x84\x05\xc5\x7d\x84\xa2\x17\xed\xd0\x87\x3a\xee\x3c\x0e\x56\xff\xcc\xdf\x5d\x7c\x23\x4d\xa8\x2d\xd5\xad\x39\xd6\x98\x60\x8d\x89\x5b\x63\x9e\x48\xf3\x96\xc9\xd9\xfc\x7c\x84\x7f\xb2\x1b\xd3\x01\xd6\xbf\x0c\x37\xd0\xc4\x1a\x4f\xc6\xed\x39\xfa\xf7\xfa\x26\x11\xfa\x34\x35\xb4\x46\x66\xc3\x68\xb4\x5e\x72\x20\xf0\x91\x5f\xc9\x91\x6f\x6f\x2f\x78\xf3\x77\xd9\x15\x8e\xe5\x0e\x3f\x6f\x5c\x81\xed\x77\xb8\x87\x01\x7e\x9a\x67\xdb\x77\xd6\x6e\x85\x64\x76\xe7\x6d\x09\x48\x6c\xe3\xcd\x69\x60\x3c\x6c\x8a\x83\xb8\x63\xe4\x78\x58\x39\x38\x69\xe3\x6b\x0a\x66\x25\xf5\x3f\xdb\x78\xaa\xd5\x42\x95\x63\x13\x36\x05\x54\xf7\x14\x5f\xd1\xde\x1a\xf6\x52\x60\xa4\x6f\xd8\xc6\xd1\x75\x37\x9f\x45\xe4\x24\xa8\xcb\xaf\x08\x13\x5a\x37\xec\x44\x48\xf0\xe1\x28\x04\xd8\x9d\xed\x9c\x8f\x0a\x9b\x89\x46\x1f\x16\x6c\x50\x52\xe6\xf0\x22\x67\xaf\x56\x72\x0e\xee\xa3\x74\xf8\x92\xfc\x73\xdb\xdb\x08\xf0\xc3\x90\x79\xbb\x28\x1d\xbe\x7a\x1e\xe6\x28\xad\x36\x13\x32\xcc\x08\xa4\xcc\xb5\xc9\xce\xaa\xf8\xfe\x53\xd1\x2e\x6a\xdc\x4f\x86\x46\x86\x94\x6a\x41\xf6\x49\x39\x5f\xcc\x8a\x70\xde\x69\xbe\x08\x67\x1c\x56\xe8\xa1\xa2\xc8\x6f\x7a\x2a\x72\xd5\xa1\x9e\x0f\x92\xb4\xa0\xa7\x9e\x23\x2e\xf0\x0a\x18\x56\x80\xe1\x02\x7b\x55\x3e\xbb\xc3\x58\x9e\xe1\x6c\xee\x6b\x8a\xbb\x9a\x22\x0d\x29\xbf\xd8\xb9\x6f\xbb\x6a\x4b\x23\xd6\x36\xe7\xf0\x64\xf5\x4d\xaf\xac\xbe\x76\x04\xee\x24\xe5\x93\xa2\x76\x4b\x20\x81\xe6\x5b\x1a\x03\xcb\xa9\x46\x65\x7f\x5b\x94\xbd\xcc\x4a\xdc\xce\x3f\xa1\x2c\x80\x6a\x62\x2c\x98\x71\x76\x3f\xa7\x96\x71\xfe\x52\x38\x43\x6c\x69\x28\x90\x89\xf7\x70\xfe\xeb\x12\x02\x70\xb6\x34\xb3\x55\x62\xc8\xe3\x65\xc7\x8c\x37\xa0\x60\xe1\xf2\x44\x1f\xa0\xb5\xb1\xf2\x03\xbc\xc4\x1f\xf8\xc0\x23\x20\xfb\x33\x1e\x27\x0c\xfe\x9c\x93\x3f\x49\x2d\x16\x1c\xaf\x36\xd2\xcc\xb9\x27\x20\x72\x1f\x65\x36\x0b\x08\x30\x87\xdd\x8f\xd2\xb4\xc9\x69\xde\x5c\xa1\x97\x37\xce\xa1\x16\xf7\xc4\xc4\x72\x1e\x29\xe2\x07\x5b\x1d\xe5\x9a\x9a\x76\xb3\x9e\xc7\xc9\x05\xb7\xa5\xe7\x4a\x0d\xc8\xe9\x4d\x16\x59\xa7\xe9\xa1\x69\xd6\xd9\x32\x9a\xd1\x22\x9b\xee\x4e\x65\x78\xd3\xbf\x94\xc5\xed\xc3\xc3\x54\x60\x2c\xee\xfc\x4c\x38\xa8\xa3\xc3\xe1\x9a\x4d\x46\xfe\xf0\x96\xdd\x2e\x20\xe1\x8e\x4d\xb2\x65\x68\x90\x5d\x2d\x87\xf8\xf0\xb0\x48\x52\x28\xba\x80\xa2\x1d\xaa\x6c\x68\xab\x4c\x3d\x82\x79\x76\xbd\x4b\x2b\xeb\xe8\x20\xbe\x4e\xd2\x28\x62\x70\x86\xa9\x94\x09\xa5\xc0\x21\x65\x8a\x31\x07\x7a\x49\xb0\x39\x4c\xc1\xe8\x8a\x4b\x62\x22\x4a\x9f\x61\x7a\x84\xc2\x6d\xea\x52\x76\x0d\x8f\x56\x27\xb3\x89\x08\xc2\x17\x68\x94\x96\x29\xbb\xc1\x46\x45\x47\xef\xcc\xb6\x8b\x8a\xc2\xfb\xde\xc9\xb6\x27\x74\xa2\x99\x6d\x5f\xa3\x02\xbf\x92\xa4\x6a\xbc\x66\xc8\x52\x31\xec\xd9\x9c\xdd\x24\x40\x1f\xec\x9c\x67\x57\xf0\x33\xc4\x73\x6e\x16\x70\x1d\xfe\x95\xe2\x55\x63\x47\xa7\xc3\x9d\x57\xac\x07\x03\xa4\x43\x1e\x4b\xc1\x46\x43\xab\x8d\x5a\xec\xe3\xe0\x7d\x89\xa1\xf6\x08\x03\x01\x12\x94\x1a\x0f\x5c\x90\x26\x15\x1b\xc4\x56\xac\xb1\x84\x54\x79\xe2\xc6\x11\x52\xb1\x54\xbf\x22\xe6\xd4\x6f\xbe\xd2\x0b\x0b\xe8\x72\x84\x32\x0c\x1d\x0b\x9e\x43\x06\x18\xef\x8b\x6a\x69\xa4\x2d\xee\xf4\xcb\x52\x37\x73\x50\x2f\x61\x14\x76\x57\x0e\x9a\xfc\xca\x7a\x31\x3b\xc4\xdf\x25\x5a\x53\x29\xbf\x97\x9d\x95\xa0\x11\x93\x4c\xc1\x9d\x6c\x25\xd8\xe3\x39\x80\x89\x55\x2f\x3c\xf8\xa8\x7c\x23\xcd\x5b\xf5\xa6\xad\xdb\x99\xa1\xa1\x66\xbc\x73\x55\x34\x23\xe1\xb3\x6e\xf8\x5d\x9d\xeb\xa1\x68\x1d\x35\x2b\xe5\x7d\x6d\xf4\x5c\x6e\x7e\x27\xc1\x1c\x0b\xa5\x18\xdf\xe0\xc6\xe0\xf2\xed\x13\x99\xce\xc8\x37\x1e\xff\x44\xbf\xda\x5a\xc2\x3a\x7d\x79\x39\x37\x00\xaa\x4d\xd6\x55\x4a\xbd\x1c\x5f\xf3\x10\x54\x76\x9a\x39\x55\x94\x60\x8d\x86\x52\x6c\xb8\xff\x72\x5d\x88\x36\x1e\xc9\x03\x9e\x75\xfe\xa5\x35\x93\x1b\x0e\x3a\x49\xea\x11\x6d\xda\x98\x3b\xb6\x54\x67\xbb\xd8\x1d\xb0\xb1\x5e\xe1\xc6\xf2\x8c\x6e\x8c\xbd\xe4\x5e\x84\x9a\xec\x7e\x46\xbe\xde\xbd\x40\xc4\xea\x7e\xe6\xb9\x8b\x8f\xfd\x34\x0a\x8e\xb9\x39\x4c\x30\x08\x09\xd2\xdb\xa6\x1e\x69\x31\x08\x39\x96\x17\x15\x1e\x1f\x91\x79\x60\x58\x6b\x50\xeb\xb6\xf1\x46\xb4\x8d\x1d\x0a\x37\xed\xd8\x68\xf0\xa2\xd8\xa8\x50\xe1\x97\xe8\xc1\x51\x5a\xfe\xfa\xe1\x35\x18\xb5\xf8\x6b\x86\x47\x15\xb0\x27\xb2\x4e\x45\xd6\x5c\x48\x4f\xc0\xf1\x28\x34\x30\x8d\x76\x42\x3e\x47\x7c\x7a\x1b\xe6\xf7\xd5\x3a\x1a\xbe\xae\x71\x82\xd0\x1b\xbb\x73\x89\x38\xca\xfc\x2c\xfc\x99\xd5\x32\xd2\x9e\x3c\x4e\x8e\xaa\xae\xd6\xf4\x9b\x30\x44\xdf\x53\xd9\x13\x4d\xc7\x99\x57\x66\x0a\xe0\xae\xd4\x1c\xcc\xeb\xaf\x76\x62\xd8\x65\x0d\x79\x0e\x84\x2b\x99\x3c\xa9\x10\x73\xd3\x01\x49\x7d\x7a\x5f\x4f\x96\x33\xe4\x9a\xf0\xb9\x2d\x92\x51\x8d\xae\x76\x9c\x3a\xe4\xbc\xd8\x4b\x45\xa3\x36\x27\xa9\x68\x8f\xaa\x63\xb4\xbc\x26\x88\x21\x9f\xa1\xfd\x88\xde\x53\x70\xba\xba\x38\x41\x7f\x28\xa6\xd9\x51\x83\xa7\x7a\x8b\x4c\x48\x22\xd7\x68\x28\x40\xa7\x69\xbe\xba\x78\xe4\x3e\x66\x9a\x81\xca\x18\x18\xe9\x82\x0d\x7f\x24\x5c\xb9\xf1\x60\x46\x76\x30\xda\xac\x10\xc1\x33\xc3\x45\x74\x44\x6e\xc9\xd3\x37\x66\x8d\x86\x93\xca\x2f\xba\x19\x7e\xf9\xf6\x2d\x17\x02\x05\x6a\x88\xac\x47\x46\x84\x28\x3e\x4a\xb8\x71\xc9\x37\xe0\xf4\x41\x5f\x16\x73\x69\x64\x3e\x73\x58\xa5\x27\x87\x01\x3a\x0d\x04\xb5\xe0\x68\x27\x8f\x37\xab\x87\x87\x80\x0b\x1c\xe5\x99\xba\x25\x76\x47\x8c\x3f\x14\xb4\xb9\x11\xf1\x33\x31\xf4\x67\xa8\x55\x89\xff\x48\x6c\x23\xa9\xc1\xad\xad\x8a\x62\x74\x72\xfe\xe4\xd3\xf5\xa0\x82\xb0\x0f\x33\xeb\xed\xcd\x66\xb2\x6a\x1b\x16\x3e\x71\x9b\x64\x51\x15\x5b\xa2\xda\x2b\xed\x29\x4a\x53\x5b\x08\xef\x45\x0b\x3e\x47\xb0\xa5\x76\x60\x3f\x29\x69\xd5\xf8\xcd\x72\xb4\x94\x12\xab\x19\x74\x73\x49\x0c\xcf\x99\x14\xa7\xcf\x06\xd6\x67\x54\xeb\x23\x54\xc4\x43\x83\xec\x9c\x2d\x12\xcd\xe8\xc8\xa1\x5b\xa6\x21\xa3\x35\x9e\x82\xac\xd8\xeb\x78\xc9\x78\xcc\x07\xd7\xbc\xd1\xb7\xb2\x85\xbe\x09\x47\x26\xf0\xe1\x31\x5a\xdb\x6f\x2e\xa1\xe6\xc5\xc5\x62\xd9\x5c\x59\xe5\x11\x5d\x60\x86\x31\x7f\x6f\xf3\x2a\x14\x97\xbe\xed\xa5\x58\x1d\x24\x97\xbe\x1a\xb2\x10\x8a\x4b\x39\x6b\xc2\x41\x70\xe9\xf0\x25\xd9\x5e\x04\xf0\x1b\xa0\xdc\x57\x41\x66\xc6\xab\xb5\xcd\x1f\x08\xeb\xe5\x4a\x13\xaa\xe0\x2b\x42\x20\xc1\x16\x96\x03\x43\x69\xa3\xed\xc2\xac\x8c\xab\x37\xe8\xde\x7e\x73\x29\x27\x1f\x6d\x84\xef\xcb\xb8\xb3\xe7\x34\x61\x66\x81\x4c\xfa\xd5\xed\x06\xfa\x42\x69\xab\x7d\xd4\x49\x19\x37\x31\xf7\x8c\x09\xb3\x82\xe2\x68\xdb\xe6\x81\x5c\xcd\xc2\x54\xf5\x6e\xf7\x80\xdb\x01\xd6\x5f\x9a\x9c\xf2\x8d\xa4\xdb\x80\x1e\x15\x66\x0a\x1f\x6f\x2c\x7a\x12\x79\x26\xc4\xa5\x77\x5d\xc6\x2a\x1f\xb5\x0d\xf9\x29\x94\x1e\x5e\x1d\x21\x2c\xb9\x7a\xb7\x3f\xb2\x1b\xd7\xb1\x9f\x4a\xb5\xf1\x9c\x46\x5f\xda\xb6\x15\x87\x02\x44\x0f\x12\x43\x21\x1a\x5b\x95\x0b\x17\x56\x3f\xfb\xc0\xe0\x13\x50\x19\x63\xa6\xd0\x20\xdc\xe4\x23\x18\xe1\x8d\xac\xe3\x95\x87\x2f\x93\xa7\xec\xbd\x98\x7f\x14\x88\xf7\x62\xef\xfb\xc7\x5e\x2c\x1d\xc8\x32\x3b\x89\xf9\x3d\x27\x8f\x75\xb0\xc7\x9b\x39\xf6\x8c\xfb\xd6\xd3\xca\xd8\xe4\xa3\x57\xfa\x98\x63\x15\xc6\xba\xea\x3d\x97\x7c\xed\xaa\xcd\xa1\xf6\x78\xd8\xef\xf8\xa2\x49\xa4\x5f\xe4\x02\x7d\xfd\x79\x2b\xb4\x49\xb6\xb6\x5a\xc8\x41\x97\xd0\x28\x5c\x8f\x37\xf1\x0d\xc8\x14\x4c\xab\x59\x47\x11\x97\x3a\x74\x04\xc7\x23\x71\x85\xe8\x8f\xa0\xea\xd7\xc4\x82\x32\x67\x8c\xb8\xb0\x94\xec\x87\xfe\x95\xe2\xd7\x11\xea\xbd\xb6\xd3\x8f\xae\x6f\xf7\x70\xbf\x1b\x3d\x99\xfd\x4e\x42\x56\x75\xa8\xa7\x31\x58\xa0\xe7\x7c\xaf\x2a\xe7\xdf\x06\x73\x05\x50\x38\x79\x15\x30\x67\xd6\x8e\x7a\x66\x0d\x4a\xe0\x41\xaf\x87\x28\xb0\x56\xc7\x65\x71\x3e\x52\x08\x4e\x39\x45\x10\x31\x01\xfb\x91\x8e\x03\xb8\xc4\xf3\x4a\x52\xe9\x6f\xa0\xf3\x85\xd1\x13\x10\xd1\x4e\x8c\x39\x66\xf2\xd0\x52\xad\xdb\x43\x57\x9b\xd6\x29\xb5\xec\xd1\xb9\x78\xb5\xbe\x4e\xb8\x65\x87\x36\x1f\xe8\x7b\x2f\x50\xad\x32\x45\xde\x40\xdd\x24\x7e\x51\x0d\x47\x9c\xb4\x9b\xc3\xdb\xaa\x5b\x1b\xd3\x1c\x77\x07\xc1\xba\xdc\xac\xdb\xae\x4b\x77\x5d\xcf\xe9\x81\x54\xe4\xbe\x90\x9b\x47\xd1\x4f\xe4\x24\x43\x25\x1f\x1d\xd0\xb1\x60\xfb\xea\x84\xd5\xab\x5d\x75\xee\x8c\xea\x1f\x2b\x15\xdb\x6c\x93\x28\x7a\x7d\x61\x3e\x81\x6e\x2c\x8a\x49\x0c\xd7\x06\x20\x91\xd0\xd7\x7a\x85\x4e\x50\x71\x7a\x84\x14\x18\xad\xf8\x30\xd9\x71\xb3\xa0\x34\xf0\x45\x70\x0e\xc9\xc2\x1b\x10\x49\x8f\xf7\x13\xd2\x28\x57\xd4\x28\xb5\xa1\x83\xb1\x3b\xd5\x08\x53\x37\x8e\x2b\x06\xf2\x2d\xc2\x6f\x21\x3e\x18\x78\x15\x1b\x12\xdc\x9f\x87\xe9\x9d\x41\x23\xa1\x00\x20\xab\x27\x01\xd9\x25\x66\xec\x83\x9d\x51\xf3\x63\xb7\x06\x24\x1b\xae\xa0\x8e\x1e\x55\x09\x9e\x80\x44\x15\x77\x15\x5e\x1e\xa5\x70\xbd\x13\x90\xd5\xb9\x23\x13\x4f\x98\x4e\x22\xe4\x38\x70\x48\x1a\x86\xde\xd8\x57\x40\xaa\x33\x1d\x39\x7c\x25\x5c\xae\x63\xcf\xf5\xae\x9a\xd6\x5d\x3e\x04\xae\xdb\xe9\xf7\xec\xe9\xf9\x32\xa7\x7d\xa1\x77\xce\xe6\x66\xa8\x95\x47\xce\x3c\x0f\x4b\x5d\xae\x7d\x1a\x60\x92\xdd\xf3\xab\x27\x27\xb1\x8d\xbb\xa8\x79\x50\x89\x45\x9b\xa1\xd3\xdd\x79\x36\x75\x04\x2c\x37\xe8\x1c\x0c\x50\x46\xd9\x62\x8c\xbb\xb2\xc5\xcd\x8e\xcf\x0d\xd7\x3b\x6c\x3a\x7c\xa9\x99\xba\x48\x63\x00\x5f\x89\x69\xd3\x19\x73\x2e\xd8\x69\xee\xa6\xa8\x2b\x77\xda\xf6\x66\xe1\xe2\xda\xeb\x4e\x1b\xb8\x41\x8c\x51\x17\x50\x17\x48\x17\x86\x16\xdb\x84\x01\x92\xe1\x28\x8e\xdf\x4d\x80\x5c\x5b\xd7\xf5\xa1\x8f\x79\xbf\x46\xb3\x1d\x71\x81\x58\x11\xce\x79\xbf\xe2\x94\x94\xeb\x65\x0e\x2d\x34\x89\x4b\x61\x37\x92\x5c\xe9\x76\x27\x03\xc9\xca\x9e\x0c\x24\x1f\x9b\x95\x28\xea\x27\xbb\xfa\x11\x7a\xc7\x6a\x42\x8b\x6e\x1a\x4c\xc6\x50\xa9\x8d\xbd\x12\xad\x82\x90\x40\xf7\x37\x1b\xa3\xa3\xcb\x8e\x35\xc7\xb6\xb5\xb5\x30\x58\x1d\x1e\xe3\x22\x4e\x06\x50\x1a\xbd\xd2\x2a\x93\xae\x58\x37\x8d\x32\xe2\xa2\x81\x81\x15\xae\x2f\x1c\x11\xdf\x02\x2f\xe5\x6e\x47\x3c\x7a\x4a\x46\x4a\x7b\xaa\x20\xab\x33\x0e\x7e\xe4\x1b\xc5\x55\x18\x88\xa1\x64\x0c\x63\x59\xb9\x40\xac\x7c\x20\x5a\x87\x46\x18\x8a\x6e\x9f\xb6\xb6\x4a\x1f\x1e\x1c\x7f\xd8\xee\x7a\x92\xfb\x6b\xd2\x2c\xf3\x3c\xf2\xe0\xe2\x59\x77\x0a\xb4\x2c\x08\x3d\xbe\xb1\x92\x15\x96\xf3\xa2\xb1\xfc\x4c\xce\x15\x33\x66\x3d\xd8\x67\xd1\xe3\xe8\x64\xda\xc3\x2c\xbc\x5e\xc1\x2c\x9c\x64\xb3\x81\xc7\xd5\x06\xd4\xb4\x18\x18\x97\x7f\x44\x4c\xab\x6c\x03\x01\x9d\xe8\x6c\x1b\x2d\x91\xfc\x74\xb5\x34\x2c\x5d\x7e\xa5\xd3\x54\xd7\x03\xc4\xd7\x31\x0f\x10\xdf\xac\xe3\xcc\x7a\x33\x18\x3e\x81\x8b\x46\x1f\x1e\x36\x85\xe7\x68\xed\xd9\xd8\x4d\xb1\x95\x82\xb9\x2f\x6c\xa9\x5c\x02\xd8\x9d\x3f\xff\x52\xe3\x8a\x6b\xd3\x90\x2f\x73\x9e\x27\x0a\x5a\xbc\xec\x36\xad\xd0\xcd\xf2\x66\x4f\xf4\x58\xc8\xf3\xa3\xda\x26\xa2\x21\x14\xf8\x22\xa4\xa9\x09\x59\xae\x85\xbe\x16\x78\xe2\x1c\x55\xfc\xab\xe9\x66\x15\xf0\x30\xf1\x6a\xb5\x36\x99\x54\x9e\xee\xd7\xf9\xed\xd1\x18\x43\xe5\x3c\xbd\x83\x7c\x7b\x0c\x96\x87\x0b\x48\x0b\x0c\xb8\x79\x9b\xf9\x9e\x1d\x05\x5c\xca\xdd\x7c\xd3\x28\x83\x8d\xbd\x6c\xcb\x32\x82\xe2\x98\xd8\xf9\x61\x13\x0a\xd8\x99\x6e\xc1\x3e\x53\x09\xa4\x00\x6b\x43\xdb\x48\xc8\xea\xd5\xe2\x21\x15\x1a\x7c\xa2\x6d\x39\xaa\xb2\xe9\xd6\x16\xa9\x48\xfd\x04\x8b\x0a\x0e\x25\xfb\x0d\x95\x94\xba\x45\xfa\xec\xd9\xed\xed\xed\xe0\xf6\xc5\xa0\x6e\xae\x9e\x9d\x7e\x7a\x76\xf2\x97\x3f\x0f\x87\xcf\xa6\xbc\xcc\x3f\xbf\xcd\xdb\x72\x7c\x42\xfc\x74\x78\x8d\x58\x34\x1c\x0c\x23\x8e\x69\xae\x91\xf0\x70\x55\xf7\xb9\xb3\x7a\xd3\x43\x7d\xd1\x76\x83\x4b\x58\x31\xf1\xb3\xbf\xc6\xa8\x71\xf7\x80\xc7\x78\xf2\x2d\x46\xf0\xbc\xa0\x38\x9e\xbf\x4e\x2e\x06\xbf\x7e\x7b\xfe\xa7\x7f\x79\x96\x30\x6d\x86\x95\x22\xf2\x28\x16\x82\x34\xe2\xcf\xe8\xe0\x59\xc9\x02\x73\xb2\x7d\xfb\xd7\xe2\x4e\xbe\x12\x89\xc1\x9f\x67\xb3\xfa\xf6\x27\x78\x3a\xa1\x25\x9a\x96\x0f\x2d\x4f\x3b\x6d\xf2\xaa\x25\xad\x85\xf1\x5d\x5a\x42\x9a\x6c\xab\xbd\xab\xc6\x88\x90\x96\x5d\x8d\x62\x61\xbc\x03\x8a\x1c\x48\xf9\x38\xcb\xef\x20\x13\x2e\x60\xb3\x8f\xb0\x6d\x30\xf2\x2d\x17\x8a\x40\xc2\x09\xba\x08\x56\x09\xd0\xbf\x13\xe8\x5f\xc9\xc8\x93\x15\xd0\x03\x39\x7c\x79\x8c\xbe\xf5\x8e\x0e\x30\x15\x9f\x38\xf3\x7e\xb7\x04\x4a\x6b\x5c\xcf\x5a\xe8\xdc\x0c\x1f\xa0\x21\xd1\xfb\xb1\x30\x45\x35\x5f\x0e\x27\x65\x97\x03\x85\x61\x24\x0a\xf9\x74\x49\x6f\x0d\xb6\x44\x1f\xab\xeb\x66\x22\x64\xb7\xe3\xa6\x6e\xdb\xe3\xa6\x94\x3a\x45\x0c\xc1\xaf\x9e\x8a\xd3\x12\x3a\x52\x32\x40\x21\x44\xdb\x4d\x4a\x21\x90\x85\x83\x2d\x27\x62\x06\xc1\x06\x1b\xbd\x42\x75\x70\xa0\xe3\x26\x4d\x7e\x75\xa5\x3b\x01\x30\x44\x02\x94\xbf\x00\xda\x9c\x43\x5b\xf8\xc3\x83\x20\x8b\x97\x43\x51\x88\xbf\x09\x4b\x15\xfe\xf2\xa1\xfe\x4b\x3e\x2b\x49\xee\xde\x52\x02\xbf\x6b\x61\x2e\x86\x1e\x7a\xcb\x7d\x14\x97\xec\x9a\xbb\xc5\x85\x87\x72\x32\x11\x93\x79\xdd\x14\x53\xfe\x61\x7c\x7a\x97\xcb\x09\x40\xad\xbb\x9f\xa4\xdc\x1b\x57\xf7\xe1\xdf\x96\xe5\x8d\xa0\xae\xc7\x72\x79\x94\x30\x2f\x6c\x96\x5f\x4a\xc9\xef\x4c\xd5\x47\x19\x2a\x7c\x69\x56\x63\x14\x69\xf8\xce\x3c\xaf\xca\x69\x41\x69\x73\xe8\x1d\x1c\x20\xbc\x33\x54\x98\xa7\x70\x1f\xc1\x22\xe1\x77\xf5\xf0\x8e\xae\x61\x58\xaf\x98\x94\xb9\xfc\xfd\x73\x53\x2f\x85\x98\x7b\xce\x61\xc1\x9f\xe5\x04\xcd\xd1\xf6\x13\x56\x1f\xff\x38\xec\x27\xbe\x82\x2a\x5a\x32\xa4\x6a\x64\x02\x0d\xb6\x8a\xa8\x07\x87\x22\x1c\x91\xf2\x05\x55\x07\xaf\xeb\xd9\x44\x4a\xd8\x17\x75\xab\xb4\x0d\x16\x4d\x31\x53\x12\x7c\x72\xad\x66\xf4\x09\xce\x9e\x09\x2a\x06\xd3\x47\x1b\x09\x9e\xa6\x00\x20\xa2\x66\x06\xa4\xd5\x33\x9c\x4b\x54\x2c\xa6\x75\x0b\x0f\x7a\xdd\xb6\x40\xb9\x5c\xd6\x02\x04\xed\xb8\x96\x6b\x83\x07\xa3\x54\x9b\xa4\x2d\xf2\x39\xfa\x31\xa6\x89\x6c\x49\x7c\x2f\x86\xd9\x5e\xe7\xaa\x0e\xfa\x45\xc6\x2f\xe0\x03\x14\x65\x2d\x7e\x06\x5e\x17\xb0\xe7\xf6\x71\x73\x89\x72\xcd\x58\x3d\x1c\xd4\x63\x98\x57\x78\xe0\x5b\x90\xdc\x3b\x00\x1d\x01\x63\x17\xc3\x23\x77\xb7\x42\x6c\x9f\x5f\x72\x47\x49\xe2\x8d\x56\x1e\x7f\x46\x2f\xcb\xe2\x51\x2d\x6f\xe4\xab\xe4\xa2\x15\xf2\x5d\x01\xfd\x5d\xa2\x3f\x71\x9a\xe2\xdb\x79\x3d\x41\xb0\x10\xf6\xc8\x17\xb0\x53\x29\xd8\xa9\xc2\x1f\xfb\x75\x83\xd4\x8d\x58\x7c\x5d\x31\x47\x2c\x07\xe5\xf1\xf1\x84\xe0\x84\xa0\xc0\x37\xb1\x57\xa4\x57\x41\x61\x20\xe1\x19\xa2\x4a\xdc\x28\xf1\x61\xc4\x5f\xbf\x1d\xf3\xf7\xc8\x40\x34\x11\x3d\x46\x6a\x67\x44\xb0\xd3\x22\x63\x6b\xd0\x19\xf0\x2d\xce\xf0\x4d\x44\x5f\xb2\x0c\x5b\xe1\x43\xf6\x98\x22\x7c\x1f\xab\xf7\xc8\xc6\x98\x3c\x57\xbc\x45\xd6\xd8\x45\x16\xbd\xf0\x1c\xae\x93\x42\xe9\x14\x93\x23\xd2\xb8\x96\x12\x61\x19\xdf\x45\x0a\xcb\x44\xf0\x80\xf3\x11\xe9\x1d\x1f\xe1\x13\xee\xdd\xc8\x5c\xc8\xdc\x5f\x20\x7a\x3c\x5f\x44\xe6\x72\x89\xe8\x99\xf0\x72\x24\x57\x4b\x04\xbf\x70\x78\x46\x72\xd1\xe0\x3b\xc2\xcf\xe2\xfc\x5d\xf7\x6a\xdb\xf7\x29\xe0\x22\xd1\xb3\xbe\x2f\xfd\xe4\x7e\x29\x8c\x32\x0a\x11\xd5\x44\x1c\x1e\xef\xca\xea\x8b\x0c\x9b\x23\xb3\x68\xf1\x61\x46\xe2\xf0\x02\xc9\x7d\x93\xdb\x10\x95\x86\xdb\x98\x95\x28\x55\x65\xdc\xfb\x63\xb0\x05\xd1\x95\x35\xda\xd0\x1e\xa7\x9c\x9e\x0e\x10\x7f\x14\xe8\x08\x02\x6b\xc4\x85\xd0\x81\xe3\x05\x12\xe7\xfa\x65\x34\x60\x40\xa1\xaf\x09\x51\x24\x11\x51\x7a\xb4\x76\x2a\xce\x94\x74\x91\xb1\xf4\xd9\x2e\xe3\xec\x1e\xf6\x52\xc7\x9d\xe6\x4b\xa7\x93\xf8\x5c\x4a\xff\xfa\xe2\xac\x81\x27\x5a\x4e\xf4\x40\x6a\x48\x18\x1b\x80\xab\x16\xa1\xcb\xf7\x59\x76\xff\xbe\xfc\x1d\xb0\xf7\xfd\x42\x7e\x31\xbd\xe7\x08\xc2\x9e\x7d\xc1\x34\x2a\x48\xe6\x3d\x3e\xe3\xae\x2c\xcf\x51\x5d\x41\x82\x12\x9f\x25\xfe\xc5\x67\x79\x0a\x4b\xaf\x9a\xe8\xa3\x85\x94\xba\xe2\xe8\x3f\xea\xe5\x06\x7c\xef\xa6\x9c\x14\x93\x8d\x7c\xe3\x37\xfa\xe0\x6f\x98\xb4\xd8\xe8\x6a\x48\xc1\xd3\x74\x63\x5a\x16\xb3\x89\x8e\x41\x5c\x6d\xfc\x26\x3f\xf5\xdb\xc6\x35\x5d\x32\x9b\xc1\xc6\x29\xc0\x1b\xca\xcc\x66\x1b\x0d\xd9\x3a\x40\x65\xec\xc4\xb7\x35\xf4\x82\xb7\x30\xd8\x38\x9a\x6e\x74\xd7\x85\x68\xaf\x85\xd6\xe0\xe7\xb2\xd8\x80\xe3\x09\x3b\xb8\x81\xeb\xfa\xb7\x89\x61\x22\xf3\xdb\x60\xe3\x18\x2a\x34\xb7\x65\x5b\xb0\x0d\x00\xda\x46\x51\xe2\xbb\xd9\x81\x1a\xde\xe4\x68\x7f\x1b\x60\x20\x5b\x49\x31\xad\x80\xdb\x3f\x04\x58\xe2\x3b\xff\x23\xc0\xb5\x2f\xfa\xf2\x87\x00\xa6\x54\xde\xda\x01\xc2\xec\x91\x84\x5e\x7f\x71\xd6\x9e\xa1\x20\xe5\x6c\xcb\xdd\x18\xf1\x06\xf3\xd2\xc5\xbe\x4c\xad\x0c\x6a\x7b\xdf\x9b\x21\xaf\x75\x63\xcf\x92\xa4\x56\xb7\x6f\xee\x66\xe7\x0b\x22\x8b\xbe\x71\x2c\x07\xf5\x15\x43\x28\xbd\xa6\x8c\xef\xe7\x3a\x53\x02\x2c\x64\x4b\xe1\x60\x8d\x74\x38\x0c\xbb\xd3\x78\xb5\x5a\xe9\xde\xc6\xeb\x52\xa5\x2c\xb6\x0c\xa0\xe8\x53\xc2\x36\x8b\x2e\xd9\x87\x80\x4d\x3a\x32\x63\xfd\xc7\x29\x6e\x75\x4d\xbe\x78\xcb\x79\x92\xae\xe0\x13\x3b\x9d\xf3\x60\x59\xc8\x2c\x5e\xc2\x55\x62\xa2\x0d\x52\x9a\x81\x5b\x95\x38\x56\x7e\x6c\xad\x11\xf7\x55\x3e\x03\x6a\x60\x66\xf3\x19\xd0\xa8\xa5\x2f\x0f\xa5\xfc\x4c\x45\xf7\xfa\x05\x76\xd2\xe7\x6a\x1e\x0c\xf0\x15\xaa\x8d\x8c\xb7\x95\x4d\x07\xac\xe4\x7a\xc1\x9d\x72\xaf\x9b\xff\x08\x25\x92\xd5\x2a\xd0\xff\xb4\x86\x29\x86\xab\xcf\x59\x7b\x76\x14\xa5\x65\x5e\xc0\x6f\x60\xab\x2c\x0c\x4a\x65\x61\x50\xdb\xb2\x3c\x19\xc9\xa1\x14\xa7\xe8\x28\xdf\xda\xda\xcc\x61\x77\x8c\x51\x85\x99\x0c\x10\xc4\x73\x86\x7e\x56\x03\xaa\xaa\x61\x36\x5b\x58\xc9\xd1\x53\x62\xb5\xb7\x88\x8a\xbb\x54\x24\xdd\x35\x4c\xd2\x06\x62\x6e\x1c\xa2\xc0\xde\x96\xcb\xfa\x0d\xde\xe1\x8d\x71\x5e\x55\x75\x87\x48\x15\xeb\x22\x6a\xd4\x8c\x30\xc3\x18\x2f\x53\x11\x17\x59\xe5\x47\xce\xb3\x65\xbf\x30\x0f\xc3\x51\xf3\x23\xb4\x4f\x9c\x14\xa5\x9c\xd5\x48\xc5\xac\x3a\x53\x79\x22\x12\x21\x7e\x7b\x33\x93\x5e\x73\xe5\xc7\x6a\xdd\x01\x52\x80\x29\x93\x8a\xeb\x4d\xc0\xf5\x20\xa1\xf8\x96\xf9\x39\x45\xe7\xd4\x1a\x5b\x9d\x1f\xfe\xfd\xf5\xda\xba\xa1\xe6\xbe\xb7\x23\xfe\x71\x18\xe0\x76\xe1\x2a\x0d\x32\x14\x2d\x1a\x2e\x48\x7b\x37\x21\xc7\x75\x32\x17\xf5\x22\xd6\xe1\x37\x79\xf7\xd1\x08\x8d\x55\x4a\x51\x00\x66\xa9\xa3\x70\x83\xb5\x13\xfc\x51\x34\x28\xbe\x5a\xf5\x7f\x15\x79\xff\xfd\x5f\x15\x40\x6b\x88\xd9\xcd\x1a\xf3\xbb\xfc\x43\xe8\x7e\xc3\xd5\x39\x14\x02\x1e\xf1\xed\xa6\xff\xdb\x75\xd6\xac\xf8\x76\xc3\xbf\x5d\x33\xa1\x57\x54\x9b\x5f\x97\xda\x55\xe8\xf9\xc3\xd9\x71\xda\x85\xb2\xea\x43\xd9\xdf\x07\xdc\x80\xfd\x7d\x28\x79\x1f\x72\xa6\x9b\x66\xb9\xd9\x8f\xd2\xf8\x28\x3a\x25\xea\x99\x79\x78\x37\x63\x10\x93\xb0\x5a\xc7\x93\x20\x59\x87\x7a\x43\x67\x8a\xa1\xfe\xfe\x08\xdb\x06\xde\x30\x54\x11\x7a\xcc\xb5\x3b\xcd\xe3\x77\xa0\x06\xd3\x10\xb5\x1a\x1b\x20\x89\x83\x4a\xeb\x7a\x62\xcd\xfa\x68\xd7\x5a\x69\x6b\x1a\xf4\x42\x31\x86\x04\xf9\x39\xf4\x97\xa1\x5e\x30\xba\x4c\x25\x35\x7a\x33\x40\xf7\x68\x68\x7b\x6f\x06\xbd\x48\x67\x40\x14\x15\x7b\x62\x9f\x52\x93\x18\x27\xa9\xbb\xad\x9d\xb4\x1a\xce\xb3\xa6\x70\x4b\x96\x6c\x5a\xde\xb8\x89\x79\x40\x55\xd1\x3b\x00\x5e\xaf\xd6\x22\x34\xb6\xab\x71\x8b\x3c\xc6\xf0\x91\x58\xc3\xb3\xc8\x0b\x29\x73\xd3\x31\x46\xf6\xa0\x40\x79\x3a\xb6\x78\x2a\x78\xab\x26\x07\x74\x7a\x5b\x76\x85\x59\xa0\xb5\x0a\x10\x1f\x51\x5f\x92\x78\x2a\x57\x7d\x38\x46\xfb\x2f\xc7\x41\xaf\xf6\x41\x3f\x13\x6e\x35\xcc\x64\xc1\x9a\x22\x03\x1f\x9d\x09\x43\xc6\x78\x4f\x8b\xcc\x4a\x32\xbb\x34\x35\xb3\x38\x65\x7c\x24\xf9\xe1\x5a\x12\x25\xfc\x3c\x9a\x52\xb2\x96\x64\x51\x3a\xf7\x5d\x71\x95\x8f\xef\x74\x27\xe7\x01\x83\xc5\x9b\xa0\x57\x45\xc8\xb8\x32\xef\x8f\x45\x33\xd5\xc1\x01\xbc\x2b\xe5\xa1\x91\x7e\x52\x34\x37\x45\xc3\x2d\xc5\xb9\x7f\x91\x7d\x23\x97\xfb\x6a\xd3\x43\xbd\x0c\x07\xe5\x11\xf1\x01\x26\xc5\xa2\x29\xc6\x82\xb0\x13\xb1\x01\xf0\x6a\x21\xba\x38\x9a\x0a\x39\x41\xcc\xa9\xb5\x8b\x6c\x6c\xcb\x8b\xd8\xad\x4a\xf9\x29\xc7\x2d\x7d\x37\xba\xc8\x26\x83\x5b\xa0\xe8\xf6\x2d\x67\x33\x17\x18\x44\xc0\xcc\x10\xc5\xe3\x5b\xde\x32\x86\x14\x98\xc3\x3e\x23\x29\x01\x0d\x24\x62\x11\xbf\xf2\x44\x6c\x3e\xe0\x4f\x09\xc6\x19\x90\x4b\x32\xbd\x9f\xe7\xe8\x72\x11\xfe\x32\x41\x3b\xa5\x2a\xe6\x1d\x50\x7c\x48\xe2\x61\x34\x6a\xd4\xa7\xc7\x21\xa5\x9f\x88\xdb\x04\x5b\x56\x01\x36\xbd\x63\x65\x55\x76\x25\x71\x96\x4c\x2d\x01\xeb\x2e\x30\xb0\x55\x08\x50\xf3\x9e\x8f\x98\x42\xd8\xa4\xf9\xc0\x78\x63\x16\x74\xd2\x0b\x66\xc1\x26\xbd\x65\xca\x56\x60\x0f\x43\xe6\x55\x14\xee\x4e\x4c\x56\x3a\x1f\xac\xc8\x5d\x55\xf3\xed\xdd\xd1\xc1\xea\xda\x58\x82\x71\x20\xa6\xef\xc5\xc3\xa9\x88\xe4\x9b\x1e\x0e\xec\x04\x23\x3f\x47\x7b\x3c\x6e\x84\x6e\x96\xd2\xc9\x6c\xc9\xa9\x69\xf5\xa5\x3d\x52\x73\x82\xde\x84\x33\x58\xd9\xd2\xa6\xe5\xb0\x9b\x0c\xcc\x57\x99\x27\xa1\x37\x1e\xd8\x09\x0c\xef\xca\x02\x83\xc0\x1d\xd4\x78\x63\x17\x17\xed\x02\x2f\xab\xe9\xa5\xe8\xbc\x86\xea\xef\xee\x7a\xd2\xbb\x43\xaf\x30\x8a\x60\xf0\x3e\x71\x2b\x2b\x10\xf5\x37\x22\x8b\xa8\x1c\x9d\x40\x8d\xba\xc0\x0d\x7e\xc3\x00\xf3\xea\x2f\xe9\x82\xd6\xf7\xcc\x64\xef\xab\x3a\x33\x51\xd0\x0f\x41\xc7\xcd\xd3\x49\x12\xbf\xf1\xb6\xdd\x69\x49\x1e\x47\x21\xb9\xf0\xc5\xc5\xa7\xc3\xbd\xfd\xd3\x8b\x83\xc3\xbf\x9c\x1e\x1f\xbf\x3b\xb9\xf8\xf3\xbb\xe3\xb7\x7b\xef\x2e\x7e\x3e\x3e\xfe\xd7\x8b\x8b\x60\xb0\xe2\xd5\x55\x04\x2a\xda\xda\x5a\xab\x98\x30\xa9\xa7\x41\x96\xcc\x3c\x61\xd2\x25\x33\x8f\x83\x74\xc1\x82\x67\x64\x5a\x31\x07\xf7\xa7\xd7\x8c\xab\x4a\xcd\x99\xc6\xe3\xe9\x0d\xb3\x50\x6e\xba\xff\x98\x8c\x4e\x65\x84\xe5\x2c\xda\x19\x0c\x9f\x0f\x9e\x47\x46\x6c\xac\x53\x8f\xbd\x6b\x1c\xcc\xe9\x77\x2f\x57\x19\x20\xac\xf2\xc0\x10\x0c\xb6\x65\x9f\xe2\xe9\x6b\xed\xc0\x58\xcf\x73\xfa\xfa\x3b\xb6\xe2\x04\x4f\x5f\xbf\x66\xee\xf9\x9d\xbe\xfe\x9e\x05\x4f\xef\xf4\xb5\xfe\x2c\x9e\xc3\xe9\xf7\x3b\x2c\x78\x08\xa7\xdf\x3f\x67\xbd\x47\x70\xfa\x83\xce\x54\x41\x2b\x7e\xf8\xce\x4d\xd3\xc7\x7f\xfa\xc3\x2b\xd6\x77\x62\xa7\xc3\x1d\x6d\x73\x6c\x1f\xd8\x90\xf5\xb2\xc7\x1c\xd9\x3d\xae\x21\x5d\x83\x81\x4e\xeb\x74\x38\x1c\x32\xff\xb0\x96\x9c\x9c\xe0\x59\x0d\x99\x1a\x3e\xf6\x51\x9d\x0e\x9f\x53\x73\xc6\x91\x0c\x57\x5a\x82\x9e\x3e\x91\xd3\xe1\xf7\x78\xc9\x7d\xbd\x5a\x07\xd8\x20\xff\x38\xb8\xf0\xa2\x6c\x12\x05\x4d\x80\x4c\xa9\xfd\xeb\x5d\x49\x41\x62\x04\x07\x26\x60\x56\x53\xfb\x4c\x1d\x8a\x06\xff\x01\x2e\xaa\xea\x73\x47\x07\x82\x83\x82\x6e\xd7\xb1\xa1\xa3\x03\xee\xa0\x2b\x6d\x94\x52\xac\x57\x20\xc4\x04\x08\x0d\x25\xfd\xe1\x75\xcf\xfc\xf9\x24\xf3\xfa\xda\x7b\x6a\x80\x4f\xdc\xe1\x85\x7d\x02\x9b\x24\xe4\x6a\x69\x72\x9e\x4d\xb7\xb7\xd9\xec\x0c\x1f\xc9\xc4\x4c\x3e\x5b\xee\x88\x5c\x86\x4c\xed\x51\xe2\x5c\x4f\xaa\xf4\xd2\x0d\x5b\x4c\x93\xea\x36\x99\x4c\x24\x1c\xd0\x44\xb7\x54\xa3\x79\x5f\xe0\x30\x0d\xe1\x84\x4b\x0f\x8e\x7b\xe3\x42\x09\x07\x43\x9b\x43\xa0\x9a\x77\x30\xc6\xb9\x34\x91\x8f\x2e\xe1\x6f\x64\x18\xc9\xcb\xc8\x47\xda\x50\x3e\x22\xae\x4e\x14\xb0\x95\x8f\x0c\x6f\xf1\xb0\x3b\xdc\x22\xdc\xde\xd9\x2c\x44\xc2\x55\xb7\x98\xb0\xa2\x37\xcb\x71\x07\xdb\x91\x6b\x54\x1f\x09\x0d\x06\xd8\xf6\xcb\x48\x59\xd7\x43\xea\xe2\x2e\x92\xf6\xf5\x11\xa0\xd6\xc8\x35\xb0\x8f\x26\x97\x33\x3d\x0a\x32\xb3\x8f\x50\x2f\x41\xbd\xd2\x68\x30\x45\x0e\x43\x5b\xdb\x8b\x64\xf2\xc4\x60\x1a\xdd\xf3\xf4\xdf\xcb\x4e\x25\x73\xd3\x7b\x4a\x17\x5e\x21\x4c\x0b\x7c\x4a\xaf\x6f\x8c\x66\x04\x7c\x30\x5d\x03\x86\xcc\xf1\x21\xad\x5e\x44\xda\x04\x3f\x12\xa2\x4e\x65\x85\x2f\x02\x48\x99\x86\xf8\xd1\x97\xe2\x0e\xd5\x2e\x64\x22\xb7\xc6\xc7\xd4\x05\x3e\xc9\xe4\xcf\x0b\x4a\x5b\xf2\xe6\xb5\x25\x3e\xf7\x38\xa1\x1a\xd0\x06\xf9\x3c\x03\x19\xd2\x3a\x03\xed\xf2\x79\x7a\x2d\x7a\xa1\xad\xf3\x45\xba\x1c\xa8\x34\xd2\xe7\xc9\xe2\xb3\xdc\x52\x3f\x5a\xe0\x4f\x64\x98\xe7\x47\x5c\xe8\x1f\x85\x4c\xf4\xa3\x56\x26\x18\x2b\x54\x1b\xe8\x93\x5f\xfa\x23\x05\x15\xd3\x4e\x3f\xea\xf0\x65\x4c\x2f\x3a\x93\xa6\x9c\x72\xe4\x9c\x6b\xb3\x7d\x9e\xae\xc6\x6c\x58\xef\xf3\x1c\x3d\x5d\xdc\x8a\x3f\xba\xc5\x9f\xe8\x11\xae\x95\xd1\x05\x39\x70\x55\xfc\xe5\xa3\x83\x68\x9b\x13\x8d\xf1\xfb\xbc\xbb\x1e\x34\x70\xa0\xd5\x73\x40\xb2\xdc\x3a\x2a\x7e\x8e\xf7\xcd\x65\x8c\x3e\x61\xd9\xbd\xc6\x04\xca\x26\xd5\x50\xf1\x2e\xb5\xe5\x71\xa0\xa0\x65\xb0\x89\x0e\xf9\xf8\xd1\x79\x2a\xd8\xc1\xf1\x7c\x70\x6d\x25\xc0\x77\x07\x7e\x33\xa4\x2d\x8e\x76\x3c\x15\x57\xe6\x31\x5b\x0d\x95\xdf\xda\x0a\xa5\x0e\x74\x0b\xc4\xe6\x41\x4d\x73\xa7\x3d\x25\xa4\x8b\x37\x43\x2d\x3c\x3c\x04\x93\x07\xaa\xa5\x18\x2d\x51\xb9\xf3\x82\xd3\xba\xc7\xdd\x7e\x9d\x75\x68\x2f\x17\xd7\x88\x4a\xcb\xa7\xcc\xf1\x48\x73\xcf\xe6\x9e\xcf\x00\x59\x2e\xb4\xcd\xed\xe2\xcd\x8c\xfc\xf4\x0b\x05\xba\x16\xfd\xf6\xe7\xae\x39\xd0\x34\xd9\xda\xca\xcf\xa6\x68\xa4\x3c\xc5\xf8\x08\x03\xb9\x4a\x76\xc7\xb1\x58\x27\xc9\x6e\x70\x6c\x9e\x08\x45\xd7\x65\xa2\x26\xab\x93\x14\x9a\xa1\xbd\xf4\xc7\xdb\x32\xaa\x63\x83\x5f\xdf\x00\x3a\x2c\xc7\x36\x4e\xc4\x76\x85\x46\xd4\x58\x79\x1a\x0e\x56\x6e\xe6\xcd\x9d\x15\x9d\x14\xa1\x67\xcc\x8f\xf0\x16\x98\xaa\xff\x75\x5d\x74\x6b\x07\xab\xfe\x72\xf4\xe1\xe0\xf8\x97\x8b\x9f\xf7\x3e\x1c\xbc\x3b\x34\x3a\x4f\xe8\xf6\xe1\x41\xbd\xe3\x19\xb9\x1b\xc3\x58\x04\x02\xc6\xa1\xc4\x5f\x33\x16\x1e\xbc\x50\x56\xaf\xc3\x9b\xae\xaf\x32\xc5\xdc\x11\x27\x74\x9d\xd0\xcc\x53\x43\x48\x1c\xa0\xcf\xbb\xf5\x81\x62\x76\x03\x6a\xaf\xec\x88\x5f\x9b\xf7\x83\x2a\x13\xbe\xaf\xd1\x31\xfc\x99\xca\x42\x8f\xf0\xf2\x9d\x3e\x84\x09\x49\x7a\x1d\xda\x19\xeb\x7d\x75\xca\xae\x61\x07\x11\xf7\x1a\x7e\xc9\x44\xf3\x91\xad\x14\x4e\x1a\x3e\x4b\xd6\xfb\x84\xe4\xc7\x7b\xa0\xff\xea\x66\xed\x89\x93\xed\x16\x15\xb2\xc1\xf8\x62\x24\xf1\xfa\xfb\xba\x2a\xe1\x96\x83\x8c\x08\x03\x09\x96\xd3\x78\x73\x21\xad\xe6\x31\x32\xf3\x14\x0e\xeb\x6b\xa3\x5a\x3b\x0a\x7e\x78\xce\x5b\x33\x0a\xa2\xc0\x0a\x28\x3c\x8c\x1a\xdd\x6b\x09\x5c\x7f\xbd\x1f\x87\x7a\x2d\x3f\x0e\xf5\xc0\x78\xb3\x7c\x31\xd4\x96\x72\xbf\xe3\x70\xa1\x1e\xd8\x09\x21\xc7\x0a\xb2\x8c\x99\x08\xb7\x73\x7d\xb3\x98\xff\xd1\x38\x8e\x41\xaf\x01\xfd\x17\x70\x9f\x42\x4f\x7f\xa0\x5c\x97\x3e\x4f\x87\x2f\x7e\xe8\x8d\xe6\x88\x97\x98\xaf\x73\xb8\x4d\xf7\x2a\xc1\x12\x95\x82\x52\x19\x9a\x4f\x24\x0b\x22\x39\xeb\x3c\x7b\x7e\x6d\x6f\x54\x8c\x6a\xb7\x15\x21\xb1\x72\x5a\xe1\x91\x32\x1d\x7b\xf8\xda\x12\xba\x4a\xd5\x0a\xe1\x34\xda\x90\xc5\x90\x0f\xe4\xd1\x82\x4c\x98\x4a\x43\xf2\x12\x97\x21\xb3\x1f\x1a\xc3\x3c\x47\x5f\x4d\x70\x49\x97\x83\x82\x04\x35\xce\x4e\x25\xc9\x31\x56\x9e\xbd\xa6\x31\x46\xb8\x6f\xd5\xba\x41\x38\xfc\x37\xbd\x88\x13\x15\x8f\x53\x21\x5d\x09\xd4\xe6\xe7\x24\x40\xf4\xe7\x44\x50\x52\xf4\x64\xd0\x3e\x3a\x96\x9c\xd2\x70\x29\x04\x14\xf4\xdf\x0e\x97\xc2\xd2\x80\x4c\x43\x35\x54\x3c\x2c\xb4\xbd\x41\x0c\x57\x2a\x10\xd5\x89\x69\x35\xb8\x8c\x2d\x5f\xeb\x8e\xe9\x8e\xd1\xca\x92\x8c\x88\x2c\x33\x1e\x33\x3a\xbb\x92\xa1\x48\xcb\xa0\x3d\xd4\x6d\x54\x12\xa1\xa9\xe7\xe8\x7c\x36\xf0\x44\x5f\x28\x4d\x81\x64\x5f\xfa\x35\x9a\x39\xf1\xe3\xd9\x14\x1b\xb0\xd2\x4a\x76\xcd\xc5\x03\x93\xec\x5e\xf1\xf8\x19\xf2\xfd\x5b\xc1\xe1\x1f\x9b\x8c\x82\x09\xdf\xce\x81\x00\xf3\xa1\x01\xa4\xc3\xef\xbf\x0f\xf8\x22\x7e\xbd\x86\xf5\x48\x50\x40\x65\x32\x55\xa4\x28\xcb\x94\xa5\xe9\xe0\xcc\x65\xf8\x0e\x1e\x54\xac\xf1\x1c\xd9\x2d\xb3\x36\xbe\x7f\x7f\xfc\xf9\xc3\xe9\xe1\x01\x27\xf1\x3f\x7f\x30\x5f\x31\x64\x1f\xde\xd6\x95\xf3\x21\xae\x2e\x1f\xf0\x41\x64\xf0\x10\x2d\x62\x3d\x8f\x37\xc7\x34\xf5\x03\xe2\xe0\x1f\xa1\x8a\x22\xaa\xaa\x10\xff\x1e\x96\x89\x64\xed\x1f\x1d\xa0\xa7\x57\xa3\x15\x36\x1d\xbc\xcd\xc7\x5f\x80\x32\x3e\x3a\xd0\x3c\x4d\xa8\x10\x48\xc5\x4e\xe2\x81\xf3\xae\x9c\x16\xfb\x77\xe3\x59\x91\x2e\x59\xa0\x18\x1f\xa1\x50\x79\x54\x8c\xa6\x00\x2f\x4a\x68\xe9\xc8\xd6\x90\xed\x5d\x10\x29\x26\x60\x43\x57\x13\xdc\xc9\x6e\x80\x2d\xad\x3f\x30\xb8\x40\xa2\x1e\x96\x82\x98\x53\x11\x2e\xf0\x42\x58\x66\x8b\x54\xae\x86\x24\xfc\xe5\x52\x83\x71\x89\x77\xb0\x8a\x2b\x7d\xa1\xd6\x02\x2a\x0b\x98\x05\x9e\xd6\x85\x62\x79\xbc\x83\x4e\x31\xe9\x7b\x04\x5c\xb8\x61\xa0\x7b\xe0\x50\xbf\x00\x69\x8e\x67\x28\x77\x46\x31\x8f\xd1\x8d\xf5\xc7\x80\x9d\x84\x03\x9d\x7b\xed\xe1\xeb\x92\x07\x71\xc6\x9e\x5f\x48\x40\x1d\x21\xe7\xa2\xca\x67\x01\x80\x35\x5f\x0d\xb0\x35\xc7\x00\xa8\x1f\x81\xd9\x28\x60\xae\xe8\xa8\x92\x77\x59\xab\x57\x2b\xf4\x4a\xe5\x61\x01\x44\x72\x2f\x8a\x96\xdc\xf4\xc0\x82\x0b\x66\x39\x50\x9b\xc9\x06\xfd\x3e\x60\xf7\x4b\x58\x9e\xd2\x78\x3c\x30\x4e\x79\x06\x79\x23\x25\x95\x7a\x5b\x18\x16\xf2\x5e\x15\x56\x90\xab\xb3\xd0\xb7\x90\xda\x0b\xa8\x04\x05\x8b\xf2\xf1\x8e\x1a\x44\xad\x5a\x1a\xd7\x7e\x2a\xa6\xa7\x9c\x81\xcb\x6a\x38\x6f\x1f\x5d\x1e\xac\x1a\x8e\x07\x22\x1b\x40\x7a\xb5\xa2\x2e\x91\x2b\xf5\xb3\x1c\x79\xf4\xe8\x00\x16\xfd\x43\xe4\xe3\x2b\xd0\x85\xbf\x08\xf3\x66\x0d\x00\xf1\x8f\x88\x3e\x6e\x4e\x32\x9c\x23\x3e\x4b\x99\x79\x03\x34\x66\xb2\x7f\x19\xe0\x4e\x1e\x17\xa5\xf1\xe5\x35\x76\x73\x70\x1d\x88\x2e\x02\x6a\x43\xf5\x5f\xbe\x98\x8f\xa6\x1f\x0a\x34\x2a\xcb\x1b\xf4\x21\xf0\xc8\xfa\x32\x6d\x9f\x39\x72\xde\x43\x9f\x31\x95\x71\xbc\x6d\x1f\xc6\x73\xa3\xe0\x6a\xae\x98\xb1\x93\xaa\xc0\x4e\xaa\xec\x9d\x14\x58\xf5\x3c\x87\x73\x64\x15\xf8\xb8\x32\xd5\x23\x73\x92\x57\x60\x65\x07\x9d\xc4\xf2\xc3\x9b\x80\x30\xc5\xe3\xc3\x03\x92\x8b\x53\x4a\x81\x5f\x19\x76\x62\x93\xbf\x3e\xbd\x7c\xa8\x18\xeb\xd4\xfa\xe1\x95\x2b\x59\xb9\x77\xe7\x50\x09\x26\x3b\x84\x7c\x25\x7b\xf9\xcb\x63\xd3\xdb\xef\x1c\x89\xd6\xfc\x7e\xf6\xa9\x00\x54\x36\x2e\x67\x05\x59\x0b\xe6\xca\x42\x5b\x50\x7f\x18\xe9\x41\x2c\x8c\xd8\xd8\x73\xde\x47\x98\xdc\x09\x40\x40\xa3\x16\xd9\x8a\xc6\x25\xdd\xd8\x20\xbe\x5f\xab\xcb\x86\xf7\x01\xa2\xaa\xad\x3a\xe4\x0e\x65\x07\x89\xf7\x9a\x5f\x01\x58\x89\x84\x73\x31\x79\x7b\x17\xd2\xab\x36\x57\x51\x26\x3c\x19\x9e\x94\x97\x48\xf4\xbd\xbd\x03\xe8\x06\x9c\x26\x19\x55\x94\x9e\x20\xea\x86\x01\xf8\xdb\x5d\xfe\x73\x56\xf0\x80\x6a\xb6\x06\xe9\x94\xd3\x84\x2b\xee\x66\x01\xf9\xa2\x90\x65\x0e\x87\x5a\x78\x29\xa9\xb7\x74\xf8\x3c\xe0\xa5\x9e\x45\x01\x7f\xaa\xaf\xd7\xf6\x5b\x2f\xc5\xa3\x26\xe5\xe3\x8a\xe9\x48\x82\x4f\x1a\xf1\xed\x72\xee\x90\x96\x52\x86\x57\xfa\x1a\x45\xa6\xa0\x28\xb4\x14\x34\x91\x09\x93\xc0\x4b\x01\x86\x14\x40\x39\xaa\xf0\x2e\x93\x97\x9c\x98\x0d\xda\xb5\x50\x52\x8b\xde\x04\xa0\xd0\xcf\xa7\xef\xdf\x91\xc8\x68\x08\xe4\xe3\x0f\x48\x74\xf6\x7e\x37\xcd\xc3\xe4\x1e\xeb\x23\x2e\xad\x45\x81\x4c\x83\x06\xa8\xd2\x03\xe2\x11\xfb\x64\x6a\x5a\x3a\xda\x44\x5a\x13\x46\x28\x66\x1b\xf2\x73\xe2\x6a\x3a\x0d\x44\xcc\xdd\xb1\x80\x75\x97\xe8\xa1\x26\xee\x28\x08\xcb\x29\x8f\xa8\x3a\x03\x9a\xc7\x7c\x5f\xa0\x08\x54\x04\xa6\x19\xe7\xd5\xa7\x82\x0c\xf9\x28\xb4\x69\x41\xa1\x1a\xa4\x6f\x9b\xd1\xd2\x68\x68\x13\x2b\x3e\x7a\x29\x6c\x8c\x11\x7c\x93\xc7\x24\xb0\xa0\x83\x4b\x26\xfd\xde\x10\x67\xdb\x0b\x26\x1d\xee\x7c\xb7\x4a\xd4\xed\x8b\xb4\x83\xab\x05\x4a\xbc\x66\x4f\x2f\x96\x74\xc8\x75\x12\xfc\x5d\x62\x2d\x15\xb8\x72\xa1\xed\xda\xeb\xaf\xb1\x71\x50\x7e\x7a\x24\xe2\x37\xfc\xec\x10\x4a\x30\xdc\xb1\x3a\xaf\xe4\x41\x63\x96\x93\xa5\xe1\x6e\xb4\x41\xb0\x21\xd3\x19\x61\x5b\xc3\x2d\x64\x37\xea\xe9\xc6\x6f\xd1\x76\x6f\xcd\xed\xe8\xb7\x41\x94\x46\x51\xc0\x01\xa2\xe5\x74\x2e\xe0\x3f\x0c\x3d\xca\xdd\xc6\x01\xcd\x17\x74\x8d\xe4\x32\x4e\xe4\x21\x78\xe4\x07\x5d\xd9\x3d\x3a\xeb\x44\xf4\xc8\x77\xa1\x80\x47\xb7\x71\x05\x6b\xf1\xc3\x00\xcd\xfa\x3f\xa1\x0b\x81\xb7\x7b\x27\x87\xa8\x89\xbb\xa2\xec\xc1\xe1\x4f\x47\x1f\x0e\x2f\xde\xef\x7d\xf8\x0f\x00\xaa\x9b\x74\xf1\xfe\xf0\xd3\x9f\x0f\x0f\x5c\xf3\x3b\x35\x19\x52\x02\x5b\xbc\xb3\x28\xa9\xd1\x2d\x85\x14\x55\xa4\x11\xec\x16\x68\x79\x8f\x93\x90\x47\x1f\xfe\x9c\xb0\x5b\xc1\x04\xb9\x96\x0e\xb0\x30\xa9\xdb\xc4\x42\x82\x06\xc3\x62\x0e\xe3\x86\x36\x18\xfc\xbd\x8d\x37\xaf\xa4\x36\x92\x54\x28\xc4\xa0\xe2\x90\x3e\x71\xb4\x94\x94\x8b\xa6\x8a\x5f\x0b\xb8\x40\x7f\xe4\x4d\xd1\x09\x80\xe4\xcb\x60\x8e\x17\x4e\xe2\xd4\x88\xc7\x64\xe4\xcc\x2d\x69\xb8\x07\xa6\x17\xa9\x92\x13\x45\x8f\x0b\xcd\x7d\xe4\x6e\x00\x55\xf1\x25\xe0\x81\xf0\x0b\x77\x8a\x55\x5a\x31\xb9\xbc\x29\x6f\x78\xa0\x0b\x3f\x75\x99\x95\x5b\x5b\xe5\xe0\x82\x8b\x0e\x0f\x60\x03\xbe\x2d\xab\x09\x60\xdf\xc0\x22\x2b\x01\x21\x2f\xd0\xf4\x02\xfe\xb7\xf0\x7f\x89\x5d\x9b\x26\x95\xac\xbd\xb7\xec\x6a\xac\xfd\x3e\x5f\x90\x1e\xb4\x9f\x4c\x3a\x0d\xa1\x0c\xf4\x88\x58\x92\x67\xaf\xac\x54\xb1\xb2\x84\xb3\xd2\xeb\xec\x08\xc1\x70\x1b\xc3\x77\x29\x26\x4e\x68\x61\x3d\x3c\x78\x39\x09\x0f\xc4\x10\x2a\xbd\x4b\x5f\x1a\xc7\xf8\x83\xd6\x58\x5e\x39\xa4\xff\xb0\xc8\x4c\x16\x49\xb8\x93\x31\xde\xc3\xc7\x47\x97\x1f\x27\x16\x94\xe3\xff\x4f\x5e\x75\xd1\x33\x53\x68\xbe\x2b\xe5\x40\x92\x2a\x7c\x81\x31\x6e\xd6\x89\xe4\x6c\x92\xe3\x49\x4c\x2a\x61\xe7\x21\x17\xb0\x31\x3f\xbb\xb4\x42\x22\xc2\x36\x01\x5c\xb5\xb5\x15\xd5\x44\xa7\xe8\x39\x2b\x02\x69\xb0\x45\x8e\xe1\x60\x50\x18\x93\x50\xcf\x6d\xcc\x2d\x11\x91\xa0\x42\x9f\xaf\xfc\x93\x1d\xcc\x57\x61\xf1\xff\x8c\x8f\x3a\xae\x77\x71\x63\xe4\x8b\xc5\xec\x8e\x93\xb6\xca\xfa\x04\xe9\x90\x2e\x9c\x63\xba\x67\xcb\xb2\x6a\x97\xcb\x9c\xb3\xac\xd9\xad\xd2\x25\xad\x79\x63\xc4\xb3\xbe\x8f\xf7\x7d\xb6\xe7\xa3\x8f\x8f\xdc\x4d\x71\x58\x1d\x7d\x6a\xa5\x4b\x6d\x73\x53\xa3\xdb\xd1\x36\x9f\x04\x99\x79\xf3\xb5\xb5\xcd\x5d\xe5\x2a\x5b\xe1\x9b\xac\x8a\xa4\x66\xbd\xa9\xf0\xed\x6a\x8e\xdf\x05\xb8\x87\x87\x3e\x39\x67\xaa\x7a\x93\xce\x19\x9e\xcd\xd3\xa2\xa1\xf2\x97\x01\xed\xf1\x77\xf5\x58\xd1\x93\xbf\x9b\x83\x72\x0b\x90\xf9\xbd\x35\x32\xc5\xb0\x54\xaa\xe1\x2e\xc7\xf2\x42\x52\x84\x24\x39\x29\xa1\xb4\x37\x1f\xb7\x3e\xd1\xf8\xde\x67\x6a\x9e\xda\x41\x7d\x8e\x45\x47\x85\xa8\x6a\x1f\x88\xa2\xcf\x6d\x21\x3b\x37\xcf\x17\xbc\x23\xd8\xb3\x8f\x82\x02\x25\xb3\x57\xde\x63\xaf\x0f\x27\x1e\xa3\xfa\x34\xbe\xe7\x78\x5d\xb0\x4c\x13\xf6\x21\x7b\x1f\xdf\x0b\x0c\x72\xfc\x61\xff\x90\x33\x1e\x0d\x94\xc2\x13\xac\x13\xd5\x2b\x23\xd0\x93\xe4\xc3\x1e\xa0\xb5\xc9\x51\x26\x3f\x65\x61\x28\xf4\x16\x81\xd1\x9a\x9c\x54\x6d\xd5\x6d\xa7\x0b\xf5\xa5\x60\x16\x32\xb4\xf7\xfb\xf3\x75\x3c\x41\xce\x8c\x0c\x21\x54\xee\x4b\x9e\x54\xe1\xe9\xdc\xee\x2d\xb4\x6f\x7c\x2c\x5c\x48\x68\x99\xab\x3c\x04\xa6\x6d\x80\xc9\x95\x68\xdd\xf1\x89\x02\x07\xe5\x64\x65\x3e\x36\xf0\x89\x73\x64\x02\xc3\x61\x7c\x1d\xa8\xc9\x17\x0a\x62\x2b\x3a\xe3\x96\xf0\x7a\xb3\xba\x80\x69\x50\x6a\x17\x71\xf9\x1b\x0e\x35\xf6\xc8\xbe\x64\xf7\x06\x55\xe9\xf0\x3f\x0a\x93\xe2\x04\x34\xce\xc4\x1a\xb2\x4b\xd9\x87\x56\xb6\x33\xaa\x94\x3f\xce\x51\xb5\xbd\x9d\x10\xb1\x84\xa7\xc1\x63\x60\x95\x38\x76\xef\x44\xc3\x5e\x0e\xcc\x72\x48\x31\x7a\xf5\xb2\x4f\xc8\xa0\x0d\x64\x48\x9e\xec\x93\x5f\x30\x1a\x0f\xb5\xeb\x36\xe9\xae\x5f\x17\x50\x4e\x7e\xe6\xa5\xec\xc2\xb1\xe7\xa6\x41\xd5\xb4\x7b\x34\xb6\x5b\xb8\xaf\x98\x2f\x4d\xca\xad\x5e\xaa\x04\xea\xa2\xdc\xcb\x76\x23\xad\x64\x75\xed\x21\x6e\x91\xb4\xac\x25\xb3\x51\xef\x9f\x0e\xf7\x0f\x8f\xfe\x02\xaf\xe4\x2d\xec\x44\x62\x90\x77\xd9\x7d\x80\xcb\x8d\xae\xfc\x48\x24\xa2\xaf\x28\x3d\x47\xe8\xdd\x9a\xe5\x88\xbd\xd2\x12\xef\xd3\xe0\x8a\x0a\x96\xde\x89\x93\x3e\x96\xe2\x54\x83\x13\x1e\x26\xff\x05\xef\x7b\x95\xdc\x46\x8e\x44\x95\xe1\x82\x54\x6c\x16\xa8\xe9\x95\xad\x6f\x9a\x37\x09\x8f\xc3\x7e\x18\xe2\x00\xd8\x9a\xed\xe2\xe2\x6f\x24\xb8\x97\x7e\xd9\x3b\xbb\x9c\xee\xa2\xb4\xd8\x5c\x0d\x05\xdd\x4b\x51\xd0\xa3\x9f\xe5\x48\xd1\x6d\x99\x4a\xa6\xdb\x68\x1b\x27\x36\xd4\xc5\xd4\xf0\x40\x0a\x62\xff\xc5\x61\xc6\xbf\xda\x69\x06\x27\xd7\xaa\x6e\xc8\x8d\x28\xd7\x5a\x08\xd2\x02\xdf\x3c\x17\x76\x43\x89\x31\x77\x76\x0b\xb7\x2e\x9f\x54\x55\xcd\xc1\x7d\xc3\x71\x99\xab\xb2\x5c\x86\xb9\xbb\xde\x64\xfa\x4f\x75\x33\x16\x42\x20\x14\x70\x0a\xa8\xb8\x07\x0b\x72\x68\xc2\x39\x71\xe8\x3b\xb2\xb8\x31\x66\x2b\xbf\xaf\x6b\xaa\xd3\xfc\xbc\x2b\xf4\x99\x93\x5d\xc4\x66\x8e\x74\x9f\xa5\x0b\xa8\x7e\x38\xf3\x85\x30\x7b\x6a\x29\xd1\x9d\xdf\x94\xc0\x79\x9f\xf7\x59\xb3\xb0\x42\xb7\x87\xda\xbc\xda\x02\x8e\x3c\x6e\x91\x53\x22\x79\x3a\x94\x00\x4f\x93\xbb\x38\x91\xb2\xb7\x38\x5c\x8d\x7a\x8b\xba\x07\xc9\x4a\xc9\xcf\x53\xdb\x43\x63\xc3\xc0\xac\x8a\xe3\x55\x6c\x91\x50\x56\xbc\x0e\xd4\xfa\xa6\xcb\x33\x54\x8b\xfb\x67\x96\x4b\xd4\x05\x4e\x70\xeb\x19\x88\x8b\x84\xcd\x9c\x90\xb2\x8f\x84\xc0\x16\x29\x94\xc7\x25\xf1\x5d\x21\x39\xe6\x5b\x8b\x8e\x1b\x7f\x09\x0a\x49\x2b\x2d\x5a\x47\xe2\x1c\xfa\x2c\x77\x62\x11\xdc\x66\xc5\x6a\xd0\x59\x38\x76\x6b\xeb\xf7\x5e\xa1\xb1\x8d\x90\x02\x1c\x7c\xee\x4d\x2e\x93\xb8\x4c\x71\xd6\xcc\xf3\x9e\xc7\xdd\xbe\xef\xb2\xfb\x47\x9b\xdf\x52\x25\xc8\x4a\xa1\x38\x0d\xda\x89\x81\xfe\xa8\x49\x94\x9a\x5f\x36\x85\x07\x0e\xf1\x2a\x96\x93\x93\x1a\x0b\x2f\x23\x3d\xac\xbf\x87\x87\xde\xb3\xe4\x51\x72\xa4\xc2\x38\xd0\x1a\xb1\x4b\x39\x25\x6e\xe0\x81\xdb\x98\x3f\xac\x51\x53\x40\x83\x93\x25\x38\x15\x52\x97\x48\x83\xc7\x25\x9b\xb4\x7f\x1b\x28\x43\x0e\x6c\x3e\x06\xc9\x20\x47\xe4\xd3\x03\x13\xd5\xf7\xb2\x3f\xd2\x46\x99\x48\x17\x04\xc5\x59\x79\x8e\x11\x88\x59\x4d\xca\x51\xd3\x38\x37\xbd\x05\xd0\x6d\x19\x1d\x83\xf1\x5d\xf4\xb8\xa6\x40\xd4\x92\x78\xf6\x30\x22\x71\x7a\x9c\xc5\xcc\xdf\x1d\xca\x4b\x4b\x0e\x83\x0a\x0e\x81\x3c\x73\x43\x06\x8e\xaa\xc4\x12\x66\x8a\xd5\xce\x04\xfa\xe6\x52\xd5\xb0\x8c\x7f\xd4\xdf\x0f\xe8\x64\x1d\xcc\xd0\x12\x5e\x9b\x3e\xa8\x0d\x62\xa0\x09\xd1\x00\xb5\x45\x00\xf4\x0b\x73\x57\x20\x71\x07\x90\x01\x4c\x6e\xde\xdb\x42\xe8\xdc\xcc\x8f\x51\x86\xb9\xf6\x69\x58\xf6\x4f\x09\xe1\xc8\x51\x00\xf3\xa9\xca\x79\xd6\x37\x77\x0f\x0f\x5c\x2b\x23\x78\xab\x94\xed\x87\xf2\x50\x8f\x05\x35\xf6\xf2\xdd\xb8\xaf\x6d\x45\xc2\x5c\x88\x35\xee\x36\x51\x93\xef\x6d\x74\x83\x92\xa4\x41\x02\x0f\x63\xd0\x68\xc2\xae\x31\x69\xb7\xd2\xa1\xd4\x2d\xc1\x7d\x2d\xc5\xd5\x18\x3d\x2b\xfc\x71\x4f\xf8\xcb\x56\xea\x98\xb0\xdc\x5c\xce\x82\xc8\xe4\x87\xd3\xd2\x5a\xf7\x23\x7f\xd2\xf9\x07\x83\xa7\xbb\x38\x63\x48\xf8\xbc\x52\xe5\x46\x90\xb6\xd6\x35\xc6\x86\x40\x63\x41\xc0\x56\x02\x72\x15\x14\x50\x1d\xc6\x59\xbd\x8a\x0f\x80\xa1\x04\xbf\x8e\x4e\xe2\xf5\xb8\x43\x62\x7e\xed\x62\x2d\x5b\xf2\x0f\x24\x4f\x6a\x97\x50\xb4\xe5\xd0\xd0\xb5\x9f\x46\x31\x99\xe8\x62\x9f\x13\x26\x6e\x93\xf6\x75\x25\xf1\x55\x2f\xd6\xba\x2a\x39\x95\xec\xbb\x92\xbe\x29\x39\xc5\x9c\x6f\x8f\x4c\xbd\x0e\x8f\xbe\x62\xa4\x54\xe2\x2c\xad\xda\x2a\x1d\xa2\xa6\x11\xb7\x7f\x8c\x71\x89\x26\xfe\xe0\xd1\xab\x8e\x21\x5b\x91\xeb\x57\xab\x01\xa1\x99\x8f\xf9\x3e\xf2\x29\xbb\x15\x14\xe1\x45\x5c\xaf\x20\xe6\x47\x5c\x51\x78\x4d\x4a\xbd\x54\x5a\x4c\x5a\xa7\x0a\x09\xf7\x45\x48\x7f\x72\x30\x41\x4b\xb6\xa6\x5e\xb6\xb3\x3b\xa1\x41\x87\xfd\xff\xa5\xec\xae\xb9\xe4\x17\x5d\x3e\xc4\xb0\xd6\x30\x94\x28\x3a\xc8\x90\x78\xe7\xab\x4f\xce\x5b\x4f\xc1\x29\x24\xc5\x73\x45\x76\xd2\x81\xa7\x21\xd7\xeb\xc7\x84\x3b\x2c\x48\x58\xa2\x6c\xbf\x77\xde\xd7\x5b\xb5\xbd\xd5\x8d\xf5\x2b\x6c\x28\x58\x97\x4d\x65\x67\x47\xea\xc9\x39\x4f\x4d\x5a\xf1\x89\x4b\xf7\xb5\xd5\xc4\xa8\x6b\xee\xee\xc5\x05\x93\xf7\x29\xe6\x6a\x46\x28\xb0\xe1\x21\x90\x36\x87\xbb\x71\x91\xcd\x11\xbf\xd8\x42\x85\x38\x21\x17\x28\x3c\x02\xec\x93\xc6\xd5\x68\xf2\x84\x0b\x6d\xcd\xe2\x8f\xd3\xb2\x82\x3d\x7a\x77\x6f\x0c\xd9\xe8\x3b\x71\x70\x94\x94\xca\x93\xaa\xe2\xe5\xbd\x80\x05\x16\xe2\x5c\x98\x37\x40\x2b\x7a\x57\x0f\x13\x84\x64\xaa\xe1\x2c\x3f\xd8\x97\xbd\x76\x7d\x81\x64\x71\x4e\x67\x0d\xc5\xca\xeb\x61\xad\xc4\x37\x83\xab\x65\xde\xa0\xe1\xc1\x2a\x02\x77\x3b\x1a\x44\xdb\x14\xb8\x23\x34\xca\x9e\xed\x44\x31\x83\x38\xce\xd7\x52\x32\x68\xe1\x73\x66\x00\xe5\x71\xf4\x29\xfe\xac\x85\xd1\xf2\x66\x29\xb9\x76\x6c\x5f\xfc\xbe\xe3\x88\xe4\x3f\xb3\x7b\xad\x2d\xbd\xc7\xde\xe6\x6d\x91\x7e\xb6\x7c\xd1\xf8\x7d\xb1\xbe\x66\x58\xb2\x67\xe8\xd2\xeb\x33\x33\x6d\xdb\x8d\xe1\xc3\x0a\x38\x90\xa6\x1d\x71\xce\xc7\xc1\x69\x40\x52\x55\x26\xfd\xe1\xce\x65\xa9\x92\x6a\xcc\xc4\xe4\xc4\x7a\x45\x62\x92\xcd\x9b\x1f\x15\x8e\x7d\xec\x0b\xd0\x51\x62\x14\x39\xab\xd0\x1e\xd2\x4e\xe0\x1c\x18\x09\xd7\x2b\x72\x2b\x24\xe5\xff\x13\xdb\x1f\x11\xca\xfd\x1f\x7d\x2b\x58\xae\x51\x6e\xc2\xeb\x40\xb9\x16\xb3\xf4\xc7\xfe\xf3\x29\xfd\xb1\x3e\x3f\x1a\x5f\xe1\x28\xe3\xab\x5d\x5c\xac\xf0\x82\x60\x08\x1c\xd3\x1f\xf4\xb7\x57\xf8\xbd\x08\x28\xbb\xf5\xf8\xb7\xd0\xb2\x46\xc8\x7b\xce\x56\x4b\x12\xa1\xc8\x8b\xde\x22\x94\xfd\x72\x85\x72\x5d\x9f\x40\x31\x1d\x72\xd0\x3f\xa5\x7e\xc7\x94\x34\x11\xde\x08\x3a\x5a\x6a\x08\x29\x04\x18\x47\xba\x98\x0e\xb9\xaf\x92\x15\xa2\x44\x28\xf2\x2a\x64\x32\xb2\xda\x1d\xa7\xa1\xe8\xe7\x0a\x50\x31\xda\x0a\x5f\x15\x18\x2f\xd3\xf4\x6f\xe4\xab\xc3\xd6\x14\x80\x44\x1e\x50\x8d\xc6\xd0\x78\xf5\x2f\x91\xca\xc1\x23\x06\xc8\xa5\x58\xe3\x74\x5d\xaa\x94\x48\xbc\x0e\xc5\x0b\xf7\x96\x37\x8e\xca\xf3\xa4\x19\x18\x95\xea\x3e\x9d\x13\x23\xcf\xaf\xe4\xf7\xab\xfd\x4a\x06\xbd\x6e\xa0\x11\x55\xf3\xe5\x43\x5d\xf1\x45\x2b\x37\x72\xe3\x6c\x6c\x44\xc9\xae\x97\x5b\x2d\x4f\xaf\xd7\x16\xe0\x3b\x92\x78\xa5\x45\x69\x88\x99\x81\x46\x2c\xe3\xfb\x3c\x8d\xf2\x88\xe5\x97\x97\x0d\x3c\xc0\x5f\x78\x9e\x4c\xb8\xab\x04\xf1\x00\x29\xd0\x45\x78\x85\xbf\xf8\xdc\x95\x88\xaa\x23\xf1\x00\x29\x6d\x39\xc1\x77\xfc\x41\xef\xf3\xe8\xe8\x3b\xa2\x9f\x88\x5d\xa6\xd1\x25\xfc\x45\xa4\x1e\xe1\x5f\x78\x9e\x94\xf0\x38\x29\xf1\xa9\xc6\x27\x2c\x55\x5e\xc1\x53\x79\x05\x4f\xb3\x7a\xfc\xe5\x6f\xcb\x1a\xbd\x21\xe8\x67\x48\xaf\x27\x77\x90\x02\x7f\xe1\x19\xbd\x74\x40\x3f\x85\xef\xf1\x88\xff\x46\x18\x63\xe7\x26\x87\x6e\xf3\xdf\x88\x62\xdd\x23\x72\x8c\xc4\x03\xa4\x94\xe4\x57\xa3\xc4\x16\xc7\xa8\x50\x19\x8d\x49\x2b\x72\x5c\xcf\xf0\x71\x46\x4f\x57\xdc\xff\xbd\x7c\x8a\x78\xb8\x8f\x08\xff\xf2\x67\x8a\x6e\x11\xc9\x27\x48\x43\x57\x19\x93\x08\x6d\x35\xe1\x01\x6d\xc8\x27\x45\x97\x03\xae\xc2\x37\x7a\x80\x94\x29\xf4\x03\xfe\xc0\x53\x99\xcf\x6a\x74\xb7\x41\xbf\xf8\x7e\x83\x2f\x37\xf0\x84\xd5\xb1\x36\xb6\x0e\xed\x16\xf3\x34\x2a\xe6\xf8\x7b\x59\x4c\xf0\x11\x7e\x80\xc0\x43\x87\xd8\x14\xad\x40\x3e\x61\xda\x95\x1a\xac\x7e\xa6\x74\xa0\x24\x29\x8d\xa2\xce\x4c\x81\x40\x2a\x28\x78\x41\x4d\xee\x3b\x28\xdc\x08\x86\x32\x80\xaf\x5c\x0f\xd3\xe8\x7a\x08\xbf\xcf\xe1\xf7\x39\xfc\xbe\x80\xdf\x17\xf0\xfb\x12\x7e\x5f\xc2\xef\x77\xf0\xfb\x1d\xfc\xbe\x82\xdf\x57\xf0\x8b\x8e\xc9\x22\xfc\xcb\x9f\xb1\x5d\xfe\x8b\xb1\x05\x30\xaa\x00\x8f\x96\x80\xa1\x11\xe6\x30\x2a\x98\x75\x98\xf3\x92\x82\x92\xc0\x23\xfd\xc2\xfb\x1c\x40\x01\x7f\xe0\xc9\xf2\xe3\x81\x52\x61\x78\x06\xc8\x7d\xb9\x84\xcf\xc0\x1f\x78\x2a\xee\xae\x0a\xee\xd7\x03\x7e\x23\x11\x7a\x24\xa2\x1f\x78\x2b\xd0\x57\x09\xbc\x16\xdc\x67\xc9\x0c\x3e\x38\x2b\xf1\xb7\xfa\x82\x4f\xd5\x97\x88\xcd\xf3\x12\x1d\x7b\xe4\x68\xf1\x8d\xf6\x76\xf0\xb8\xc0\xa7\xe6\x0b\x3e\x36\x58\x82\xdc\xaa\x70\x7f\x2a\xf8\x17\xa3\x49\xf0\x77\x7c\xc2\x34\x5c\x0b\xf8\x97\x9e\xc9\xbd\x47\x41\xb0\xac\x72\x98\x47\xf8\x03\x4f\x75\x3b\x6e\xca\x05\x0c\x46\x3e\x45\x8c\xb3\x4f\x53\xc9\x46\x65\xb8\xe0\x70\xbd\xd5\x8b\x4e\xac\x37\xf9\x44\x69\x34\x93\xb5\x98\xc5\x7a\xd9\x11\x68\xf8\x6f\xc4\xa0\x30\x94\x5a\xe4\x00\x41\x74\x19\x02\x3f\xf0\x56\x52\x60\x21\x78\x2f\x45\x84\xa1\x05\xbd\xf1\xa7\xfa\x8a\x6f\x68\xf9\x14\xb1\xbf\xa5\xd1\xdf\x22\xd6\x60\x9c\x07\x68\x0b\xfd\x78\xa0\xff\x8e\x66\x79\x09\xbb\x0c\xff\x46\x0c\x8a\x43\xb9\x36\x9f\x43\x19\xfc\x1b\x31\x39\x2a\x39\xa6\x56\x10\x1f\x91\x78\x88\x44\x18\x12\xe9\x99\x04\xde\xe7\x39\x39\x31\xc1\x1f\x78\xab\x97\x70\x3b\x82\x57\xfa\x8d\x78\x2c\x92\x08\xff\xc2\x73\xd7\xd4\x18\x8b\x82\xff\x46\x22\xc6\x48\x44\x3f\x11\x86\x0a\x80\xe7\xe5\x25\x3e\xcd\xe7\xc8\x28\x8d\xc4\x03\xa6\x60\x07\xc9\x8f\x0a\x05\xd5\x89\xe8\x07\xde\x38\xca\xe8\x38\xce\xe8\xd0\xb7\x09\x7a\x35\x81\x53\x88\x63\x33\xf9\x04\x69\xb8\x1d\x20\x01\x7f\xd0\x1b\x1c\x3c\x5e\xe3\x2f\x2d\xf0\x8e\xaf\xf0\x0e\x83\xfc\x44\xf8\x37\x12\xa1\x4d\x22\xfa\x81\x37\x58\x02\x1d\xba\x76\x69\x72\x74\xac\x43\x3f\x11\x83\x45\x04\x2b\x68\x09\x83\x5f\xc2\xc8\x23\xc0\xe8\x51\x4a\x7f\x19\x7a\xd0\x07\xbc\x47\x3f\x11\xbb\x45\x64\x76\x8b\xd8\x6c\x5c\x36\x84\x56\xf9\x2f\xe2\x90\x29\x21\x90\x29\xcc\x42\x31\x9b\x95\x0b\x44\xa1\xe2\x21\x62\x00\xaa\x2b\x5a\xdb\x05\xad\xed\x82\x3f\xe7\xcd\x9f\x31\xce\x02\x9e\x5c\x91\xfd\x8e\xab\xbc\xa5\x55\xde\x7e\xc1\xb5\x83\xa3\xc4\xbf\x91\x8a\x79\x13\x89\x07\x48\xa9\x67\x77\x57\x38\xaf\xe2\x81\xa7\xf0\x6f\xc9\x27\x1e\x2b\x24\x9f\xe9\xef\xd9\xef\x11\xe3\xe1\x4a\x78\x9c\x92\xb6\x43\x1f\x3e\xf8\x17\x9e\x6f\x70\x9a\x6f\xae\xf8\x5c\xf0\x79\x80\x67\xbe\x18\xe8\x27\x7a\x44\x26\xa3\x3e\x74\x73\xd3\x53\xd6\xd7\x12\x95\x61\x12\xd1\x26\x9b\xf0\x44\x5f\xdb\xf5\xec\x9e\x8c\xb9\x22\x9d\x52\x05\xfc\xd1\x2b\xda\x4a\x96\xa9\x5d\xbd\x3e\xd7\x9d\x6c\x19\x3c\xee\x73\xdb\x90\xa2\xcf\x74\xb6\x74\x68\x08\xb8\xdb\xd0\x91\x28\x64\xaf\x63\xb4\xad\xad\x2b\xee\xf9\x69\x73\x87\xd5\x95\xe9\x0a\x8a\x12\xb4\xdb\x23\xfd\x4a\x8e\x7f\xf4\xeb\xe7\x05\x7f\xa1\x5a\xc2\xc5\x83\xd7\x9a\x95\xae\x1a\xf5\x53\xb1\x6d\x3f\xf5\xf3\x42\xa7\xa1\x9b\xb1\xac\x36\xbd\x90\xc6\x96\x62\x51\x24\x81\xf2\x56\x9c\xfe\x42\x95\xe8\xac\x62\xcd\xb9\x54\xd7\x72\x99\x21\xa6\x04\xae\x53\x77\x76\x2e\x23\xd8\xd4\xcf\xbe\x42\xb9\xe0\x8a\xf3\x5c\x19\x25\x63\x6b\x6b\x4c\xf1\x34\x62\x0c\xab\x61\xb0\x8a\xe1\x4d\xdd\xe2\x48\x21\x56\x57\x1d\x0b\x33\x6d\x64\x5f\xf9\xd1\x13\x9c\xa5\x95\xbe\xd4\x77\x89\xf0\xc2\x4a\x5f\x3f\x67\x2b\x96\x95\xe9\xe3\xd0\x75\x5b\xe8\x6c\x24\xcf\xcc\xe7\xfb\xaf\x09\xc8\x8d\xfa\x06\x57\x2a\xe4\x8d\x1c\xa4\x66\xe6\x1a\x5c\xbd\x13\xc3\x52\x22\x61\xba\x12\x61\xfa\x87\x07\x5f\x90\xcc\x73\x12\x2f\x6e\xac\x61\xbb\x35\x1d\xc0\xcd\x60\xa2\x6e\xa8\x64\xac\xf1\x53\xdd\x90\x1d\x0d\x29\xaa\x4b\x2e\x7f\x6d\x1a\xb5\x5c\xec\xd6\x03\x62\x32\x1f\x88\xb8\x7f\x69\x3d\xda\x47\x29\x5e\xf2\x48\x3e\xfc\x3e\x6a\x07\x1e\xff\x46\x4c\x70\xc5\x0e\x37\x72\xa4\x7b\x13\x3b\x06\xd0\x31\x67\x10\x9f\xc2\xf5\x05\x96\xc7\x55\xfc\x9e\xc2\xf7\x11\x5b\xe9\x14\x79\x37\xe8\xbf\xc5\x36\x39\xa0\x20\x1b\x9c\xa5\xd3\xe5\x57\x52\x02\x00\x8f\xa4\x29\x57\x0c\xba\xfa\xf3\x02\x16\xe3\x3e\x9a\xb7\xf1\x0b\x82\xc0\x0d\xfb\x27\x27\x41\x4f\xd8\x6d\x28\x12\xe4\x72\xb5\xf7\xec\xf1\x1a\x98\x6c\xd6\xa3\xa1\xbc\xf0\xeb\x3a\x51\x39\x4c\x1d\x66\x69\xda\x65\x6a\x30\x5b\x5e\xa4\x27\xbe\x92\xf0\x3c\x7c\xd9\x14\x7a\xc9\x45\x0b\x54\x6f\x81\xee\xcf\x60\xe6\x45\x07\xb4\x72\xb2\xa9\xa8\x7b\x27\xee\x50\x01\xaf\x80\xa6\xba\x2e\x2a\x2a\xf7\xe8\xeb\x2e\x1c\x2f\x2d\xa8\xc0\xbc\x18\x48\xdf\x5b\xec\x12\x5e\xfa\x7c\xc4\xfc\x9e\xdd\xb7\xdc\xf9\x2e\xa0\xbd\x6a\x09\x24\x7d\x43\x11\x90\x3e\x65\x77\xf1\xbd\x0e\xac\x86\xbc\xc7\x6c\xc8\x6e\xb3\x7b\x22\x56\xa0\x2c\x5d\xa1\xf0\xb7\xa1\x60\x4b\x40\x3f\xc2\x0f\xbf\x19\x60\x9c\xa5\x86\x87\x5d\xa2\x66\x39\x25\x0d\x0f\x82\x60\x86\x27\x22\x82\xe1\x97\xc8\x57\xf8\xe5\xc4\x23\x06\x61\xe2\x34\x19\x3c\x71\xfa\x05\x1e\x6e\x2f\x79\x97\xde\x67\xcf\xfe\x8a\x71\x25\xf7\xbe\xfd\xdf\xe7\xe2\x37\xbd\xf8\x75\xf0\xeb\xb7\xbf\x4e\x30\xc8\x24\x7a\xad\x7e\x64\xc7\xf0\xc7\x41\x97\xa3\xd2\xd2\xf2\x54\x88\xda\x60\x52\x97\x9c\x05\x98\xdd\x3b\xca\x35\x13\x87\xf9\x6d\xd7\x5a\xad\xd7\x06\xd8\x60\xb6\x8e\x5e\x1b\xda\xc1\x9a\xca\x61\xc2\x1e\xfd\xf6\x4c\xed\xbe\xf3\xdd\x08\x88\xb5\x1f\x9f\x45\xdb\x2a\x69\x3b\x7a\x13\x59\xaa\x46\x17\xfc\x60\x82\xed\x53\x9d\xe6\x57\x5c\x36\xb1\x57\x4d\x0c\xcc\x80\x66\x71\xdb\x66\xd9\x7d\x1e\x82\x52\xd8\xcd\x41\x66\x8d\xb3\xfc\x74\x3b\x7d\xa2\x0d\x2e\x96\xac\xb2\xe8\x47\xa3\xa3\xea\x78\xab\xfb\x0d\x7a\xea\x44\x5b\xf2\xd4\x46\x0c\x8e\x12\x4b\x5f\x06\x4a\x37\x1e\x7f\x1d\x8d\xeb\x95\x04\xaa\x06\x64\xfa\x09\x4e\x00\x0c\xcf\x0d\x6d\x72\x84\x9d\xcd\x49\xc7\x47\x62\x6f\x20\x70\xa4\x4b\x71\x3e\x48\xd8\xa5\x27\x98\xd5\xa2\x1a\x85\x90\x28\x2d\xdd\x12\xba\x13\x68\x4a\x84\xbc\xd8\x6a\x3b\x8b\x36\xa2\x6d\x94\xff\x90\x4a\x46\xd0\x21\xb4\xe4\x4c\xd3\xac\x61\xd3\x63\xbf\xe9\x90\xd0\x60\xa4\x2b\xc2\x37\xc6\x58\xfd\x91\x85\x66\x6f\xe5\x94\xf4\x9d\x76\x1a\xd0\x9d\x69\xed\x3e\xb8\xb8\xc0\x0b\xb2\xec\xb4\x7c\x7f\x54\xc2\xbd\x2a\xfb\xfd\xcc\x54\xba\xb1\x29\x89\xf3\xdd\x40\xa2\x08\x38\x99\x09\x83\x6f\xee\x98\x36\x50\x4e\x77\xa9\x92\xdf\xbf\x11\xfe\x80\x78\x72\xc8\x3c\x5a\xd4\xc5\xa0\x22\x0a\x62\xf5\xe0\x3f\xeb\xb2\x8a\xa3\x48\x85\x63\x89\xa2\x7f\xa8\x14\x78\xf6\x47\xa5\xc0\x4f\xa0\x94\x27\xe4\xbf\x55\x58\x1c\x26\xb4\x4a\x66\x6b\x49\x87\xc5\xb1\xce\x0b\xe9\xa3\xb7\x84\xa5\xdf\x19\xde\x55\xec\x42\x0a\xca\xba\x08\x62\x8b\x40\x23\x21\x17\x03\xb4\x3d\x4d\xed\x05\x42\x0b\x95\x52\x65\xda\xf4\x9c\x34\x56\x09\x06\x31\xf1\x2d\xc1\x70\x25\xe0\xf6\xe6\x0d\x2f\xc9\x0a\x8b\x1a\x23\xfc\xb2\x4c\x96\x3e\xba\x20\x2c\x50\x3e\x3c\x20\xff\x16\xf0\x4b\x86\x8b\x82\xcc\xd4\x3c\xd4\x52\x25\xbb\x87\x3e\x6a\xa9\x92\x34\x46\xc1\x2c\x6c\xe9\x6a\x92\x37\x13\x3c\x45\x48\x5c\x82\x89\x4e\x9c\x64\xec\x22\x2e\x8e\xa0\x28\x99\xce\x68\xf9\x31\x12\x1c\x07\xbe\xa5\x21\x23\x3c\x60\x8d\xb3\x1c\xbe\x86\xf4\x8c\x30\x90\x0b\xc2\x6a\x4c\xa6\xcc\x0a\x3a\xf0\x30\x86\x71\x43\x5d\x13\xfb\x8d\x31\x5e\x07\x97\x12\x12\xb8\x16\xc9\xa6\x27\xf3\xab\x81\x42\x84\xaa\xe3\x50\xba\x07\x47\x0d\xf9\x71\x12\xa8\xb1\xb5\xb5\x80\x82\xd0\xb3\x31\xfc\xb8\xd3\x80\x69\x62\x22\xca\x6c\x3c\xea\x9d\x91\x00\xb2\xaf\xd8\x18\x2d\x0b\xfe\x21\xb3\xc2\x57\xf0\x13\xb3\x02\x90\x7b\x2c\x57\xb7\xc0\x0f\x8f\x70\xfd\x12\x25\xec\xde\x56\xea\xf7\xc5\xc1\x77\x58\xa3\xf1\x6c\x61\xa0\xd7\xc2\xc1\xaa\xb5\x2e\x56\x19\xc5\x2a\xa7\x58\xd9\x7f\xed\xa1\x70\x41\xe1\x2c\x81\xfc\x49\x7b\xa3\xb7\x76\x6f\x96\xac\xdd\x0a\xc4\xdf\x70\xc4\xaf\x47\x00\x17\x00\xe1\x5b\x87\xe7\xe8\x4e\x03\xed\x2f\xea\x48\x6d\xc0\x52\x38\xd9\x82\xc2\x32\x29\x17\xca\x7b\xad\x54\x83\x58\xee\x9a\xaa\x46\x12\x65\x09\x99\x6a\x0a\xcb\x7a\x53\xda\x00\xf0\x22\xdc\x37\x3c\x1d\xa4\x78\x56\x30\xd9\x19\x34\x2f\xae\x57\x94\xdc\xae\xb9\x32\x3e\x74\x61\xb7\x84\xb2\xf9\xea\xb5\xa1\x00\x12\x5e\x1e\xb9\x6c\x6c\x69\x7d\x52\xf5\x7f\xc9\x0f\x92\xa7\x34\xbf\x65\x01\x59\x4d\xdf\x0b\x4c\xcf\x8c\x01\x97\x3d\xb3\x35\x54\xad\x1f\xd9\x3c\x2e\x0d\x21\xba\xa8\x23\x29\x67\x76\x2d\x7e\xc7\x09\xf3\x5c\xca\x87\xaf\x84\xe9\x4b\x62\x06\x04\xe2\xef\xae\x8c\xd9\xd0\x2f\x22\x7e\x9a\x25\xb1\x22\x5c\xe0\x0a\x21\xf3\x1f\x8d\x58\x10\xbc\x01\xa6\x43\x3e\x46\x5f\xb2\x1a\x74\x46\x19\x10\xb0\xfa\xe2\x54\xe4\x8e\xac\x76\xbb\xbf\x46\xa4\xc2\x77\x2a\xf2\xe2\x69\x93\x2f\x42\x7c\xc2\xbe\x1b\xb8\x17\xb2\xca\xe5\x25\xe6\x41\x5e\x62\xeb\xf1\x12\x97\x8a\x24\x97\x8c\x43\xf2\x9f\x39\x57\x6c\xc3\x72\x0d\xf6\xdb\x4f\x24\x3c\x92\xcc\xb7\x3a\xcc\x7c\x53\xcc\x30\xe3\xde\xf5\x18\xb0\x8e\x74\xb7\x98\xe7\xa4\xd6\x89\xe6\x88\x6f\x9f\x30\x9e\x30\x86\x8d\x41\x49\x98\xa0\xa3\xd6\xa9\x77\x42\xe1\x87\x59\xc4\xc3\x10\x47\x0e\x47\x6e\xbc\xca\x87\x6a\x68\xee\xd2\x57\xaf\xff\x8f\x30\xeb\x70\xf1\xad\x76\x97\x6a\x2c\xbe\x3e\xe6\x50\xa3\xf8\x40\x12\x7b\x59\xd9\xf5\x6a\x36\x51\x19\x60\xe4\xe4\x3e\xbf\xa6\xf5\x59\x2f\xcb\xa0\x63\x9d\x71\x76\xdf\x73\xa0\xa5\xd1\x6f\x3d\x39\xbf\x6d\xcc\x81\xe6\xc0\xd8\x95\x18\xe7\x17\x7d\x38\x5f\x6d\xfc\x16\xc2\xfe\xc9\x6f\x03\x25\x4d\xfa\x8d\x7e\x57\x54\x35\x88\x0a\xac\x47\x81\xa9\x7d\x82\x25\xcd\xfd\x3b\x85\xe5\xb0\x46\x5e\x2b\xcc\x4a\xbe\x15\x1e\x97\xf2\x97\x2a\x5c\x08\xdc\xa6\xda\x78\xd3\x23\xeb\x50\x39\x49\xde\xe3\x6a\xf4\x23\x4f\xce\x8d\xcd\xcb\x31\xf7\xa3\xaa\xfc\x02\x87\xf2\xf1\xf2\xe0\xd3\xc3\x6b\x0c\xc4\xaf\xf4\x77\x0d\x64\x55\x1f\x91\x8d\x9a\x30\x77\x22\xd6\x06\xb6\xae\xe2\x5e\xe2\x02\xfd\xab\x4c\x40\x0a\x3e\x84\x00\x53\x60\x11\xad\xdd\x07\xab\x56\xa8\x1b\x95\xdd\x0d\xf4\x26\x61\x7c\xd4\x20\x7a\xbe\xea\xb3\x4e\xbd\x35\x3e\xdc\x04\xc8\x2c\xd1\x95\x75\x34\x70\xd7\x59\x38\x6b\x34\xb3\x56\x47\x9f\x6a\x28\xd0\xef\x8f\x86\x5a\x2b\xe0\x36\xa1\x87\xf5\x75\x9d\x0e\xb7\xe1\xf6\xd8\xb6\x52\x2f\x4c\x2b\x75\xbc\x1d\x0d\x16\x39\xb2\x0d\xb0\xc3\xe6\xb0\x74\x0e\x31\x9d\x06\x42\x0d\x57\x7c\x83\xdb\x57\x27\x81\xe8\xda\x4f\x11\x76\x01\x64\x9e\x7e\xf7\xfc\x49\x12\x6f\x2d\xe7\x59\xeb\xf9\xbc\xfa\x7e\x6d\x37\xc3\xff\x97\xd1\x45\xe5\xfc\xea\xab\xc8\xa2\x23\x54\x69\x11\xe2\x9b\x34\x3a\x7a\xff\xe7\xff\x4f\x69\xa4\x77\x75\x3e\x61\xd1\x0c\xfe\x7e\x0d\x85\x44\x4a\x97\x2c\x2a\xb8\x9c\xf9\xff\x22\xfa\x68\xb5\x87\x42\x43\x74\x29\x40\x68\x18\x01\x88\x1b\xa1\x61\x59\x60\x47\x9d\xf7\xa4\xff\xeb\xd1\x4a\xef\xca\xea\x4b\x31\xa1\x03\x47\xba\xcd\xc9\xd7\x58\xd2\xed\x53\x4b\x7a\x19\x5c\xd2\x63\x6f\x49\xcf\x02\x24\x9b\x29\xb1\xd3\x5e\xbc\xa7\x61\x29\x00\x13\x40\xec\xbf\xdb\xb5\x4f\xcc\x4d\x14\x53\x5d\x6e\x93\xf1\x80\x44\x4f\x62\xa3\xcc\x51\x3e\x74\x93\xb5\xeb\xec\x16\xae\xf4\x25\x77\x48\xa3\xae\xb9\xf9\xb9\xe7\xc3\xc5\x93\xe9\x9b\x9c\x77\xae\x95\x4d\x70\x1e\xfd\x13\xdf\x51\xf7\x22\x18\x2a\xf9\xc5\x2b\x26\xa9\x5f\x5c\xe4\x3c\x3c\x6c\x0e\x65\xe4\x54\x6a\x41\x70\x09\x8a\x5d\x21\x93\x7b\xec\x55\x2b\x98\x2a\x7b\x66\x21\x53\x2a\x9c\xb6\xb9\xad\x61\x61\x75\x50\x9b\xea\x75\xfc\x70\xe0\x51\x2b\xe8\xfe\x0f\x0d\xdc\xa8\x32\x9b\x59\xb7\xdb\xa5\xda\x0a\x6c\x60\x76\x72\x64\x1c\x9a\xe2\x63\xa2\x09\x69\x0e\x3b\x18\x1b\x7d\x20\x69\x40\xa0\x2d\x51\x15\xba\x28\xe3\x4b\x09\xce\x3c\x8f\x91\xc4\x93\xd8\xa4\x4f\x9b\x61\x35\x9e\xe2\x40\x9a\x91\x87\x05\xc1\x8f\xd1\x11\xf8\xd0\x5f\xf2\x5c\x1a\x34\x3c\x86\x7d\xd0\x84\xe7\xdc\x6c\x83\x75\xaa\x7d\xa0\x1a\x38\x91\xb9\x31\x3f\xeb\xce\x1f\x43\x6e\x6f\x9e\x6e\xcf\x34\x53\x95\x83\x25\x08\xa1\xa9\x5c\x88\x08\x2f\x58\x24\x4a\x44\xcc\xaf\x85\x6b\x2b\xe9\x9b\x6b\xf1\xa9\x15\x2d\xd3\x5a\x00\xfa\x24\xda\x26\xab\x74\x73\x4e\x7c\x51\x14\x13\xb4\xee\xb1\x98\x48\xb9\x1c\xd0\x92\x21\x6b\x4c\xe1\x04\xb2\xa7\x61\x8b\xe7\x44\x43\x51\x21\x43\xd8\xc3\xfb\x5f\xa1\x2d\x74\x39\x8d\x49\xbd\xab\x8e\xa4\x37\x77\x9e\x89\xfb\x9c\xb3\x02\xc9\x5b\xb7\x24\x86\xf2\xc0\xf4\xb4\x59\x3e\x6a\x0d\x72\x68\x94\xb4\x99\xf5\x2e\x2b\x2f\x21\xf9\x6f\xcb\xa2\xb9\xe3\xe1\xce\xea\x66\x0f\xba\xcb\xb5\x42\xcf\x2a\x92\x27\x6f\xff\x3f\x27\xc7\x1f\x06\x5c\x8a\x5e\x4e\xef\x38\x7b\x70\xfb\x9b\x73\xe2\xca\x66\xa2\xa3\xe7\xdf\x20\x1a\xdc\x01\x74\xb6\x94\x44\xd9\xf4\xcd\x78\x34\x96\xc1\xaa\x00\x79\x9d\x8d\x89\xbd\x3f\xe1\xfc\xc4\x09\xb1\x3e\x60\x7c\x39\x3d\xf0\x52\x37\x6a\x51\x4d\x92\xd1\x75\x7c\xc3\x01\x74\x95\xcd\xcf\x6e\xce\xe1\xfd\xca\x80\xdf\x15\x5a\x58\x28\x23\x7e\xeb\xac\xbc\x59\xa5\xdd\xb3\x92\x32\xf3\x8e\x8d\xf4\xd5\xab\xbf\x97\x29\xf7\xf7\xe9\x09\xf5\xd1\x8a\xab\x1d\x09\xe3\xa1\xbc\xda\x1b\xaa\xeb\x36\xb8\xef\x44\x6c\x9e\x3a\x11\xeb\xe0\x89\x58\x7a\x27\x62\xee\x79\x4f\xab\x9d\xd3\xac\x1c\x70\x05\x5c\x7e\x9c\xe1\x12\x6e\xd6\x38\xca\x8e\x85\xd2\xae\x52\x47\x3b\x0f\xb9\x09\x33\x0d\x98\xfa\x69\xc1\xdc\xa0\x05\xd7\xd0\x22\x6b\x0d\x3d\xc9\xff\xee\x75\xe0\xd8\x8a\x7c\xbf\xda\x56\xe4\x09\x92\x4b\xf8\xaa\x11\xce\x45\xe2\x7b\x42\x77\xa9\x65\x58\x49\x7b\xe0\xd1\xb1\xb6\xe4\xc7\xe8\x8e\xab\x1a\x66\x48\xd7\x51\x33\x8f\xfb\x6e\x98\x23\x0b\x79\x31\xe3\x8e\xe6\x1d\xa7\x3d\x54\x4a\x69\x0d\x14\xb7\xdc\x63\x43\x1c\x9d\x5e\x17\xe4\x33\x77\x3b\xfa\x6d\x03\x21\xbf\xd1\x2e\x17\x8b\x59\x59\x4c\x36\xba\x7a\xe3\x47\xae\xe4\xfc\x46\x71\x93\x72\x98\x30\x6c\x6e\xa3\x9c\x6e\xfc\x26\x3f\xf7\xdb\x46\xd9\x6e\x74\xcd\xb2\x18\x48\x29\x28\x7c\xfe\xbf\xe5\xeb\x1b\x2d\x60\x76\xc4\x59\x08\x14\xbf\x0f\xd3\x1c\x3e\x8e\x9d\x08\xba\xe3\x45\x53\x78\x12\x59\xf1\x05\x26\x6b\xa2\x1c\x4a\x11\x20\x85\xa0\x18\xe8\x03\x4c\x7a\x24\x93\x18\x5e\x6c\x16\x72\x76\x52\x92\xf7\xb6\x0a\xe9\xbf\x06\x70\x70\x0d\x38\x55\xe0\xe0\xfa\x4d\x33\xda\xde\x6e\x92\xea\x0c\xb0\x76\x7e\xd6\x9c\xa3\x2e\x1c\x97\x45\x56\x19\x26\xd1\x39\xc0\x2b\xb5\x66\xa5\x46\x22\xee\x65\x56\xee\x7a\x2e\x63\x5b\x68\x89\xf7\x2b\x49\xf5\x33\x20\xf3\x6a\xb4\x04\xf4\x4e\x49\x1c\x60\x78\x80\xc7\xd6\x7b\xb6\x14\xbe\x37\xcb\x1e\x0a\x3f\xef\x25\xe1\xdb\x35\x10\xd6\xf2\x29\x84\x35\x0e\x22\xac\x99\x87\xb0\xbe\x92\x5c\x1f\x3b\xd8\x6c\x26\x06\x2c\x88\x73\x4d\xbc\xaf\x42\x66\x27\x42\x8f\x5f\x22\xb3\x92\xe5\x82\x30\x6f\xcf\x0d\x2f\x73\xf7\x26\x59\x9b\x36\x8c\xef\xdf\xe6\x71\x15\xed\x2e\x88\x73\x63\xab\xfb\x24\x3c\x5a\x48\xea\x1c\xb9\x28\x77\xcf\xce\x53\x52\x34\x79\x02\xb1\x06\x50\x05\x77\xdc\xd6\xeb\x9d\xc3\xa2\xa5\x36\x03\x9f\x46\xc9\xad\xea\x46\x10\x69\x9d\x19\xa4\x35\xa5\x9c\x3f\x26\x69\xb0\xa5\xcd\xc2\x78\xe9\x47\x80\x46\x53\x67\x3b\xd0\xd8\x57\x5c\x42\xd4\x05\x60\x15\x49\x6f\x5e\x34\xd8\xf5\x1f\xa3\xef\x45\xd8\x88\xdc\x21\x6c\x93\xd5\xb4\xb7\x52\x9d\x72\xeb\xb1\x2a\xdb\x34\xa0\x03\x38\x64\x33\x34\x19\x23\xa9\x41\xf5\xf0\x50\xc1\x26\x47\x2d\xa1\xda\x70\xdd\xf4\x24\x91\x9c\xaf\x4b\x24\x73\xaa\x78\x24\xed\xb8\xed\x5e\xc0\xe8\xb3\xb3\x73\xed\x2e\x08\x75\x75\xf3\x06\x5a\x96\x08\x11\xb0\xc4\x0e\xe9\xe8\x0b\x6c\xb6\x7c\xd3\x8e\x5a\xc0\x66\xe5\x59\x6b\x22\xa5\x9a\x1b\xea\x52\x2a\xc7\x64\xfc\xb8\xa8\x75\x83\x94\x6c\x6b\x21\x5a\xab\xbb\x76\xa8\x79\xe6\xd0\xa1\x93\x55\x74\xe8\xff\x50\x52\xd3\xa4\x2b\x91\xce\x58\x6d\xbd\x69\x6a\xa5\x4b\x15\x71\xb9\x0b\xf0\x34\x80\x8d\x06\x3f\x8d\x45\x2f\xc8\x55\x38\x11\x5a\xe0\x03\x15\x56\x19\xdd\x0e\x09\x24\xf9\x89\xd6\x48\x42\xae\x3c\xd0\x60\x45\x4c\x26\x9c\x52\xd5\x60\xb2\x84\x53\x79\x4c\x9c\xa2\x51\x3d\xc0\x78\x2c\xa7\xb5\x18\x0a\xb2\xd7\x63\x8a\x4a\x45\xf1\x7f\x27\x1f\xeb\x12\xf5\x19\xe0\x89\x34\x16\xd1\xe4\xaa\x92\x9e\xb5\x6b\xab\xe1\x3c\x2b\xb7\x65\x4c\x90\x7b\x8a\xae\x9c\x96\x0c\xed\xdb\xf2\x47\x47\xd7\x9c\xf7\xfe\xb6\xac\x26\xf5\x2d\xae\x68\x15\x26\x7a\x6b\x2b\x90\xc8\xfd\x8a\x6c\xc2\x9e\xa1\xc8\x5c\x18\x7d\xf9\x0a\xa6\x07\x36\xb4\xa2\x40\x0c\x5f\x7c\x83\xbc\x1a\x5f\xd7\x0d\x85\x61\xa9\xd5\xeb\xf1\x74\x8a\x22\x57\x54\xf5\xa4\x10\xa8\x94\x9d\xcb\x37\x91\x2b\xec\xe4\x09\x70\x7b\x5d\xbc\x83\x27\x21\x6a\xb3\x19\x2d\x3a\xed\x99\xad\x59\x6d\xe1\x19\xb9\xdc\xdd\x49\x91\x29\x29\x22\x47\x27\x12\x4e\x33\xe4\x2f\x61\xc8\x2d\x31\x43\x23\x79\xce\x61\x33\x42\xb2\xd1\xe2\x14\xcc\xc4\x14\xc4\x84\x52\x1b\x6d\x28\xc0\x44\x82\xf8\xd6\x88\xbb\xe1\xae\xf0\xc0\xb4\xcb\xcd\xcc\x72\xf0\x06\xb3\x61\x66\xc2\xab\xec\xee\x34\x5b\x40\x77\x67\x81\xee\x5e\x67\xd3\xed\x31\x1c\xbe\x6a\xb1\x59\xcb\x6b\x34\x11\x67\x40\xd3\x91\xe3\x17\x36\x91\x9d\x86\x83\x97\xf7\x6c\x9e\x4d\x06\xe3\x7a\x36\xcb\x17\x6d\x31\xb1\xd7\xc7\x7c\xf7\x3a\x9d\xd2\x1a\x99\xef\x4e\xd3\xeb\x47\x27\xbc\xa4\x41\xe9\x05\xd6\xba\xdd\x11\x6b\x4d\x47\x4b\x38\x6f\xa6\x30\xca\x89\xe1\xfd\x0d\x87\xbb\x1b\x57\xa4\xed\x0b\x1f\xc7\x8d\x01\xe7\x1c\x7f\x79\x63\xe4\xc2\x03\x39\x5a\xa7\x8c\x24\xb5\x6a\x50\x2e\x6e\x8e\x9e\x3d\x83\xc9\x1c\x18\xd1\xf8\x3a\x6f\x00\x1b\x90\x9d\xe5\xca\xed\x54\xcb\x8a\x08\x35\xb3\x5a\xf3\xad\xa8\x88\x03\x8e\x83\xa1\x17\x02\xdb\x45\xca\xa4\x82\x3b\x09\x2f\xa3\x67\xe3\x38\x39\xd7\xd8\x80\x22\x9a\xcf\x4b\x5c\xe8\x62\x94\x78\xf7\xec\x87\x60\x9d\x1a\x35\x08\x56\x7c\x7f\x56\x80\xb4\x61\xe9\xe2\xb9\xf0\xa6\x94\x5e\xe6\xca\x11\x60\x09\xa4\xa6\x1f\x85\xba\x34\xf4\xbc\x46\x52\x71\xc9\x43\x2d\x60\x70\x82\xad\xad\x19\x2f\xbe\xe8\x5b\x63\x0b\xbd\xc6\x5a\x32\x87\x81\x0d\x50\x8b\x85\x8b\xfa\xb5\x08\xbc\x3d\xa0\x8b\xb0\x38\xba\x69\x85\x0e\xc0\x54\x62\xb0\x28\xde\xc2\x02\x8b\xf1\xde\xc1\x1e\xa1\x06\x66\xb2\x01\x98\xe0\x85\x5c\xb2\x6e\x1e\xb3\xda\x40\x6e\x09\x1f\x05\x97\x06\xfd\x5e\x8c\x97\x08\x55\x33\x82\x8d\x22\x9e\x85\xe0\xec\xa7\xba\xd9\x97\x13\xca\xb7\x9a\x26\x9f\xa1\x88\x21\xcb\xdc\x1b\xa3\x3c\x8d\xac\xe3\x08\x41\xe4\xd5\xe7\x16\x55\x01\xb7\xb6\x02\x58\x7e\x91\xdd\x23\x21\x40\x0d\xb6\xe9\x6c\xb7\x49\x6b\x74\x74\xa9\x13\x4a\x40\xba\xc6\x31\xba\x10\xa2\x8f\x50\x97\x53\x1e\x20\xa6\xbf\xc3\xe9\xf0\xd5\x0b\xd6\xdf\x5f\xc8\x46\x09\xc6\x0f\x6b\xfb\x17\xf8\xff\xa5\x04\x43\x5f\x7f\x16\xe1\xeb\xcf\xd4\x97\x56\x5c\x7b\xfc\x1e\x5f\x7a\x21\x4d\x82\x25\xc7\x67\xb2\x96\xf0\xe2\x54\x19\x12\xff\x43\xe5\x17\xac\xcb\x02\xa4\xb8\x66\x16\xc7\x3a\xd0\x2e\x73\x7c\x10\x27\x94\x2b\x69\x89\x1f\xb3\x21\xb2\xc7\x3b\xb8\x3e\x24\xac\xc8\x88\x89\x2c\x7c\x34\xa1\xdd\x5e\x41\x8a\xc5\x86\x14\xc1\x64\x4d\xdb\x22\x14\x7e\xbf\x83\x06\x62\x2d\x4a\x40\xcf\x32\xbd\x57\x92\x45\xcf\x95\x44\x75\xbd\xdf\x32\x30\x20\x2b\xb1\xef\x2a\xab\xaf\x35\xea\x26\xe3\x4b\x4c\x9e\xb8\x96\xc8\xbe\x7b\xb0\xd0\x4c\x25\xcb\xe6\xc3\x92\x1a\x84\x39\xf8\x9d\xc9\xc1\x27\x80\xfd\x41\x16\x3e\x87\x5e\x98\x93\x3f\xfb\xe3\xb4\xff\xff\x8d\x3c\xe8\xa7\x23\xd7\x39\x2c\xca\x1f\x56\x5b\x78\xfb\x38\xb5\x29\xc4\xaa\x29\xff\xcb\x0c\x16\x16\xfb\xfe\x59\x34\x3e\x12\xb8\xd4\x8e\x44\xb7\x3a\x30\x72\x81\x5e\x8f\x7e\x92\x61\x8d\x10\x63\xde\xeb\xef\xa6\x39\x03\xea\xb6\xb5\x96\xe7\x02\x36\xfa\x5b\x8c\x54\x0f\x83\x13\x5f\xce\x36\x87\x18\x7b\x32\x58\xb3\x19\x4c\x67\x70\xb3\xa4\x1a\x85\x58\xed\x2d\x77\x7e\x85\x21\x0d\xc7\xd9\xd9\x92\xb5\xe7\xa3\x32\xae\x0c\x75\xe3\x5a\xe0\x2f\x3c\x19\x8d\xc1\xfc\xd2\xe4\x68\x85\xda\x06\x78\xd5\x63\x5c\x6f\x08\x98\x19\x39\xe1\xa2\x63\xd5\xeb\x67\xba\x39\x64\x97\x56\x47\x7a\x42\x48\x06\xc6\x38\x0a\x8e\x7b\x87\x35\xbb\xe4\x4c\x33\x01\x7a\x5b\x86\x93\x2c\x18\x57\x41\x47\x8d\xb2\xc0\xc9\xdd\xbf\x72\xdd\x45\x65\xc7\x88\x7b\x41\xca\x0d\xf6\x7c\xa5\xc3\xef\x30\x82\xfd\x0f\x6b\x5b\x4b\x27\xf7\x17\x03\x53\x21\x7a\xc0\x3d\x77\xf1\x75\x8e\xe9\xca\xb2\xf8\x53\xc2\x44\xd1\x8f\xb3\xe5\x55\x59\xfd\xbc\xbc\x14\x85\x8d\xc4\xe3\x06\x7d\xee\xb5\xbd\x45\x8f\x84\x1b\xe2\x9f\x09\xdf\xc4\xb7\xbd\x05\xb9\x2f\xf9\xf7\xeb\x7c\xb3\x7d\x4b\x27\x60\x7c\xff\xff\x92\xf7\x66\xdb\x6d\x2b\x4b\x82\xe8\xea\xd7\xfe\x0a\x0a\xdd\xad\x4d\x96\x52\x34\x29\x0f\xdb\x06\x0d\x6b\xf9\x78\xe8\xe3\x3e\xdb\xc3\xb2\xe5\x3a\x75\x5a\x47\xe5\x82\x48\x48\x44\x99\x04\x58\x00\x68\x5b\x25\xf1\xcb\xfa\xe1\x7e\xd2\xfd\x85\x1b\x43\xce\x48\x50\x94\xf7\xae\xee\x7b\xd7\x7d\xb0\x45\xe4\x3c\x44\x46\x46\x44\xc6\xf0\x29\x5f\xae\x16\x99\x95\x13\x7f\x10\xaf\x30\xbc\xf2\x6f\x59\xfa\xcd\x49\x5f\x0b\x46\x64\x76\x5a\x29\x14\x1a\x40\x22\xca\xca\x48\xc5\xdb\xf2\x3c\x5f\x64\x9f\xd2\x0b\x38\xd2\xe4\x57\xc0\xce\x5e\x09\xa6\xc1\xed\xb4\x13\xf1\xa7\x0c\xb6\x3e\x23\x45\x02\x3b\x03\x7d\xb8\x7f\x19\xbe\x03\x94\x66\x1b\x8d\xf1\x94\xfe\x3b\x2e\x73\x3e\xd5\xc9\x7c\xc9\x2f\xbb\x2b\xb8\x25\x81\x3a\xbe\x96\x2e\x88\xbe\xb1\x27\x9d\x4b\xb2\xc0\xbd\x92\x06\xb8\xaf\x94\x23\x97\x17\xca\x2f\xca\xb9\x71\x3f\xf2\x83\x7d\xe3\xbc\xeb\xb3\x77\x9c\x01\xbb\xd3\xc1\xcf\x8c\x94\x74\xc8\x79\x09\x7c\x92\xf7\x12\x32\xfd\x1a\xb6\x91\xe6\xd0\xf2\xfa\xd6\xbf\xc0\x32\x16\x26\x97\x99\x56\x0a\x10\x9b\x17\xf9\x65\x7f\xb1\x6b\xc1\x4f\x04\x0c\x8e\x53\x36\x05\x0c\xae\x23\x47\xe3\xe7\x06\x6b\x28\x14\xa3\x00\xbb\x1d\x6f\xb1\x3f\xef\x0e\xe2\xda\x6e\x41\x9d\xf9\x4f\x68\x4e\x9d\x5d\x5e\xf5\x67\x58\x06\x43\x34\xbe\x01\xaa\xe3\x87\xda\x1b\x66\x72\xa8\x59\x95\x05\x24\x9d\x26\xfd\x8f\x95\xd6\x96\x5b\x24\x7e\x1f\x4c\xd6\xeb\x6d\x4f\xda\xd0\xf9\xfd\xb9\x73\x09\x84\x61\xcf\x5c\x07\x2d\xd8\x37\x97\x02\x40\x77\x56\x34\x6e\xe7\xe6\x6e\x08\x1f\x10\xcb\xba\x9f\x49\x24\x1f\x1f\x18\xb2\x3a\x78\x1a\x0d\x7d\xdd\xc1\x76\x49\x5a\x1b\x09\xb1\x16\x54\x18\xa2\x7b\xdb\x21\xf5\xcc\xfd\xbb\xb8\x83\xb9\xcf\x1d\x60\x66\x20\x96\xa9\xeb\x0f\x40\xce\xda\x87\x0b\xe3\x22\xa0\x6d\xe8\xe9\x86\x2f\x33\x5e\x43\xdc\xe8\x65\xca\x9c\xc1\x8d\x5b\x26\xb5\xf9\xdc\xc0\x65\x5a\x69\xc9\x0d\x5e\x66\x1e\x80\xdd\xb8\x65\xe6\x2d\x05\xe3\x95\x39\xe9\x9a\x7d\xd0\xf1\xc8\xda\x77\x81\x09\x4a\x46\x79\x6f\x94\xdf\x47\x13\x89\x4c\xa6\xdb\xc8\xbe\x36\x41\xc9\x1c\xbd\x2f\x19\x95\xac\x85\x44\x29\x42\x99\xcc\xaa\xbe\x65\x55\x0b\x28\x65\x50\xb2\x16\xd6\xa7\x58\x64\x9c\xf5\x8f\xff\x3d\x04\x30\xef\x38\x57\xb2\x5b\x70\x35\x7f\x48\x2f\x6d\x26\xd0\xba\xa2\xa5\x23\xcb\x18\xbd\x8a\x5e\x77\x1f\xad\xf8\x01\x51\x82\xed\x83\x15\x3f\xa0\xdb\x3c\x78\xac\xe2\x87\x44\x17\x76\x1c\xaa\xf8\x21\xe9\xb9\x76\x1d\xa9\xf8\x21\x51\xbd\xe1\x03\x15\x3f\x24\xe2\x75\x9b\x48\x20\x7c\x98\xe2\x47\x34\x8f\xad\x47\x29\x7e\xf4\xf8\xae\xa4\x75\xc7\x31\x8a\x7f\x7d\x24\xda\x67\x20\x7e\x3c\x16\xc1\x43\x13\x3f\x3e\x12\xfe\xd1\x88\x1f\xdf\x17\xde\xc1\x88\x1f\x3f\x14\xad\x63\x11\x3f\x76\xba\x92\x87\x22\x7e\xec\x10\xf9\xf2\x48\xc4\x8f\x1f\x8b\xd0\x81\x88\x9f\x18\x16\xa0\xeb\xcc\xc7\x4f\xc6\x7e\x19\x56\x5b\x7e\x62\xc6\xe9\x1e\xa5\x78\x3c\x32\xcd\x9a\x93\x04\xc9\x63\xd1\x75\x90\x20\xd3\x34\xe7\x6a\xbf\x04\x41\x1e\xe8\x47\x2a\xdf\x3e\x63\x90\xf3\x40\x74\x1d\x31\xc8\xa4\xa5\x6c\x9f\x30\xc8\xa1\xde\xba\x8e\x50\x3c\x7e\x80\x4e\x7b\x9e\x6c\x37\x4b\x0b\xfa\xa5\x24\x01\xe4\xc5\xa2\x2c\xab\x3e\xac\xcc\x3f\x64\x83\x7b\xf0\x27\x10\x05\x98\x9c\x1c\x91\xb2\xc2\xcd\xcd\x68\x70\x50\x6c\x58\x57\x2c\xe0\x65\x26\x6f\xe3\x6a\xdc\x93\xe7\x45\xba\xb8\xaa\x73\x5f\x72\xa4\xd0\x92\x2d\x29\x92\x16\x44\xf2\x12\x93\x64\x3d\x6e\xc8\xbb\xf2\x3b\x1b\x0c\x7d\x01\xde\xf7\x2d\x6b\xf3\x53\xb0\xaf\xf8\xf4\x4c\x86\x7c\xff\xd4\xa0\x1f\x93\xd3\x11\x7c\x33\x2e\x41\x0f\x29\x63\xc1\x32\x72\x8b\x6f\x99\x0e\x75\x3e\x19\x31\x2b\x48\x50\x44\x95\x34\x15\x98\x2a\xa3\x01\xe8\x76\xe8\xf7\x2a\x25\x2c\xc9\x48\xd4\xc3\xac\x40\xa7\x50\x32\x37\x41\x07\x2a\xe4\xf5\xcc\xea\xb1\x55\x66\x4c\x2f\xe4\xbf\xa5\x75\xe3\x4c\x25\xc0\x5c\xb5\x7a\xc6\x20\x6f\x39\x30\x11\x3f\xa6\xc0\xdc\x01\xa9\xea\xc8\x10\x32\xf4\xbd\xdd\xae\x63\xeb\x1f\xea\x8a\x9f\xd8\x8f\x1e\x6a\x4d\xa2\xab\xe4\x72\x81\xcf\x8d\x30\xc8\x7e\x33\x5c\xa6\xab\x7e\x3b\xbe\xca\x75\xa4\xc1\xae\x37\x45\x3a\xb8\x87\x6a\x79\x11\x5a\x19\xab\x74\xe4\x0e\x44\x74\x52\x36\xe9\xa2\x97\x17\xb2\xa3\x1e\x3a\xcf\xeb\xf5\x97\xf5\x20\x8a\x0b\x8c\x9f\xac\x32\x06\x22\xd2\xa3\xe9\xd1\x16\xfa\x45\xb3\x1f\xa1\xa2\x32\xbc\xb5\x57\x56\xba\x5e\x16\xd1\x5b\xd3\x12\x00\x90\x8e\xc7\x12\x6a\xf6\x1e\x8e\x1d\x9f\xc0\x44\xf4\xd1\x6a\xb4\xa3\x1a\xf7\x60\xea\x28\x64\x51\xc7\x32\x09\x38\xe1\x81\xdc\x9f\x37\xc5\x4f\xee\x8f\xae\xf8\x13\xfb\x43\xae\x8f\x7b\xcf\x7a\x53\x83\x1e\x5a\x9b\xf3\xa6\x6b\x5b\xf0\xb3\x63\x4e\x42\x0d\x60\x51\x5e\xf6\xe5\xf6\xb2\x5f\x44\x41\x63\xa6\x94\x13\x48\x80\xc1\x0c\x9b\xf2\x75\xfe\x23\x9b\xf5\x8f\x06\x07\x51\x6f\x09\x87\x9e\x60\xdd\x9e\xae\x9c\xd9\xdb\x34\xe4\x4e\xa5\x63\x11\xc4\xde\xc8\x84\xfc\xfa\x5d\x0b\xf0\x57\x38\x75\xa8\x4a\x65\x66\xcf\x73\x0f\x4e\x5d\xee\x26\xd7\xd9\x65\x2b\x85\xbb\x57\xd3\x61\xe7\xdc\xc9\x29\xd8\xef\x5c\x58\x1a\x1c\xe0\xe0\xbb\x02\x19\x5e\xc1\xbb\x83\x17\x57\xbc\xde\xe8\xf5\x3f\x2d\x87\x6f\x5e\x7e\x79\x7e\x72\xf2\xf1\xcd\x9f\x3e\x9f\xbc\xfa\xf2\xee\xf9\xdb\x57\x67\x09\x9c\xec\x99\x60\x35\x23\x54\x5d\x40\x69\x52\x33\x4c\xab\xcb\x3a\xf1\xf4\x76\x33\x4a\x45\x49\xe5\xef\x5f\x81\x2f\x15\xb0\x92\xd5\xec\xaf\x55\x1e\x88\xf2\xa2\x7c\xd8\xb4\x17\xe3\xb4\x13\xa5\x1f\x8e\xcf\x86\xdf\xb1\xb5\x7a\x52\xa2\x72\x3a\xfe\x77\x73\x03\x97\x0c\xfe\x60\x55\x8d\x6b\x9c\x5b\xdc\xb0\x6b\xd0\x02\xe3\x4e\xd6\x28\x6e\xd8\x08\x79\x61\xb4\x44\x5b\xed\x18\xd1\xda\x59\x13\x86\xd4\xcd\xf1\x1a\x49\x74\xf8\x4a\xa5\x2f\x52\x3f\xcb\x27\xf9\xc1\xc1\x40\x2a\x88\xe8\xfc\xd3\xfc\x4c\x0a\xdc\xc4\x4a\x5c\x90\x8e\xb6\x0c\x0b\xf1\x2e\xfb\x8e\x34\x85\xa1\x0e\xf0\xa5\xff\xe6\x26\x0a\xc8\x01\x29\x6b\xd0\x79\xcb\xc8\x89\x6a\x44\x89\xee\xbc\x35\xde\x8e\x8d\xea\x2a\xfa\x3a\xc1\xa3\x52\x93\xbf\x6f\x5a\x36\xfc\x65\x3d\x97\xd0\x77\xa3\x76\x31\x46\xf7\x8e\x17\xc9\x1a\x7d\x26\x24\x85\x1d\xbd\xb3\x0c\x5d\xb3\xdb\xb7\x49\xb7\x8a\xed\x1d\x5e\x88\x15\xad\x45\xd0\xc2\x8f\xa3\x52\x44\xb7\x12\xca\x58\x8e\x9e\x84\xbb\xc6\xb8\x90\x7d\xb1\x4b\xb2\x37\x4b\x20\xc6\xde\x14\x4d\x89\xaf\x00\xbc\xa4\x32\x46\x7c\x2a\xd5\xc7\xcb\xd3\x31\xec\xd6\x74\x68\xc3\x69\x7f\x0e\x60\xb1\x00\x80\x1a\x49\xbf\x2c\x3b\x98\x1f\x62\xdb\xc7\x58\x43\xc7\x31\x08\x9e\x50\x7e\xa7\x80\xe3\x77\x51\x95\x4b\xa2\x2d\x29\x8c\x81\xfe\xb2\x73\x94\x75\x31\x39\x19\x34\x65\xe5\x6f\x93\x6a\x97\x33\x2f\x97\x5c\xd6\x7c\xbb\xb9\x56\x9d\x25\x19\x6b\x9a\xf6\xf9\x3b\xc1\x85\x39\x75\x72\xcf\x08\x02\xec\x75\xca\xb4\xb1\xa4\x90\x08\x65\x41\x16\x92\xb1\x57\x0e\xd7\x85\x96\x94\x9f\xc3\x4c\x38\x86\x1a\x58\xaa\x8c\x9f\x4b\x4a\x31\x1e\xe8\x1b\x64\xb5\xd1\x90\x12\x78\x91\xd8\x63\x60\xf1\x9c\xce\xa1\xcb\xaa\xfd\xfd\x96\xdf\x28\x99\xdc\x1d\x98\x65\xcf\x3a\x68\x1e\x34\x4d\xd8\x20\xc1\xef\x49\xef\x75\xdc\xf2\x60\xb2\x4c\xb6\xf4\x84\xf5\xc4\xb7\x60\x73\xe2\x12\x91\xa0\x21\x93\xc5\xd5\x5d\x91\x22\x9e\xad\xe5\x71\xd5\xbf\xe2\xbb\xb1\x16\x33\x58\xd0\xf8\xdb\xfe\xfe\x25\xe3\x8a\x51\xf7\xb9\x56\x67\x66\x39\xc0\xea\x3c\x7c\xa8\xbe\x60\x2f\x72\xa8\x17\xfd\x8d\x41\xf8\x55\x02\x8d\x95\xab\xfe\x60\x72\x79\x7a\x69\xba\x3e\x48\x16\x02\x6b\x6a\x6c\x84\x95\x0f\x5f\x0d\x28\x51\x63\x25\x6a\x91\x55\xe7\xda\xe9\x6a\xe3\xaf\x6c\x0f\x85\xf5\xe9\xec\xcc\x78\xfc\xdf\x16\x33\x45\x90\x37\x32\xb9\x1d\xf4\xfb\xd8\xfa\xdd\x55\x2b\x8e\x9e\xe2\xd6\xa1\x2f\xb9\x95\x1b\x85\x43\x1a\x51\x06\x5c\xb2\x74\xf2\x4e\xf1\x93\xdd\x4d\x76\x3d\xbe\x29\x1e\x3f\xbe\x8f\x3c\x62\xcb\x7b\x84\xcb\x16\x6a\xff\xb8\x70\x1d\x05\xcc\x9a\xe5\x03\x0d\x39\xc7\x6a\x0e\x92\xca\xa0\x5f\x63\xfd\xe2\xaa\xd7\x99\x06\xe1\x92\xeb\x6c\x11\x65\xa5\xca\xb7\x18\x05\xc7\x2c\xe5\xfd\x3b\x50\x3f\x50\x69\x3b\x84\xf5\x1a\x79\x4b\xe5\xb3\xb8\x12\x74\x27\x4f\x4f\x19\x4f\xc0\x8d\x2d\x11\x06\x5d\xce\x4c\x70\x6c\xd0\xb6\xba\x3d\xd4\xd2\x19\xaa\x50\xca\xeb\x93\xca\x0c\x56\xeb\xa0\x97\x14\xb2\x13\x2e\xec\x1a\xdf\xb7\x4b\x0b\x22\x4b\x8b\xad\xd1\x3a\xa1\x18\x0c\xb2\x97\x0f\x9a\xa4\x74\xc1\x2e\x3d\x53\x71\x2c\x44\x81\xcc\x75\x41\xbc\xf5\xb5\x43\xa8\x02\x7d\x61\x2e\xdc\x91\x30\x37\xf1\x48\xdd\xbd\x23\xbe\x7a\xe1\x4a\x85\xde\x39\x0d\x5a\x46\x57\x89\xd0\x9c\x4c\x38\x48\xac\xac\x81\x3d\x62\xab\xa8\x4e\xc3\xd2\x76\x81\x81\x3d\x2d\xab\x82\x4e\xc3\x0a\x76\x01\xb2\xa5\x21\xf4\x60\x95\xa6\x04\x2c\xa9\x73\x58\x86\x3e\x55\xea\xb3\x0d\x87\x44\x75\xc7\xf2\x0c\x9d\x34\x4d\x79\x87\x0b\xdb\xb1\xf2\x74\x58\xc3\x19\xea\xbb\x90\xac\x39\x03\x5d\xff\xd0\x62\xf3\x80\xe6\x98\xb6\x94\xe2\xb4\x05\x3f\x46\x2d\x81\x25\x84\x2d\x2f\xcd\x96\x97\x6a\xcb\x73\x14\x99\x9f\x96\x67\xa8\x4f\x44\xae\xdd\xac\x4d\x9f\xda\x9b\xde\x90\xdf\xb5\xb4\x3f\x1d\x18\x00\x58\xe1\xcc\x16\x03\xa9\x78\x99\x9f\xae\xce\xb8\xd1\x0b\xc0\xbe\x0e\x44\xac\xce\x26\x45\x72\xc1\x5e\x89\x81\xb6\x7d\xd6\x8b\x0e\x74\xfc\x2a\x51\x61\x88\xa0\x8a\x7c\xae\x79\x30\x52\x30\x0d\x6a\x41\x82\x35\x24\x68\x14\x86\x84\xf5\x88\xbf\x39\x48\xdc\x3c\xbc\x6d\xe5\x8e\x98\x82\x72\xaf\xac\x1c\x69\x23\x31\x57\x9b\x45\x1e\xf3\xaa\x81\x6e\x96\xf6\x69\xce\xfb\x84\x89\x7a\x9f\xe6\x5b\xf7\x09\xab\x1e\x32\xe3\x05\xbb\x33\x77\xb4\xf2\x0c\x3d\x03\xa7\x51\xbe\xd9\x7e\xcd\xae\x6a\xa0\x07\x24\x66\x80\x2d\xab\x39\x70\xbd\xd9\x8c\x2c\x74\x02\x4b\x1e\xed\xb5\xd1\xd2\xde\x1b\x8b\x14\xb6\x3a\x7d\x5a\xa8\xad\x4e\x51\x27\xfb\xa2\x8f\x6a\xb1\x05\x1e\xcd\x1c\x89\x91\xf7\x17\xe4\x2d\x35\x47\x2b\x95\xf3\x2a\x4b\xbf\x6e\xf6\x72\x34\x02\x90\xeb\x52\x9e\x3d\x1b\x21\x35\x83\xfe\xf5\xd0\xa7\xb3\x46\x2b\x96\x6a\x9b\xff\xec\xbf\x4e\xc6\xc3\x23\x14\x61\xb5\x49\x47\x0c\x9c\x80\xa7\x40\x39\x55\x10\x6f\xde\x7d\x7a\xf5\xf1\xe4\xcb\xdb\xe7\x1f\xff\xf2\xf9\x43\x2b\xf7\xed\xfb\x7f\x7c\xf5\xe5\xd5\x3f\xbd\xf9\x84\x91\xe9\xe2\x08\x15\xf7\x22\xf1\xf1\x15\x25\xbf\x7b\xff\xf2\x15\x7a\xdf\xe7\xc4\x93\x57\xff\x74\xf2\xe5\xc5\xfb\x77\x27\xaf\xde\x9d\x70\x33\x16\x91\x16\x89\x80\x8b\x1b\x49\xe0\xf4\x52\xe5\xd3\x2f\x0a\xf9\x8f\x91\xee\x61\xec\x52\x2d\xff\x2d\xaa\x25\xf2\xbd\x53\x47\x41\xff\x2a\xfe\xcc\x76\xf2\x41\x12\xc9\xd0\xd0\xec\xa6\x27\x20\xd3\x8a\x4b\x11\x10\x22\xc4\xb9\x70\x58\x5f\xb8\x34\x6c\x06\x33\x2e\x02\x8e\x37\x42\x81\x84\x9e\xec\xec\xea\x42\x12\x98\x1c\x3a\xcb\x33\x61\xb4\x83\x67\x99\xf0\x3e\x46\x49\xed\x1a\x20\x1e\x9d\x32\x57\xd9\x05\x3b\xc5\xcf\x13\x9f\xbd\x45\xcb\x2d\xe5\x0b\x82\x98\x6e\x56\x7c\x82\x8a\x2a\x76\x28\x54\xf6\x82\xa5\xaa\xc0\xa1\x2a\x90\xa8\x13\x73\x35\xdf\x4c\x2c\xd7\x73\xc9\xf5\x97\xbc\xb6\xd5\x70\xc8\x39\xb4\x7a\x4d\x55\x21\x4b\x9d\x41\x49\x4f\x9a\x35\x6a\xa4\x6c\xa4\x67\x41\xd8\x23\xd2\x2c\xb7\x9d\xe0\x2e\x92\x6f\x65\x3e\xeb\x49\x4d\xf4\xec\x42\xfa\xa9\xc5\x9f\xb2\x16\x66\xc0\x44\x38\x03\x35\xd7\xf0\x8b\x8e\x75\xcd\xfe\x8d\x5b\xce\x8d\xeb\xc1\xfe\xfe\x5e\x19\x4a\xed\xaf\x4f\xeb\xb3\xa4\x81\xff\xf8\xe2\x59\xb5\x78\xed\xc3\x23\x1c\xde\x38\x41\xd7\x9e\x6b\xad\x72\x97\xa4\x9a\x40\x5d\x3d\x1b\x1b\x24\x72\x91\xb0\xba\xdd\x0a\xdf\x31\x47\x93\xd5\xb3\xf9\x64\x0e\x38\xe4\xe2\x74\x7e\x66\x5a\x3e\x9d\x1f\x1c\x9d\x4d\xac\xc6\x2e\xc8\x6f\x31\xb9\x80\xb4\x42\xc8\x29\xa3\x64\x37\xd5\x4c\x74\x36\x08\xe9\x10\xe3\x84\xd4\xbc\x66\x34\x2f\xcb\x8a\x10\xef\xb7\x29\x30\x43\x95\x21\x32\xf4\xaf\xf5\xc0\xec\xa0\x54\x7f\x4c\x42\x32\x38\x67\x8f\xad\x80\x79\x99\x25\x84\x53\x30\x47\x2d\xa2\x26\xfe\x73\x74\xc5\x4f\x27\x93\xe3\xe5\x85\x7c\xfc\xc8\x01\x32\x71\x96\xe1\xa6\x8a\x8c\xb6\x5d\xc7\xb0\xcd\x34\x70\x0a\x3b\xd6\x20\x74\xe2\xc6\x6a\x0c\x8c\x7b\xaf\xbf\x87\x31\x8e\xa1\x05\x17\x70\xcd\xa0\x37\x6d\xa7\x89\xce\x21\xbd\x2d\xbe\x9d\xaf\x5a\x76\x07\x87\x23\x52\x31\xd2\x44\x3c\x93\xe6\x29\x7c\xab\x74\xc4\x67\xe7\x63\xd2\x32\x73\x85\x19\xd6\x50\x96\xd4\x22\x99\x0b\x54\x9e\x3a\x69\x49\x31\x32\x45\xab\x04\xaa\x4c\xe5\x7d\xc0\x9d\x30\xb5\x2f\x50\xe8\x8b\x9a\x8b\xf8\x05\x29\xeb\x1e\x01\x2a\xb9\xc3\x55\xe6\xac\x1c\x39\xae\x37\x4f\xbf\xa1\x95\xe9\xba\xc8\xff\x6d\x9d\xf5\x30\x08\x53\x44\x66\xa9\xc3\x5f\xc8\xcb\xb1\x6f\x58\x4a\xba\x5c\x2a\xec\xc1\xfe\xbe\xee\xb2\x80\x73\x01\xcb\xe2\x76\x1d\x91\x9c\xa3\xc7\xb1\x1f\x6a\xa7\xc7\xa2\x2c\x0e\x65\x9d\x1e\xde\xfe\xbd\xba\xec\x95\xf8\x22\x8b\x6e\xdb\xf2\x1a\x86\x90\xd5\xf8\x96\x36\x1b\x46\x5e\x24\x86\x9c\xdd\xc2\x9b\x18\xcf\xa8\xb2\x9f\xba\x44\xb8\xa8\xd1\x45\x6e\x0a\x88\x6a\x8e\xb1\x35\x91\x42\x6b\x79\x34\xae\x81\x00\xa0\x23\x86\x4e\xf2\x0f\x92\xfc\x38\xea\x91\xb7\x8c\x5e\x33\xd7\x8f\x10\x4b\x8a\x9a\xd9\x83\x33\x19\x1d\xe4\x18\x5a\x33\x6e\x17\xb2\x9e\x4d\x80\xbd\x96\x8e\xe7\x9e\x46\x07\xe9\x41\xf4\x6c\xa8\xfc\x94\x13\x8e\xac\xe4\x21\xd8\xdf\x57\xbf\xd0\xdb\xb0\x02\x19\xf2\x33\x5c\xdd\xc2\x74\xe2\x48\xa3\xde\x9b\xa6\xf7\x3d\x85\x35\x42\x6d\xa5\x19\x6c\x1e\x6f\x2e\x8a\x7e\xd8\xbf\xf9\x10\xdd\x01\x61\xc1\x4f\x59\xd6\x9b\x37\xcd\x2a\xbe\x77\xef\xe2\x7c\xb8\xcc\xee\xd1\x66\x1d\xca\x0d\x3a\xa4\x85\x07\x64\xd4\x5b\x02\x2c\x01\x70\x10\x5b\x49\x8f\x65\x91\x00\x6c\x26\x0c\x3d\x1a\xd7\x46\xb9\x96\x8e\x4c\x3c\xdd\x18\xe9\x2e\xb6\xd7\x6f\x06\x1b\x9b\xce\x53\x47\xa2\xc0\x08\xbc\x51\x34\x99\xb5\xa3\xa2\x02\x20\xcf\x38\x6c\x86\xb8\x50\x70\xc4\xb0\xf2\x65\x99\xae\xbe\x28\xdc\x1a\xd9\x40\x58\x6b\xb3\x0e\xcf\xda\x7a\x30\xd8\xe2\xb4\x4b\x42\x0a\x71\xa2\x53\x3f\x2a\x6c\x0e\x70\x5c\xf5\x73\x94\x3d\xa9\x0b\xa1\x55\x06\x9a\x0f\x9e\x39\x7d\x85\xc0\x41\x6f\xc7\x38\x19\x5c\xc3\x3a\x68\x6a\xb5\x66\x3f\xdd\x65\xbf\x16\x19\xc0\x9d\x70\x16\x6c\x6d\xa4\xda\x77\x71\xf5\x4f\x51\x14\xd9\xe1\x7f\x1f\xdd\x83\x67\xd0\xc0\x66\x8a\xb2\xe0\x7e\x8a\xf4\x6d\xba\xc9\xf5\x5b\x17\x8c\x88\x4c\xd0\xe1\x22\xed\xe7\x00\x0c\x75\x0d\x34\x2a\xf6\xb1\xc4\x5b\x74\x79\xaa\xd3\xdc\x1d\xb9\x48\xf3\x45\x36\xfb\x32\xcb\x58\x17\xac\xac\xbe\xe0\xf4\xbe\x90\x07\x94\x48\x5c\xcb\x3a\xb1\xae\x8d\xaf\x64\x92\x03\xbc\xcd\x02\xba\x1d\x68\xd3\xb5\x87\xf6\xc8\x28\xa9\x7a\xd4\x8a\xdb\xd1\xb6\x01\xb8\x6e\xe1\x41\x96\x6a\x77\x60\x2a\xc8\x44\x4f\x73\x48\xd5\x48\xef\x46\xf7\xfe\xf9\xef\xb3\x83\xff\x7a\x4f\x5c\x26\xd7\xce\x65\x19\x78\xd2\x9a\x7a\xd7\xa9\x25\x1d\xd3\xe4\x82\xd6\x32\xb7\xa4\x85\x8d\x09\x23\x9b\x1c\x01\xc0\xb6\x5e\x08\x10\x70\x6b\xeb\x61\xa0\x38\x13\x1c\xf7\x26\xd3\xd2\x1a\x1b\x35\x4c\xd8\xca\x9f\x4c\xb7\xf7\xf7\xd7\xe8\xc7\xdf\x24\x08\xe5\x6f\x7e\x41\x7f\x51\x0f\x5f\x5e\xc3\x4e\x79\x3b\x4d\x98\xf0\xd0\x50\x4b\x05\x8a\x36\xbc\x90\x70\xe8\x8c\xc0\xc2\x5c\xde\x8d\xce\xb0\xe9\xf3\x4b\xfb\xf2\xbe\x4b\x20\xda\xee\xd0\xad\x1d\xf1\x53\xfd\x2b\x7f\xbb\x3b\x13\xe7\xca\xd7\x9e\xdd\x52\x0c\x33\x3c\xf0\xc4\x63\x53\xc6\x6c\x9e\x24\x4a\x32\x56\x98\xe9\x45\x0a\x52\xf2\x0f\xcc\x21\xe9\x92\xa3\x39\x61\xce\xcf\xba\x6d\x03\x33\x45\x98\x5d\x28\x1d\x2b\x57\x89\xd3\xd9\x97\x54\x1b\xbe\x98\xb0\xa4\x9b\x0d\xaa\x74\x77\x86\xe0\x66\x66\xcb\x6b\xb3\xb0\x42\x14\x2f\x44\x5e\xfb\x75\x72\xd1\xd5\x5a\x15\xd0\xdb\x0e\x6d\x66\xcb\xcf\xcc\x93\x5d\xa2\xd6\x5e\x53\x84\x6c\x67\xca\x8a\x0e\xdb\x04\xc2\xbd\x3e\xd9\xdd\xea\x18\x1a\x52\x51\xa2\x48\x7f\x87\x6c\x4f\xb5\x87\x47\x4a\x92\xc1\xa4\x6c\x05\x52\x57\xe3\x9a\x18\xc1\x6b\xb6\x10\x39\x91\x4e\xf9\xdc\xc7\x44\xe2\xf8\xd8\x28\xb0\x42\x5b\xbc\x4a\x69\x39\xd5\x3a\x7b\x52\x00\xb8\x39\x93\x29\x2d\x97\x7d\xa6\xaf\xf8\x11\xae\xda\x78\x74\x97\x88\xb6\x7c\x6c\x8d\xbf\x2d\x51\x24\xf4\xc2\x6d\xd4\x99\x5e\xbe\x06\x1a\x83\x1f\x2b\xe0\xbe\x07\x96\x77\xd1\x19\xa2\x0b\xcd\x32\xb9\xad\xd7\x79\x55\x37\xea\xdd\xae\x5f\x99\xe0\x22\x2d\xc2\x97\x99\x5d\xcb\x5f\xa1\x62\x7a\x0b\xd2\xdb\xa6\x29\x2a\xe6\x97\xde\xf2\x01\x86\xeb\xe4\xf4\xac\x4b\xdc\x1b\xea\x7f\x0e\xc4\xb3\xd5\xdc\x00\xa8\x10\xb6\x02\x45\xcb\xd5\x49\x35\x81\x7b\x5e\x37\x2d\xe5\x5e\x64\x1f\xde\xb7\xe2\x7e\x97\xc9\x88\xbc\xaa\x98\x82\x12\x65\xe7\xcf\x4a\x96\x2d\x36\x76\x2e\x46\xe3\xe1\x5d\xd5\xbe\xd2\x98\x26\x5a\x2a\xeb\x26\x05\x0e\xc8\x3a\x59\xd3\x47\x9e\x5b\xb8\xc3\xdd\x78\x68\x43\x1a\xb9\x4b\x23\xd7\xc1\x24\x43\x3a\x8c\x3b\x33\x20\x68\xe9\x9b\xee\x64\x98\xf9\xa1\x04\xaa\x6e\x46\xda\xf0\x9e\xd1\x5e\x5b\x15\xf5\x8f\x72\x41\x88\x58\x86\x5c\x4b\x92\x53\x04\xa3\x1a\x0c\x1f\x9f\x8b\xf3\x12\xd9\xe4\xd9\xa7\x69\x55\x2e\x16\x1f\xa4\x96\x27\xc6\xcd\xe8\x57\x96\x75\x0b\x60\x31\x45\x33\xb7\xdd\x69\xda\x50\xc5\x66\x24\x3e\x60\x99\x54\x7f\x5f\x93\x11\xd2\x07\x6b\x34\x74\xc5\xa5\x81\xfb\xe2\xa4\x84\xfb\x72\x3d\x6c\xbe\x97\xcf\xe5\xfd\x4c\x6b\x56\x29\x6b\xee\xeb\x2f\xac\x13\x46\x51\xbc\xbc\x4d\xe6\x40\x12\x7f\x7d\xf3\xee\xe5\xfb\xbf\x7e\xf9\xf3\xf3\x77\x2f\x7f\x7b\x15\x5b\xc6\xac\xc7\xbc\x95\x5c\xaa\xce\x9a\x3f\x77\x21\x8c\xc1\x75\x0b\x7e\x92\x6c\x23\xc8\x4e\x97\xfb\xf6\xca\xca\x21\xa1\x17\x0e\x60\xb8\xeb\x56\x29\x8d\x2d\x4d\xd9\x8d\xf0\x3d\x8a\x76\x58\xf6\x50\xcc\xa1\x4a\xd1\x36\xa9\x8c\x9a\x46\xfe\x9f\x97\x44\xa5\x20\x4d\x4a\x0d\x38\x74\xc0\x80\x3b\x90\xf1\x21\xef\xd4\xc3\x94\xeb\xec\xd2\x85\xbc\xfb\x19\x7c\xd8\xda\x31\x24\x16\x71\x08\x14\x3d\x05\x89\x1d\x30\x3c\x6e\x89\xe1\x6e\x01\xef\xb5\xf2\x80\x59\xcd\xff\x1d\x83\xc6\x0e\x58\x3b\x42\x8f\xc4\x0b\x4e\x82\xaf\xac\x7a\x6d\x95\xd0\x84\xa3\x12\xd2\x91\xa3\x52\x44\xd3\xaf\x86\xae\x41\x55\xbf\x24\x26\x58\x47\x4a\xaf\x80\x90\xc0\xa0\x81\x68\x0a\xe5\x5c\x07\x4b\xeb\x3a\x30\xca\xb1\x0f\x9f\xdc\xa6\xc8\x1c\xb4\x9e\xb2\x11\x41\xfc\xeb\xe8\x67\x14\x69\x83\x06\x58\xde\x61\x8f\xc7\x8f\xc6\x62\xfb\x59\x87\x22\x8f\xe8\x42\xdb\x39\xa0\xab\xab\xbc\xda\x7d\x23\x07\x4c\x15\xee\xec\x75\xd8\x21\x8f\xc2\x1e\xa4\xbc\xa8\x89\xb6\x7d\xb4\x67\x95\xe4\xa1\x5c\xa9\x34\x6b\xe3\x59\x5b\x7b\xbf\x0b\xd7\x5e\x1b\x72\xad\x34\x5a\xb0\xa2\x3d\x17\xe0\xdc\x4c\xb6\xb5\x68\x71\x61\xa5\x7b\x04\x60\x6a\x67\x39\x4b\x1a\x57\x7e\x96\x9c\x73\x6c\xe9\xe2\x0a\x6f\xc6\xf1\xda\xca\xc3\xf9\xc6\x53\x2b\xc1\x18\xf5\x2c\xac\x54\x65\x68\xb8\x32\x69\xf6\x31\xb8\xe8\x7c\x83\x6f\x13\x4a\xbf\x33\xb0\xc9\x2d\x56\xaf\x1e\x70\xc4\x4f\x4c\x96\xbf\xf1\x70\x66\x9e\x84\xdf\xfc\x5b\x1a\xe5\xe3\xc7\xc1\xc3\x45\x47\xe4\x2e\x21\x5e\x15\x2d\xd6\xd7\x1e\x14\xd4\x0f\x49\x91\x63\x84\x32\xdf\x30\x56\xeb\xf8\xb3\xad\x8a\x3c\x43\x53\x26\x00\xc9\xd3\x8b\x39\x41\xda\xf9\x8b\x39\x33\x70\xcc\x9f\x4f\xe9\xde\xb5\xbc\x75\x03\x61\x5c\xeb\x46\xe1\x3e\x48\xcf\xf3\x45\xee\x05\x42\x33\xe4\xfc\xfe\x7e\x3f\x7a\xf3\xee\xc3\xe7\x13\xd2\xe9\x22\x97\x14\xc8\x03\xef\xef\x73\xdc\x69\x4a\x44\x9a\x00\xc8\x2c\x7c\x24\x7b\xfe\xf1\xd5\x73\xb7\x24\x64\xa0\xfb\x3e\x4e\x9c\xf2\x8b\xd9\xab\x59\x4e\x4a\x92\xac\xd3\xaa\x07\xf3\xc6\xc8\xc5\xda\xe6\xe4\x28\xe0\x91\xfa\xa9\x34\xd3\x8c\x44\x46\x71\x26\xb4\x23\x0a\x72\x8d\x11\x53\xf0\xe1\xe0\xfc\x60\x5a\xc7\xb5\xeb\x82\x24\x1b\x18\xcf\xc4\x24\x73\xd2\x59\x21\x37\x5b\xec\xb1\x64\x68\x75\x8f\x3b\x32\x74\x07\x30\x69\xd0\x97\xd6\xfe\x3e\xd2\xb1\xe8\x2a\xaf\x7b\x38\x98\xcf\x4e\xcb\xf4\x78\xc8\x69\x4d\x0e\x39\xde\xca\xb4\x47\x43\x3a\x7a\xba\x67\x76\xde\x42\x52\xaf\x26\x91\xee\x6c\xac\x81\x51\x36\x79\xb6\xb1\x12\x5f\x15\xb3\x8d\x96\xaa\xb5\xdd\x7a\xc0\x0e\x07\xf6\x5d\x5d\xa5\xb7\x39\xc0\x99\x14\x52\xe7\x4c\xc9\xf5\x06\x09\x7b\x4b\xd0\xc3\x3b\x2c\x3a\xfc\xd3\x1c\x4a\x2f\x05\x92\x24\x1c\xd0\xb8\x65\x69\xdf\x29\x8d\x5f\x76\x23\x25\x8b\x0d\xdf\xf5\xd2\x05\x49\xdf\x12\x83\xdc\xdc\xc8\xfe\x47\xd4\x2e\xd0\x9b\xa2\x0e\x2f\xb4\x15\xe3\x4c\xfa\xa2\x29\xd9\xe3\x0e\x2d\x7d\xe0\x35\xa9\x84\xe9\x95\x09\xb0\x63\xc1\x7d\xf1\xb7\x23\x29\x84\xbb\x19\xc6\xf7\x4d\x29\xbc\x69\xfd\xe4\x36\x21\xe7\xc4\xbb\x82\x26\x41\x6a\x67\x72\xed\xff\xa8\xbf\x37\x02\x68\xeb\x76\x13\x94\x07\xd7\xbc\x3c\xa4\x2c\xed\x08\x88\x55\xc5\x86\xb5\xb5\xdc\x24\x71\xed\x70\xac\xea\xa0\xb4\xf8\x31\xa1\x61\x07\xa1\xc5\x63\x76\xaa\x60\xf0\x59\x3c\x7e\xf8\x50\x84\xd0\x19\x64\xfc\x4a\x88\xf8\x27\xcc\x76\x2e\x0e\x32\xe3\x5f\xea\xfe\xa3\xb6\x0f\x54\xcb\xfd\x77\x5a\x3d\x6f\x80\xdd\x83\x25\xbe\xb8\xb9\x69\x68\xa5\x79\x67\x3c\x7e\x58\x45\xee\x64\x35\x59\x5d\x73\x44\x35\xe9\x81\x8a\x13\x32\xad\x94\x37\x00\x64\x71\xd1\xd2\xa9\x91\x5d\xf3\xbb\xae\xd2\xa3\xc8\x48\x7a\x0e\xc7\x58\x03\xbb\xab\xec\xa1\xc6\x7b\x0c\x60\xb5\x3e\x87\xb9\xf7\x47\x58\x36\xad\xf9\x2a\x83\x16\x2e\x06\x83\x38\x8a\x42\x22\xfe\x55\xbf\xa4\xf6\x4b\x0a\x32\xb3\xea\xf3\x38\xd0\xdb\x89\x25\x47\xcd\x2c\x39\xaa\x1a\xc4\x01\x7a\x5a\x2b\x26\xe9\x53\xe5\x2c\x65\x7f\x7f\x0f\x07\x99\x0e\x48\x1f\xc4\x48\x1f\xf5\x90\xd2\x81\x27\x8b\x57\xa7\x4c\x83\xbf\x6a\x5b\x34\x1a\xfe\x95\x5e\xc9\x40\xad\xb0\xe5\x2f\x70\x44\x8a\x28\xc5\xb3\x24\x55\x2a\x28\xb8\x81\xa9\x5c\xad\x74\x30\xc8\xad\x07\x68\xbd\x05\x29\xae\x7c\x63\xbe\x06\xa4\x9d\x22\xe3\xe8\x5a\x2b\x98\x1b\x65\x57\x58\xa3\x1a\xdd\x18\x9b\xf1\x4f\x2d\x15\x82\xb5\xb4\x18\x88\x22\xf4\x15\x43\x7f\x57\x1c\xa0\x75\x20\x9f\xa6\x72\xdc\xbc\xc1\x64\xd5\x9f\xde\xdc\xc8\x05\xd6\xd3\x58\x90\xab\xed\xe9\x71\x1a\xd7\xc8\xa7\x4f\x26\xf3\xe4\x02\xf5\x9b\xe5\xf3\xc3\x92\xa2\xb0\xef\xef\xcf\x19\xb2\xd6\xfc\x0b\x7a\xe9\x2f\x93\x02\xca\x4d\x05\x5c\x19\x02\xbd\x6f\xef\x8d\x6f\x6e\x28\x4f\x4e\x68\xd5\x5f\x1c\x1c\x3c\x9d\xc9\x97\x82\x5b\x68\x5b\x5b\xd6\x79\x91\x44\xc3\x08\xfd\xad\xa9\xdd\x98\x25\x68\xf8\xb7\x54\x72\x7a\x4b\x56\x15\x60\x6c\xd1\xfd\x5b\xc8\x2e\xbc\x4f\x4e\x2d\x4d\x86\x5d\xd9\x39\x75\x07\x0d\xdd\x80\x41\x89\x98\x73\x1b\x2a\x6d\x80\xd6\x59\xe3\x61\xa3\xc2\x01\x5f\xdf\x99\x3e\x49\x17\x62\x6c\x20\xf3\xd9\xe1\xd8\x3e\x31\xcd\x20\xd6\x8a\x98\xec\xed\x14\xd8\xe6\x6f\x59\x55\x03\x1e\x54\x96\xab\x2d\x03\x09\xf3\x44\xca\x10\x3d\xc1\x18\x8b\x30\x2a\x84\x8f\x9c\x0a\xec\x8d\x05\x21\x5b\x56\x73\x9e\xe2\x23\x98\xc0\x67\xa4\xbd\x11\x64\x0d\x4c\x27\x27\xdf\xcb\x0f\xf3\xb4\x6e\xdb\x3e\xe0\xdd\x39\xed\x03\x50\x71\x97\x5c\x4f\x60\x07\x51\xc4\x29\xd4\x83\xd5\xd4\x73\x25\x5b\x69\xb5\xd5\x6a\x67\x23\xbe\x28\xf1\x1d\xd0\xc8\xc0\xc4\xab\xba\xb0\xd6\x6b\xca\x7b\x07\x17\xc8\xcb\xac\x9e\xc2\xf5\x97\x92\x7c\xb9\x16\x79\x6d\x4a\xbd\xbf\x88\x73\xf1\xe9\xd5\x87\xe7\x1f\x9f\x9f\xbc\xff\x18\x5f\x04\xf8\xe4\x0e\xc2\xba\x25\x7f\x1e\x8f\xb6\x47\x67\x73\x5d\x54\xd2\xfe\x47\x2a\xcd\xf2\x0e\x67\x1e\x29\xbb\x1f\xf7\x8a\x81\x12\x79\x34\x32\x54\x6d\xa0\x25\x6d\xfd\x52\xb1\xd8\xa2\x31\x87\x36\x97\x3a\x7c\x7e\xbb\xf8\xce\xd9\x2f\x4f\x73\xd4\x36\x44\x23\x13\x7c\x0d\x4d\x4a\xbe\x28\xe9\x77\xb5\x91\x94\x7e\xbf\xf3\x09\xce\x3f\x8f\x46\xb7\xa9\xf5\x2a\xe7\x3f\xc9\x91\x92\xd3\xf5\x06\xd0\xe2\xf5\x66\x92\x0e\xbf\xa3\xd8\xe7\x16\x4d\x15\x9d\xa2\x4f\xa0\x59\x89\x3d\xbd\xa6\xe8\x28\x06\x9d\x14\x4a\xad\x90\x77\x65\xf1\x5b\x76\x99\x4e\xaf\x64\xbb\x98\xcd\x9e\xbf\x4c\x99\xce\x02\x1b\x4b\x97\xc4\x1e\x63\xb7\x56\x8a\x3d\x46\x67\xab\xcc\x00\xf5\x4d\xd5\xf1\x36\x48\xf0\x60\xee\xa4\xae\x79\xf4\x8b\x64\x8b\x05\x84\x6e\x4f\xc0\x81\x2e\x4e\x47\x67\x49\xa3\xd4\x70\xac\x5e\x01\xb6\xba\x56\x01\x16\xe1\x0b\xfa\x9b\x9b\x7e\x55\x5e\x70\xd8\x08\x04\xfb\xf9\xb2\x2c\x31\xdc\x05\x43\x04\x4a\x83\x5e\x18\xf5\x84\x04\xcd\x41\xfe\xa8\x91\x71\x02\xc9\xe0\x76\x6a\x71\x0c\xa8\xa5\xb5\x65\x21\x80\xaa\x42\x87\x28\x53\xb1\x3b\xda\x37\x45\xc7\x5e\xe9\xce\x0a\x22\x79\xd8\xe9\x76\x78\x41\x51\xf9\xce\x35\x97\xc3\xf1\xa1\x45\x8c\xbf\xb3\xee\x40\x55\xff\x1d\x60\x90\xe4\x22\xc3\x86\xa4\x82\x42\x77\x13\xa1\xf9\xe2\x05\x14\x1c\x6b\x82\xcf\x48\xba\x51\xda\xe2\xd0\xa8\xfc\x6e\xf1\xfd\x10\xaa\x01\xdc\x70\x73\x2f\x60\x77\xfe\xca\x47\xfe\x95\x12\x36\x8f\x2c\xa5\xac\xf4\x96\x77\xdd\xb6\xb7\xaf\xdd\x9e\x6d\xc7\xa3\x9d\xb5\x36\xd3\xd9\x22\xab\xee\x1f\x91\x48\xf0\xfa\xc5\x9f\x5f\xbd\xf8\xcb\xa7\xcf\x6f\xc9\xda\x91\x0c\x1d\xe3\x68\x96\x36\xe9\x21\xeb\xc9\x90\x8e\x43\xbd\x5e\x46\x22\x9d\xcd\x5e\xc8\x8f\x93\x92\x95\x55\x03\xac\x78\x61\xb1\x74\xa8\xf7\x46\xda\x72\xfd\xe8\x59\x24\xa2\x5e\x74\x50\x0d\xdb\xdd\x1d\xfc\x92\x44\xbf\x1c\x34\x07\xbf\x44\xcf\x7e\x41\x12\x24\x2d\x3e\x66\x30\xf0\x56\x0f\x8a\x1e\x2d\xd9\xfd\xae\x09\xc9\x1d\x6a\x74\x30\x29\x31\xec\x32\x70\xba\x35\xea\x20\xa3\x71\xd4\x48\xb9\x23\xb6\x87\x98\xd3\xb6\xdb\x97\x62\xc5\xfb\xa3\xd6\x08\x78\x9e\x31\xad\xee\xce\x8a\x70\x7a\x29\x5e\xd9\xdc\xed\xfe\xfe\x1b\xfd\xf0\x15\x74\xd2\x8c\x64\x3e\x39\xe2\xc6\x0b\xf1\x6d\x20\xc2\xa4\x22\xc6\x4f\x9b\xb3\x49\xc1\x54\x4c\xff\xbc\xbf\x57\x53\x94\xc0\x81\xc0\xf4\x44\xb9\xd6\xe6\x0f\x83\x15\x42\xcc\x10\x1f\x05\x7b\x25\xfd\xef\xfe\x77\x7a\xa3\x0b\x7b\xdb\xe5\x01\x17\x4c\x36\xc9\x37\xfd\xb7\xa4\xa0\x81\x0c\xa7\xd5\x06\xbe\x16\xf0\x78\xc2\x6c\x51\x6b\xae\xc8\xee\xd4\xfd\xb7\xa7\x19\x2a\x7b\x00\x21\x8d\xbf\x92\x37\xe6\x95\x15\x49\x4d\x0a\x64\x9a\xd1\xb4\x6d\x35\x02\xc3\x37\x41\xfb\xe7\xc4\x3a\x25\x9a\xce\x2f\xec\x46\xbc\xa7\xda\x86\xd5\x53\xf6\xf7\x2f\x61\x39\x33\x15\xb3\x62\x6f\x24\x09\xce\xbd\xb1\xc3\x1a\x69\x25\x06\xb7\xf7\xa9\xd9\x4d\xcc\xb0\xf6\xbe\x26\x06\xe3\x18\x95\x1d\xfb\x2f\x61\x3c\xb1\xdd\xe0\x02\xab\xbd\xe4\xb7\xb7\xe5\xb0\x45\x24\xa2\xb2\xab\x42\xd2\x2f\x55\x9b\xb2\x78\x23\xd5\x7d\x03\xd2\xfe\x80\x93\x22\x4f\xfe\x3e\xbf\x8d\xc8\x71\xd5\x2e\x5c\x4f\x45\x8c\xec\x8c\xf4\x72\xb9\xf5\x85\xf4\x5b\x5b\x98\x7f\x19\x94\x98\x4a\xef\x44\xb3\x6c\x55\x65\xe8\xa4\x79\x66\x9c\x13\xd9\x3c\x87\xec\xf7\x4d\xa1\xb7\xd1\x78\x2b\x62\x5d\xaf\x26\x57\x8c\x8c\xfd\xa8\x70\xde\xe6\xa6\xa4\xcf\x22\x56\xcc\x64\x39\x72\xab\xda\xc7\x96\x76\xd5\xac\x4d\x18\xf5\xe7\xae\xb2\xcf\x00\x3d\x1b\x2d\x87\x9a\xf6\x16\xdf\x93\x55\xdb\xaa\x5c\xbc\x45\x82\xf0\x24\x19\x8b\xf7\xc9\x13\xf1\x01\x3f\x3e\xe1\x7f\xef\xd0\xa4\x4c\xee\xf2\x1b\x54\x54\x57\xb6\xfb\x7f\xba\xb2\xf9\xbb\x0f\x82\xdf\xe4\xde\xf2\x1d\xe1\xa1\x4b\x14\x02\x89\x2f\x6c\x96\xe0\xd8\x4d\x77\x1a\x92\x4b\x1d\x29\x05\x66\x6f\x86\x4e\xf3\x70\x36\x2c\x32\x41\xa3\x77\x52\x86\x06\x14\x5b\xa1\x37\xb7\x8c\x4c\xd6\x59\xf5\x25\xdc\x1f\x9e\x4c\xb6\xae\x45\xa1\x18\xbd\x46\x27\xc9\xc9\xcd\x8d\xf3\xfd\x1e\x96\xef\x62\x98\x15\x68\xa8\x69\x3d\x5a\xca\x81\x90\xe7\x71\x7d\xa8\x4d\x77\x12\x18\xfa\x46\x21\xfa\x03\x52\xf5\x99\x28\x68\x54\x21\x13\xf2\xf8\x9b\x17\x3b\x95\xdf\xee\x44\xa7\xc9\x79\x47\x90\xe0\x17\xd2\x37\x23\xb2\x03\x6f\x86\xed\x25\xa0\x20\xbc\xda\xcf\xe9\xd0\x35\x61\x55\x66\x32\xb0\x88\xd8\xa4\x40\xdf\x7e\xbe\xe7\x59\x52\xf9\xc5\xb5\x9b\x07\x34\x33\x65\x78\x33\x98\x2d\xcc\x9d\x18\x26\xcd\xf8\x96\xc3\x2f\x52\xbd\x56\x96\xc7\xdc\x1f\xc0\xe7\x6a\x34\x07\xdb\x1c\x02\x12\x94\x76\x52\x9f\x93\x37\xc3\x75\xe1\x0e\xf8\x39\xc7\x7b\xd5\x8a\x16\xaf\x50\x17\xa6\xc6\x68\x63\x6f\x88\xba\xc2\xa1\x67\x33\x09\xab\xa8\x1d\xb6\x4e\x6a\xb4\x5e\x10\x53\x5e\x9c\xd0\xca\xd2\x0c\xd7\xb6\x2f\x58\xe9\x08\x76\x8a\xd6\x6d\x42\xab\x03\x93\x16\xbe\xa3\x76\xdc\xf1\x5c\xfe\x91\x59\x7e\x3d\x49\xee\x16\x36\x82\xc3\x7e\x74\x36\x47\x36\x38\xe1\x26\xb5\x98\x17\x9f\x6f\x79\x39\xa1\xf4\x0c\x18\x56\xd5\xcd\x39\x2a\xcb\xbc\x19\x6e\x69\x5e\xee\xe4\x46\xb4\xe0\xf6\x16\x7a\x8a\x0e\x0d\xa0\x94\x2d\xfa\x48\x40\x89\x63\x68\x19\x28\xd4\x92\x05\xf5\x21\xf3\x13\xdd\xc3\x48\x86\x87\x37\xb4\x63\x00\x40\x27\x7e\x40\xb2\x43\xed\xcc\x71\xbf\x0d\x11\x6a\x18\xa8\x44\xa9\x22\x72\xf7\xb0\x96\xfa\x8d\x7d\xa3\x20\x04\xef\xbe\x56\xf7\xaa\xb6\x87\x28\x90\x9f\xcf\x5a\x5d\x61\x4c\x44\x07\x57\xd0\xba\xb4\x9e\xed\xd0\xf9\x1a\x0a\x59\x49\x03\x7f\x32\x68\xa4\x07\x78\xfa\xec\x5b\x59\xb0\x13\x1d\x64\x41\x60\x39\xb6\xac\x3e\x69\x8b\x7d\xb2\xd6\xa9\xb0\x1a\x56\x44\x4b\xa0\xc9\x6e\xaa\x24\xb3\x80\x17\xcb\xe8\x15\xc0\xbe\x89\xa4\x40\x25\x16\xef\xb4\xf9\x32\xb8\xf1\x9e\x7a\x7f\xc0\xe5\x52\x94\xcd\x78\xa2\x3a\xd7\xa1\x25\x15\x94\x1d\x37\x8e\xc8\xee\x4b\x2c\xbd\x39\x39\x4a\x64\x4e\x2f\x46\xdb\x2c\x43\x2b\xd1\xc6\x8a\x7e\x88\xf4\xe1\x84\xc6\x11\x42\x0c\xcd\xc0\xa8\x02\xe3\x0e\x9a\x7a\xae\xa4\xaf\x35\xf9\xe0\x6b\xd0\x3b\x19\x93\x6b\x41\xca\x65\x2c\x14\x27\x66\xbb\x84\xd5\xab\xe4\x6e\x0b\x65\x16\x99\x8c\x27\x95\xb1\x91\xb4\x2c\x28\x51\x6e\x7e\x5a\x1d\x1c\x9c\x4d\xd2\x89\x34\xf7\xd2\xcb\x94\x0e\x26\xf5\x31\xbe\x33\xd4\xc7\x79\x92\xc6\xcb\xa1\x2b\x6b\xeb\x63\x84\x1e\x34\x0b\x56\x7d\xe0\x80\x0a\xe9\xde\xc4\x1a\x04\x30\xfa\xa1\x54\xe8\x39\x1d\x16\xd9\x8f\xe6\x53\x7e\x8e\x2a\x56\x1b\x8a\x38\xa6\x5d\x2b\x68\x97\x5c\xf9\xc6\xfa\x00\x1e\x60\x3c\xf0\x45\xb2\x71\x41\x06\x82\x2f\xe3\x0a\x1f\xd1\x48\x1f\x55\x7a\xee\x8f\x53\xb1\x5a\x57\x97\x28\xac\x5d\x6f\x26\x0a\x29\xea\xc5\x4d\xae\xbc\x6b\xd0\xcb\xd7\x29\x1c\x0b\x54\xa8\x06\x06\x16\x8b\xfb\x66\xbb\xf1\xff\xad\x2a\x06\x77\xd1\x76\xde\xaa\x86\xe3\x12\xa9\x90\xf5\x20\xac\x5a\x10\x7c\xe5\xb2\x68\xd0\x78\xcc\xfe\x15\x6f\x21\x41\xe3\x31\xeb\x11\x75\x53\xa0\x50\xa2\x83\xc9\xdf\x42\x7f\x02\x83\xff\x28\xc8\xf0\xef\xac\xa8\x2d\xaf\xb0\x99\x74\x27\xa0\x7c\x8e\xc4\x99\x30\x07\x8e\x95\xed\xd8\xc9\xc0\xd0\xb1\xce\x15\x96\x0b\x13\x80\x78\x6a\xa3\x19\x1c\x8e\x85\x65\x69\xcb\xb5\xb5\xe7\x15\xd9\x58\x29\x3f\x36\xfe\x1b\xde\xdd\x46\xe3\x58\x03\x3b\xa3\xe1\x52\xdd\xc3\x68\xc2\x63\x90\xf1\x01\x77\x1f\x81\x65\x7a\xfc\xb3\xfd\x23\x1e\xf3\x4d\xb8\xee\x32\x04\xdb\xd0\x79\xfb\x18\x9a\xce\x7d\xf0\xc6\x80\x16\x4a\x33\xfd\x3a\xd8\x5f\x0f\xff\x94\x4e\xbf\xc2\x69\xb6\x1d\x0b\x0d\x6f\xf5\xdc\xd3\x9f\x89\x25\xd0\x7e\x7d\xd7\x44\xc9\xb4\x0c\x28\x6a\x69\x94\x48\x11\x9d\xb6\x02\x07\x06\x54\xbe\xde\x62\x10\x32\xea\x89\xbb\x21\x7b\x0c\xa3\x03\x76\xb1\x48\x01\x6f\x14\x2f\xb4\x7d\x94\x79\x28\xeb\xe6\xfe\x2e\x76\x60\xf5\x70\xb8\x33\xe4\xbd\x96\xf8\xdf\xb7\xe4\x9a\xfc\x90\xc6\x6c\xd2\xae\xba\x0b\xde\x3e\x0b\x26\x94\xd0\x91\x56\x32\x9a\x48\xc7\x36\xf2\xbe\x53\x15\x93\xc2\x7d\xa2\x28\x94\xae\x7b\x71\x9a\x13\xd5\xde\x8a\xff\x98\x0f\xd4\x15\xb4\xea\xa7\xcc\x60\x4c\xb0\x70\xc2\xee\xce\xd6\x89\xef\x41\xe7\x00\xfd\x39\xd4\x1e\x7f\xd1\x5f\x0b\xa9\x33\xce\x2e\x72\x5e\x66\xab\x66\x7e\x30\x86\xcb\x4c\x26\xb0\x47\xa4\x12\xf5\xf9\x11\x1e\x81\xe2\x2e\x0f\x0e\x74\xd4\xdf\x6a\x23\x6d\xdb\xad\xc0\x2e\x0e\x01\x30\x3f\x38\x90\xf4\xc4\xde\x88\x74\x37\xa5\x7a\x46\x70\x11\xf4\x12\x54\xd2\x2d\x86\x3f\xe7\x4a\x45\x7a\xf9\xa2\x28\x3f\xac\x29\x5d\xb3\x17\xe8\x9f\x04\x78\x92\xff\xac\x02\x0b\x5a\x63\xc2\x1d\x68\xd0\xf9\xa4\x52\x12\x9d\x1f\x1e\x8a\x39\x12\xc4\xc7\x00\x91\x71\x8a\x30\xaa\xa6\xd2\xb1\x97\x6a\x26\x85\x9a\x89\x1c\x88\x53\x87\x8a\x62\x2c\xbf\x76\x4f\x85\xdd\xd3\x97\xad\x5d\x39\x60\xd3\xb1\x54\x08\x12\x37\x37\x8a\x3d\x17\xea\x4d\x1d\x57\xb0\xe4\xd5\x0b\x01\x4d\xa9\x81\x06\x99\x28\xf4\xed\x41\xec\x57\xed\x73\x82\x68\x8a\x8e\x9a\xf9\xe8\x0e\x0c\x40\x64\x3a\x18\xd0\x30\x0c\x95\x5c\x8b\x54\xe4\xf8\x68\xc5\x2a\x00\xe9\x8f\xbe\x03\x30\x98\x87\x36\xf8\x14\x67\xd2\x00\xdb\x14\x57\xc7\x85\x2c\x7e\xe7\xbf\xae\xc9\x85\x48\x77\x63\x9d\xbb\x8e\x6e\x96\x98\xc9\x9d\xc3\x41\x98\xca\x83\x60\x41\xb4\x55\xf8\xb9\x7c\xd0\x9e\x8b\x12\x86\x0f\x2c\x6a\x0a\xa0\xac\x57\xac\x1a\xec\xb5\x9e\x05\x4b\x20\x17\x8b\xfd\x7d\x5c\x8b\x9b\x9b\xce\x31\xd0\x42\x96\x04\x41\x45\x07\x3a\x70\x02\xdf\x74\x03\x7e\xc3\x66\x90\x12\x02\x32\x92\xe8\xb6\xb8\x1c\x18\x4f\x80\xf3\xd9\x74\x21\x16\xa2\x93\xf5\xce\xb5\x5f\xa9\xed\xa5\x7e\x5a\x90\x0a\x86\xef\x7b\xcb\x29\x43\x8a\xdc\x32\x44\x50\xab\xc5\xc1\x75\xd1\xae\xde\xb8\x0d\x10\x83\x1b\x1a\x90\x8a\xaa\xd9\xdd\xf7\x80\x54\xbf\xba\x90\x4d\x1e\xa8\x8d\x72\xae\x0e\x38\xe8\x96\x75\xf9\x98\xb3\x21\x8b\x16\x6f\xc5\x01\x27\x06\x31\xa7\x33\x60\xe5\x83\xc2\x5a\x2f\x0a\x5c\x26\x3a\x76\x2b\x9c\x7c\x73\xa3\x62\x0a\xb5\xb2\x58\x7e\x2e\x02\x60\xe9\x8b\xfc\xd8\x2b\x86\x39\xc2\xd9\x40\x78\x43\xe5\x10\x43\x01\xa6\x5a\x32\xea\x9d\x23\x70\xb5\xec\xbf\x39\xde\x05\x42\x5a\xc1\xe1\x3b\x1c\xc8\x70\xd2\x2f\xf0\xaf\x70\x20\xb2\x77\xa4\x9e\x6f\xa1\x95\x89\x36\xde\xc5\x56\x8e\xa8\x81\xaf\xd9\xd5\xdb\x1c\x6d\x82\x23\xb6\x71\xba\x76\x3d\xd3\xd0\x6a\xb9\xee\x68\x28\xc9\x76\x46\x43\x09\x8e\x23\x1a\xa6\xb4\xda\xaf\x4a\xa6\x33\xa0\xfb\x79\xa0\x77\x0b\xfb\xa9\xe4\x50\xa9\xf5\xbe\xc0\x46\xb5\xd5\x71\xbf\x04\x6a\x41\x28\x07\x19\x18\xb2\xae\x40\xa5\xa4\x50\x3a\xfc\xae\xe8\x45\x56\x49\xf0\xaa\xb0\x61\x52\xd9\x96\x97\xe7\x0c\x40\xa8\xc2\x20\xb4\x53\xfb\x60\xbc\x11\xf7\xd0\x22\xf8\x86\x63\x8d\xb8\xda\xcd\x40\xe5\x90\x45\xe6\x5a\xa9\x33\x29\x0e\xef\x75\x59\x9d\xa4\x97\x8e\xe1\x65\x6d\xc3\xe3\x7a\x4b\x08\x9c\xb6\x2e\xcb\x78\xbb\x55\xa0\x05\x20\x14\x15\x87\x5b\x35\x46\x14\xf6\x8a\x94\x18\x0e\x88\x04\xb2\xec\x16\xa0\xfd\x68\xcc\x6e\x3b\x02\x7a\x11\xd9\x10\xce\x40\x3a\x9d\x7f\xcc\x2e\x3a\xf2\x67\x99\xcc\xc7\x57\xe6\x99\x11\x82\x3c\xaf\x21\xed\xa4\x6c\x7b\x62\xed\x97\x43\x7b\x34\xa8\x4a\x83\xf1\x09\x55\x37\x52\x6a\x24\x31\x84\xd3\x1a\x8a\xb2\x76\x6d\xaf\xca\x2e\x6a\xc4\x49\xf4\x0c\x59\x98\x51\x22\x3c\x09\x49\x32\x6b\x11\x68\xcb\x12\x0d\x6b\xa3\x05\xaa\x1e\x95\xaf\x6a\xd6\x47\x7d\x02\xec\x0f\x90\x9c\x8c\xb8\x3c\xb1\x90\x36\xd5\x4f\x92\xe2\xd8\x7c\x5d\x6f\x62\xfd\xc1\x7e\x6d\x9b\x8d\xd0\xc3\x72\xf6\xc4\x46\x73\x34\x8f\xcc\xc3\x6c\xd2\x9c\xd4\xde\x78\x40\x4e\x81\x58\x5c\x04\x48\x3b\x07\xdf\x72\x7d\xe5\x16\xf2\xdc\x5d\x3b\x9e\xd3\xd9\x9f\x7b\x09\x78\x57\x25\x14\xb7\x39\xdd\x2d\x36\xd6\x89\xb8\x76\x5c\xbc\xbb\xa0\x38\x74\x1a\x86\xf3\xd8\x7a\xf7\xa6\xf9\xfc\x84\xe9\x84\x51\x00\xe2\xfb\x15\x95\xb6\x92\x80\x52\x17\xaa\x19\xe1\x13\x71\x35\x88\xab\x4d\x4b\xad\xf7\x4e\x7a\x61\x53\xd4\x0b\xab\xd0\x81\x5e\xbb\x17\x6c\x0f\x2e\x64\xf4\xd5\x16\x67\xed\x7c\x74\x1e\x43\x03\xc4\x02\x8a\xc5\xc9\x6c\xa7\xff\x3e\x1a\xcc\xc3\xf1\xcc\xd2\x36\x2e\x90\x56\x4f\xff\x5a\xe6\x85\xc4\x6e\x64\xe8\xe4\x3f\x1f\x16\x61\xaf\x71\x25\x05\x15\xc4\x03\x3a\x20\x93\x76\xe5\xfe\x23\x06\x9e\x0e\x5b\x63\x97\x78\x18\x13\x8b\x5c\x8e\xc5\x6b\xb2\x79\xa7\x10\x43\x17\x59\x25\x23\x47\xa0\xbd\xc8\x14\x80\xa6\xba\x6c\x85\x7e\xb7\xba\x82\x73\x4d\xfe\xe5\x06\xc2\x3a\xb1\x8d\x6c\x89\xea\x39\xc8\xc5\xa8\xbf\xf4\x95\x1f\x23\x7c\x58\xa7\x78\x7c\x28\xa2\x67\xcf\x0a\x56\x3c\x44\xe1\x81\x57\x97\xbb\xb1\x70\xdc\xb1\xb0\x8c\xcc\x5e\x55\x48\x7b\x18\x12\x8a\x8d\xb7\x2b\x9c\x4b\x23\xf9\x80\x25\xfc\x78\xbc\x5d\xbb\x71\x1b\xc9\x80\x53\x66\x2a\x40\xfa\x88\x90\x1f\xb8\x7d\x2f\xac\x94\xdd\x48\x82\xf1\x76\x45\x1e\xf7\x04\xea\xaf\xa6\x6f\xb9\x4c\xc3\xf7\xbf\xa4\xbc\xb9\x79\x21\xbd\x14\x23\xd3\xac\x55\xf0\xfa\xaa\x98\xb4\xc8\xbe\x44\xd9\x83\x16\xfe\x23\x6d\x40\x3e\x52\x50\x0e\xfc\x6f\xeb\x1c\x30\x46\x8f\x3c\xf9\xf4\xfe\x25\x3a\xa8\x0e\xa2\x7f\x21\xbf\x3b\x45\xd9\xf4\xea\x55\x36\xcd\x2f\xf2\x8c\x7c\x2a\x45\x07\xfd\x08\x0a\x94\x50\x60\x18\x01\x89\x21\xfd\x3a\x29\x33\x0d\x63\x57\xba\x67\x34\x7c\x0b\x7a\x11\xe0\x3e\xdc\x32\xa8\x25\xe7\xfb\x5a\x6d\x4d\x54\x3d\x70\x12\x4a\x49\x93\x59\x9f\x03\x05\xa7\x7b\x89\x8a\x63\x59\xc3\xdc\x88\xf9\x5d\xf6\x8d\xb6\xb8\x35\xc1\x37\x05\x39\xb2\x81\xc1\xd7\x3c\xbf\x02\xe7\x87\xfa\x8a\x70\xfd\xe2\xf7\x1a\xbf\x71\x6a\xf5\x7a\xb5\x5a\xe0\x54\x9b\x52\xad\x83\xe8\xc1\x4e\x52\x90\x0d\x4c\xc9\xe4\xc4\xb5\xcc\xa4\x70\x14\x7d\x4a\x5b\x01\xfb\xd5\xb0\x99\xa7\xcd\x47\xfa\x74\xe5\x66\xf9\xed\x33\x25\x4f\x4e\xae\xe3\x1f\x25\x23\x4a\x79\xba\x35\x2f\xc5\xb6\xe9\xa6\x81\xe9\xca\x1d\xac\x31\x6d\xfb\x74\x95\xff\x2c\x9a\xaf\xc2\xda\xeb\x64\x34\x59\x3f\xcd\xd5\x7b\xca\x5a\xb9\x1c\x42\xa1\x5e\x2e\xd6\x34\x0d\x1c\xfb\xb4\xe5\x8c\x47\x3b\x69\xef\x58\x3b\x14\x53\xea\x8f\xcc\x70\x71\xb8\x10\xdf\x5a\x6f\xe1\xe8\x49\x55\x71\x78\x97\x00\xf6\x5b\xd7\xa1\xe4\x75\x68\xfc\x39\xcb\xb5\x28\xbc\x79\xf7\xec\x67\x08\x6f\xb7\x33\xd7\x43\x53\x78\x1b\x71\xc8\x74\x05\x5a\x6b\x90\x29\x47\x46\xbc\x7b\x29\x3e\xd6\x91\x75\xde\x8b\xad\x43\xcf\xad\x2d\x0c\x0c\xdd\xdb\x32\x1d\xec\x03\x3a\xfc\x17\xda\xff\x6d\xd0\xba\xee\x1a\xbf\xb1\xed\x90\x87\x0e\xfd\x8c\x6a\x37\x53\xd2\xc8\x03\x75\xea\xc8\x57\x2e\xb7\x3d\x71\x4e\xa2\x1f\x29\xe1\x4e\xc7\x92\x4c\xaf\x30\x21\xdf\xed\x5c\x02\x6d\xcb\x8e\xcb\xd6\xe4\x10\x6c\x10\x9e\xed\xf4\x4e\xe8\x45\xb9\xb8\x02\x2c\x93\xda\x58\xe6\xce\xe8\x45\x6e\x54\xba\xd3\x79\xe3\x4e\xdd\x03\xc7\xbe\x97\x71\xc1\x7d\x1a\x67\x3d\xf8\xa3\xce\xde\xe2\x76\x48\x18\x4d\x72\x03\x02\xb9\x3a\xf6\x00\xc6\x4a\xa4\x4d\xec\x69\xaa\xab\xca\x2e\x37\x3f\xb1\x74\x1d\x70\xde\xbd\xb5\xab\x2d\xa8\x63\xfe\xbf\x03\x57\xa0\x64\x69\x0b\xa2\xb8\xf8\x3f\x03\x7a\x0a\xec\x76\xb8\xd9\xb8\xcb\x7f\x69\x43\x5e\xa6\x41\xec\x74\x4d\xfb\x3c\xe5\x84\x45\x32\x75\x60\x6e\xa1\x40\x6c\xb1\xb1\x61\x4c\x44\xad\x3e\x22\x6b\x61\xe6\xb8\x30\xf5\xf7\x1c\xbd\xb8\x19\x57\x72\xd3\xb4\xce\xa2\x62\xbd\x3c\xc7\xc7\x56\xfa\x60\x4c\x12\xc5\x4a\x5f\x73\x42\xa9\xe7\xe8\xb3\x21\x2d\x74\x72\xc6\xc9\x72\xf9\xe2\x90\xe7\x3c\xad\xb2\x9c\x7d\xcb\xaa\xab\x3e\x5b\xb6\xb5\x6f\x17\xa3\x19\xea\x0b\x73\x6d\x90\xd2\x3a\x16\xba\xb0\xf4\x7d\xaa\x06\x34\xb6\xb8\x9f\x99\xd1\x04\x51\x33\x55\x1b\xea\x8f\xf2\x38\xa2\x7b\x37\x8a\x33\xfb\x20\x7f\xcc\x2e\x5f\xfd\x58\x1d\xeb\xe9\x59\xea\xbe\x4b\xdb\x3f\x4e\xe6\x00\x11\xc7\xf2\x40\x4d\x59\xbb\xad\x97\xc0\x41\x28\x53\x3e\x14\xaf\x45\x13\xbf\x04\xf7\xa6\xca\x54\xd9\x25\xec\x63\xe4\xba\x87\xb6\xb5\x3d\x8d\x86\xa8\x1d\x8e\xd2\xf7\x51\x46\x3e\xc2\xb7\xab\x7f\xfa\xcc\xd7\x8b\x24\x7a\xfa\x34\x2d\xca\xe2\x6a\x59\xae\xeb\x67\xcf\x22\x71\x4e\x76\xe0\x3f\x12\x38\xf4\xe2\x63\x72\x4d\x4b\x15\xc3\x59\xe0\x35\xc3\xc0\xb3\xe5\x02\xbf\x15\x74\x0c\x48\x93\x2f\xb6\xcd\x22\x30\xaa\x07\x42\x17\x26\x4a\x38\x1b\x08\x5e\x30\x4c\x2a\x95\x14\x88\xc1\x0e\x93\x24\x00\x02\x33\x58\x5c\xc5\x25\xba\xe1\xc4\xde\xc8\xea\x2a\x93\xfe\xf2\xce\x85\x5a\x3e\x48\xae\x05\x6a\xe2\xc4\x3f\x64\xab\x90\x32\x15\x70\x4d\xc1\xdf\x35\xff\xc5\x65\x89\x17\xa2\x9e\xa7\xf0\xf7\xc2\xb8\x9c\x8c\x95\x62\xc6\x50\x2d\x5e\x1d\x89\x68\x6a\xe9\x65\xc8\xfe\xa4\x62\xc6\xb9\xd2\x20\x44\xe9\x42\xb8\xb2\xc9\x87\x0f\x1c\x96\xac\xfa\x63\x60\xf3\x47\x1f\xbb\x5d\x94\x6d\xd9\xcb\x18\x38\xb1\x0e\x2d\x8a\x60\x98\xe9\xf1\xf8\x0e\x9e\x66\x89\xcf\x5c\x48\xcf\x2e\xc0\xa8\x7e\x58\x63\x04\x06\x5b\x90\xe9\xba\x6f\x2a\x6f\xd5\x85\x0e\x07\x32\xf7\x42\x87\x5f\x4b\xf7\x67\xd0\x9d\x72\x2b\xd3\x12\xca\x04\x86\x26\x9f\xf8\xcd\x43\x03\x3e\xf2\xc3\xa2\xfd\x25\xbb\x8a\x1b\xfa\xc5\xfe\x78\x0a\x8a\xc6\x65\xda\x76\xc2\xe5\x29\x6c\x93\xc1\x7d\x9b\x3d\x0d\xf5\x22\x6f\xe0\x4c\xdd\xc0\x4d\x12\x28\x85\x62\x63\x0c\xb7\x64\x62\x71\x37\x43\xfb\x09\x67\x28\x07\x26\x7f\xd1\xc0\x06\xec\x84\x21\x6b\xcb\xf1\x82\x23\x48\x46\x28\x78\xeb\xf4\x42\x45\x2d\xf5\x07\xe8\x4d\xaa\x72\xbd\x49\x15\xb6\x0e\x51\xb1\x45\x5e\xd0\xe5\x92\xa7\x43\xb1\x88\xa0\xeb\x0e\x4e\x0d\xe5\x30\x4d\xc0\x79\x3b\xbe\xf3\x40\xf9\x1d\xc7\xa3\x73\x52\x7e\x6a\x00\xe6\xa7\x6c\xab\x82\x9e\xf7\x65\xa6\xd2\x9f\x82\x61\xcd\xae\x1c\xef\x46\xac\x22\xcc\x82\x12\xb3\x0b\xe4\x38\x2f\xa9\xad\x72\x8e\x58\x1e\x6d\x8a\xce\xd3\xe9\x57\x2a\x66\xe0\xd9\x05\xf2\xfc\x56\x20\xb7\xfd\xf5\x50\x2c\x53\xdb\x83\x89\x13\xa4\xd2\x1b\x99\x71\xd6\x63\x87\x8d\xd7\x0a\x1b\xbe\xb8\x8c\xfc\x30\xaa\xc5\x8b\xd3\x61\x87\x27\x11\x31\x5d\x94\x35\xe6\xfb\x1e\x3e\xc8\x1d\xa3\xd5\x42\xeb\x79\x15\x3d\x65\x4b\xe3\xaa\xbe\x31\xe5\x19\x1a\xb7\x5f\xa8\x12\x87\x9a\xe8\xdc\x83\xf3\x0e\x61\x97\x22\xd0\xbe\xe8\xea\x2b\xb4\x97\x1a\x7c\xfd\xa6\x3b\x8a\x17\x65\x03\x6c\xce\xf3\xc5\x02\x21\x5e\xcc\xb7\x76\xe5\xc3\xc3\x6d\x7d\xb5\xca\xdb\xb8\x83\xfa\x9b\x25\xa7\x73\x41\x41\xd4\x50\x9f\x05\x03\x09\x58\xfb\xf7\xd7\x2a\x5d\xad\x3c\x2c\x23\x97\x72\x66\xd4\x09\xcd\x5c\x02\xe5\x42\x53\xa6\xaa\x3e\x00\x75\xd5\xf5\xa7\xd0\x85\x39\x8c\xb3\xaf\x50\x97\x83\xf0\xb1\x63\xef\x71\x6e\x4d\xbf\xc3\xae\xa3\xc8\xbe\x67\x26\x53\x07\xff\xaf\x87\x24\x27\x45\x75\xa7\xf2\x76\xd4\xe5\x1e\xda\xf8\xc1\xe3\x3b\xbb\x18\xbb\x4d\x51\xd2\x3b\xc3\xf1\x78\x64\xa2\x1a\xb7\x8e\x30\x5c\xc8\xa4\x45\x68\x9f\xe0\x78\x7c\xff\x31\x61\xc7\x9d\x3c\x8b\x76\x47\xa3\xf7\xde\x19\x42\xee\x05\xf0\xb9\x01\xcd\x0d\x83\x91\xea\x69\xa7\xcc\x23\x46\x11\x7c\x97\xb8\x8b\xa7\xd2\xa9\x79\xb5\xf2\x8d\x24\x1a\x4b\x3f\x29\x0f\x69\xc9\x6b\x51\xa8\x83\x8f\x11\xa1\xc0\x9d\xc8\x71\xa7\xfa\x1e\x46\xaa\xc8\xbb\x80\xb2\xfe\xf0\x8d\x3b\xd0\x40\x4f\x98\xe0\x9e\xe9\x30\x60\x49\xd9\x2f\xe1\x98\x53\x03\x5a\xa3\xc8\x82\xdc\xc1\xc6\x13\x86\xfe\x07\xcc\x6f\xb4\xdb\xfc\xba\x2c\x58\xe4\x24\xb7\x4f\xc2\x7a\x62\xf1\x98\x83\xdc\xb9\x9a\x7c\xf3\x31\x27\xa8\x32\xad\x97\x5a\x3f\xef\xe2\x52\xb1\xa7\x0b\xf6\xa2\xef\xde\x56\xeb\xdb\x35\x04\xa7\xad\x17\x1d\x3b\x80\xbb\xb9\xf4\x89\xfa\x2f\x44\x88\x0a\xc0\x97\xad\xed\x04\xf3\x76\xcf\x81\xee\xf4\x20\xcf\x54\xdc\x32\xbb\x78\x7c\x34\xfa\x19\xd5\x63\x3c\x59\x47\x77\x71\x90\xfb\xd3\xc4\x51\x16\x46\xd2\xe5\x8e\xb4\x51\xde\x45\x1b\x05\x29\x7d\x9f\x60\xca\xb7\x13\x37\x69\x88\xb8\xe9\x0c\x72\x14\x64\x47\xa7\xbf\x87\x8a\x58\x6f\x3c\x9a\xe9\xae\xa4\xc1\x1a\x49\xa6\xd3\x85\x98\x9e\x21\x39\xb3\xf3\x3d\xbf\xfa\x7f\xdb\x3d\x5f\xfe\xf4\x3d\x9f\xff\xae\x7b\xbe\x76\xee\xf9\x54\xde\xf3\x17\x3b\xb1\x28\xbf\xff\x9e\xdf\xf9\xae\xee\xe6\x9e\x8f\x7e\xc6\x27\xa8\x15\x3e\xd6\x8b\xdd\x64\xa1\xc4\xad\xf8\xda\x3f\x1c\xf2\x20\x65\xf5\x34\x5d\x91\xb2\xf0\xeb\xb2\x92\x54\x0c\x9d\x28\x6b\xab\x37\xc0\x5c\xd7\xd6\xa2\x57\x72\xd1\xaf\xdd\x7b\xc5\xf3\x0e\x8e\xe4\x05\x95\xf3\xae\x1f\x36\x14\x24\xe9\x05\x97\x93\xb6\xfe\x69\xdf\x7a\x93\x36\xfe\x45\x42\x18\xea\x38\x8f\xa3\xa7\xf5\x2a\xc5\xb7\x4c\xe5\x33\x8f\x73\x94\x31\xd6\x41\xf4\x8c\x9e\x1e\x9e\xde\xc3\x62\x18\xf5\xd2\x57\x7d\x0d\x58\x77\xc9\xb7\x71\x72\x3e\x68\xc6\x82\x16\x6b\x26\x2c\x55\x03\xb3\x0f\xe9\xde\xb7\x94\xae\xc9\xec\xbd\xad\x78\x89\xf2\xe5\x81\xd4\x07\x0f\xbc\xd9\xa3\x5c\x18\x43\x6e\xd0\x41\xf1\xfe\x03\x16\x68\xb2\x66\x1f\x1d\xb5\x68\x29\x53\x85\x81\x25\x7e\xd8\xed\x2e\x77\x8b\x3a\xa0\x77\x17\x06\x81\x04\xe0\x99\xf8\xf5\xa3\x9d\xb5\x50\x06\xd7\xb3\xfe\x97\x21\x53\x38\xd9\xb4\x2c\xa6\xf9\xc2\xbe\x93\xf6\xf7\xaf\x1c\xe3\x93\xdd\x6e\xb0\x59\x5e\x59\x0e\x4b\xeb\xdf\x58\xb0\x61\xbc\x63\x4f\xed\x33\xcf\x1e\xe2\xd5\xdd\xa4\x70\x54\x7b\x28\xc9\x96\x61\x3a\xb7\x9b\x6b\xa7\x82\xef\x15\x38\xb0\x2b\xdf\x1d\xb2\x34\x23\xf5\x4d\x4a\xb4\x24\xdb\x52\x58\x3d\x6c\xec\xaf\x60\x2c\xc2\x2c\x3c\xe9\xc9\xac\x8f\xe6\x6e\x4b\xed\xf3\x71\xc9\x51\x0f\xf3\x81\xe5\x73\x6e\x34\x69\x9e\x15\x76\x0c\xd5\xa5\x7c\xa8\xae\x86\xe8\x4e\x07\xfa\xc5\x79\x19\x77\x4d\x5f\x56\x00\xe9\x80\x51\x15\xea\xac\xb9\x6c\x2b\x99\x57\xbc\x52\x64\x29\x4f\xfc\xcd\xc5\xbb\x0c\xcd\x50\x28\xb6\x7b\x70\xa1\x01\x69\x69\x27\x53\xfc\x44\x59\xda\x4f\x94\x99\xbb\x7d\x2a\xa8\x41\xbf\x3c\x4d\x51\x35\x69\xb3\x69\xf9\x93\x50\x6c\x31\x05\xb9\x0c\xfa\xb4\x12\xbc\x43\x79\x4d\x41\xc8\x61\x0e\x72\x93\x8e\xfb\xd2\x60\x0a\x6e\x20\xf2\xfe\x80\x36\xbc\x59\x7b\xa6\xc7\x81\x34\x65\x69\x15\x07\xf2\x12\x7a\x67\x90\x6a\x16\x2d\xc8\x20\x24\xd8\xf6\xe6\x37\xeb\x07\x46\x08\xe3\xd2\x2b\x40\x66\x0d\x97\x18\xb2\x43\xbd\x1e\x06\x68\xa9\x45\x88\xee\x5a\xed\xe4\x4b\x82\x5d\x3f\x68\x43\x1c\x97\xde\x9a\x87\xaf\x94\x59\x5b\xc9\x6a\xd9\xd2\xa7\x3a\x3d\x43\x1f\x13\xee\x39\xbc\x44\x79\x9c\xa4\x0e\x5e\x6d\xa5\xae\xc2\xa7\x5d\x81\x7c\x97\xf8\x25\x58\x6b\xcf\x1c\x15\xdc\xfa\x7a\x85\x1e\x9b\xd0\x79\x5d\x67\x8d\x81\x40\xd7\x7b\xb1\x65\x22\xb5\x11\x2f\xb6\x0e\xd7\x85\xde\x5b\x84\x44\x6e\x61\x57\x1c\x75\x9e\x9c\xbe\x12\x2f\xce\x26\x73\x27\x84\xc0\x85\xba\x88\x77\x26\x23\xcf\xb7\x0a\x7c\xb7\xe0\xd2\xa9\x4b\xb4\x39\x63\x1d\x84\x30\x2d\xd5\xda\x86\x46\x3d\xf2\x31\x84\x1b\xba\xf1\x33\xdb\x50\x48\x64\xd3\xa5\x6e\x29\x97\x47\xe1\x24\x8b\xf0\xe8\x6c\x58\x95\xed\x2e\xc1\x3e\xff\x48\x28\xbe\xf0\x42\x2c\xf0\xbd\xfe\x23\x59\x79\x6e\x2a\x94\xcb\x6b\x11\x5d\x2c\x00\x4f\xfc\xc9\xc1\x00\x91\xed\xa7\x03\x51\xe1\x44\xc1\xd7\xcd\xcd\xe5\x44\x3a\xe1\x97\x18\x5d\xca\x54\x6d\x21\x35\x5a\x37\x28\x51\x40\xaa\xe8\x04\x61\x84\x70\x40\x34\x40\x0b\x97\x83\x6b\x3c\x63\xd2\xf0\xeb\xdb\xc4\x3f\x80\x8d\x0d\x6e\xf6\x5e\x23\x8a\xa5\x27\x3a\x16\xf9\x84\x36\xd2\x55\xd8\x45\xec\xb9\x65\xd7\x8d\x6a\xb9\xc2\x6d\x52\x15\xf2\xaa\xdd\xcc\x2c\xe8\x04\xcd\x43\xa0\x54\x4c\x3d\x13\x5a\xa5\x02\xc8\xf3\x8a\x04\x5b\x5f\x92\xeb\xce\xd1\xb1\x74\xcb\xed\x20\x2e\x85\xc4\xb9\x9c\x10\xd7\x22\xb0\x8b\xf1\x0f\x4b\x28\xf6\x51\xa4\x75\xba\x42\x9b\x6d\x43\xa5\x7d\xf9\xa3\x38\x90\x4e\x93\x6b\xc7\x4c\x3a\xc4\x8e\xb4\xb5\x34\x7d\x8d\xcc\xa3\x5d\x34\x32\x83\xe1\x0a\x2c\xef\xfb\xc3\xb7\x9f\x3f\x9d\x7c\xf9\xfc\xe9\x95\x71\x9f\x83\x7a\xf7\xb2\x38\xaa\xbc\x5e\x4f\x7f\xc4\x95\x98\x62\xd0\x5b\x8c\x96\x3e\xc3\xaf\x19\x7e\x5d\xe4\x8b\x85\xfc\xf3\x7e\x95\x4e\xf3\x86\x12\x81\x9e\x7e\x9d\x2e\xf3\x85\xfa\xf8\x84\x98\x16\x7e\x62\xb5\x0b\x8a\x9c\x5b\xa5\xb3\x1c\xd6\x84\xb5\x6b\x11\x21\x98\xb4\xcf\x80\x9c\x6b\xf8\x46\x33\xdc\xac\x7a\x55\xcc\xf4\xef\xb7\xb9\xf9\x4d\x9e\x9b\xe1\xab\x24\xe7\xcb\xf8\x43\x77\xbf\x42\xd3\x97\xaa\x90\x54\xbd\x6a\x4e\xa6\xea\xcf\x32\x2f\xf8\x87\x0c\x04\xf9\x1c\x35\x2e\x9b\x8f\x48\x85\x43\x6a\x85\xff\x70\xb8\x14\xe8\xb7\x86\x42\xe9\xec\x2d\x05\x6b\xc4\xcf\xa6\x5c\xbd\x28\x17\x65\x25\x7f\x9b\x99\xc3\xba\x97\x5f\x33\xfd\xe3\x65\x5a\xcf\xe5\x4b\xb9\x4c\xf9\x2d\x2f\x32\xa0\xcc\xf5\xb7\x5f\xf5\xaf\xf9\xac\x99\x63\x3c\x7a\xa0\xdc\x9f\x17\xd3\x39\xf5\xd1\x58\xab\x84\xee\xab\x10\x62\xe1\x57\x9e\x7d\xff\x53\x89\x63\xfc\x31\xc6\xff\x8e\xf0\x3f\xf8\x77\x85\x5f\x57\xf8\x05\xcd\x6e\x30\xe2\x82\xf6\x17\x46\xaf\xc7\xf1\xb5\xbd\x5b\x11\x7e\x1c\xca\xc5\x8b\xec\xad\x8b\xf0\xf7\xe1\x05\x7d\x44\x66\x1b\x39\x99\xc3\x91\xb4\xb7\x31\x6a\x25\x45\xde\xc6\x46\xce\x67\x64\x6d\x73\xc4\x3f\x0f\x81\x1a\x8b\xac\x1d\x57\xc9\xcb\x5c\x27\xf3\xe6\xab\x0c\xf2\x52\x1e\x05\xb7\x3d\x0a\x24\x46\x2e\x28\x44\xf6\x57\x14\x04\x87\x28\x90\x18\xb9\x40\x11\xd9\x5f\x91\x05\x21\x11\xfe\x3c\x9c\xe2\xef\xc8\x01\x16\xce\xd0\x0b\xef\x03\x4c\xc4\x09\x87\x33\x95\x12\x79\x10\xa4\x0a\x2c\xf8\x3b\xf2\x00\x4a\x65\x7b\x1d\x30\x7c\xa9\xcc\xef\xf8\x15\xd9\xc0\x46\xe1\x0d\x0e\x53\xfa\x88\x34\x88\x45\xf2\x47\x14\xb2\xe4\xf0\x3c\x51\x10\x56\xda\xdd\x97\x2d\x3b\x35\x0d\x78\x8e\xdf\xdf\x4f\xb7\x85\x34\x90\x3a\x32\x77\x71\xfa\x0f\x1d\x71\x3c\x1d\xe7\xcd\x54\xb1\x68\x81\x2c\x13\x7a\x81\x17\x84\xdc\x06\x34\x43\xf3\x21\xf8\x27\x3b\x80\xd7\x39\xfc\x29\xb4\x23\x77\xc8\xd0\xbf\x39\x55\x57\xb0\xbe\x36\x9b\xa0\xa3\xfb\x9d\x23\x0f\xc8\x91\x3a\xe1\x07\xe2\x56\x38\x02\xc1\xea\xf2\x43\x0e\x90\x8c\x8a\xf5\x43\x8a\x87\x43\xf4\xd0\x4a\x2c\xb2\x8b\xc6\x4a\xfa\x0d\x3e\x37\xfe\xf3\x08\xea\x62\x5d\xee\xef\xb3\xee\xfb\x6c\x7f\x7f\x96\x24\x6b\xc5\x7f\xa2\x47\xa3\x19\x69\x42\xed\x7d\xbb\xb9\xd9\x5b\xf5\xbf\xb1\x2f\xef\xa4\x99\x30\xef\x6a\xbf\x8a\xcc\xe5\x5c\xc4\xd2\x0a\xd8\xc8\x96\x73\x89\x84\x88\x08\xe8\xa2\x86\x62\xf8\x24\x33\x91\x0f\xd3\x29\x2c\xc2\x7a\x81\x62\x1b\xe9\x30\xfa\xa5\x0c\x86\x44\x71\x25\x44\xb5\x71\x9e\x41\xe8\x6d\x8f\x3c\xc9\xc2\x15\x6a\xbd\xe2\x73\x84\x16\x80\xd9\xf4\x32\x45\x27\x80\x3b\xbe\xde\x7f\xba\x2a\x9a\x79\xd6\xe4\x53\xaa\x6f\xa4\xd5\x81\x70\x23\xea\xa9\xa3\x46\x09\x0c\xb5\xd7\x0a\x50\xfa\x35\xbb\x7a\x7f\x61\x5c\x2b\xc0\x29\x5f\x2c\xca\xef\xaf\xfe\x6d\x9d\x2e\xc8\x9b\x42\xe9\x84\x14\x43\xf7\xe8\xd7\xbc\x26\xf1\xf5\x0a\x67\x3e\xfb\x48\x0e\xae\x2a\xa3\x16\x14\x5f\x9f\x73\x1c\xad\x78\xd1\xbf\x86\x83\xc0\xa5\xd9\x34\x42\xc8\x68\x56\x4e\x9e\x8c\x8a\xa5\x5c\x57\x00\x9f\x81\x9c\x70\x06\x34\x16\x34\x76\x7a\x81\x03\xf8\xd3\x62\x0d\x57\xf6\x90\xd0\x19\x99\x5a\xbc\xcd\x8a\x35\x27\xbc\x46\xd8\xe5\x9f\x7f\xc9\xae\x5e\x96\xdf\x0b\xfe\x78\x5b\xc2\x59\xf7\x3e\x3f\xaf\xf8\xc3\x9c\xe6\x39\x82\xed\x19\x3d\xa3\xb3\x6f\x46\xfe\xf3\x8d\xff\x48\xf6\xf2\x3a\xa3\x20\x4e\x38\xff\x78\x2e\x9c\x80\x85\xbe\xe1\x71\xa9\x35\x1a\xa5\x2a\x63\xcf\x0c\x32\xee\x4f\x39\x22\x9e\x8a\xc8\xd2\xb4\x22\xb2\xec\xef\xf7\x67\x49\x83\xa3\x90\x43\x18\x4c\xd8\x91\xbc\x69\x0a\x97\x22\x0e\x8d\xb6\x55\x52\xaf\x40\x8c\xec\x7e\x2b\xdb\x5a\xc9\xd8\xab\xf4\x79\x25\x95\x18\x7b\xb4\x02\x55\xbf\x1c\x58\x15\xbd\xd5\xb3\x2a\xcb\x0d\x70\x53\x4c\x63\xd8\x8e\x6b\x31\x74\x65\x45\xf1\x32\x27\x24\x7e\xf8\x58\x84\xce\x47\xfc\xe8\xd6\x77\x71\xef\x70\x00\x05\xab\x9c\xfa\xb8\x67\x03\x63\x57\x88\xf0\xd1\x00\x1a\x97\xba\xe1\x93\x01\x5f\xbf\x0a\xff\x60\x00\xd9\xfb\x90\x2e\x98\x5d\xdc\xf1\x92\x27\x84\x55\xf9\xbd\x7f\x24\x1e\xde\x1f\x74\xbe\x8f\xb7\x59\x6e\xaa\x38\xcd\xf2\x45\x9f\x7e\x01\x25\x33\x2b\x97\xfd\xc1\x3f\x14\x83\xa0\x51\xdf\xd1\x76\xe5\x3a\x8b\x06\x6f\x21\xa4\x76\xd4\xb0\xcf\x4d\xbe\xb0\xde\xda\x02\xa8\x2a\xf7\xb0\xd1\x8b\x45\xbe\x3a\x2f\xd3\x6a\xa6\xd0\x52\xda\x81\xae\x7c\x34\x46\x67\xc3\xc3\x65\x3a\x13\xe0\xc7\x69\x74\xea\xe5\x13\xb8\xaa\xcc\x85\x97\xf9\xb2\x4a\x2f\x55\xde\xca\xcb\x3b\x29\xd7\x32\x76\x9d\x71\x1a\xa3\x33\x3f\xbf\x51\x39\x73\x2f\xe7\xaf\xf3\x2c\x5b\xa8\x4c\x13\xba\x91\x57\x14\x28\xa4\x17\xec\xe2\x74\xd9\x16\x68\x7d\x73\xf1\xed\x65\xdb\x5e\xd0\xc5\xb4\xc8\x76\x5e\x9f\xe3\x61\xbf\x1d\xd1\x7e\x43\x64\x4a\x88\x61\x6f\x64\x23\x59\x9d\xae\x50\x2c\x66\x6f\x50\x8c\x94\x4f\xbf\xee\xda\xee\x0b\x2a\x1c\x68\x98\x32\xfc\x96\x2d\xa4\xb2\x6b\xfb\x56\x95\x50\x2f\x26\xbb\xd5\xd7\xea\x6a\xf7\x4e\xa0\x6c\xb0\xf5\xd5\x95\xdf\xec\x7a\x97\xbb\x8d\x6b\x43\xd1\x50\xa3\xeb\xc6\x6b\x73\x56\xae\xa1\xd6\x8b\xbb\x2c\xfb\x4b\xab\x4a\xa0\x0f\x2b\xdb\xef\x0b\xa0\x7e\xe7\x4e\xb0\x6c\xa8\x75\x48\x0f\x34\x8b\xec\xd1\x1d\x5a\xc6\xe2\x1d\x8d\x43\x56\xb0\x7d\x8c\xa0\x77\xa7\x1e\xb0\x42\x67\x1f\xe8\x77\x33\xd0\xcb\x8f\x7c\xe7\x1d\x7e\xa9\xca\x77\xf5\x01\x79\x81\x2e\x38\x50\xc9\x1d\xfa\xe0\x0a\x1d\x9d\x50\x66\xa0\x97\xf7\xdf\xee\xb6\x5a\x54\xbe\xa3\x0f\xcc\x0b\x74\xc1\x2c\xee\x1d\xfa\xe0\x0a\x1d\x9d\x50\x66\xab\x17\x20\xff\x77\xee\x00\xca\x06\xdb\x2e\x57\x5e\xb3\xc4\xd2\xec\xda\x2e\x93\x67\x81\x86\x29\xc3\x6b\x39\x47\x62\x61\xd7\x96\x89\xb2\x08\xb5\x4c\x19\x5e\xcb\x5f\x25\xf9\xb4\x63\xdb\x8a\xda\x0a\xb4\x2e\xb3\xda\xed\x7f\xa8\xb2\x7a\xe7\x65\xf9\x8b\x2a\x1f\xee\x81\xf2\xda\x5d\x7c\xde\x79\x3b\x99\x38\x0c\x37\xfe\xd9\xdf\xd0\x45\x99\xee\x8c\x7c\x7e\xc3\xb2\x81\x76\x31\xdd\x6b\x36\x43\x5b\xaa\x5d\xdb\x25\xc3\xab\x50\xc3\x94\xe1\xb5\xbc\xd4\xe4\xf7\x8e\xad\x1b\x7a\x3d\xd0\x83\xce\x0c\xf5\xf2\xb6\xdc\x1d\xdb\xbc\xd5\x15\xba\x7a\xc1\xcc\x50\x2f\xef\x77\x07\xfb\xb7\xaa\x7c\x57\x1f\xef\x5b\xc0\xcf\x5d\xdc\x01\xa3\xbd\xd5\x15\x3a\x3b\x69\xe3\xb4\xa5\x64\x6f\xee\xd2\x47\x18\x46\x65\x96\xd7\xfe\x2a\xad\x9b\x9d\xb7\xe2\x03\x15\x0e\xb4\x4d\x19\x5e\xcb\x6c\x9d\xb1\x63\xcb\x1f\xa9\x70\xa0\x65\xca\xf0\x5a\x66\xf7\xef\xbb\x36\xcd\x8e\xda\x43\x6d\x73\x8e\xdf\xf8\xfa\x7c\xb9\xfb\x75\xfb\x89\x4b\x87\x1a\xa7\x1c\xaf\xf1\x06\x89\xf8\x17\xa8\x67\xb9\xf3\xf0\x4f\xac\x2a\x81\x6e\xac\xec\x50\x5f\x77\x20\x80\x4e\x54\xf9\xae\x5e\xda\x24\x10\x75\x71\x97\xb3\x7c\xa2\x2b\x74\x75\x12\x38\xcb\xd4\xcb\x9d\xee\xf5\x13\x53\xa3\xab\x9f\xd0\xcd\xfe\x1d\x79\xa5\x5d\xfb\x20\xc6\x2a\xd4\x3c\x65\xb8\x2d\x6f\xf0\xad\x5f\x89\x42\xae\x86\xc8\x24\xa1\x10\x91\x69\xe5\xab\x21\x71\x37\xc2\x93\x70\x5c\x0d\x2d\xd6\x84\x33\x81\x23\xc0\xd4\xd5\x15\x7d\x02\xb2\x82\xaf\x35\x89\x23\x6d\xda\xfb\x6a\x68\x11\xef\x94\x89\x34\x33\xa4\xc2\x1f\xf5\x89\xdb\xcc\x29\xf0\xcb\x24\x22\x6d\xaa\x92\xe1\xb7\xce\x40\x7a\x52\xa6\xc3\x4f\x95\xcc\x24\x20\xa7\xd3\x6f\x95\x41\x38\x8e\xd3\xf1\xa7\x4a\xe6\x0d\xe1\x74\x96\x36\x53\x06\x50\x48\x98\x56\xae\xf0\x93\x2f\xac\xab\x21\xdd\x72\x42\x0b\xa2\xae\x58\xe2\x8b\x09\x4c\xa0\x5c\x0d\x89\xaa\x11\x96\x0c\xe7\x6a\x28\xc9\x11\x99\xc8\x94\x00\xa5\xd2\x4f\xa1\xa5\x3b\x94\xf6\x99\xfa\xa3\x8b\xf7\x6a\x88\x77\xb5\x70\x24\x50\x57\x43\x7d\x1d\xea\x0c\x02\x5c\x99\x81\xbf\x75\xc6\x7b\x1a\x91\xba\x73\x4c\x32\xaf\x83\xbe\x28\x84\x25\xae\x92\xc9\x3c\x0a\xc6\xab\x57\x43\x42\xc6\x98\xc0\xe8\x50\xaa\xe4\x62\x82\x44\x62\x57\x32\xf4\x05\x25\x31\xea\xb9\x1a\x32\xc6\xc2\x24\x1b\x57\x5c\x0d\x2d\x64\xa3\x33\x79\xe3\x15\x6a\xd0\xc9\x72\x66\xfa\x3c\xeb\x0c\xb5\x67\xe6\x0c\x62\x16\xc3\xfe\xd5\x90\x0e\xcc\x46\xeb\x5c\xbd\x40\xa3\xe3\x57\x83\x57\xa7\x2f\xce\x86\xb6\x4c\x34\x81\x04\x12\xe7\x9c\x3b\x92\xc9\x2b\x91\x51\xdc\x7b\x2d\x8c\x0e\x86\x37\x40\xd5\x2c\xaf\x9c\xcc\x9e\x94\x14\xc0\x92\x74\x97\xf0\x51\x48\x89\x7b\x58\x65\x0e\x55\x1c\xa9\xb3\x97\x6c\xe5\x4c\xa1\x24\xb7\x8a\x42\xa5\x0f\xc6\x6f\xc9\x2b\x34\x48\x24\x59\xbc\x76\x73\x8e\xe2\x4a\xcc\xbc\x9a\x78\xd2\xd2\xcb\xa1\x86\x49\xf3\x4d\x50\x65\x3e\x19\xa8\xcd\x37\xef\xae\xf9\x56\x3b\x99\xa4\xb6\xcc\xf3\x72\x68\xc3\xb1\x0c\x69\x3a\xc3\x60\xcf\xf6\xa0\x9c\xa2\x46\x96\x79\x69\x64\x99\x57\xc9\xba\xd5\x2c\x21\x22\xf3\x29\x0f\x59\x52\xb7\x0a\x32\x4a\x81\xce\x8f\xa0\xf3\x6a\x78\xbe\x6e\x9a\xb2\xe8\x18\x40\x4b\x3e\x4b\xa9\x36\x6a\x32\xa9\xe6\xa0\x79\x69\x04\x89\x5e\xda\x7b\x67\x71\xcd\xd1\xf2\xd2\x68\xae\xd3\xd6\x14\x08\xfd\xb9\x9f\x78\x0a\xfc\x94\xc6\x69\x50\xa3\x3d\x37\x89\x51\x9e\x9b\xe6\x0d\xc5\x60\x3a\x3b\x0d\x91\x5c\xb2\x68\x8d\xcd\x3e\xb0\x5e\xaa\x3b\x46\x73\x4a\xbd\x34\x79\x40\x93\x55\xab\x6d\x85\x32\x92\x8b\x56\x96\x3c\xbf\xc9\xbc\xbd\xdf\x78\xc9\x58\x9f\xce\xca\x4b\x34\x95\xe4\x9b\x65\xff\x8a\x55\x80\x5e\x24\x57\xd6\xcb\xd4\x37\x3a\x45\xea\x49\xaa\xdc\xfe\xee\xf4\x62\x20\x5e\x38\x72\xe1\xf3\xdb\x65\xeb\x96\xa8\x37\x7e\x74\xb4\x4d\xe6\xde\x25\xe6\x8d\xc7\x47\xbf\x8a\xb0\xcc\x15\xb2\x9e\x6c\x11\xc9\x87\xe4\xbf\x90\x37\x16\xdd\xe2\x5f\xc8\x76\x07\x63\x49\x7f\x21\xef\x81\xe8\x10\xf0\x42\xde\x43\x11\x92\xef\x42\xc6\x23\xd1\x21\xde\x85\xbc\x5f\x45\x48\xba\x1b\x8f\x1f\x76\x68\xc5\xb8\x2f\x06\x2d\x1d\x99\xbb\xba\xf2\xaf\x3c\x85\xf7\xc2\xb1\x89\x69\xc9\xd5\xcb\xe4\x7a\xaa\x36\xe7\x65\xda\xa4\x01\xcf\x6e\x91\x53\x80\xde\xb7\x8f\xb3\xa1\x5b\x4b\x3e\x40\x3b\x89\x00\x57\xd5\x30\x5d\x5f\xe2\xfb\x08\x29\x16\xf5\xf1\xa5\xab\x6d\x26\x11\xd8\x6a\x9a\xf9\x76\xd3\xc3\x3f\x62\xe6\x18\xcd\x90\x1f\x10\x7f\xdf\x48\xef\xea\xa9\x75\xc7\x91\x3a\xcf\x14\x72\xb8\xca\xa5\xdf\x4f\x0d\xdb\x83\x7c\x1c\xfb\xfd\xdd\x4d\xbc\x2c\x37\x06\x33\x89\x41\x00\x43\x5c\xe4\x97\xca\x82\x4b\xa5\xbe\x25\xd5\x96\x44\xfa\x95\x2f\x52\x7a\x42\xc3\x5e\x93\x42\xbe\xa4\xb3\x02\xa7\x09\x93\x3a\x7c\x83\xa8\xff\x22\x9d\x9a\x78\xe5\xd2\x25\x37\xa9\x7f\x77\x38\x31\x4f\x13\x74\xbc\x4d\xbe\xbe\xe1\x6f\x92\x1e\xa7\xfd\x62\x10\xa3\xaf\x6e\xe9\x42\x48\xba\xb8\x1b\x4a\x1f\x2b\x1f\x98\x16\xc9\x66\xc7\xed\xa4\x18\x35\x44\x11\xda\xc9\xb1\x01\xd1\x34\xec\x44\x3c\xaf\x5f\x7a\x45\x31\xc2\x8b\xed\xa7\xed\xa4\x5a\x67\xb1\x93\xf2\x3a\x5d\xd4\x72\x4d\xf2\xda\xa2\x88\x3e\x01\xfe\x5e\x41\x03\xed\xc2\xb7\xda\xad\xdd\xcd\xf1\xa4\x42\x3f\x27\xa4\x7e\x40\xcf\x67\xd7\x14\x2d\x82\x0d\x15\x28\x35\x4e\x85\xf4\xf9\xce\xa5\xdc\x29\xbc\x23\xd5\x4e\xc2\xeb\x14\xdb\x9a\x55\x15\x89\xf7\xaa\xa5\x0f\x43\xba\x31\xc9\x87\x08\xb7\x9a\x2f\x33\xb8\x08\x97\xab\x00\x0a\xe9\x65\x43\x9d\x7d\x73\x83\xae\x64\x86\x45\xf9\xbd\x4f\xcf\xf6\xfe\x3e\x90\xcd\x16\x2e\x6a\xad\x3e\x37\x93\xd2\xf5\xb6\xe1\x12\x95\x6d\xbd\x62\x7f\xc3\xf6\x46\x13\xcb\xfb\xba\x05\x90\x13\x9f\x40\x3d\x6e\x53\xac\x71\xe6\x40\x86\x72\xe5\x10\x80\x8b\x16\x54\x6c\x84\x47\x12\x77\xf8\x83\x77\x47\xe4\xd5\x39\x0e\x10\xd6\x31\x5a\x2a\xe0\xf2\xff\x89\x76\x84\xe2\xc8\xee\x06\x6d\x3c\x2c\x54\xd7\x06\xc6\xba\xb5\x72\x50\x9f\x73\xf0\xb0\x06\xea\xd9\xf9\x21\x90\x0f\x2b\x7b\x5b\x33\xdd\x7e\xe6\xa5\xc3\x24\x3a\xd0\xcd\x19\xeb\x27\x84\xf0\x8d\x31\xb7\xf1\x50\x8e\xc9\x70\xb0\x0e\x99\xf2\xe1\x5b\xa9\xee\x32\xa9\xd1\xf5\xb1\x85\x3a\x13\x17\x09\x9a\x28\x15\x70\xd2\xe4\xd9\xe3\x07\x78\x1b\x12\x81\xfb\xc1\x68\x79\x56\x82\xfd\x91\x38\x59\xf6\xd4\x13\x0c\xef\x6c\xc6\x42\xfe\x56\xad\xc1\xa1\xad\x45\xe6\x8e\xce\x1d\xac\x6f\x7c\x88\x36\x72\xcd\xbc\xca\xb2\xe7\x32\x16\x33\xa1\x10\x0a\x24\xe7\x59\x29\x76\x14\xfc\x79\xf7\x2a\x61\x0f\xad\x1e\xfe\x89\xc7\x8f\xc8\x16\xf1\xfe\x9d\x3d\x22\xef\x76\x51\x9a\x97\xf7\x12\x6d\xb1\x91\xd6\x9d\x49\xa4\xf6\x33\xd7\xa4\x4d\xe8\xd1\xb0\x77\x77\x7c\xfc\x7f\x98\x12\xb9\xbf\x5d\xa3\xfa\x0f\x59\xe0\x2e\xed\x85\xdc\xcd\x01\x22\xbc\x7d\x1f\xbd\x2d\x67\xe8\x17\x16\x75\x60\x9b\x8c\xaf\x25\x20\x7f\xe3\x5c\x2c\xa4\x8b\x28\x79\xb5\x34\xd5\x02\x7d\x20\xb1\x9f\x8e\x79\x7e\xd1\xe8\xaf\x74\x61\x7e\x2f\xb3\x26\xd5\x1f\x55\xb6\x82\xe3\xc9\xbf\xb1\x35\x75\x2d\x41\xd7\x4e\xaf\x78\xed\xc9\x41\x87\x68\x5d\x18\x0e\x2a\xcc\xd6\xa8\x69\xc5\xa1\xc9\x8f\x31\x56\x70\x3c\xa2\x57\xaa\x2d\xb5\x80\xfc\x2d\x4c\xa5\x9b\x1b\x4c\x5b\xaf\xac\x66\xb2\xa1\x6a\x60\x84\x52\xce\xdc\x11\xb5\xdc\xda\xff\x9d\xbb\x08\x00\x52\xbd\x2b\xd0\x6f\xe5\x60\xec\x0d\x86\xb4\x27\xa2\x73\x7f\xe1\xd8\x33\x54\xee\xae\x51\xfb\xfb\xa0\xf2\x1f\xf3\xec\x3b\xce\xee\x6d\x86\x4d\xd7\x6d\xa0\xf4\xe1\x2f\x4d\xae\x6b\x40\xeb\x59\xf1\x4f\x12\xd6\xe8\xe3\x6f\x12\x0a\x17\xa8\xe9\xfd\x4f\xf6\xc7\xdf\x7e\x1e\x3e\x5b\x70\x98\x0b\x16\xe4\x04\x2d\x83\x39\x4b\x32\xf1\x11\x41\x0b\x33\x5e\x4d\x8c\x42\xa0\xe6\xf8\x28\x7e\x40\x7f\xc7\x08\x4d\x5c\xba\x56\x07\xc1\xc6\x7f\x41\x5a\xcc\x29\x82\x4e\xcf\x87\x18\x17\x4c\xaa\xb2\x11\x38\xd5\xd5\x54\x7e\x02\x50\x35\xa5\x52\xc9\x75\x0a\xa2\x4f\xb2\xf4\x32\xfb\xa7\x10\x18\x53\x86\x62\x15\xb9\x14\xb1\x8c\xb8\xa0\x07\xe5\x50\x12\x9e\x2c\x1d\x21\x45\x5d\x6a\xea\x6f\x5d\x4d\xfd\xcd\x6e\xea\x6f\xba\xa9\xbf\xf9\x4d\x9d\x94\xab\x10\xe0\xa7\x77\x01\x7c\x1f\x88\x20\x7d\x17\x18\xdf\xdd\x35\xf7\x1f\x83\x79\x7d\x50\xce\xf1\x71\x63\x8d\x42\x1d\x9b\xc8\x3f\xb1\x93\xa6\xa4\x79\x39\x73\xd2\x3a\xe1\x75\x0b\x8c\xb7\x40\xb9\x0c\xac\x79\xfe\x33\xc8\xa6\x63\x6d\x77\x76\x00\xf8\xb3\xf7\x6f\x98\x69\x82\x25\x45\xdb\x01\x3f\x6c\x6a\x36\xc4\x54\xe3\x17\x14\xbf\xa4\xa9\x5b\x29\x5d\x69\x32\xe3\x49\x01\x4f\x59\x32\x42\x3e\x35\x75\x40\x53\xe5\xfb\x9c\xbc\xe5\xbf\x94\xca\xf1\xda\x57\xab\xe1\x4e\x11\x14\x6f\x6e\x94\x1e\xfc\x5f\xa9\x25\x29\x6a\xe1\x10\x16\xf9\x22\x7c\xc0\x39\xef\xe6\x26\x78\x0d\x6c\xdd\x99\x96\x06\x6c\x90\x8e\xfb\x0f\x12\x4a\xb5\x04\x1e\xd9\xa2\x49\x83\xf8\x85\x73\x14\x56\x90\xe5\x22\x7a\x0a\x79\x69\x65\x1d\x66\x43\x2b\x2d\x26\xff\x83\xf0\x2b\x88\x67\x38\xc7\x69\xf2\x6f\x76\x93\x7f\x0b\x34\xe9\x14\x08\xe4\xeb\x1e\xff\x27\x9f\x1c\xfa\xfd\x56\x05\x70\xfc\x23\xc4\x37\x3b\x47\x33\xb2\xb5\x4a\x2b\xa4\x92\x83\x6e\x0e\x5a\x1c\x61\xd3\xb6\xf3\x65\x4e\x2e\x6c\x03\xac\xbc\x1c\x7c\xe7\xef\x37\xd0\x07\x8a\x02\x8f\x43\x89\xda\xae\x39\x0e\xe5\x62\xb8\x44\xf6\x67\x91\xd7\x6f\x0a\xdb\xa6\x13\x83\x0e\xfb\x89\x18\x1d\xa5\xc3\x2a\x59\x0a\x14\xdc\xe2\x2d\xbd\xe9\xbd\xbd\x60\x67\x1d\x46\xbf\x14\x25\x41\xa4\xa2\x16\x6b\x74\xc1\xb0\x27\x99\x67\xa7\x6a\x5f\xba\xdd\x9a\x8a\x85\x15\x2e\xb0\x35\x99\x91\x98\x1a\xf6\x5d\x6f\x09\x5a\xc6\x8e\x48\x37\x59\x9e\x1c\xa7\x4b\xac\x62\x02\x0c\x62\xe3\xe4\x65\x59\xf7\x42\x06\xdf\xdc\xc4\x66\x4a\x8f\x75\xab\xc1\xf5\x06\xe3\xec\xf5\x5a\xf9\xba\x95\xae\xb5\x56\x1e\x7c\x17\xa8\xc4\x66\x8d\xaf\x23\xce\x73\x17\xd4\x08\x80\xc3\x49\xf1\x54\x7b\x23\xb5\x7c\x42\x50\xf0\x02\x3d\x78\x0f\x0e\x30\x1e\x4b\x39\x7c\xff\xa7\x4f\xaf\x3e\xfe\xe3\xab\x97\x5f\x5e\x7d\xfc\xf8\xfe\x63\x10\xc6\xb0\x60\x65\x2d\xe1\xb1\xfd\x61\xf0\xcf\x80\x8f\x9e\x9a\x36\xc6\x92\xe9\x68\x2c\x69\xf5\x6b\x56\xd8\xdd\xa9\xe2\x60\xac\x16\x3a\x87\x85\xde\x6c\xa4\xcd\xbd\xbf\x4a\x32\x34\x5e\x00\x50\x76\x58\x3f\x40\x96\x93\xca\xac\x5f\xa5\xd6\x0f\xa3\x52\x37\x18\xfa\x52\x1e\x4c\x7f\x26\x15\xaf\x6d\x8e\x50\x56\xef\xb5\x27\x85\xb6\x6a\x34\x5a\xfd\xc3\x42\xd6\x35\xde\x82\x16\xac\x51\xd8\xe9\x36\x9c\x55\x66\x01\xd6\xb4\x00\x5b\xcf\x3b\x2c\x4f\xa9\xc2\xa7\x56\xc2\x1d\x4d\x7c\x1d\x32\xd3\x6b\xbb\x26\xbb\xbf\x5d\xe6\x6e\x21\x3e\x40\x0b\x9f\x0b\x32\x0a\xcb\x66\x4c\x25\x7e\x28\xeb\x5c\xca\x4b\xd1\xae\xc2\xa7\x45\xe3\x91\xf0\x89\x4a\x48\xaa\xb2\x0b\xe0\xcb\xe6\x9c\x44\xa2\xc0\xba\x2d\xe3\x2a\xa4\x91\xde\x00\x30\x7b\xab\x5d\x38\xcb\x3f\x44\xd5\x22\x58\x21\xf9\xaa\x65\x9a\xb1\x7d\xdc\x70\x0f\x93\x60\xe2\xc1\x5d\x84\xf7\x44\xbb\x54\x8a\x34\x19\x08\xf6\xbe\x9f\xf9\x54\x89\xef\x59\x1c\xb6\xca\x4d\x6a\x4c\x60\x86\xfd\xfd\xf2\x18\x43\xfc\xac\xeb\xf9\x10\xb6\x7a\x71\xc5\x7e\x42\x80\x5d\x2d\x54\x7a\x9f\xbf\xcb\xe3\xd3\xec\x0c\x45\x60\x00\x24\xe8\xb8\xe4\x14\x0a\x3a\x6e\x99\xc3\x8e\xf5\x8a\xae\xed\x7f\xb0\xbb\x24\xc9\x46\x4e\x63\xc0\x42\x23\x8a\xc2\x5b\x9a\xc8\x04\x25\x9c\xa4\x26\xe9\x37\x07\xd9\x50\x49\x06\x9e\x37\xf8\xc8\xf0\xdf\x2a\x28\x0e\x87\xbb\x81\x5f\xda\x43\xd4\x4d\xf1\xf4\xe9\xf8\x91\x1c\xfa\xa3\x87\x0f\x8f\xc6\x81\x88\x41\x0f\x5a\x12\x23\x77\x44\x16\x27\xb6\x5a\xa4\xd3\xac\x5f\x09\xb7\xb8\xf6\x47\xd5\x94\x9f\xf1\x0c\xbd\x40\xf7\x08\x83\x8d\x22\x9b\xee\x1d\xf6\x87\x83\x7b\x97\xa1\x9e\x77\x97\x00\x59\x11\x9f\xcc\x40\x4a\x11\x2d\xeb\x43\xf4\xe9\x6f\x6d\xce\x34\x5d\x66\x88\xeb\x88\x2a\xbb\xf7\xcf\x87\x50\xe2\x5e\x7b\x97\x74\xa9\x18\xe6\x4f\x63\x69\xf1\xfd\x3e\x44\xaa\x75\x00\x42\xf9\x38\x23\x7e\x76\x6f\x14\xa3\xa1\xe6\xf1\xde\x18\xfe\x36\x83\x63\x2a\x38\x34\x91\xaf\x49\xf4\x2d\x83\xb2\x1f\x9b\x9f\xec\x0c\x07\x7d\x9e\x43\x49\x45\x51\xab\xf3\x72\x00\x48\x3f\xb7\xc0\xbc\xb7\xd7\x1f\x3f\xda\xef\xcc\xef\x63\xe4\x43\xe8\x10\xf0\x9c\x0d\x91\x64\xe4\x45\x81\xdf\x43\x20\x69\x72\x01\x26\x89\x16\x7b\xd0\x62\x01\x43\xab\xbd\xb7\x07\xb3\xb5\x7c\xed\x2b\x17\x12\x41\xf7\x41\x68\xdb\x17\x31\x98\x4a\xbb\xe2\x3d\xb4\x37\x6e\x48\x54\xfc\x2d\x5d\x50\x22\x96\x91\x2e\xe9\xad\xf0\x80\xe8\xb5\x1d\x55\x7c\xa0\x33\xff\x48\x43\x57\x88\xe1\xb3\x8c\xaa\xc3\x57\xde\x64\x4b\x6e\xca\x33\x97\xb5\x42\x53\x1c\xb7\x42\x0e\x64\xc3\x9a\x7c\xd8\xc0\xe9\x46\x09\x15\x06\xcb\xb3\xec\x57\x9b\xf2\x39\x7b\xd7\x6f\x63\x36\x95\x15\x8f\x1f\xff\x4a\x0b\xb7\x3b\x7f\xa7\x24\x24\xa5\x94\xc6\xbf\x4e\x51\x9e\x4e\x78\xaa\x48\x94\x7f\x59\x26\xa6\xaf\xf1\x6d\x60\x91\x72\x28\x54\xf6\x8c\xf2\x1a\x50\xde\x87\xf4\xd2\x78\x65\x8b\x0e\x32\xe3\x47\xff\xaf\xf9\x62\xf1\x99\x63\x9f\xda\x98\x3d\x47\x0f\xaf\x1b\xe9\xd1\x33\xe4\xc6\xd0\x76\x24\x87\xde\xd6\xbc\x30\x7e\x9e\xf3\x3c\x00\xb9\x6c\x67\x2f\x7a\x5b\xb1\x62\x57\x9b\x31\x6b\x12\x84\x3c\xab\x05\x10\x69\x8b\x95\x0b\x2d\x77\x36\x5c\xd2\xe5\x3e\x35\x9e\xf2\xe0\xc8\x9e\x8e\xcf\x00\x3f\xfd\x56\x7e\xd7\xf8\xc9\x86\x1e\xf5\x8c\x52\x25\xeb\x49\xdd\xdf\xdb\x5b\xab\x40\x8d\xd8\x2e\x50\xb0\x25\xd0\x1b\x7d\x19\x7d\x06\x39\xc4\xbc\x00\x66\xf8\xcf\x27\x6f\x7f\x4b\xa6\xd0\xf0\x41\x76\x30\x3d\x3d\x3a\xd3\x84\xd1\x02\x52\x47\x67\x93\xc5\xe1\xe1\x64\x50\xc1\x4e\xc3\x16\x73\xac\x5b\x26\x6b\xed\xea\x19\xf5\xb3\x62\xbf\x35\x72\x01\xea\x3f\x5d\x9d\xa4\x97\x14\xac\x39\xaa\xa7\x55\xbe\xc2\x15\x5d\x99\x08\xf7\x88\x40\x44\x0e\x64\xf2\x10\x3a\x7c\x95\x62\x6c\x11\x8b\x2a\xbb\x48\xf2\x3e\x00\x17\x76\x87\x27\x1e\xfd\x05\x9a\x01\xc0\x78\x9c\xb0\xba\x56\x96\x5e\xad\x0b\xc7\xb2\x9b\x14\xe9\x72\x34\xec\xff\x96\x57\x65\xe1\x6e\x39\x83\x30\x1d\x10\x0c\xbb\xe9\xc8\xd0\xd9\xe9\x20\x52\x84\xc6\x22\xd2\xe6\xeb\xd6\x78\x2e\xd2\xe2\x73\x9d\xbd\x7c\xff\xf6\x58\x5b\xdd\x73\x93\xca\x8c\x3e\x9a\xe5\xdf\xa2\x81\x14\xf2\x00\x36\xff\x7b\xfd\x0f\x4f\xfb\x7f\xff\x7e\x30\xb8\x37\xf9\xcf\xad\xa3\x1a\x1c\x6b\xfc\x88\x94\x66\xfc\x91\x02\xda\x7f\x28\x5a\x03\x05\x5a\xa5\x23\x3e\xe6\x83\x16\xef\x1a\xc2\x97\x6d\x4c\x79\x2c\xdf\xa6\xbe\x66\x57\xe8\x4c\x61\x78\x91\x2f\x00\x1b\x1a\xcf\xc4\xd6\xbd\x82\xa1\x89\x07\x43\x8c\x0e\xd8\x8f\x7a\x30\x69\xc6\x61\xe6\x4d\x0e\x73\x98\xda\x4d\xe5\x83\x58\x2d\xb0\xe0\x26\x70\xb1\xde\x45\xc9\x43\x3d\x20\x32\x8d\x85\xae\xe1\x5a\x3e\x83\x30\x91\xcc\xb9\x49\x5e\xa4\xa2\xa6\x44\x52\x41\x22\xaf\xdf\xa5\xef\x2c\x52\xab\xba\xb9\x41\xcd\x43\xa8\x54\xfa\xda\x10\x88\xff\x31\xac\xe9\x71\x14\x1d\x34\xb1\x8e\x3b\x62\x3a\x42\x8f\x92\x09\x50\x12\x55\xbe\x04\x56\x43\x34\x07\xd1\xea\x47\xe4\x46\x11\xf8\xf4\xc9\x72\xaf\x83\xca\x9e\x79\x8d\x2e\x45\x16\x59\x5d\xbf\xa3\x9b\xa5\x8d\x7d\xec\x3a\xf1\x03\x22\x47\x1f\xb6\xc8\x51\x5f\x12\xc4\x21\x8c\x94\x6a\xda\x26\xa8\xd9\xe0\x1a\xb8\xb6\x3b\x0e\xbe\x4c\xfa\x6a\x53\x0f\x5b\xf4\x61\x90\xf2\x69\x63\xf3\x6c\xe3\xfa\x84\xdc\x54\xf6\x2b\x77\xc2\x0f\xa8\xee\xab\x37\x20\x34\xf4\x01\x5e\xf9\xcf\xe5\x98\x3e\xf2\xd2\x51\xad\x02\xd2\xd9\x9f\xb1\x5b\x03\x2e\x91\x24\x70\xbb\x40\xf2\xc6\x2d\xa9\xde\x6e\x43\x0e\x3d\xb3\x8d\x68\xdb\x78\x3f\xdc\xfe\x7e\xf9\xad\x3b\xf2\xe5\xc3\x9f\xa0\x26\x11\x16\x83\x64\x44\x1f\x00\x14\x8e\xab\xa2\x34\x73\x25\x05\x04\x5e\x30\xda\x8f\xe2\x68\x3f\x5d\xae\x26\x91\x88\x9e\xe1\xef\xcb\x06\x7f\x3e\xc5\x9f\x0b\xfc\xf9\x4b\xf4\x0b\xfc\xfc\xb7\x75\x49\xe9\xbf\x60\xfa\x7f\xf9\x71\xf4\xeb\x24\xda\x00\xe2\xbc\x77\xba\xff\xec\x69\xf4\xcb\x99\x43\x11\xeb\xd9\xdf\xf5\xf5\x49\x1e\x0c\x64\x7c\x5b\xaa\x47\x05\xdd\x57\xb9\xf2\x20\x22\x0f\x7a\x8a\xbc\xb7\x3c\x6d\x93\x34\x31\x47\x30\xa9\x8f\x4b\x24\x4d\x15\x7d\x26\x53\xf0\xa4\x0e\xe2\x46\x54\x28\x66\x48\x03\x3e\x4a\x3c\xde\x2c\x93\xe2\x65\xd8\x23\x15\xd2\x82\x03\xd9\xc2\x69\xde\x5c\xfb\xbe\xd3\xd9\x2b\xac\xa1\x30\xe4\xc5\xd2\x54\x29\xfa\x5f\x42\x7e\x5d\x47\x56\x1f\x4c\xdc\xd3\xb6\x69\x5d\x00\x81\x16\xe3\xf1\x11\x3d\xf2\x87\x1a\x84\xf3\xf7\x38\x78\x1e\xef\x12\xb9\x14\xe5\x0b\x19\x1b\x1b\xf4\x95\x58\xa1\x41\xb1\x42\x00\x40\x77\x71\x5f\xe0\x6b\xb4\x07\x28\x59\x7d\xeb\x43\x7e\x8c\xec\x08\xdf\x0a\x05\x79\xc1\x0d\x74\xbb\x8d\x6a\xe2\x09\x28\xcf\xa0\xea\x12\x4e\x6d\x4f\x12\x37\x37\x3a\xfd\xbc\x9c\x5d\xc9\x39\x9a\x33\xe4\xe6\x86\xe6\xbd\xbb\x72\xa4\xa4\xe1\x50\xfe\xa6\x9e\x87\xd5\xbb\xa2\x62\x77\x59\x72\xdd\x47\x3a\x4f\x25\x09\xba\x6e\xf6\xf7\xc7\xf7\x31\x9c\x36\x5d\x21\xe3\xfb\xc0\x26\x35\x80\x02\x9b\x67\xc9\xfd\xa3\x9b\x1b\xca\x6a\x8e\x9b\x78\x14\x1a\xe0\x5d\x82\x32\xd0\xa3\x0a\x8c\x4d\x53\xf7\xa7\xf4\x79\x76\x73\x43\x7f\x29\x38\x19\xdc\x47\x33\x58\x11\x0a\x2b\x8b\x71\xee\xcc\x73\x0a\xfa\x1e\x0a\xbc\x9b\xab\x3b\xb8\xb2\x42\x49\xf2\x6c\x8e\xa3\x57\x05\x45\xcc\x60\x77\xfd\xf4\xa6\xa9\x9e\xb9\xe1\x84\x6f\xee\xf0\xa8\x9f\x9f\xea\x45\x85\xd1\xba\x83\x8c\xa3\xc8\xbe\x64\x03\x2a\x13\x80\xf9\x5e\xd5\xd3\x38\x7a\x45\x0e\x8f\x23\xf1\x69\x05\x88\xf1\x3c\xad\x62\xa0\x41\x04\x89\xa2\x22\x80\xd1\xf2\x3b\xfe\x8c\xc4\xe7\x95\xfc\xfc\xbc\x8a\xc4\xc7\xfc\x72\xae\xb2\xe9\x77\x24\x48\x93\x9f\x53\xf0\x27\x24\x64\x8b\x38\x7a\x49\x31\xcd\x23\xf1\xd7\x1c\x32\xdf\x7f\x8a\x04\x99\x06\x44\x96\x9d\x40\x24\x9e\xaf\x56\xb5\x97\x24\x15\xd7\x23\x29\xbe\x2a\xa7\x5f\xa1\x66\xf9\xef\x1f\x60\xc1\xc8\xe9\x0c\x3e\x06\xba\xd3\x45\x44\x7c\xfd\x38\x8e\xd0\x5d\x75\x8d\x13\x89\xc4\x93\x38\x3a\x49\xcf\x23\x31\x3e\x82\xd6\x81\xfc\xa9\xe0\xe7\xfd\x58\xae\xbe\x18\x3f\x82\xe6\xf1\x61\x11\x7e\xfe\xca\xdd\x43\x5f\xf0\x01\x8d\x3c\x5f\x60\x2a\xd4\xff\x90\x02\xd8\x44\xe2\x68\x04\x05\xd2\x55\xcd\x03\x39\xfa\xd5\xac\xd9\xfd\x23\x5a\xad\xfb\xf7\xb1\xec\x65\x86\x6b\x73\xff\x01\xff\xe6\x55\xb8\xff\x10\x7b\x9c\xc1\x0f\xe8\xef\xcf\xe5\x12\xeb\xfc\xea\x2c\xec\xfd\xc7\xd6\xc2\xde\x7f\xe2\xae\xea\x83\x91\xb3\xa6\xc0\xe4\x47\x6f\x8a\x3a\x43\xa7\x6d\xc0\xb7\xea\xe5\xc5\xe8\xe8\xd1\xeb\x71\x44\x71\xa6\xa3\xd7\x47\x11\x85\x8d\x8e\x5e\xdf\x8f\x28\x6c\x73\xf4\xfa\x41\x44\x91\xcc\xa2\xd7\x0f\x23\x0a\x3a\x15\xbd\x7e\x14\x51\x7c\x95\xe8\xf5\xaf\x11\x05\x31\x89\x5e\x3f\x8e\x28\xe6\x42\xf4\xfa\x49\x44\x8e\xdb\xa1\xc1\x51\x44\x2e\xaf\xe1\x17\xb6\x7d\x84\x6d\x8f\xb1\xf1\x07\xd0\x38\x90\x66\xbc\x1e\x28\x7a\x70\x76\xea\xe8\x08\xb2\xdf\x66\x4d\x1a\xf9\xd8\xab\x4b\xb3\x03\xcf\xec\xa3\xbb\x84\x7b\x30\xd2\x6a\x81\x4f\x99\xb6\x0a\x23\x5e\x60\x43\xff\x91\x58\xdb\xab\xb4\x72\xf0\x7c\xf2\x39\x41\xd2\x41\x53\xbc\xc7\x7b\x7b\x18\x9c\x1a\xa5\x32\x0e\x45\xe6\xb0\xd7\x70\x82\x00\x54\xe2\x88\x9f\xb1\x23\x21\x81\x28\x8e\xe4\xf3\x35\x82\x7b\x93\xc6\x91\x7c\xda\x06\xb8\x46\x80\x8b\x23\xf5\xa0\x1d\x85\x7c\xe2\x3c\xba\x8b\x70\x51\x31\xc8\x8d\x54\xa6\xb0\x75\x27\x6e\x6e\x58\x1c\xac\xe6\x44\x08\x53\x4b\x66\x8e\x6d\xb9\x56\xdc\x04\x90\xe8\xa3\xdd\xc4\x88\x25\x70\xd7\xf9\x40\xac\xda\x9c\x01\xea\x76\x24\xd1\x3f\x20\x13\x19\xcc\xcc\x2d\xb6\x19\x8a\x21\x5e\x3b\x8e\x9e\x2e\xf2\xe2\x6b\xef\x1e\x92\x61\x4f\x29\x7c\xf5\xb3\xa7\xf7\xf8\x6f\x24\x52\xd8\xa1\x64\x2f\x07\x9e\xab\x52\x3c\x2e\xa5\x1d\xaf\xe0\x3f\x7e\x59\xb1\x50\x5e\x07\xa7\x5b\xb6\x39\xd7\x1c\x85\x37\x77\xe1\x5c\xd3\xe4\x7a\x9a\x57\xd3\x05\x5a\x77\xa2\x12\x31\xba\x1b\x10\xd9\x62\x91\xaf\x6a\x4a\x42\x07\x25\x02\xdd\x0b\xaa\xbf\x69\xf5\xdf\xa5\xef\x46\x4c\x59\xa5\xcd\x9c\xfe\x96\x8b\xab\x4b\x7c\x3e\xe4\x9f\xaa\x02\x96\x4c\x17\x76\x85\x0a\xdd\x91\xe1\x0b\x4a\x43\xce\x24\xd8\x15\xdd\xde\x68\x03\x94\xdf\xe9\x58\xfc\xf2\x94\xdd\x9b\xf5\x96\xeb\x45\x93\xaf\x16\xb0\xe8\xe4\xae\xeb\xd9\x2f\x02\x63\x02\x50\xde\xb3\x08\xa3\x1c\x43\xe1\xe8\x29\x61\xd0\x67\x48\xdf\xde\x93\x3f\xcf\x80\x15\x3f\xbd\xaf\xb3\x9e\x36\x78\xf1\xc3\x9f\x4a\x96\xaa\x60\x0f\x64\x9a\xa9\xb2\xe0\xd6\xea\x6f\x97\x5c\x8a\x7e\x9c\x61\x88\x34\xd8\xcb\x18\xf3\x8e\x9f\xc2\x92\x71\x26\xfd\x38\x13\x00\x70\x29\x65\x3d\x5d\xa6\x2b\xce\xa1\x1f\x30\x00\x38\x36\xa7\x47\xad\x21\xa8\x6e\x21\xfb\xb2\x2a\xd7\xb2\x8e\xfe\xb2\x87\x93\x5d\xa2\xe7\x42\x6a\x1c\x0e\xf7\x62\x56\x67\x0d\x97\x36\x5f\x30\xba\xb4\x4a\x97\x5c\x88\x39\x7b\x2e\xa2\x7e\x9f\x89\xa6\x0a\x0c\x83\x57\xc1\x5f\x80\x72\xd5\xd0\x28\xe2\x1a\x7f\xe2\xbb\x6e\x4d\x76\xc0\xf8\x6b\x2d\xd4\x18\xe1\x27\xd5\xc4\xbf\x17\x65\xd9\xe0\xdf\x79\x96\xce\xf0\xef\x2c\x9e\xc2\x07\xfc\x27\x81\x69\xc1\xb0\xb4\xd0\xa0\xb4\x00\x48\x5a\x30\x20\x2d\x7c\x38\x5a\x30\x18\x2d\x34\x14\x2d\x0c\x10\x2d\x7c\x18\x5a\x30\x08\x2d\x18\x82\x16\x0c\x40\x8b\x00\x7a\xde\x26\x72\x69\x0b\x51\x1e\xdd\x85\x43\x23\x7f\xcf\x40\xdd\x66\xd6\xf9\x9d\x0c\xb2\xc4\xf9\xd6\x9c\xa4\xcb\x95\x70\xdd\x89\x24\xd6\x0a\x18\xfd\xa7\xfc\x1c\xd5\x8a\x8d\x22\x8c\x95\x38\xc1\x46\x0d\x76\xdb\x78\x91\x0b\xcc\x9b\x8c\x14\x07\xe6\xc9\x88\x62\x86\x97\xdc\xc1\x7d\x7c\xa6\x54\x78\x92\x52\xd2\x24\x3f\x28\xc9\xf3\xa3\x74\x87\x2a\x65\x77\x48\x8c\x02\x3b\x96\x3e\xd3\x04\xe1\x35\x85\x51\x2d\x95\x73\xdd\xe6\x30\xdf\x4c\x72\xe0\xb2\xb0\x27\xf4\x25\x37\xb0\xe9\xe9\x52\x61\xda\xbb\x38\xfd\x54\x13\x3e\x36\x52\x76\x34\xcc\x44\xad\x11\x89\xb8\x2c\x7d\x39\xbd\xb0\x36\x76\x7c\x12\xe0\x29\x1e\xed\xcc\x22\xe9\xa7\x84\x72\x7f\xdf\x42\x9b\x40\xa4\x97\x49\x64\x2d\x11\x92\xf5\x1a\x95\x7a\x43\x3b\x76\x0a\xc6\x11\xdd\x03\xc8\xe7\x21\x7e\xde\x09\x87\xb3\x76\xfe\xae\xd0\x4b\x33\xbc\x8b\x9c\x5f\x2d\x32\xac\x2c\x5f\xa2\xc7\xd7\x3f\x94\x99\x19\x29\x14\xb2\xe7\x51\x8b\x93\xf2\x66\x28\xad\xb4\x91\xc4\x13\x57\x76\xcd\xbf\xed\x58\x13\x95\x09\x63\xe8\x34\x73\x5b\xca\xac\xec\xd0\x9d\x7d\x8b\x40\x3d\xf0\xf4\x17\x1d\xfe\xd7\x71\x34\xf0\x44\xe9\xf2\xa1\xaf\x7f\xfa\xfc\xf0\x7f\x9e\x85\xdf\xfa\x1e\xdd\x85\x09\x34\x6f\x7d\x03\xfb\xb1\xef\x90\x5e\xfb\xec\x0d\x9f\x5f\xad\xe6\x59\xc1\x4a\x85\xf8\xda\x17\x7e\xec\x33\xa5\x62\x98\x32\x8d\xe6\x27\x04\xa4\xfa\xad\x24\x69\x89\x2d\x25\x83\xa5\xde\x74\x54\x68\xb4\xd7\x65\x75\x92\x5e\xf6\x39\x57\xc8\x10\x3a\xd0\x5e\x8c\xa1\x6c\x38\xb5\x2f\x53\xd1\xe0\x43\x1b\x5d\xd0\x0b\xd1\x46\xca\x76\x7c\x27\x7a\xa1\x17\x18\x93\xf6\x5b\x76\x99\x4e\xaf\x42\x39\xef\x88\xe8\xb5\x64\x2d\x52\x9e\xc2\x4d\xa1\x65\x84\x95\xb7\x09\x3f\xe0\x84\xe2\xc0\x79\x55\xe3\x27\xe6\x41\xc7\x1d\x4c\x3c\x1e\x3d\x10\x5d\xa3\x81\xcc\xa0\x6c\xf4\xd7\xed\x64\x7e\x48\x66\x62\xb4\x8f\xd8\x85\xae\xa4\x7b\xd7\x14\x0a\x1d\x03\x8d\x90\xb4\x60\xb0\x4e\xac\x40\xf3\x6f\xf3\x82\x18\xc3\x5e\xf6\x63\x9a\xad\x18\xf7\x4f\x49\xf9\x61\x36\xe9\xad\x49\x15\x29\xeb\x15\x65\x71\xb8\x54\x05\x67\xd9\xb7\x5e\x66\xd0\x46\x0f\xee\x08\x2a\x74\x01\x98\xa6\x47\xce\x28\x7a\x4b\x0c\xef\x72\x99\xf5\xd2\x62\xd6\x4b\x67\x33\x7a\xbe\x4d\x17\xbd\x79\xb6\x58\x41\xa9\x9e\x9c\x6a\x3d\x44\xc9\xd6\xa2\xce\x64\x20\xfa\x53\x6b\x02\x48\x36\x8d\x26\xce\x48\xdf\xa8\x5b\xb5\xf7\x8f\x79\xb9\x60\x3b\x84\x5e\x74\xd0\xe8\x73\x72\xef\xbf\xd5\xf7\x2e\xed\xc0\x09\x12\x6c\xa7\xa7\x8b\x83\x83\xb3\x0d\x5c\x29\xcd\x1c\x38\xc4\xde\x7a\x78\x51\xa1\x97\x92\x93\xf2\x43\xb9\x4a\xc6\x62\xbd\x09\x09\x8f\x7e\xbd\x8b\x15\x0c\xaf\xb7\xf5\xac\x73\x73\xd3\xd0\x2b\x30\xcc\x9e\xb8\x2d\x15\x1f\xcc\x46\xf6\x56\x9c\x79\xde\xcd\xa8\x2c\xf0\xa9\x33\x4f\x8a\x9e\x55\x8c\xdc\x2b\xe4\xca\x96\x72\x2b\xd1\x3d\x49\x31\x3a\xae\xf6\xc5\xde\x2f\x30\x46\x38\x76\x31\x21\xe2\x3d\xf0\x74\x8d\x2a\x54\x52\x92\xb2\x07\x17\x74\xb5\xbf\xcf\xaa\x92\xc4\x64\xc0\x55\x95\x9b\x0e\xf3\xe5\x8a\x3b\xa3\xa5\x47\x46\xe5\x35\x8c\x80\x02\x5a\xb0\x93\x08\xd6\xa8\x04\x1a\xf0\xfe\x70\x84\x51\x62\x72\xc6\x57\x62\xeb\x83\xda\xa4\x74\xae\xc6\xaa\xab\xbf\xfd\xfd\xdb\x07\xb2\x4b\x99\x7e\x04\x03\x8c\x06\x7b\x49\xc2\x11\x33\xef\x70\x31\xfe\xba\x13\x9f\xb7\x07\xe7\xee\xe6\x66\x2f\x14\xa6\x02\x69\xac\xe3\xac\xa7\xa2\xc9\xcb\x94\xb8\xfd\x76\x66\x54\x05\x92\x90\xaa\x40\x00\x0b\x63\x26\xbe\x9b\x0e\x42\x8f\x62\xbf\xfe\xc4\xfb\x00\xa9\x3f\xbc\x79\xf7\xe1\xf3\x09\xcb\xd1\x54\x07\x00\x23\xa7\x8c\xc0\x51\x92\x76\xf2\xea\x9f\x4e\x9e\x7f\x7c\xf5\xdc\x2d\xa3\x2e\xaa\x6b\xf2\x49\x4f\xac\x5f\xda\x64\xea\x2f\x9a\x98\xe2\xef\x48\x7d\x1c\x92\x21\x50\x44\xac\xe1\x12\x95\xa5\xe1\xc7\x12\x48\x1e\x62\xfd\x78\x1d\x98\x19\xac\xeb\xef\x65\x35\x63\xce\x0f\x9d\x13\x23\xa3\x07\x94\xfe\x74\xce\xac\xde\xc2\xe2\xf8\x84\xea\x65\x5d\x51\xf2\xf7\x2c\x23\x57\x9b\xa1\x83\xbe\x55\xff\xc5\xb9\x92\xf7\xf7\xef\xab\x79\xe2\x4e\xb8\x7a\x28\xdd\x3a\x28\x4a\xff\x84\xd4\x6d\x7e\xbd\x8b\x8c\x3d\x63\xd1\x40\x24\x43\xc3\x8a\x22\xd1\x2f\xa0\x4a\x2f\x0a\xc5\x38\xcf\xc6\x3a\x5e\x56\x95\x8c\x27\xc5\xb3\x8a\x14\x0f\x1b\x53\x1a\x35\x0f\x29\x74\x15\xdc\xaa\xc7\xd9\x41\xd4\x43\xb9\xe7\xe0\xc0\x3c\x5d\x66\x21\xb8\xd9\xd9\xeb\xb0\xab\xb6\xdc\x32\x95\x41\x05\xbe\xcd\x04\xbe\x6d\xd8\xe7\x17\x42\xc0\x92\xbe\xa0\x9f\x5f\xf4\xa5\x95\x69\xe6\x4b\x44\x1a\x74\xa4\x5d\xa1\xe1\xa9\xf5\xee\x1a\x50\xcc\x6b\x33\x61\xbf\xb6\x68\x3e\xff\x12\x95\xc3\xb5\xfb\x27\x3e\xaa\x35\x04\xa3\x8e\x67\xf9\x77\x09\x02\xd7\x5d\xdd\x23\xf0\xbd\xed\xfb\xd2\x29\x71\xfd\xd4\x16\xe7\x3c\x32\xa9\xad\x0f\xf7\x05\xae\x48\x79\x9a\x9f\x25\xe6\x3d\x04\xbe\xe0\x22\xc5\xb5\xd4\xcf\xb8\x0c\x1d\xf2\x5d\xd6\x3c\xae\xbb\x73\x0b\x4d\xe1\x2e\x6f\x04\xfe\x0b\x98\xae\x58\x58\xda\x72\xad\xd7\xba\x63\xd4\x2d\x8e\xf1\xbf\xc4\x56\x6b\x2d\x06\x21\xd2\xfd\xf1\x5d\xe4\x9f\x70\x6a\x01\xc2\xee\x9d\xfe\x73\x7a\xf8\xef\xa3\xc3\x27\x5f\xce\xee\x01\x77\x5a\x53\xb4\xe5\xdf\xa1\xd7\xf8\xf8\x2e\xa2\x47\x2d\xfe\xab\x02\x21\x9f\x45\xd6\xd2\x3f\x32\x24\x6c\x5b\x02\xd7\xa1\x5e\x74\xab\xfe\xd0\xe3\x1d\xde\x96\xc5\x56\x56\x72\xe2\xb2\xb0\x85\x0a\x66\x21\x15\xef\xf1\x4c\x2b\x39\xea\x70\x89\xf6\xe7\xad\xd4\xef\xd9\xf9\xd7\xbc\xb1\x72\x9c\xeb\xf7\xe6\xe6\x7a\x73\xfb\x15\xfc\xb8\x75\x93\x59\x48\xc8\x1a\x0a\x8c\x17\x28\x86\x02\xdd\x17\x00\x06\x2d\x12\xf4\x65\xa0\xc4\xd7\x94\x3a\x3c\x87\x41\xe1\x3b\x71\x0b\x6f\xd8\xad\x00\x2d\x4e\x38\xfb\xf1\x76\xb9\x83\xed\x7e\x3d\xcc\x87\x03\x8b\xf8\xcf\xa7\xbd\xbf\x57\x7f\x2f\xfe\xde\xfc\xfd\xe2\xec\x1e\xb2\x6c\x4f\xfb\x7b\x87\x87\x37\x28\xc5\xbd\x29\x4a\xd6\x76\xba\x41\x01\xf8\x8d\xfc\x5d\x37\x57\x8b\x6c\x60\x6a\xfd\xfd\xde\x33\xa8\x98\x7b\x26\xf0\x99\x25\x1b\x6e\x36\x2c\xd4\xd7\x1b\xb5\x2b\xd1\x68\x89\x97\x7b\x48\x1e\xc1\x6d\x6e\x25\x12\x19\xe8\xf6\x4a\x58\xd1\x08\x8e\x50\x56\x65\xbe\x14\x41\xce\x8a\x56\x19\x87\x1e\xa3\x53\x47\x11\x12\x9e\x92\x3e\xcd\xe9\xe8\x6c\x7f\xbf\x54\xc9\xee\x3c\xa2\xff\xfb\x7f\xfd\x5f\x40\xd8\xab\x75\xb5\xc5\x5e\x63\x7c\x19\x1c\xce\x8c\x9e\xfa\x71\xe6\xa8\x75\xa1\x67\x11\xb4\x0a\xca\x9a\x0c\x95\xd9\xfb\x23\x31\x1e\xb0\xee\x99\xbb\x50\x36\x99\x94\xef\x00\x77\x77\xb1\x1b\xe4\xe5\xb1\x6c\xc9\xa4\x63\x8b\x82\x30\x78\xd1\x7d\xaf\x14\x88\xc8\xf7\x02\xf8\xf1\xe6\x26\x03\xdc\x88\xcf\xa9\xf0\xc7\x62\x1b\x74\x7b\x0d\xb6\x17\xa8\x08\xb8\x2f\xd0\x8b\x69\x40\x8d\x2f\x84\x66\xef\x62\xce\xe7\xe8\x08\x23\x34\x34\x2c\x6d\x6b\xe8\x07\x26\x7c\xcd\xae\xe8\x1b\xfe\xe2\xe7\x17\x32\xaa\xa3\x14\xfe\x89\x2a\xc5\x7b\xe3\xd0\x38\x76\x54\x7d\x34\xe4\x50\xd5\x6f\x91\x14\x77\xd1\xe5\x05\x68\xed\xb7\xc8\xef\x06\x53\xa5\x6e\x57\x73\x38\xe6\x3d\x14\xfe\xda\x0e\x2c\x95\x02\x5f\x89\x8d\xb4\x70\xe5\x95\xad\xd4\x25\xe0\x52\xdc\x18\x11\xab\x52\xdc\x47\x31\xeb\xa4\x79\x96\x4f\x72\xa0\xe1\xe8\x5e\xc7\xeb\xdc\xbf\xc8\x7f\xea\xde\xfa\x09\x51\xd4\x85\xaf\x28\xe4\xee\x36\x6b\xd8\xd0\xfe\x1e\xe7\x52\x3f\x20\x46\x85\x78\x7e\xb5\xef\xdf\x7f\xe4\xc6\xc3\xed\x50\x33\x9a\xe3\x65\xaf\xcb\xe5\x96\x62\xe1\x7f\x8d\x0e\xb0\x9a\x13\xf3\xd6\x09\xe8\x28\xb5\x70\x8e\x47\x31\x22\x1b\x60\xef\x46\xc6\x74\xb1\x0e\xde\xab\x6b\x27\x12\x0f\x13\xa4\x7f\x4e\x8b\xd9\x22\xab\xad\xc0\x3a\x16\x49\xbb\x48\xd6\xc3\x4f\xaf\x3e\x3c\xff\xf8\xfc\xe4\xfd\x47\xb1\x4a\x80\x78\xc6\x38\xed\x11\xfe\x48\x46\x80\x31\x87\xf8\x63\x0c\x3f\x62\xfc\x71\x14\x6d\xc4\x3c\xb9\x77\x9a\x0c\xe3\xb3\x7b\x97\x62\xe6\x8b\x69\x4a\x91\x4a\xc9\x8c\xb8\x80\x82\x23\x04\xda\x16\x11\xac\xe0\x62\x09\xf9\x4b\x63\x06\xb1\x54\x06\x45\xdf\x00\x2a\x96\x67\x93\x75\xd2\x1c\xf4\x9b\xe3\x55\xbc\x18\x1c\x40\x05\xb1\xc4\x88\x17\xc5\xc1\x5c\xcc\x0f\x12\xf4\x32\x87\x5d\x60\x7f\x1b\x2d\x68\xb9\xd4\xa0\x2e\xae\x12\x56\x6e\x14\xaf\x92\xab\xe3\xc5\x01\x6e\xee\x08\x76\x6f\x62\x74\x9b\x1c\x9d\xc8\xe4\x72\x50\xaa\x78\x92\xaf\x60\x89\x61\xec\x63\x12\xe0\xf4\x28\xc0\x96\x56\xa7\xba\x84\x5a\x46\x95\x0a\xbe\xea\x00\xe5\x83\x2d\x65\x81\x66\xf4\x31\x85\xde\xae\xa7\xc4\x4c\x8f\xf7\x6c\xae\x6b\xe0\x3a\xd1\x0c\xb0\x08\x2f\xf0\xbc\xdb\x0b\x93\x43\xd2\xc1\x0a\xe7\x77\xfa\xe2\x0c\xa6\x68\x2f\x11\x25\xa9\x55\x1a\x68\x3b\xba\xb9\x4d\xcd\xa7\xb7\x48\x02\x7d\x20\x8a\xc7\xa3\xfb\x1d\x84\xd8\xce\x06\x51\xbe\xcf\x28\x20\x5c\xda\xc4\x4a\x38\x98\xfc\x93\x16\x85\x6c\x2a\x52\xdb\x8b\xfc\x9c\x07\x1e\x0d\xb8\x1d\x93\x10\xff\xca\x4d\xb4\x28\x5c\xaf\x89\xba\x9a\xaa\xca\xf8\x33\x3e\x1a\x51\xd4\x9c\x27\x77\x75\xc2\x42\x5a\xf9\x17\x85\x72\x4e\x26\x1d\xf9\x2a\xaf\x64\x25\x2c\x2a\xd2\x86\xbe\x76\xc1\xc6\x0a\x78\x3b\xfc\x42\x9e\x9d\xea\x84\x45\x9c\xc2\xce\x5a\x48\xb1\x5b\xed\x30\x79\xc8\x63\xb1\x21\x25\xd7\x84\xf6\xed\x4f\x40\x78\xf2\x86\x3c\x25\xdf\xa6\x5e\x1e\x8c\x56\x65\xb7\x73\xce\x2c\x1b\xc1\x91\x60\xdf\x44\x76\x09\xf9\x1c\x56\x91\x60\x93\xcf\x3a\x10\xa1\xc5\xb3\x66\xd2\xc0\xc1\x66\xb6\xd6\xad\x02\x49\xd0\xae\xe1\x74\x9d\xf9\x65\xcb\xbc\x09\x0a\x81\xef\x30\x49\x29\x7e\x24\x9b\x55\xbf\x73\x40\x86\x21\x81\x43\xe0\xde\x5c\xe3\xb2\xa8\xf8\x58\x6b\xda\x38\x20\x05\x38\x5e\x2e\x92\x67\x4a\x00\x0a\x83\xc4\xa2\x02\xa5\x6f\x53\xe9\x18\x76\xac\x82\x48\x61\x0e\x5f\x91\x6b\x05\x09\x03\x28\xc9\x4e\x37\x8f\xb6\x94\x12\x56\xb9\xfb\x5b\xcb\x21\xbe\x51\x25\x1f\xdc\x52\x52\x54\xa6\xec\xc3\x5b\xcb\xa2\x55\xb8\x2a\xfd\x68\x87\xd2\x68\xe1\x0f\x94\x17\xc2\x4b\x9d\x8c\x45\x6a\x81\xc4\xf4\x70\x3c\x98\x4c\x9f\xd5\x93\x1a\x80\x22\x3d\xad\x0f\xc7\x67\x96\x28\xa7\x06\xac\x8f\xcd\xb2\x2d\x9f\x69\xd7\x46\xf2\x0b\xb8\xa5\xd6\x6a\xc7\xb8\x8b\xd1\x64\x25\x5b\x54\xbb\x04\x2d\x6d\xdf\x28\x2c\xd0\xda\x2b\x99\x2a\x67\x85\x1f\x6a\xab\x6c\x17\xa9\x47\xdd\xe5\x84\x5b\xf2\xfe\xb6\x92\xe8\xbb\x98\xcb\x4a\x67\x0b\xe8\x60\x77\x2f\xa5\xdb\x71\x11\x5e\xb5\xc5\x64\x41\xab\xb6\x70\x57\x6d\x01\xab\x26\xfb\x91\x0b\x67\x77\x94\x6a\xcc\x8f\xda\x22\xf6\x11\x2b\xbd\x57\x96\x4a\xf9\x5a\xc6\x8e\x0b\x34\xf9\x06\x8a\x10\x2d\x96\xb5\xcd\x8d\x73\xe8\x1c\xec\x91\x5c\x6f\xa4\xe5\xbd\x39\x62\xc7\x6d\x24\xe2\x27\x25\x3e\xa2\x11\xe5\x59\xec\x57\x23\x33\xce\x72\xe0\xa7\x27\xa5\x50\xca\xe9\xf6\x9c\x00\xad\xee\x34\x2b\xdc\xfb\xff\x0f\x4d\xcc\x05\xe1\x96\x4a\xf1\xce\x38\x91\xe6\x6a\x7b\xc1\xb4\x87\x98\xc8\x6b\x01\xe5\x90\x30\x29\xf9\x67\x8f\x78\x03\xf8\xda\xab\x68\x7d\xd1\xde\x83\xc7\x8e\x58\x04\x4b\x18\x9a\x8e\xf5\x28\x2a\x75\x3e\x53\x49\xeb\xf7\x2b\xa0\xf3\xdd\xa6\x30\xc1\x6b\x0d\x92\x2c\xbf\xc1\x92\x0b\xf6\x17\x67\x4c\x76\xf1\x32\xb3\x04\x66\x3b\x2e\x63\x66\x8b\x7b\xfe\x7c\xba\x56\xf1\xf9\x62\xf1\x5b\xf0\xfa\x0c\x80\xc3\x71\x3f\x3b\x0e\x37\x1f\x7b\x60\x22\xd8\xba\x3f\x00\x93\x17\x17\x49\xf7\x56\x3a\x45\xd3\xd9\x4c\x6f\xb1\x0b\xd6\x4e\xb1\x1a\x2d\x9c\x7e\x04\xe6\xd0\x32\xdb\xa0\xf7\xab\x57\x70\x97\x36\xd8\xa2\x97\x70\xd4\x4a\xb9\x0f\x29\x6d\x7d\xc4\x27\x2d\xd9\x54\xdf\x5e\xb5\x3d\x2b\x8f\x1c\xa8\x17\xb8\x4f\xf8\xdf\xcd\x0d\x90\x34\x22\x42\x13\xf2\x8b\xbc\x20\xbd\x69\x63\x14\xa4\xfb\x39\xb6\xf8\x3b\x5c\xd7\xc0\x1d\xcc\xf5\xf7\xf7\xf9\xef\x30\x5d\xce\xd4\xef\x7e\x7b\xee\xd8\xc8\x66\xb0\xe9\x47\x40\x36\x2f\x73\xd4\xde\x0d\x8d\x20\x3b\xce\x68\xaf\xec\x67\xd5\x30\x45\x97\x49\xe6\x1c\x77\x87\x0d\xcc\x57\x80\x24\x56\x40\x61\x5f\x60\x18\x83\x1c\xc0\xdf\xd0\x70\x8d\xad\xf0\xae\xba\x9a\xb8\x0c\x1d\x30\x11\x92\x17\xd8\x43\xd5\x76\x33\xdf\x3d\xa4\x08\x49\x0d\xbe\x99\x67\x70\x9d\x07\x56\x02\xf5\xdd\x6d\x9a\x11\x87\xad\x0e\x5f\x06\x37\x61\xf6\x94\xa9\xcd\x39\x8c\x4b\x9d\xc2\x0c\x09\x30\x16\x3c\xe3\xe9\xa1\x02\x35\x6a\xbe\x1e\x9b\xb2\x88\x8f\xea\xf5\x74\x8a\x6e\xe6\xdd\xd4\x8b\x34\x5f\xac\x2b\x45\xc5\xca\xd4\xc1\xa4\xd5\x4d\x32\x72\x99\x69\xed\x4b\x1f\xe8\x01\xf2\x00\x51\x90\x57\xdb\x63\xb4\x56\xc4\xc9\x03\x4b\xbd\xac\x2f\x07\x71\x1f\x50\x33\xe6\x8c\x8e\x29\x21\x96\xb7\xa5\xa4\x79\xb9\x90\x28\xc9\xf3\xfc\x8a\x37\xd4\x34\x81\x5c\x93\x7c\x44\x97\x9b\x7d\x48\x43\xea\x4d\xaf\xa6\x8b\x2c\x1a\x40\xeb\x79\x42\xb6\xf4\xc7\x39\x37\x5b\x0a\xac\x5c\x97\x8b\x6f\x99\x50\xcd\x0c\x62\x9d\x46\xfa\x59\x2c\xc2\x48\xd1\x28\x54\xf6\x83\x97\xa8\xc5\xeb\x57\xca\xec\x66\x0d\x64\x24\x21\x54\xc4\xbf\x53\x34\x71\xbb\xbc\xcc\xaa\x6c\x06\x24\x85\xf9\x20\x1f\x2b\xe8\x52\x09\xf0\xe9\x34\xa1\x5f\x03\x5a\x90\x7e\x0a\x63\xab\x60\x6c\x7d\x56\x07\xa8\xfb\x53\x54\x94\xa5\x71\x56\x36\x5c\x96\xea\x62\x17\xfa\xd6\x07\x0e\xc5\x2a\x90\x87\x0a\xe0\xec\xa7\xb8\x7c\x70\xa8\xa7\xbc\xe1\x40\x57\x4c\x9d\x4d\x7b\x36\xda\xdf\xc7\xd7\xf4\xa9\x9e\xf6\x02\x5b\x63\x7a\x05\x30\xb5\x1a\xd5\x62\x60\x87\x32\xce\xfb\xda\xb6\x96\x66\x5f\x99\xc9\x02\xfc\x56\xee\xd4\x2b\x39\x75\xc4\x68\x38\x75\x48\xc0\x31\xc1\x45\x2c\xc7\x74\x84\x4e\x29\x02\x63\xaa\x06\x6d\xd9\x08\xc2\x94\x91\x2b\xa1\x1b\x85\xc6\x76\xa3\x60\x50\x51\x89\x82\x57\xb5\xa9\xcd\x69\x79\x36\xa0\x33\xe5\x20\x2e\x28\x85\xf6\x35\xd0\xe6\x06\x63\xbc\xea\xbe\x6a\x32\x02\x92\x9e\x7c\x15\xff\x66\xcd\xc9\x3a\x7e\x6b\x5d\x54\xc2\xa6\x2a\xce\x53\x1b\xb5\xeb\x5a\xe7\x48\xbb\x18\xc2\xf5\x60\x78\x37\x2d\x63\xd4\xdd\x6b\x87\x23\x31\xc8\x73\xc0\xea\x1e\x16\xf4\xbf\x2b\x9b\x5e\xaa\xdf\xa4\x22\xb2\x12\x1b\xed\xc9\xb3\xfe\xe5\xcb\xbb\x0f\xef\xbf\x7c\xe9\xaa\x25\x47\x1e\xc9\x33\x2d\x4b\x27\x63\xf5\xaa\x00\x30\xb0\x66\xd7\x35\x5c\x00\xd7\xd1\x5c\x39\x0d\x5a\x54\xf2\xd5\x7f\xad\x10\x48\x17\xde\x1a\x09\x89\x4c\x42\x25\xca\xe3\x12\x31\x9b\xb6\x30\xd3\x2b\x8a\x03\xf0\x9d\xf7\xf6\xdd\xfb\x28\xbc\x4e\x8e\x1c\xf4\x6e\xab\xa7\x40\x07\xcd\xf0\x24\x12\x40\xd9\xba\x86\x54\x22\x58\x80\xcd\xc1\x35\x96\x70\xac\x80\x56\xe8\x91\x33\x49\x70\x1a\xd1\xc1\x8a\xce\x3a\x49\x0d\x02\x4c\x85\xef\xd0\xde\x0b\xfd\xdb\x38\x58\xd0\xae\x59\x2a\x04\x91\xd9\x38\x20\xd3\xc7\x96\x32\x2c\x24\xa6\x93\x11\x89\x49\x0e\x8a\xa4\x73\xad\x07\x53\x25\xda\x14\xb3\x24\x74\x63\xa2\xdf\x87\xe5\x32\x9b\xe5\x78\x73\x04\xe6\x62\xe7\xa3\x5c\x33\x86\x84\x93\x7c\x99\x95\xeb\x86\xa6\x24\xfb\xe3\x76\xb5\x48\x0b\x08\xa7\xe8\x47\x24\x90\xcc\x5e\xb4\x18\x7e\xdd\x76\xb8\x2e\x96\x02\xd8\x5b\xac\xb3\xb8\x10\xdf\x2b\x0e\x47\x8d\x60\x36\x25\x3f\xcd\xeb\x8a\xbe\x2b\x54\x89\x19\x63\x08\x26\x5e\x93\xe5\xe0\xda\xef\xc9\xb1\xd8\x4e\x0a\x81\x0a\xc3\x36\x55\xe5\xd3\x02\x9e\x6c\xa7\xce\x16\x17\xda\xdd\x3c\x0a\x79\xe4\x61\x96\x74\x80\x50\xde\x5b\xae\x81\x82\x30\x1e\x1c\x48\x98\xc1\xe7\x2b\xa3\x0f\x81\xae\xf7\xa8\x7e\x15\xc3\x3f\xf4\x28\x21\x2a\xd5\x96\x20\x52\x23\xe0\xd6\x9a\xdf\xf4\xe1\x0e\x5d\xc9\xa2\xa8\x25\x9d\x69\xae\x33\xa3\xd1\x0d\x04\x2a\x44\x63\xdb\x80\xc7\xfb\xfc\x60\xf8\x2d\x59\xd0\xea\x5b\xc7\x2a\x12\x53\xb1\x37\xd6\x44\xf8\xd4\x72\x26\xfd\x4d\x00\x34\x8a\x48\x62\x07\x94\x45\xa3\xd1\xf1\xa2\x3f\x45\x4d\x2c\x3a\x2b\x91\x03\x8d\xc6\x3e\x67\x62\x64\xea\x21\x85\xa0\x31\x69\xd8\xc8\x76\x81\x28\xa3\xe3\x6e\x59\xd3\x4b\xf6\x26\x74\x92\x83\xe7\xbb\xd8\xe1\x7c\x23\x95\x06\x00\xa1\xc7\x4f\x83\x12\x01\x98\x56\xb8\xe7\x3f\x78\x3c\x85\x33\x1e\xd8\xb6\x5b\xd6\x32\x3a\xe5\x85\x64\xf9\xc0\x19\x74\x36\x57\x0f\x30\xc7\x4d\x80\x38\xa2\x0e\xe1\x12\x65\x8f\x28\x83\x78\x44\x6b\xae\x38\x2c\x7d\x4f\x9e\x9e\x0d\xfc\xe5\xa7\x43\x18\x9e\x6e\x11\x9c\x6e\xb5\xc3\x74\xa5\xc5\xb0\x92\x19\xe6\xf2\x81\xa8\x44\xa7\x12\xa3\x49\x0a\x6b\x9c\x79\xfe\x88\x72\x64\x29\x1a\x71\x70\x50\x23\xfb\xb7\xbf\x5f\x00\xf2\xa5\x8b\xdb\x6c\x22\x59\xfc\xfd\x87\xae\xda\xff\x8e\xa5\x09\x4d\x1e\x5d\x4a\xe8\xc9\x4e\xf1\x7f\x4b\x95\x24\x84\xa9\x2f\x17\xe5\x79\xba\x38\xe6\x3f\x71\x18\x97\x2f\x2e\x8e\xf1\xbf\x60\xae\x54\x78\xe7\x3f\x31\xa0\x66\xc5\x08\xb6\xb4\x05\x0c\xeb\x46\x4a\x0e\x54\xc8\x7b\x51\xc6\xf3\x52\xc8\xf7\xf9\xd9\x27\x40\x32\x18\x0b\xec\x4c\xe8\xa4\xe7\x54\x52\xa6\x51\xac\x33\x07\xf3\xa2\xd9\x87\x57\x5d\x51\x7c\x03\x3f\x7d\x55\xae\xfa\xfc\x88\x32\xf1\x9b\x6f\xd7\x51\x19\x54\x49\x0f\xbe\xf5\x36\x6c\x3d\x5c\xac\x65\x78\x79\xf9\x44\x89\xce\x3b\xe0\x73\xa8\x34\xbf\xfe\x07\x7c\xbf\xc0\xb6\x4b\xd4\x0c\xb5\x21\x51\x4b\xce\xc9\xfd\x17\xab\x8c\x3d\xed\x67\xec\xd1\xa5\xca\x00\x5a\xe0\xe4\xa9\x11\x1e\x1c\x00\xc6\x48\x4c\xe6\x69\x71\x26\xf0\x5a\x52\xca\x61\xf8\xdb\xd2\x0f\x73\xf4\x26\x2c\x35\x25\xad\x36\xc7\x4f\x49\x52\x5f\x22\x63\x47\x7d\x25\x10\x06\x62\x9d\xe4\x7d\xa4\xe9\x20\x29\x49\x75\xf9\x29\x96\x5f\x73\xf9\x45\xb2\x3e\x9d\x9e\x61\x89\x03\xbc\x4d\x56\x70\xc1\xa2\x83\x2d\x60\x08\xce\x92\x85\x7e\x50\x6a\xec\x07\xa5\xeb\x79\x5a\x2b\xc1\x44\xd8\x43\x23\xcb\x88\x89\x76\x67\x49\x5b\xbd\x3e\x67\xc5\x10\xdc\x0e\x6f\x29\x4a\x92\x2c\x55\x00\x1c\xda\x79\x5b\xab\x0a\x10\xf7\xf2\x39\x04\xaf\xfb\x81\x68\xf0\x91\xf9\xa9\x96\x41\xe1\xf3\x03\x3e\xfb\x25\xb8\x7a\x02\x59\xcd\x0c\x7d\xda\x5a\xe3\x44\x7d\x1a\xeb\x13\xdf\xf0\xb4\x7a\x83\x7a\x49\xd8\x08\xee\xe2\xa4\x7c\x9b\x16\x57\x01\x9f\xd9\xf8\xb2\xeb\x2e\x7a\xa3\x25\x8f\x74\x5c\xcf\xd3\xe9\x57\x72\x00\x54\xa1\x4b\x1d\xa2\x0c\xcb\x33\xa0\x79\xe9\x57\x75\x76\x5c\xc5\xf2\xfa\x4e\xa5\xd4\x5a\x75\xd8\x27\xef\x8a\x29\x13\x93\xe5\x41\x24\xe3\x7e\x44\x67\x2c\xc8\x3c\x4d\x9d\x24\xa4\xf2\xc4\x37\x7c\x92\x04\x20\xe7\x29\x01\x49\x17\x74\xd3\x2b\x65\x01\xc7\x91\x9a\x79\x2f\xaf\x7b\x05\x62\x24\x58\xc7\x5e\x53\xf6\x78\x04\xf8\x2b\x6f\x10\x59\x44\xc0\x9c\xe7\xf5\x6b\xdd\x94\x1c\x22\x3a\x30\x70\x96\xd3\xf9\x64\xd6\xc1\xea\x64\x9a\x16\xd8\x89\x69\x1c\x0b\xf4\xcc\x0e\xf6\xce\xb3\x29\x5a\x5d\xf7\x00\x13\xa1\x59\xdc\x7a\x81\xa0\x58\x96\xab\x48\xae\x50\x8c\x6a\x9e\x50\x05\x68\xec\x1a\xe6\x06\x08\x54\xb6\xb5\xcc\x9a\x79\x89\x96\xe0\x6a\xe9\x3c\xaf\xa9\x5a\x1e\x21\x52\xe5\xad\xd2\x81\xa4\x40\x12\xc2\xa3\x16\xdf\x0c\x09\x7f\xbf\x91\x0f\x67\xad\x45\x26\xb5\x37\x26\x0d\x33\x20\x34\xdf\xb0\x8f\x4e\x69\x63\x8c\x9c\x01\xdd\x79\x54\x9a\x5a\x00\x78\x84\x2d\x64\xb9\xa1\x7d\x8c\x15\x69\x87\x6e\x3e\x67\xd9\x8f\xf7\x17\x70\x5a\x27\xa6\xf3\x43\xa2\x98\x44\x74\x52\xa1\xd1\x02\xac\x1f\x0b\x14\xd5\x22\xa4\x0b\xc0\x41\xb3\xab\xde\x65\x59\x64\x3d\x74\x2d\xd0\x73\x26\x44\xc5\xf6\xd0\x7f\xd3\xb0\x5e\x91\xff\xb4\x4c\x00\x21\x57\x62\x30\x1c\x74\x47\x8f\xd6\x81\xb9\x30\xbb\x11\x63\x14\x19\xe6\x77\x00\x67\xa4\x1c\x52\x46\x4f\xd9\x59\x62\xfb\x90\x57\xe4\xe7\xb0\x6b\x3d\x9f\x96\xb6\x1b\x51\x14\x39\x27\x25\x29\xf2\x5a\x07\x39\xb1\x9d\x43\x52\x08\x9a\x3e\x5a\xd4\x98\x55\x20\x5f\xa2\x6a\x85\x9a\x81\x88\x5e\x03\x73\x19\x5a\x91\x2d\x8b\xe0\x9c\x70\x6f\x66\x8e\xf7\x54\x4b\xca\x26\x9a\xae\x79\x01\x35\xae\xef\x19\xd4\x03\x6b\x8f\x5a\xe5\xe3\xbb\xff\xe1\xf8\x67\x86\x0c\x3c\x9f\x0f\x5c\xb1\x77\x27\x93\xe3\x6f\x0d\x5f\x96\xb0\x9f\x95\xe8\xac\x13\x8c\x2a\xc7\xde\x91\xbe\x44\xef\x7e\xa6\xed\x81\x42\x62\xad\x1c\xb8\x69\x4b\xaf\x76\xc9\x72\xcb\xe3\xd2\x93\xb5\x20\x9d\xc0\x02\xaa\xca\x11\x50\xc5\x8d\x45\xc8\x94\x88\xb8\xf0\x4e\x3d\x01\x46\x07\x6d\x38\x63\xa0\x8f\xd0\x95\x19\x6c\x13\x26\xff\x06\x50\x2d\x53\x49\x6d\x4e\x26\xbf\xa0\x6b\x01\x53\x91\x6c\xe6\xb4\x4f\x24\xc2\xc5\x34\x29\xcc\x1d\x48\x0d\x4c\xbe\xb2\xe3\xa3\x11\x79\x7d\xe7\xfb\x3c\x3e\x1a\x93\x02\xc3\x93\x0e\x25\xea\xd0\xd5\xaf\x70\xd9\x5b\x42\x38\xb5\xab\xa3\x04\xbf\x20\x73\xd6\xbf\x0e\x7a\xf6\xab\x86\x6d\x30\x23\xe2\x8e\x06\xe8\x37\x1c\x03\x45\x12\x18\x6a\x4b\xdb\xa9\x3d\x54\xfb\x4e\x5e\x55\x19\x0a\xf8\x6d\x68\x06\x68\x9f\x97\xeb\xc5\xcc\x4f\x37\x4f\x85\x0c\x89\x6d\xd8\xe2\x5b\xc7\x37\xd3\x2a\x50\xde\xc6\x7b\x4c\x3a\x4a\xa2\x72\x78\x3f\x3a\x30\x19\x3f\x32\xd8\xaf\x1c\x8c\x49\xe9\x0d\xe5\xb7\xf4\x3c\x5b\xe0\x23\xb6\x3d\x1a\x5d\xc7\x7b\xc2\xad\xdc\x3a\x18\xc3\x9c\x65\x2e\x81\x9b\x59\xf9\x88\x60\xb9\x1b\x13\x55\x1a\x6f\x44\xb8\x49\xf8\xbc\x33\x8b\x06\xcf\x92\x91\xbc\x7a\xdb\xc5\x2e\xe8\xa0\x52\x19\x12\xf6\x2a\xae\xce\x98\x71\xfd\xf2\x61\x7d\x0e\x6b\x36\x87\x1b\x6e\xb9\xae\x9b\xde\x3c\x85\xe3\x6c\x35\x4f\x36\x63\xaa\x9d\x1e\xf5\xd0\x5b\xa9\x2a\xf5\x2f\x83\x49\xd6\x96\x50\x6a\xf4\xa7\x9b\x21\x46\x11\xe8\x41\x25\x54\x0a\x17\xe7\x5e\x98\xa9\x94\x1b\xf9\xbc\x98\x7d\x68\x2d\x91\x1b\x6a\x4a\x6f\x96\xda\x64\x61\xd1\x21\xf6\x69\x66\x55\x7e\x7f\x01\xa2\x57\x3f\x56\xc0\x41\x01\x3a\x33\x1c\x4d\x8f\x9b\xe4\x5b\x5a\x6e\x51\xef\x7c\xdd\xc0\xed\xd4\xf4\x50\x4f\x4e\x62\x27\xe3\xfe\x0e\x31\x8d\x82\x23\x13\x46\xb4\x50\x32\x35\x65\x07\x00\xd8\x42\x20\x57\x24\x45\xab\x6d\xb9\x88\x69\x51\xa2\x6b\x79\x08\x54\xe3\x38\x3d\xe8\x3e\x4b\x8c\xfd\x20\x0a\x1f\x48\x51\x4d\xd6\x44\xff\xaf\x4d\x6c\x91\x9e\xf2\x76\x37\x27\xc7\x6d\x4c\x02\x8f\x02\x59\xfc\xdb\x82\xef\xcc\x8c\xf9\x79\x7d\x55\x4c\x6f\x1f\xf8\x84\x65\x42\x27\xf9\xf4\xab\x8b\x51\x65\x33\x7a\xb5\x78\xb7\x65\x6a\x6b\xaf\xed\x30\x68\xc2\xb2\x9f\x11\xd5\x1f\x7c\x32\xaa\x3f\xfe\x64\x68\x32\x9a\x38\x37\x39\x35\x8f\x11\x57\xb7\x94\x6e\xb6\x05\xb7\x28\x3b\xed\xa3\x97\x4d\xb8\x90\xf9\x18\xe5\xa8\x82\x4d\xdd\x6e\x2b\x5c\x51\x61\x3c\x9e\xd6\xbe\x59\xfe\xa6\x37\x96\x29\x8a\xbc\x67\x3c\x74\xdd\x52\x8d\x6b\xb3\xcd\x47\xa3\x2d\xaa\x6d\x6e\xba\x22\x44\x0a\x8b\xc9\x90\x4e\xec\x03\x62\xf5\x0a\x5f\x5a\x43\xea\xd8\x19\x3b\xac\x27\x73\x01\x34\x1a\x31\x0e\x08\xe5\x80\x5a\x8a\x72\x8e\x59\x14\xec\xbe\xb9\x0f\xdb\x77\x8e\x5b\x53\x8a\x3f\x3d\x0a\x22\xe0\xcc\xb6\xda\x4e\x8c\x1c\xdb\x87\xb5\x4d\x90\xc0\xe5\xca\x12\x9e\x3e\xb2\x7a\xa7\x81\x12\x67\x03\x74\xf0\x6e\x7c\xee\xbe\xcc\x67\x6f\x7d\x87\xbb\x95\xba\xc0\xf9\xe2\x18\x7a\x77\xb2\x02\x47\xca\xcd\x6d\xf4\x21\x65\xc1\x8d\x4f\x94\xa1\xcc\x5e\x25\xf7\xbd\x21\x9e\x0d\x50\xe0\xef\xb0\x7b\x68\xf7\xb4\x09\xbb\x05\xb6\x06\x83\xde\xeb\x87\xa1\x42\x0a\x06\x79\x8b\x50\x7d\xb1\x45\x40\x1c\x8d\x5a\xca\x8c\x3f\xbb\xb7\xb6\x3f\xcd\xa4\x72\x69\x4b\x40\x9e\xa5\xd8\xb6\xe9\x14\x5c\xf5\x16\xea\xd3\x2f\x63\x4c\xd4\x4a\x3b\xa8\x4b\x7b\xab\x07\x92\x44\xb9\xb5\x98\xba\x62\x8e\xdd\xad\x29\x18\x56\x24\xe8\xfe\x21\x40\x93\x33\xd0\xa4\xbe\xce\xa6\x3f\xc1\xdc\x80\x8b\x1c\x3d\x5b\xbc\x69\x25\x38\x3d\x2b\x4c\x9f\xe4\x5d\xd0\x85\x26\x15\x9b\x36\x78\xa5\xff\xe1\xe0\xb5\xcd\x98\xc9\x23\xa5\x15\xb4\x49\x93\xb0\xbf\x64\xd9\x8a\x43\x1f\x29\xa2\x75\x6c\x53\xaa\xe3\x8d\xb7\x7a\x19\x4a\x73\x28\x7c\x65\x5e\xf3\x23\x91\x72\x3b\x75\xcd\xf1\x2b\xc8\xfd\x76\xb6\x19\xb8\x41\x3e\xab\x21\x8b\xff\xd4\xf6\x90\x25\x3a\x09\xd9\xaa\xa1\xbe\xad\x64\x26\xca\xdb\x5a\xb4\xce\x0b\x16\x62\x00\x4d\x5a\x55\xf9\x2c\xeb\x3d\xff\xf0\x46\x8a\x1f\xd0\x72\x1f\xe5\x13\x45\xef\x63\x76\xb1\x58\xff\x70\x7b\x1a\xf6\x3e\xd7\xe8\x3e\xa0\x6c\xe8\x3a\xe4\x1a\x05\x8c\xb1\x57\x56\xa6\xb5\x1c\x5a\xd6\xf5\xfd\xf1\x90\xa9\x29\x30\x43\xe8\x64\x40\x4d\xaa\xd6\xb6\x37\x30\x8d\x3a\x3c\x8d\xfa\xae\xd3\xa8\x79\x1a\xa9\x7c\x90\xc6\xcb\x17\x7e\xfc\xc1\x33\x30\x82\xce\xc4\x15\x88\x62\x08\x52\xbc\x69\x3f\x66\xf5\x7a\x41\x16\xbe\xa1\x92\x8a\x36\x3b\xb5\xe8\x09\xa1\x68\x89\x33\xcb\x87\xf6\x3a\xc1\x48\x37\xd7\x9b\xc9\xfa\xa9\x55\x5b\x72\xeb\x6b\x65\x7b\xb0\xb0\x05\xaf\xeb\xb3\xc9\xf4\x74\x71\x96\xa4\xfd\x05\x1b\x5d\xac\x2c\xe6\xce\xd0\x74\x71\xc4\x2b\x14\x09\x49\xf9\xd1\x43\x41\xe1\x28\x56\x61\xc0\x20\x86\x83\x98\xd5\x30\xfd\x25\x11\x1e\x44\xa2\x6d\x99\xfb\x04\x79\x7a\x31\xc4\xe5\x38\x8e\x24\x19\x12\xc5\x91\x4d\x90\x44\x67\x92\x24\xb9\xb0\x59\x6c\x43\x3f\xcb\x71\x5f\x88\xa9\x58\xc1\x69\x6b\x49\xc1\x51\xc0\x73\x01\x7d\x06\xac\x03\xe8\x4c\x02\x27\x2a\x4d\x30\xb7\x9c\xfb\xd6\xfb\xc0\xdd\xcf\x3d\x7d\x2d\xf3\x1f\x30\x41\x8a\x8f\xd8\x85\x06\xa4\xb6\x3e\x92\x2f\x21\x2e\xdc\x91\x4a\x19\xe5\x2c\x63\xb6\x3d\xd2\x0a\xf0\xae\x08\x50\xe9\x64\xc8\xbd\x4c\x02\x7b\xe9\xd1\xf4\x49\xc4\x81\xed\x22\x51\x2b\x4e\xc0\x84\x53\xf2\x24\x24\x3a\x5d\x31\x0b\xf8\x5b\x05\xad\x32\xb2\xaf\x7a\xc0\x8f\xba\x9e\xd8\xdb\x2e\xe0\xc7\xe2\x71\x90\x3c\xca\xa8\x49\x6c\x3c\xd8\x48\x04\x69\xce\x01\xa3\x3f\x7a\x31\xb1\xb1\x5f\x0a\xe0\x4e\x0a\x9f\x2d\xbc\xb1\x46\x3d\x3e\xff\x42\x83\xd4\xc1\x1d\xd1\xc9\xda\xc1\x8a\xf6\x00\xfe\x08\x94\x72\x4f\xe5\x78\x03\x0d\x61\xcb\xa9\xc1\x96\xe9\xe9\xb4\x63\xda\xd3\xe0\xb4\xa7\x77\x9e\xf6\x94\xa7\x5d\xe3\x7c\xff\x50\x24\xba\xcb\x8c\x33\x7a\x97\x10\xfa\xf8\x5b\xea\x1e\xa2\x35\xb9\x30\x5a\xb2\x37\x4a\x48\x86\x7d\xc1\x4a\x39\x46\x59\xd7\x7b\x87\x43\x64\xb2\x18\x88\xc5\x26\x80\x40\xec\x13\x0b\x68\x64\xd4\x46\x2a\x7c\xfa\xe1\xeb\x49\x00\xc5\x04\x5f\x17\x1d\xd4\xc9\x88\xc1\x49\x8a\x06\x6d\x92\xac\x43\x92\x07\x05\xfd\x45\xe0\x92\x7e\x2a\x15\xb5\x17\x47\x06\x13\xb4\x52\xa8\x88\x0c\x53\x40\xc3\x71\x42\x2c\xc8\x27\x5f\x5d\x84\x6a\xda\x25\x28\x21\x92\x6e\xa4\x0a\x54\x41\xe2\x4c\xfe\xb0\x33\x5e\x53\x08\x02\x27\x9b\x93\xdc\x89\x23\x51\xe7\x4d\x1b\x93\xa8\x90\x42\x1d\xca\x8e\x8a\xbf\x9c\x2c\xc4\x2a\x6e\x36\xa6\x44\x4a\x86\xe3\x3c\x8a\xa2\x4a\x54\x3e\xb5\x9e\x44\x27\xc5\xd0\x16\xee\x62\x44\xf1\xc5\x22\x31\x22\x5e\xce\x96\x42\xde\xc4\x12\xf2\x72\x06\x8b\x74\x13\x4b\xa4\x2b\x33\x58\xfe\x9b\x28\xf9\xaf\xd2\x2d\xb0\x39\x17\x77\x0f\xea\xdd\xdf\x4b\x73\x7e\x2f\x4d\xf1\x9d\x41\x51\x97\xf9\xe0\xb8\x8a\xf3\x49\x73\x9a\x9e\x25\x6e\xc3\xa8\x92\xa0\x9f\x44\x61\x74\xb5\xf4\x73\xab\xd4\xaf\x8d\x0a\x49\x50\x5e\xeb\x5e\x32\x89\x6a\x42\x4a\x3b\x6e\xaf\xad\x0a\x7a\x15\x65\x84\x9a\xdb\xeb\x3b\xc2\x15\x6e\x45\xc9\x9d\x6e\xaf\xac\x4b\x52\xbd\x2f\x5f\xbe\xc2\x89\x77\x2e\x76\x75\x03\x5a\xea\x66\x88\x08\x6e\x6e\x50\xfb\xa8\x5c\x64\xc3\x8c\x51\x69\x47\x39\x7e\x96\xfc\x06\xb0\x83\xb7\xdf\xb0\xf7\xea\xd3\xc3\x5e\x3d\xcf\x97\xbd\x2a\xfb\xb7\x75\x5e\x65\xb3\x61\x6f\xde\x34\xab\x3a\xbe\x77\xef\x32\x6f\xe6\xeb\x73\xe4\x5d\xee\xd5\xab\x32\xff\x9a\xdd\xab\x08\x4d\xfe\x6b\xfd\x5f\xb2\xfa\xa1\x32\xed\x73\xd1\x03\xe0\x26\xf2\x63\xe6\x20\xaa\x2e\x59\xbc\x7b\x76\x20\x95\xbc\xa3\xb5\xd0\x03\x64\x90\x2b\x7a\x07\x21\x40\x22\x21\x35\x75\x86\x01\xc9\x8d\x45\xeb\xd0\x42\xea\x91\xf0\x11\x05\x24\xde\x17\x1e\x6e\x80\x34\x1a\xb7\xfb\xae\xa1\x0f\x2f\x24\xfc\x2a\xfc\xe3\x0a\x89\x8f\x03\x78\xf5\x51\x1b\xaf\x3a\xea\xdc\xb6\x96\x9c\x27\x54\xc4\xe7\xfc\xc2\x25\xa3\x80\x90\x2b\x8f\xcd\xeb\x5c\x36\x88\x0f\xd9\xa8\x7f\xed\x3e\x63\xe6\xed\x67\x4c\x9c\xcb\xce\x8f\x98\x48\xc7\xf9\x84\x10\x1c\x59\x7c\x9b\x52\xcf\x9b\x39\x3a\x4a\xf0\x2c\xb5\x33\x9b\x94\xe2\x13\x37\xb3\xec\xad\xb2\x21\x1b\xf9\xbe\xbf\xf8\xcd\xa2\xb8\x90\x21\xa9\x2e\xeb\x5b\xcb\x39\xd6\xde\x96\x4d\xb9\xb7\x6a\x45\x52\x7b\xa1\x5f\x48\x6b\xb7\x09\x0c\x0d\xc5\x44\xd2\xb4\x0d\x5f\x42\x2b\xd8\xff\xcb\x2b\x36\x5b\x53\xe8\x30\x6e\x11\x25\x8c\x31\x79\x39\x99\x1f\xd2\x0f\xeb\xca\x78\xb4\xa7\x15\x93\x7b\xcd\x77\x34\xe2\x87\xb3\x4c\x8d\x12\x4e\x8e\x1b\x9a\x2f\x19\x73\x58\x66\x6d\x84\x67\x4d\x1e\x5f\xf6\x85\xf4\x45\xd1\x31\x7a\x8a\x30\xaa\x5b\xa3\x16\xc8\x43\x82\x9a\xcb\x31\x7a\xc9\x29\x50\xf9\xc9\xde\xaa\xd4\x0d\x9e\x87\x5a\x1d\xc1\x15\x57\x2a\x1e\x7b\xa1\x6d\x45\xee\x5d\xba\x8a\xcb\xb4\x1e\x86\x92\xde\x6a\x33\x5a\xb9\xb7\xf8\x0e\x9e\x29\x03\xfb\xa0\x9f\x03\x65\x62\xaf\xb8\x99\x69\xe8\xc2\x5e\xe0\x3b\x3a\x3d\x41\x46\xe6\xee\x8a\x04\xdd\x68\x9c\x24\xef\xb9\x48\xe0\x4a\x73\x92\xba\x19\x23\x91\xa2\xe3\x7b\x73\xb7\x45\x1b\x40\xb0\xad\xfb\x34\xa4\x4d\xec\x41\x58\x13\x80\x30\xa5\xd9\xd9\xbf\x46\xce\xc3\x0f\xb7\x7b\xba\x80\xfd\x39\xb3\x5f\x35\x1a\xc5\x80\xb8\xcc\x26\xca\x95\xf0\xd5\xad\x08\x69\x3f\xdd\x32\x34\x83\x02\x7c\x0b\xdc\xa7\x80\xe0\x24\x2d\xcd\x0b\xda\x4b\x19\x7e\x01\xf6\xe7\x3d\x8c\x06\xd4\x6b\x80\xd5\xea\x1d\x59\xda\x22\xf5\x9e\xf1\x21\x06\x37\x75\x6b\xc6\x68\xe8\xcb\x3a\x5e\xb0\x2d\xca\xb7\x0a\xfa\xa8\x0e\x00\x52\xbc\x10\x0a\x42\x58\x2d\x07\x79\x80\xa9\x50\x40\xc2\xf6\x42\x0a\x66\x51\x31\xe2\x02\x2d\xe6\x98\x55\x1b\x4d\x16\xd2\xd6\x79\x7d\x9b\x9a\x48\x8a\x30\x39\x68\xd5\xbb\x90\x5a\x16\x68\x17\x2d\x9f\x23\xf2\x7e\x83\xdc\x3a\x69\x88\x98\x57\x86\xfe\x0a\xa3\xcd\x5d\x5b\x3a\x1a\x29\xdd\xf9\x4d\xb9\x02\x3a\xa8\x10\x17\x52\xa5\x24\xc0\xdd\x76\x6a\x5c\xc9\x5d\x2e\xd0\x4b\xa9\xa4\xda\x43\x17\x8d\x77\x69\x6c\x7b\x32\x97\x0c\x7e\x97\xdc\x58\xeb\x76\x5f\x6f\x95\xab\x6a\x63\x0f\x24\xcb\xda\x62\x55\xc9\xc3\x9f\x96\xe8\x43\xa6\x95\x8d\x66\x1f\xd7\xa6\x08\x33\x6e\x08\x61\xbf\xc8\x47\x28\x66\xbf\x56\xf2\x5d\xa4\xf7\x4b\x74\x50\x1e\x44\xbf\xf4\xbe\xcf\xb3\xa2\xb7\x26\xdd\x22\xc9\x62\xa9\x1b\x74\x2f\x9a\xc8\xc6\x82\xbd\x6d\x7c\x51\x6b\x43\x2f\xfb\xb7\x09\x5b\x25\x17\x1c\x50\x0c\x68\x09\x5b\x69\xd9\xb7\x3d\xff\x6f\x5b\xf6\xbb\x2d\x79\xb3\x7d\xc9\x9b\xf0\x92\x37\xd6\x92\x37\x3b\x2d\x79\xb3\x7d\xc9\x91\x68\x51\xcb\xde\x84\x96\xbd\xf1\x96\x9d\x84\x1f\xd9\x7f\xc0\xb2\xb7\x9e\xf1\xb6\x6a\x5d\x04\xb8\x0c\x42\xb9\xa7\x67\x42\xc9\xb4\xe0\xa7\x25\xd4\x3a\x3d\xdb\x58\x2e\x06\x99\x50\x61\xce\xca\x78\x9d\xcb\x86\x4b\xa4\x3a\x6b\xd4\xb1\xe3\x5f\x3a\x74\x90\xdd\x9f\xe6\xf7\x2b\xba\xd0\xf0\xad\xd3\x4a\xca\x06\xc2\x0e\x61\xd7\x0c\xda\x6d\x90\x3a\x47\xe0\xd5\x10\x5f\x19\x19\x4d\xe1\xf3\x21\xb6\x5b\x6d\xac\xf8\x36\x0d\xc9\xb3\x94\x1d\xd7\x98\x04\x2b\x98\xd2\xd6\x6d\xd3\x08\x7a\x22\xeb\xb4\x86\xd0\x18\xad\x21\x29\x55\x93\x26\xb6\x68\x90\xad\x5f\xf3\x9d\xae\x64\x62\xc8\x1e\x56\x57\x00\x62\x67\x3d\xcd\xfa\xa1\x8d\xf4\x75\x03\x64\x5d\xfd\xc2\x57\x1c\x67\x31\x7a\x95\xe5\x37\x53\xc6\xb1\xb6\x3a\x13\x0c\xcb\x52\x0d\x70\x46\x66\xd2\xb7\x2d\x85\x54\xbe\x71\x9a\xa9\xcb\x65\x16\x88\x2d\xb8\xd7\xb9\x36\xb7\x6d\x2d\x80\x07\x59\x81\x1a\xa7\x1d\xa4\x59\x8c\xfa\xf5\xe8\x94\x63\x24\x77\x35\xf0\x90\x0d\xff\xb7\x99\x04\xe5\x7a\x4e\x31\xc8\x01\xb8\xf7\xcc\x60\xed\x47\x6a\x8a\x4d\x68\x1c\xe3\xa0\xd3\xcc\xbd\x0c\xe9\x1d\x06\xd6\x96\x73\x13\x4b\x39\x17\xda\xb3\x75\x8a\xcb\x64\x0c\x4c\x47\xdb\xa7\xc7\xb3\x92\x2c\x03\xaf\x6d\x97\xa1\xe5\x99\xed\x60\x8c\x1e\xc2\x1b\xe3\x2e\x18\x83\xd8\xd9\x42\xdb\x00\x02\x0d\xb9\xd7\xc2\x4a\x0e\x07\x0f\x78\x81\x84\xc4\x52\x92\x7c\x9f\x44\x16\x6d\x96\x1a\x1a\x35\x86\x52\xe4\xa7\x08\x5b\x32\xda\xd6\xc1\x30\x7b\x14\x27\xeb\x79\xd3\x1f\x0d\xdc\x08\xcd\x07\x2a\x28\xee\x58\xb6\x62\xf4\x8e\x43\xd3\x40\xb7\xcc\x8e\x66\x77\x46\xd5\x4a\x7f\x27\x1d\xb5\x03\xb4\x75\x67\xbe\x2b\xb3\xf9\xae\xe2\x14\x85\x25\x67\x14\x0b\xde\xc4\xa0\x15\x46\x30\x01\xeb\xc1\x51\x7a\x0e\xa5\x2e\xcf\x61\x59\x2c\xae\x2c\x01\x58\x4b\xd4\xe1\xda\xe1\xe8\x96\xe4\x28\x2d\x4d\x9d\xe0\xdc\x02\xbe\x87\xad\xb0\xc3\x41\x4f\xc4\x3c\x9d\x8d\x51\xd8\x0c\x78\x07\x94\xe2\x5f\xe6\xb2\x30\xe0\x0e\x29\x17\x3a\x3b\x0d\x5c\x3e\xf0\xef\xa1\xc9\x42\xce\x7d\x3a\x49\xdb\xfd\x6c\xea\x8b\x85\x45\x17\xc4\xe8\xa2\xd3\xf8\x45\x39\x4b\xeb\xb9\xf4\x01\x3f\xbc\x57\x97\xd3\xaf\x19\xba\x7d\x17\xa5\x27\x8b\xaa\xfb\xa7\xc4\x41\x44\x22\x5a\xa5\x18\x2b\x0a\xe6\xfc\x2d\xc7\x40\x51\xd1\xd7\x1c\x23\x34\xa1\xff\xee\xcf\x35\x86\xc1\x8a\x98\xef\x6e\x7d\x3c\x47\x2b\x24\xf8\x46\xa9\xb4\xcc\x04\x38\xc5\x5f\x35\xff\x3c\x29\x57\xf9\x94\x7f\xbe\x45\x3f\xc0\x02\x86\x97\xe2\xa3\x1b\xf0\xde\x14\xd8\xb4\x85\x8e\x99\x1b\x1e\xd6\x78\x0d\xc9\xe1\x01\xec\x57\xdf\x90\xb4\x16\xf8\x88\x52\x00\x13\x89\x8f\xb5\x1b\x51\xa2\xdb\xc5\xe6\x96\x26\x78\x6a\xdd\x4d\xf0\x9c\x83\x8d\x90\x34\x43\x36\xa3\x96\x46\x35\x54\xa8\x86\xa0\x49\xd8\x95\x4a\x35\x87\x2b\x77\x6b\x63\xbc\xbc\xdb\x9b\x72\xe3\x7f\x58\x3b\x19\x1f\xdd\x3f\x12\xbc\xc9\xf1\x43\xc1\x9b\x0f\x20\x33\x26\x90\xd9\x25\x8a\xa6\x0b\x32\x6d\x98\x80\x5d\xa7\x4d\x85\x3d\x23\x98\x80\x7c\xf2\xf9\x25\xa2\x59\xa6\x7e\x9f\xf9\xbe\x43\xbd\x71\x6c\xf7\xb9\xfd\x87\x80\x2e\x2e\x25\xc3\x28\xfc\x7f\x5e\x01\x58\x4d\x51\x22\x81\x23\x46\x17\xa6\x11\x1a\x2d\x2e\x97\x29\x15\x82\xa9\x60\xa0\xdf\xbf\xe6\xb3\x66\xce\xc0\x87\xb5\x6f\xdd\x27\xd8\x97\xc6\xde\xa7\xa6\x84\x2d\x92\xee\xfd\x7f\xcf\x2e\xed\xe8\x50\x75\xeb\x2e\x01\xc1\x85\x27\x77\xba\x28\xeb\xec\xd6\xed\xd8\xee\xc0\x73\xb7\x0e\x8b\xf4\x5b\x7e\x89\xc1\x34\x6e\xeb\x6c\x47\xbf\xd9\x56\x67\xee\x76\x07\x77\x5b\x09\x43\x01\x08\xf3\xda\x7c\x7c\x9f\x97\x39\xa2\x9a\xf4\x7b\x7a\xc5\xfb\xfc\x8e\x51\x97\x41\x33\xb2\xf0\xed\x9b\xad\x1a\x55\xfb\x9d\x89\x22\x47\x26\x9f\x0e\x25\x62\x38\xe0\x0b\xd4\x4f\xb4\xc9\xd0\x2e\xd9\x01\x8b\xc9\x9f\xb0\xd1\xe9\x42\x16\x55\x3f\xc9\x7c\x03\xf0\x0d\xdc\x17\x0b\xf4\xb9\x33\x16\xb2\x00\x67\x4a\xbc\x61\x66\x15\x18\xa8\x19\xe4\xbf\xad\x73\x7b\x84\x5c\x97\x16\xe1\x16\x34\x28\x17\xca\xe0\x41\x1b\x69\xe1\xea\xdd\x52\x9f\x17\xd8\x54\x77\x4e\x01\xa9\xae\xbd\xeb\xc2\x7c\xa6\x91\xc2\xc1\x7b\x0d\x5c\x7f\xd9\xf7\x68\x97\x83\xe4\x41\x58\x4b\xa4\xb0\x13\x84\xdd\xab\x80\x78\xca\x3a\xe0\x8b\xe3\x9f\x29\xdc\xb0\xe8\x02\x18\xe6\x5b\xa5\xc9\x61\xf4\x5f\x94\x33\xdf\xc9\x00\xa3\x57\x2b\xaa\x6a\x52\x0d\xd5\x61\xe9\x47\x1c\x96\xee\x1e\x46\xd3\x55\x61\xe0\xdd\xcc\xc0\xe4\xe5\x48\x81\xa4\x6e\xa1\x0e\x87\xad\xf7\x26\xfe\x9f\xa5\x37\x58\x0b\x91\x4a\xce\x93\x1e\x96\xeb\x7b\xf2\x9e\x31\x2b\xc2\x4a\x29\x76\x46\xe9\x66\xc8\x6d\x36\x5a\x17\x2a\x83\xf7\xd0\x44\x7e\x57\xe9\x4d\x7a\xce\x61\x2d\x18\xf7\xb6\x75\x66\xd1\xd1\xde\x40\xc6\x3c\x31\x84\x28\x09\xe2\x1b\x0a\x80\x2e\x16\xc9\x14\xed\x62\x9c\x50\x43\x13\x29\xda\x5e\x48\x89\x36\x41\x52\x3c\x3d\x1d\x9f\xed\xef\xe7\x0a\xfa\xfa\xf8\x0d\xad\xdb\x82\x68\x3a\x30\x71\x6e\x9d\xaf\xbe\x5b\x80\x48\x0c\xd9\x12\x30\x61\x14\x87\xfd\x14\x3f\xb1\x25\x91\x4a\x60\xe8\xaf\x05\xa6\x0d\x9c\xaa\x44\x5a\x50\xd5\xe3\x8a\x48\x11\x53\x31\xae\x51\xbd\x8a\xd3\x6a\x7f\x4c\x4b\xd8\xda\xa9\xc5\xfb\x95\xf2\x78\xfc\xa7\xe7\x2f\x4e\xde\xbc\x7f\x87\xfa\x00\x66\x61\x74\x60\xf8\x83\xe8\x3f\x45\xb4\x78\x76\x53\x0d\xd1\x57\xb1\x52\x3c\xba\x94\x14\x17\x0c\xb7\x1e\x4c\x56\xc7\x25\xf9\x23\x52\x07\x6e\x8d\x17\x58\xad\x8f\xee\x6a\x33\x88\x91\xfe\xc1\xdb\x12\xad\x8c\x7b\xd4\x58\x8f\xae\x7d\xaa\x6f\xf5\x23\xc9\x1f\xb9\x4e\xd3\xd3\x23\xf8\x7f\x7d\x5c\x49\xea\x89\x17\x1e\x53\x71\xea\x5c\x86\x16\xc0\xce\xf6\x87\xfe\xd5\xda\x42\x2a\xfc\x55\x6f\xa1\x5f\x74\x59\x5f\x46\xe8\xfa\x4e\x2f\xda\x11\x43\xd0\x45\x42\xc5\xe7\x89\x5a\xaf\x23\x6b\xbd\xe4\x25\xdf\x9f\x8b\x0b\x68\x6e\x63\x35\x57\x03\x2a\x73\x9a\x1b\x73\x73\xa6\x9d\x71\xb0\x9d\xda\x6b\x87\x71\xaa\x86\x42\xfa\x0c\xc1\x20\xe1\x4e\x80\x41\xfc\x1b\xca\xc7\xc8\x40\x91\xd9\x8a\x53\x40\x07\x14\x38\x16\xf0\x03\x49\xb6\x9f\xca\xe3\xf9\xac\x77\xd8\xfb\x1f\xf4\xf2\xd5\x33\x07\x36\xba\x87\x50\xd6\x3b\x95\x29\x67\x50\xe6\xb7\x0c\x85\x68\x18\x95\x88\x42\x19\x15\x0d\x2a\x8c\x20\xeb\x81\x8f\x38\xaa\xa6\xb0\x7a\xc1\xd3\xd4\x7b\x8a\xff\x63\x17\x2f\x48\x53\xa9\x47\x47\x0c\xdb\xc7\x23\x04\xc9\x2f\xf5\x09\xe2\xc7\x36\xbb\x7d\x89\x0d\xec\x36\x97\x59\xef\xa9\x84\x34\x6c\xf4\x53\x86\xd1\x90\x58\x6a\x65\x90\x4a\x74\x8f\x61\x0e\xf2\xe7\xc0\x2f\xf1\x87\x0a\xa9\xa4\x1a\x0f\x8d\x18\x20\xa2\xf7\x94\xc3\x99\x3e\x6b\xf7\xa3\x22\x30\x91\xdd\x68\xe6\x4f\x1d\x57\x03\x6f\xbf\x68\x60\xb7\x08\x40\x71\x6b\x43\xd6\x88\x1a\x1a\x3d\xee\x68\xef\x54\x96\x3a\xa3\x5a\xb4\xd8\x53\x0c\x24\xdc\xa3\x5c\x35\xd9\x33\x3a\x53\x9b\x8d\x7c\x5b\xf6\x31\x2f\xe0\x7a\x7a\xe4\xf5\x11\x2f\xa4\xdf\x17\x6d\xbc\x0b\xc9\x8f\x84\x87\x76\x21\x8d\x5e\x72\x3d\x64\x0f\x17\xe8\x7d\x4d\x89\xd2\x1d\xb2\xa3\x17\xde\x8a\x7d\xe4\xf2\x5d\xa1\xef\xd2\x52\x67\x1d\xd2\x2d\x55\xd1\xdd\x50\x0e\x3f\xe2\x07\xbb\x00\xae\x48\x1b\xe2\x1d\xdf\x72\xd0\x89\xd2\xc3\x3b\x49\xcf\x51\x86\x3a\xfc\xd7\xfa\x87\xf6\x43\x6d\xa6\xa0\x6e\xe7\xa9\xbe\x9d\x5f\x2c\x80\xac\xea\x5f\x03\xea\x5e\x2d\xd2\x2b\x52\xd2\x8d\x9e\xaf\x56\x91\x60\xa9\x66\x7c\x9a\x8a\xca\x08\xd2\xd7\xfa\x5e\x15\x86\x56\x1d\x9c\x09\xf5\xdb\x51\xb6\x97\x2e\x97\xd2\xa2\xa6\xf0\x5c\x27\xf4\xa4\x07\x77\x6d\x31\x73\xed\x84\xb4\x6a\x64\x20\x76\x00\xbb\x82\xf6\xb3\x6a\x4a\x1e\xb4\xd2\x73\x4e\x47\x08\xb0\xc8\xe7\xa9\x24\x76\xdc\x45\xa0\x8b\xdf\x5b\xb0\xf8\xe8\xe8\x57\x41\xeb\x0e\xb4\xc0\x48\xb8\x5b\x10\xdf\x1f\x79\x84\xc2\xd1\x2e\x01\xd4\x9c\x4d\xee\xdb\xbb\xdc\xda\x63\x4d\x19\x00\x76\x68\x4e\xf2\x66\x91\xc9\x6d\x94\x74\xc1\x5b\x86\xd7\x3f\x95\x3f\x64\x7a\xea\xa4\xbf\x29\x56\x6b\xb5\xf1\x12\x1a\x50\x4a\xb0\x05\x1c\x88\x90\xb8\x05\x18\x5e\x10\x7f\xa6\xa0\x01\xd5\xd0\xa0\xe0\x99\x2b\xd3\x6f\x3d\x5d\xa0\x88\x50\x06\xe5\x40\x26\x01\x1d\xb1\x19\xab\x27\xbc\x41\x3f\x60\xf4\xd7\xba\xcf\x6a\xc7\x74\x86\x8e\xd7\x8a\x0c\x40\x4f\x39\x78\x00\x05\xd0\x7e\x07\x3a\x7f\x10\xab\x74\xb8\x15\xfd\xa2\x28\xfa\xf9\x23\x00\xab\xec\x04\xac\x6b\x7c\x83\x80\x49\xaa\x00\x24\x6a\xc9\x31\x71\xd3\xae\x90\x76\x34\x54\xef\x04\xa1\x36\xa6\x71\x61\x01\x20\x94\x50\x98\x07\x0a\x90\x7c\x5f\x84\x20\x01\x32\x08\xca\x1d\x40\x80\xc4\x27\x77\x01\xf3\x9d\x65\x64\x9d\xb8\x6c\x18\x20\x8f\x73\x37\x83\x77\x34\x9b\x9d\x10\x4c\xa6\xb7\xc2\x24\xad\x89\x0d\x98\x8a\xf4\x2c\x45\xa4\xe4\x4f\x11\x39\x0a\x93\xe9\xb9\x88\x9c\x3e\xce\xc4\xad\x66\x50\xd7\x5a\x90\x55\x22\xd0\x4a\x4b\x15\x61\x35\x03\x14\x87\xc9\x08\x02\xa1\x05\xf7\xe4\x9e\x6c\x68\xd5\x16\x4d\x42\x0d\x93\x30\xcf\xc0\xbd\x81\x79\x2d\xd7\xdd\x06\xc9\xd7\x53\x5c\x22\x5e\x19\xbc\x35\x0f\x1b\x5c\x9a\xc3\xf3\xb4\x8a\x36\x2d\x00\xdc\x02\xfc\x51\xbd\x4a\x8b\xae\xe6\xa0\xa9\x8c\xb8\xe9\x41\x1b\xa8\xbb\x2a\x22\x01\x30\x45\xd4\x00\x95\xd1\xdd\x6c\x00\xf2\x53\xc5\x88\x06\xee\xd3\x0e\xe0\x80\xbc\xc7\x16\xf4\x7a\xb0\xba\xb3\x70\xce\x82\x55\xcd\xc9\x95\x1e\x7e\xd4\x0c\x58\xee\x65\x18\x28\xbe\x05\x50\x95\xbc\xe3\x76\x50\xab\x81\x38\x7b\x4f\x9a\x00\x29\xc0\xdb\xde\x18\x80\x69\x4e\x37\xfd\xa7\xf5\xb9\x63\x1b\x4e\x6a\x53\xc0\x37\xa3\xa0\x5b\xfa\x1b\x91\x8e\xc4\x4c\xf8\x79\x64\x49\x60\xdd\x48\xe9\x61\x4d\x06\x93\xcb\x3e\x31\xaa\x2a\x1f\x09\x4f\x37\x13\xbd\x05\x5f\x90\xda\x1b\x70\x68\xcb\x74\xd5\xd7\x65\xd5\x21\x90\xe5\x25\x17\x29\xe8\x70\x61\xe5\x01\x5e\x37\xd7\x24\x70\x31\xed\xc3\x97\xdb\x7e\x5d\x2f\x4c\x36\x7c\x40\xb3\xd9\xf4\x6b\x36\x93\x66\x51\xf2\x6c\xd8\x8b\x00\xbc\x62\xad\x25\x3c\x66\xe8\x2a\xc5\x6b\x5e\x8b\x8d\x4c\x49\x95\xe2\x97\x54\x92\x24\x53\x52\xa5\x38\x25\x91\x74\xd5\xd6\xb5\xc3\x68\x80\xfe\x30\xd1\x17\xb3\x16\x77\xa1\x85\xbd\xc0\xb7\x47\xcb\x61\x66\xce\x4c\x4d\x0a\xa0\x37\xd0\x3b\x08\xb3\x7a\xb1\x40\x39\x97\xa7\xe6\x63\xec\xc5\xfc\xed\xef\x5a\x93\x4d\x90\x82\x62\x1c\x43\xb1\xdc\x6c\x3b\xff\xf0\x9a\x66\xc9\x5d\x70\x42\x8e\x57\x09\x9c\x6d\xda\xde\x48\xad\x28\xf0\x09\x57\x2b\xf8\x46\xcf\xe6\x91\xa0\x00\x2b\xf3\x72\x81\xa3\x8a\x3e\xab\x22\x81\x5b\xd1\x6b\x4d\xad\xfa\x96\xd6\x3e\xa8\x22\xb7\xb7\xa6\xe0\x62\x4b\x6b\x1f\x55\x91\xcd\x20\x84\xc6\xda\xd8\x54\x1e\xdf\x00\x1a\x65\xf1\x37\x8a\x65\x63\xf9\xbb\x5d\xef\x90\x33\xca\x42\x1e\x61\xda\x14\xfb\x50\x07\xda\x9d\x8f\xe5\x4e\x68\xdc\x71\xeb\xc4\x6f\x99\xf4\x3b\xca\x96\xce\xed\xff\x91\x9c\x34\x46\xaf\xab\x2c\xc3\x68\x27\x3b\x2c\xab\xc4\x24\x5b\x3a\x78\xae\x4a\xb8\x7d\xe4\xd5\x74\x78\x21\xfb\x19\x16\x59\xb3\x43\x5f\x2c\xbb\xec\x9e\x09\x66\xdf\xde\x8a\xbe\xfd\xbb\x5b\x7a\xa1\x8a\xa0\x0f\x87\x76\x7b\xab\xae\xd3\xb0\x40\x3b\xa3\xdd\x8e\x0a\xa0\x38\x35\x00\xc2\x74\xe7\xe5\x0f\xec\x2d\xfa\xf4\xe9\xb7\xe0\x96\xba\x90\x97\x03\x08\x1d\x66\x8b\x45\xbe\xaa\x51\xa4\x5c\x16\x8c\x3f\x6c\x08\x52\x48\x65\x13\x02\x65\x35\x16\x1e\x40\x4d\xd0\x16\x09\x76\xd1\xa9\x21\x0b\x4f\x41\xf8\x3a\xee\xe0\x9c\xc3\x2c\xb2\xf5\x02\x23\x2f\x65\xba\x89\x77\x7e\x9e\x0a\x53\x8d\xfe\x5b\x15\x13\xa9\x79\x71\x81\x5a\x2a\x19\x45\xff\xc5\x1a\xe9\xba\x29\x31\xc2\x9d\x2d\x27\x95\x54\xf0\x9f\x33\xe0\x3c\x2a\x87\x21\xd2\x04\x85\xa4\xdf\x7f\xcb\x8b\xcc\xe2\x8b\x82\xa4\xe8\xd4\xbb\xfb\x8d\x64\x65\xb1\xf5\xee\x37\x24\x7a\x88\x4a\xad\x45\x24\x1b\x72\xa9\xd4\xf5\x4f\x50\xa9\xaa\xa1\xb8\xee\xa2\x52\xd7\x76\xc6\x3c\xcb\x2f\xe7\x9a\x93\xe1\x98\x75\x94\x74\x38\x1e\x8d\x6e\xb3\xaf\x96\xb5\xfc\xa8\xd3\xb8\x3f\x75\xfe\xef\x88\x87\x0c\x88\x7e\xa4\xa4\x2e\x05\xb0\x76\xa3\xfc\xe6\xfd\xd3\xed\xae\x66\xde\xf2\x58\xa4\x37\x00\x16\x2b\xa6\xe1\x42\xbc\x7c\xff\x16\xa3\x08\xf6\xa5\x1f\x65\x04\xa1\x4f\xd3\xaa\x5c\xa0\xd1\x69\x4d\x3f\x4e\xca\xd5\x01\x05\x0c\x80\x0b\x9a\xd7\x86\x1c\x75\x72\x26\x27\xb8\xeb\xd4\xee\x5c\x59\x35\xae\x29\x87\x5e\x45\x95\x7d\xa1\xe9\x70\x97\x31\x5a\x63\xf2\x87\xa0\x08\x0c\x5e\x90\x16\x75\x11\xe8\xda\x10\x1c\xdb\xa1\x00\x16\xd7\xaa\x7d\xa7\x45\xb5\x82\x29\xca\x15\xa4\x36\x78\xad\xbf\xe3\xcf\x3d\x8e\xfc\x6d\x12\x92\x0c\x1d\xa3\x5b\xef\xc7\xa4\x2b\x77\x77\x66\x4a\x33\x4e\x37\x37\x9a\x99\x42\x9f\x85\x82\xe2\x42\xac\x93\xeb\x15\xc6\x8a\x2f\x2e\x7f\xcb\x2e\xe4\x6d\x8c\xfa\x8f\xec\xde\xad\x68\x0e\xa2\x15\xa0\x68\x23\x91\xd8\xdf\xe7\xc7\x27\x9d\x70\x3a\x3a\xbb\xb9\x41\x9a\x94\x00\x62\x64\xd9\x31\x26\xa3\xc9\xf4\xa9\x35\x2c\x75\x22\x15\xff\x36\x35\x76\xcd\x81\x52\xa7\xd3\x33\x0c\xf9\xa6\x10\x8b\xb8\x48\x16\x72\xf4\x07\xcd\xc1\x74\xb2\x90\x21\x0e\xfb\xab\x83\x24\x52\xb2\xce\xc3\xe8\x80\xd3\x11\x79\xb0\xea\x7f\x4b\x04\x71\xfd\x35\xbb\x8a\x2f\xf4\x5b\xc4\x62\x63\x99\x61\x63\x44\xb4\xf9\xd3\x05\x6c\x5f\x61\x86\x39\xc7\x00\x05\xe1\xd6\xf0\x4e\xe4\xf6\x0e\x22\xe8\x7b\x6e\x91\x3b\x2b\x41\x81\x44\xe3\x75\x80\x9c\x91\x9c\xe1\x0c\xa5\xdd\x55\xb9\xae\x17\x57\x9f\x10\x9d\xc9\x30\x99\xf1\xf5\x97\x2f\xf3\x66\xb9\x00\x2e\x1a\x71\x78\x5f\x0e\xe7\x74\x7e\x86\xf7\x92\xf1\x85\x32\x26\xef\xde\xd2\x4d\xee\xed\x64\x9b\x9c\x30\xde\xb8\x72\x68\x75\x7b\x68\xa5\x24\xde\x10\x7e\x23\x74\x54\xdd\xa4\xb9\x3e\x03\xb1\xb5\x4b\x7c\x50\x44\xc6\xf5\x64\xfe\xd1\x03\xf4\x15\x86\xa1\x40\xff\x90\xc1\xc8\x6a\x66\x40\xd4\xba\x7b\x37\x2f\xbc\xbb\xd9\x93\x5e\x07\xaf\x36\xe0\x95\x1f\x6d\xe5\xa3\x83\xb7\x65\x7c\x74\xf4\x40\x98\x8b\x35\x3e\x0a\x5c\xf1\xc2\xbf\x90\xe3\x47\x3e\x2b\xbe\xb3\x06\x46\x97\x74\xd4\xbe\xdb\x0d\x73\x8e\xaa\x90\x01\x96\x7c\x55\xe5\xdf\xf0\x26\xe6\x67\x83\x34\x28\xe9\xac\x77\xb9\xb0\x79\x21\x22\xc5\xbb\x11\x0e\x6a\x71\x6f\x16\x22\x62\x14\x22\x57\x7d\x92\x0f\x51\x69\xc4\x96\xe5\xe0\x43\x8e\xf5\xc8\xe9\xe7\xdc\x82\xe6\x9c\xd6\x01\xc5\x11\xe9\x99\x1b\x64\x61\x14\x92\xb1\x35\xc4\xaa\x6d\xf6\xae\x2d\x9e\x51\x48\xa4\xa6\xae\x15\x60\x5e\x2f\x81\x1b\x46\x9b\x98\x0b\x7d\x2f\xa0\x7a\x23\x61\x64\x46\x8e\x41\x42\xd4\xac\xd0\x46\x4d\x0a\x6d\xb4\x24\xd2\xca\x5d\xa4\x95\x49\xa4\x15\xc4\x2f\x66\x84\x79\x37\x2e\x09\x4c\xa3\xc9\x91\xa7\x13\xe5\x10\x7f\xc0\xa9\x5d\x92\xf4\x22\x27\x61\x55\xf3\xd3\x48\x29\xea\x45\x07\x15\x23\xa6\x4c\x22\xa6\x11\x23\x26\xf7\x60\xd6\xde\xc1\xb4\x21\x11\x0e\xe7\x03\xd1\x21\xda\x95\xa0\x0c\xb8\x64\xe4\x9e\xb6\x4e\xe1\xd6\xce\x2a\x46\x3b\x08\x62\x89\x43\xf8\x73\x8e\x5f\x57\xb7\x4b\x63\xbb\x48\xe0\xda\xcb\xf1\x5a\xfd\x99\x07\x07\x5b\x86\x1d\xa2\x9c\x7d\x39\xae\x70\x44\xbf\x73\xdd\xb7\xf3\x6c\xc5\x35\x44\x04\x03\xf8\x24\x2b\xef\x46\x5b\x77\xc9\x7a\x85\xec\xc8\x95\x0c\x4b\x06\x2b\xba\x8d\x8a\x36\xe4\x13\x2d\x98\x47\x3f\x95\xd3\x75\x8d\x6e\x60\xad\xc1\xde\xbd\x32\x1f\xce\xbf\x64\xae\x8f\x64\xa0\x4a\xc7\xf7\x89\xa6\xf9\x3e\xcf\xa7\x73\x0a\xa4\xcc\x22\x30\x1a\xba\xed\xaa\xb1\x4d\x61\x4d\xa2\x7b\x4c\x0f\xd9\x55\xe0\x4c\x1c\xa7\x4a\x15\xa5\xef\xe6\x09\x2d\x3c\x44\x95\x7c\x7e\xa9\x89\x53\x7e\xea\xbf\xbd\xa4\xa8\x39\xd2\x93\x3b\x42\x51\xb3\x73\xf2\x36\x45\xab\x17\x5f\x2a\x01\xdd\x7f\x6c\x26\x7a\xdc\x6f\xcb\x4c\x05\x2e\xa0\x54\xb6\xec\xc3\x5d\xfe\x60\x64\x95\xc7\x98\x33\x3a\x2f\x8e\xfe\x94\x4e\xbf\x02\xda\x98\x66\xbc\x00\x40\x08\xdd\xdc\x44\x2f\x29\x1e\x99\x4e\x39\xd6\x23\x8b\xa3\xcf\x45\x8e\x24\x65\x7e\x91\x03\xa0\xa9\x02\xfb\xfb\xba\x84\xda\x1f\xd6\x03\x68\x3f\x9b\xfa\xb3\x72\x17\x21\x2c\x05\xdc\xf9\x91\x40\xa1\x4d\x02\x9f\xc3\xef\x40\x74\x87\x24\x5c\x4a\x84\x40\x44\x89\xfc\xe8\x6a\xc4\x15\xb5\xf0\x90\x6d\x12\x8a\xcf\x0a\x3b\xb3\x94\x69\xbc\xed\x65\x01\x10\xfa\xb2\xfc\x5e\xd8\x37\x0a\x24\xe1\x45\xc3\x4b\x63\xa5\x73\x4a\x0b\xff\xfa\xaf\x67\x0e\x0e\x02\x5c\x7b\x24\xb6\x92\x4d\x41\xcc\x1c\x42\x92\x40\x30\x3d\xf8\xb9\x47\x89\x9d\xb5\x35\x15\xde\xde\x86\x1f\xe1\xae\x6a\x80\x87\xa9\xa3\x3f\xe4\xc5\xd3\x12\x38\xea\x86\xfd\x05\x66\xfd\x53\x5b\xb6\xb3\xb3\x72\x60\xe7\x45\xa4\x45\x3b\xb9\xa3\xb7\xf0\xa6\xc9\x96\xce\xe3\x76\xe0\xe1\xd0\x13\xe5\xb8\x84\x5f\x4b\x94\x23\x5f\x70\x7c\x29\x8e\xd2\x84\xd8\x2e\xc3\x91\xa3\x0a\x5d\x43\x24\xa8\xc1\xc6\x5d\xf9\x4d\xda\xf1\xfa\x58\x8b\xc8\x1a\x68\xbd\xeb\xe5\x43\x1d\xb8\xe2\x1b\xfd\x26\x99\xda\xa9\x76\xe3\x8e\x1c\x48\x0b\x09\xa4\xd4\xaf\x45\xca\x4e\x2d\x5d\x49\xed\xd2\x44\x3f\x5d\x48\x98\xd8\x5a\xab\xd6\x80\xb3\x9d\x98\xa5\xe7\x4e\x7c\x5a\xb2\xd0\x80\x9a\x8d\xf1\x36\xac\xfd\xc3\xa7\xaa\xb4\x17\x86\xa3\x03\xc8\x73\xad\xf4\x5a\x59\xca\xfe\x24\x8c\x6d\x36\xb6\x73\xd0\x61\x86\x76\x58\x99\x1c\x80\xbd\x70\xe8\x64\xc4\xed\x2b\x0d\x73\xc3\xdb\xfb\x42\xc3\xad\x74\xb8\x2e\xea\x79\x7e\xd1\xec\x54\x97\x8f\x26\x56\xa7\xad\x96\xe1\x09\x50\xb2\x9b\x6e\x06\xbb\xbf\xfe\x62\xdc\x25\xe6\x1e\x5b\x65\xcf\xd7\x4d\x53\x7a\xe4\x33\xa7\x1d\x6a\xa5\xec\x00\x71\x6f\x03\xcd\xc6\x7e\x93\x08\x90\xd5\xad\xe1\xd4\x70\x07\x1e\x72\x27\x75\xf0\x86\x09\xc8\xbc\xa7\xe5\x65\x58\xdc\x6d\x03\x62\x5b\x70\xed\x33\xc7\x8e\x8e\xcf\xad\xcf\xcb\x2e\xc5\x7e\xff\x57\xd1\xc6\x20\x90\xfc\x44\x04\xf0\x14\xf0\xca\x8f\x43\xec\xb1\x77\x03\xb4\x2c\x85\x7f\x07\xe5\xee\x52\xbf\x3e\x1f\xdc\xec\xa0\x3f\x61\x4d\x22\xa8\x41\xb1\x0b\x72\xea\xd9\x84\xaf\xc6\x31\x3e\x9a\xc8\x15\xdb\x6b\x31\xb3\x92\xff\xb5\x52\x94\xba\x43\x37\xfa\x30\xc1\x1f\xda\xd5\x50\xd8\x47\xa7\x14\xe1\xff\x50\x63\xfc\x56\x8f\x4e\xc8\x4d\xad\x4b\xd4\x6e\xcf\x2d\xa7\x85\x81\xaa\x93\x5a\xf3\x0f\xb7\x31\xb1\x99\x51\x70\x0d\x9e\x2d\x3e\x54\xd6\x00\x48\xbf\x62\xfb\x8b\x4c\x88\x4a\xd9\x9d\x10\xf9\xfd\x5a\x89\xee\xbd\xed\x3f\xca\xa8\x17\x18\xa5\x6e\x64\x5d\xe7\x75\xd7\x75\x7e\xcb\xe3\xcb\x36\x38\x56\xdd\x74\x3c\xb0\x04\x2f\xe2\x9f\x79\x60\xd1\x57\xee\xff\xdf\x1e\x58\xb6\x3e\x2f\xdc\xe1\x2d\xa1\xfb\x58\x8b\x2e\x66\x53\xd8\xe6\xf6\x8d\x2f\x93\x6f\x2c\x99\xfc\x71\x26\x09\x85\xda\xe8\x52\x35\x1a\xcb\x68\xe4\x12\x0c\x2b\x17\x96\x99\x67\xa4\x1f\x63\xcc\x77\xd0\xa1\xb5\x04\xbc\x24\x2a\x60\xa1\x23\x81\x22\xe9\x6c\x77\x91\x34\x36\xc5\x92\x66\x16\xb5\x55\xed\xeb\x10\xe8\x82\x9f\x91\x42\x67\x3b\x49\xa1\x77\xe8\xdf\x62\x12\xb2\x2e\x16\xeb\xae\x6a\x5a\x21\x54\x00\x19\xa3\x9f\x12\x28\xdf\xbf\xb3\xba\xed\x16\xc4\xe2\xab\x7a\xb9\x5c\xc4\xcf\x5c\xaa\xf6\x44\xa3\xae\xfb\x90\xc1\xbe\x22\x6c\x41\x00\x4a\x1e\xb2\x58\x64\x6c\xdf\x04\xb8\x5f\x04\x84\x18\xc6\x54\x49\x8e\xc3\x05\xee\x22\x0a\xc0\xfb\x69\xa7\x9b\x88\x9a\xe7\x76\xdf\xdd\x7e\x29\xed\x2e\xf1\xbc\xf5\xc6\xa2\x8d\x1e\x6f\x31\xc0\xd2\x7e\x39\x1a\x87\x1b\xc8\x0e\xfa\xcd\x71\xd4\xeb\x93\x1b\x93\x41\x14\x47\xc0\x8c\x18\xbf\x20\xfa\xd6\x92\x36\x59\x96\x19\xa4\x6d\xbb\x15\xa2\xac\x82\x3a\x7f\x1d\xf6\x5b\x75\x87\xfd\xd6\xda\x4d\x97\xbc\xe7\xa4\x6d\xd4\xb5\xa9\x86\x30\x65\x69\x92\xed\xc8\xed\x86\xd2\x4e\x1c\xf8\x16\xdc\x1b\xd1\x56\x16\x25\xe9\x34\xf0\x1d\xd2\xc2\x85\xcb\x1d\x44\xe4\xb8\x09\x1d\x8b\xa1\x6d\x85\xb2\xf2\xe8\xa8\x4d\x81\x75\x71\x00\x6c\xd0\xed\x0e\xc0\x58\xa4\xef\x3c\x86\xc6\x8c\x62\x91\x5d\x34\xfe\x18\x60\xd3\xeb\xb2\x18\xdc\x3a\x1a\x36\xc8\xb4\x47\x93\x0e\xb5\x31\xb2\xdd\x09\x17\x0c\x36\x8c\x25\x06\xc2\x9e\xc5\x73\x0a\xca\xea\x4c\xc4\x74\xc9\x9a\x48\x5d\x5d\x66\xc3\x72\x31\x3b\x88\x7a\xec\x6f\x78\x46\x66\x3c\x68\xbf\x12\x1d\x64\xa7\x64\x6f\x79\x66\x77\x0d\x65\xb9\x67\x65\xc1\xcf\xf5\x45\xab\xac\xe9\xde\x3c\x05\x3b\x23\x20\x71\xa8\xb5\x4b\xcb\x5b\x0a\x2c\xcb\x66\xe6\x16\x29\x14\xf3\x8b\x57\x0d\xa0\x04\x8b\xed\x56\xf5\xb5\xe1\xab\xbe\x42\x4b\xf3\x5b\xbd\x25\x13\x47\xad\xfb\x59\xb3\x33\x02\x17\x5e\x6a\xa3\xd7\x4c\xf9\x81\x6d\x36\x2d\xb0\x8d\x5d\xbb\x05\xb6\xb4\xc3\x90\xc8\xf0\x77\x6b\x0b\x4b\x72\x7d\xd0\x6a\x00\x3d\x22\xd8\x4b\x22\x6d\x74\xdb\xce\x51\x6c\x76\x66\xa2\x21\xf8\x94\x94\xce\x62\xdc\x59\xa6\x09\xb4\x7e\x23\xa7\x29\x85\x48\xa1\x75\x0b\x39\x5d\x29\x23\x8a\xe8\xcf\x65\xdd\x70\xda\x1c\x7e\xa1\x94\x8d\x56\x97\x52\x94\x9d\x83\x52\x47\xe3\x54\x75\x06\xce\x44\x80\x8a\xd1\x13\x51\xc2\x27\x67\x2a\x8e\xcd\x05\x3a\xfb\xc3\xeb\x3c\x21\x75\x8b\x75\x48\xcc\x23\x6a\x2a\xfb\xff\x94\x76\x65\xbd\x6d\x23\x49\xf8\xaf\x48\x04\xd6\x20\x43\x4a\x91\x92\x19\xef\x40\x5a\x46\xbb\x40\x1e\x76\x17\x48\xe6\xc1\x33\xd8\x07\x43\x08\x68\x89\x4e\x08\xc8\xa4\x40\x52\x89\x0d\x47\xff\x7d\xeb\xe8\xbb\x9b\x3a\x30\x79\x88\x2c\xb1\x8f\xea\x66\x75\x77\x55\x75\xd5\x57\xe6\x04\x69\xef\x39\x7b\x2e\x75\xb9\x4e\x85\x7b\x07\x92\xb5\xa8\x99\x93\xb6\x02\x50\xda\xa7\xd3\x69\x24\xb2\xe2\xfc\x95\xb0\x2c\x3b\x6e\xe7\x9a\x60\x2d\x23\xca\x39\xbc\xd9\xd3\x19\x64\xc6\x6f\xbd\xbf\xc4\x8f\xdc\xc4\xea\x92\xa7\x52\x79\x36\x37\x0c\xa9\x22\x2a\x2b\x36\xbe\xa4\x96\x8d\xe1\x14\x1b\x2b\xb3\x67\xc3\xef\xc9\x31\x94\x6d\xbb\x2a\x3b\xce\x76\xe3\x02\xfa\xd9\x89\xba\x6b\x4c\x83\x6e\xa2\x4c\xc3\x76\xd8\xd2\x6f\x98\x00\xb1\xc7\xe4\xd3\x59\xeb\x87\x5d\x87\xb2\x29\xdf\xdc\x20\x17\x61\x12\x7b\x03\x71\xdb\xc8\x9d\x7b\x77\x00\xba\x46\x20\x1b\xa0\x17\x28\xce\x01\x25\x17\x2a\x2b\x02\x18\x7b\x28\x47\x58\x1b\x03\xf6\x74\x36\xaa\x8c\x60\x64\xe1\xa8\x96\x99\xe0\x97\xa5\x91\xe1\x5a\x8c\x9a\x45\x97\x18\x73\xe8\x19\xc3\x78\x35\xb2\x64\x2f\xe4\xe5\x48\x56\xd6\x87\xa7\x92\xb3\x8c\x8f\xe7\xc3\x19\xc8\xc7\xa0\x7d\xc1\xe0\x29\x87\xc1\x97\x2f\xd4\xe8\x97\x2f\x39\xa6\xaf\x6a\xfc\xa9\x18\xc7\xe5\x48\x82\x2a\x12\x91\xe1\xd1\x4b\x9c\xc4\x02\x06\x59\x8c\x48\xe4\x1e\x15\x9d\x95\x4c\xf8\xc8\xa2\x04\xdd\x3e\x21\x26\xb3\x05\x62\x6f\xa7\xd1\x30\xa4\x1b\xd3\x72\xba\x6c\x04\x0a\xa4\x30\x6b\xfc\x60\xf4\xd3\xff\x95\x0f\x77\xc4\xdb\xb0\xaf\x21\xe4\x6e\x94\xaa\x0d\x60\xc3\xf0\xe6\xb8\xe7\xa4\xd1\xdb\x1f\x5d\xa4\x6a\xc2\x2a\x47\x79\x33\x00\xce\x55\x72\xaa\x2c\xd3\x0a\xac\xeb\x10\x08\xc6\x89\x4a\x06\x64\x84\x55\x4f\xac\xe6\x00\x74\xf1\x7f\xef\x7e\xff\x8c\xe1\xdb\x1d\x32\xea\xb6\xe8\x0b\x64\x03\x6a\xac\x9e\x32\xcb\xe2\x6d\x19\xe8\xb5\x1d\xca\x9f\x32\x31\x11\x25\xd8\xca\x90\xdd\x5f\xf1\x1e\x51\xf2\x80\xfd\xfa\x64\xf7\x74\xd3\x48\xfd\xe0\xca\xad\xbf\x56\x8f\x2f\x31\xfb\xc4\x96\x19\x22\x16\x97\xb0\x37\x93\xc1\x96\xf8\xe2\x18\x57\x56\x02\x41\x98\xe1\x42\x42\x0a\x75\x0b\xc2\x0b\x7a\x7f\xda\xab\x55\xbd\x3e\xf1\x10\x39\x68\xb4\x5f\x11\x82\xdf\xfe\xbe\x44\xf7\x31\xfc\x40\xfc\xbc\x57\x3a\x14\x11\x6c\x2e\x59\xd0\x8f\xe8\xa2\x16\x78\xa8\x61\x58\x5b\x4b\xe0\xad\xe2\x57\x82\xce\x28\x33\x2d\xa6\xc3\x17\x3c\x06\x17\x08\xe6\x15\x99\x55\x1b\x03\x5e\x6d\x19\xfd\x53\x42\x2a\xac\xea\x3c\x6a\x40\x56\x4e\xe5\x0f\xb0\x32\xe0\xa7\xef\x68\xda\x22\x57\x12\x8d\xb7\x80\xc2\x14\xd9\xbf\x5a\xca\x2b\x68\x83\xeb\x1a\xcc\xa0\x89\xc9\x27\xac\x23\x23\x45\x3a\x8e\xa2\x89\x92\x15\x10\x20\x8e\xd3\x45\xb0\xcc\x77\x2c\x93\xaa\x32\xe2\xe4\x2d\x2d\x40\x5a\x1c\x8e\x98\x2d\x16\x2f\xa6\x1d\xbc\x34\x07\x4e\x4e\x25\xd8\x35\xe9\xb2\x41\x0f\xd0\xfe\x30\xfc\x90\xa7\xaa\xa4\x99\x81\xbf\xc7\x62\xda\x26\xf3\x85\x9e\x44\xf9\x84\x6e\xc2\xe7\x62\x32\x45\x95\xd4\xaa\x62\x4c\x33\x3f\x11\x55\xfa\x0f\x25\x3e\x2f\x3f\xf4\xf0\x05\xed\x25\x8c\x7b\x6b\xda\xde\x0e\x96\x16\xe3\x5e\x66\x69\xd5\x64\x37\x14\xc1\xb4\x47\xf6\x7a\x44\x58\xd6\x56\xa1\x89\x86\xb1\x67\x6d\xfc\xc6\x8d\x95\x13\xe3\x8f\x26\xde\xc9\xd3\x9f\x60\x81\xee\x2c\x6b\xab\x51\x48\x6f\x07\x12\xcb\x6a\xb0\x28\x4a\x16\x0c\x26\x73\x27\x2f\xd4\x60\x25\x80\x06\xe2\x2c\xea\x83\x90\x5d\x2d\xc1\x64\x4b\x77\xf0\xb0\xb8\xfa\x35\x70\xc3\x51\xb4\x2e\x30\x72\xe3\x3d\x26\xd3\x65\xc5\xc9\x4e\x41\xdc\x50\x36\x77\xf8\xc8\xa8\x66\x23\x99\x48\xb0\x38\x3a\x0e\x15\xfc\xdc\x6b\x4f\x6b\x10\x76\x93\x35\x32\x24\xb4\x55\xe3\x2a\x3a\x08\x45\x23\x16\x3f\x09\x11\x58\x2c\x59\x9f\x4c\xab\x5d\x2b\xe1\xad\x39\x74\x6c\xcc\x92\xd8\x55\x37\xbd\xdb\x41\x68\x26\xb4\x06\xe2\x51\xae\x3a\xa8\x8d\x0e\x5a\x9c\x26\xe6\xc5\xc3\xf4\x11\xb1\x16\x5b\xb7\x9b\x25\x47\x69\xd5\x04\x39\x9f\x61\x1e\x73\x98\x37\xcc\x0a\x19\x24\x40\xaa\x04\x5e\x3a\x68\xbe\xf5\x13\xb9\xb9\x68\xca\xda\xf5\xb2\xe2\xce\xd0\x48\x18\x7c\xf5\x4d\x5c\x49\xcd\x82\x6e\xdc\x84\x68\x13\xe8\x94\xb4\x88\xa1\xb7\xc5\xba\x45\x5e\x06\x6b\xa2\xfa\x10\x48\x65\x2a\xa6\x03\x36\x20\x21\xa1\x03\xf3\x49\x11\xdd\x79\xd7\xf4\x0d\xad\x27\xc4\x15\x42\xfb\xe2\xb7\x66\x8d\xa6\xa7\x4d\x30\xe7\x0f\x28\x40\xf1\x2a\x40\x2a\x1a\x32\x12\x35\x01\xa8\xa1\x05\xaa\xa5\x39\xf2\x54\x85\x99\x31\x8b\x50\x1c\x69\x80\xdd\x70\xbd\x59\x23\x0b\xce\xb1\xe5\xc9\x48\xd7\x13\x22\xd2\xd0\x1e\x3a\x3e\x59\x2f\x7b\xfd\xc2\x7a\x39\xab\x42\x73\x53\xf4\xf3\xdc\xd8\xaf\xb1\xb7\x5f\xa3\xdb\xe3\xc0\xa2\x16\x8a\x94\x15\x17\x49\xe7\xac\x38\x64\x71\xc3\x1b\x5a\x65\x81\xba\x6a\x23\x29\xd7\x7e\x77\xc6\xe6\x74\x7e\xce\x4a\x19\x7d\x69\x50\x23\x7f\x42\xaa\x82\x03\x02\xe5\x53\x69\x81\x01\x43\x35\x92\x45\x85\xfc\xf5\x63\x95\xb9\xb9\x11\x87\xe2\xca\x3a\x1c\x09\xd3\xf6\x6b\x68\x21\x9c\xa9\x4d\x6f\x8f\x43\x77\xe9\x92\x9a\x5a\x19\xba\x11\xdc\xdb\x56\xc2\xc7\xbf\x18\x4c\x64\xd9\x7e\xaf\x87\x73\x0b\x80\xdd\x85\xbd\x14\xd1\x0a\x38\x7f\xf7\x1b\x08\xe9\xf7\x98\x63\x64\x32\xcf\xba\x1c\x05\xe8\x1d\x1e\x92\x20\xba\x4e\xcd\xe2\xb4\xe1\x55\xa6\xec\xda\x89\x0c\x87\x07\x65\x1d\xbe\xf8\x70\x6d\x99\x93\x9d\xd8\x5e\x8e\x3e\x05\x5d\x0d\x24\x84\x8a\x85\xb2\x4a\x79\x13\x94\x68\x4a\x12\xe1\xa6\x0d\x86\x9b\x0a\x48\xf5\x21\x7a\x73\x47\xfa\xad\x78\x11\xc0\xd6\x66\x92\x46\x62\x58\x01\x1d\xd1\xf0\x2d\xe6\xac\xee\x0b\xcc\x5e\x98\x29\x57\x39\xb3\x5e\x81\x24\x0a\x72\x26\x88\xb0\x5b\xa4\x69\xb8\xba\xf2\xa6\x0b\x77\x3b\x99\x84\xab\x0d\x73\x1b\xd7\x5d\x61\x41\xe6\x4c\x8b\xf7\x0e\x67\x7d\xc2\x86\x18\xed\xb4\x8f\xad\x2b\xe0\x23\x10\x29\x79\x1a\x93\xb6\xf0\x11\x28\xcd\xd8\x8b\x50\xa8\x3d\x5a\xa8\x15\xc0\x53\x51\xa2\xe0\xaa\xc9\x55\x7a\xc9\x1f\xec\xd7\xcd\xce\xd1\xb9\xce\x63\x27\x9b\xc9\xeb\x54\x37\xc9\x22\xf9\xdf\x93\xa3\xdc\x28\x71\x9f\xd9\xb1\x92\xb1\xd3\xdb\xf2\xca\xf8\x1b\x97\x32\xa3\x45\x27\x0b\xfb\xe7\x1c\x16\xfa\x22\x36\x7e\xc3\x6d\xd3\x2f\xc2\x32\xe9\x05\x7e\x5c\x2e\x66\x99\xef\xb6\xe5\x9b\xcd\x5d\x2f\xe1\x41\xa7\x2d\x53\xce\x45\x6d\x29\x6f\xaf\x5d\x71\x9d\x2b\x7e\x1e\x2c\x49\xd5\x54\x62\x9d\x82\x1b\x42\x1a\x13\x30\xae\x24\x1c\xd4\xdb\x80\x1c\xa3\x7d\x7b\xf0\xb5\xb2\xcb\x30\xe1\xa6\xa1\x68\x62\x43\x5b\x2a\x6d\x5e\x32\xfd\x2e\xb0\x1d\xa8\xb8\xfe\x06\xdd\x1c\x0c\x8e\xb9\xb9\x11\xba\x13\x7e\xb1\xe2\xd4\x49\x73\x53\x36\xe5\x8c\x39\xd5\xef\x49\x99\xb3\xbd\x51\x08\x0f\x29\xf2\x2f\x93\x87\x12\x8a\x16\xaa\x5c\x95\x15\xc9\x6b\x3c\x6e\x7f\xfe\x6c\x11\x59\x8d\x64\xa1\xca\x12\x7b\x40\xe2\x01\x3a\xf4\x74\xf4\x38\xf8\x42\x0f\x5e\xf8\x8b\xa2\xad\x30\x3a\x62\x22\xd4\x00\x81\x6c\x48\x0c\x50\x87\x80\xc3\x94\xf6\x25\x59\x35\x61\xa1\xc5\xea\xb6\x1d\xea\x16\xe8\xc7\xac\xd1\x8b\xab\xca\xfb\x74\x6a\xa6\x09\x09\x14\x3b\x4f\xa0\xd8\x85\xd5\x9b\xe0\x50\x54\x23\x41\xf5\x66\xc7\x3b\xe4\x27\x19\xff\x19\x3c\xd8\x77\x74\xb0\xef\xc4\xc1\x2e\x3e\xa5\x40\x30\x74\x94\x3b\xdb\xe9\xfe\xd2\xa3\x7c\xd0\xbb\xd6\x31\xd3\x3a\x37\xc8\x96\x97\xd5\xd0\xce\x7c\xda\x8b\xd6\xd8\x99\x93\xd7\x4d\x4e\x0b\x4f\x4e\x4c\x2c\xe3\xe9\xb2\x9d\x76\x1a\xda\xa9\x15\xd2\x4c\xd1\x07\x5a\x15\x06\x69\x35\x53\x71\x2f\x92\x17\x18\xe9\x27\xbc\x0d\x06\x24\x0d\x0e\x52\xd2\x79\x34\xd5\x5e\x57\xc8\x6d\xd2\xbc\x69\x3c\xb5\x35\x9a\x4e\x15\x1c\x48\xe9\x86\xe6\xe4\x8d\x38\xdf\x39\x74\x32\x1a\x45\x59\x34\xbf\xdd\x3f\x8f\x3e\xb6\x88\x98\x7f\x57\xd4\xdd\xe8\x53\x53\x63\x0e\xb9\x10\x7a\x51\x7e\xfb\x46\x35\x45\x82\xcc\x86\x12\xb4\x18\xb7\x21\xb5\xc0\x17\xb9\x6e\xbf\x8d\x3b\x2b\xa4\xd3\x01\x08\x76\xb7\xd7\x4a\xc7\x43\xb3\x9b\xf7\xd6\x2b\x52\x58\x9e\x3b\xaa\x14\xe9\x69\xaa\x61\x5b\x3c\x07\xad\xee\x8a\x97\x6b\x2f\xae\x0d\xb4\xec\x90\x64\x8e\xb5\x8e\x03\xe5\x7d\xfa\x2c\x7a\x76\x40\x4f\xb0\xde\x89\x95\xb8\x39\xbd\x12\xbd\x05\xa7\x63\x8a\x0c\xbe\x83\x75\xf5\x6b\xe6\xb0\x9d\x75\xe7\xe1\xae\xb5\xd3\x0e\xde\xae\x14\x24\xed\x6c\x94\x5f\x93\x05\x11\x4c\x30\xb5\x1a\xcf\x17\x71\x27\x4d\x9a\xc7\x6c\x3c\x4b\xf8\x3b\x7e\xb1\x7f\x1f\x12\x2f\x2e\xf6\xd0\x70\x57\x58\x40\x9a\x10\x41\xc0\x57\xcb\x0c\x8d\xc7\xab\xa4\x85\x4b\x7e\xfd\xd7\x76\x1b\x62\xd6\x41\xb9\xe2\x98\xa1\xf9\xdd\xd9\xab\xf9\x43\x78\x23\x4a\xce\xe8\xd0\xb3\x0b\xcd\xee\x4e\x61\xa9\xaa\xea\x09\xe1\xb9\xcc\xbc\xda\x26\x89\xae\x96\x01\x02\xc5\x90\x04\x21\x02\x35\x82\x91\x8c\xe7\xce\xbb\xce\x3b\xef\xba\xd3\x0c\xde\x9d\x96\xdc\x07\x4f\x94\x93\x4e\x27\xe6\x71\xe3\xb0\xf6\xc5\xae\xb8\x26\xb0\xb1\x03\x11\x35\x8c\x0c\xd5\x07\x03\xe6\x86\xa5\x60\xc7\x47\x24\x04\xd5\x88\x02\xf9\xf5\xba\x65\xe5\x73\xa4\x29\xc0\x66\xee\x5e\x7d\xa1\x18\x5c\x48\x47\x94\x8c\x6e\xfd\x87\x98\x5f\xdb\x74\x15\xd4\x8a\xdf\x65\xc0\xf0\xeb\x49\xe7\x21\xbc\x49\xb9\xcf\x06\x04\x65\x95\x23\x46\x27\x19\x99\xaf\x57\x64\xbe\x30\x7f\x59\x6e\xa4\x4f\x30\x22\x0f\x48\xbf\xdf\x3e\xdb\x90\xc5\x29\xef\x57\x3d\xc7\xf5\x91\x23\x7e\x19\xd8\xb0\x03\xf2\x1b\x42\x44\xc8\x66\x95\x70\x2e\x57\x95\xea\x04\xa5\x73\xd5\x39\x29\x7d\xba\x7f\xf1\x95\x48\xa0\xbf\x9d\x6e\x87\xd7\x5e\x69\xf5\x1d\x6f\x3c\xdb\x17\x55\x56\x2f\xcc\x33\x85\x6e\xb4\x7f\xa5\x3d\x0c\x6c\xb8\x51\x3a\x0c\xee\x50\x34\xb0\xda\xbe\x27\xf1\x87\x69\x3f\xe7\x41\xab\x61\xaa\x31\x06\x68\x34\x59\x26\xf0\x7e\xe9\x32\xb4\x0d\x5b\xdd\x94\x97\xb7\x41\x3e\x75\x34\xc6\x9f\xd4\x00\xc5\x9b\x21\x60\xb0\x81\xd7\x23\x29\xe5\x52\x92\x5c\xf1\xad\xb7\x08\x3e\x61\x1c\x64\x8a\x5b\x56\x8f\xca\xec\x55\x98\x00\x17\x92\x3c\xdc\xf6\x56\x1b\x2d\x90\xc6\x92\xfb\x44\x3f\xce\xdc\x2c\x86\x5e\x6b\x10\x7c\x95\xb2\x7a\x96\xae\x5e\x78\x92\xf3\xfc\x96\x95\x97\x62\x48\x2e\x91\xa3\x30\x4c\x97\xc1\x62\xa2\x8f\xf3\x42\xce\x2e\xe4\x4f\x62\x19\xb6\x0c\xf1\xc5\xb5\x6b\xb1\x99\x78\x30\x1e\x64\x50\x61\x71\x02\x45\xc2\xea\xca\x80\x5b\xc9\x05\x3a\xcb\xc5\x0e\xf7\x27\x0e\x9b\x0b\xf0\x08\xe5\xa9\x83\x72\xd5\xf5\x47\x45\x43\x1e\xe4\xee\xae\x62\xa6\x95\x32\x18\x69\x11\x25\xcb\x16\x91\xee\xe2\x52\x61\xcb\xcf\x10\xad\x22\x2b\x48\xb2\x93\x5c\xae\x32\x3b\x38\x99\x18\x6c\x36\x2b\x4c\xff\xd6\xb3\xb2\x45\xe1\xc9\x16\x05\x8b\xff\x9f\x2d\x37\x5b\x8e\xdc\x42\x9b\x17\xdd\x4b\x95\x7e\x15\xef\xf2\x23\xb8\xa5\x14\xa6\xdd\xde\xbb\xb4\x2b\x78\x81\x38\x5d\x2b\x96\x46\x5a\x57\xf8\x1f\x5f\x62\x2b\xe3\x39\xdd\xd3\x9f\x2e\x4f\x13\x76\xce\xd8\x5e\x9c\x06\x21\x38\xcb\xc0\x03\x1c\xfb\x4b\x20\xb5\x98\xc7\xb3\x16\x97\x2e\xeb\xe9\x9f\x7f\xfe\xe7\xa3\xef\x1a\x12\x3d\x8b\x7f\x13\xfa\xef\x17\xfc\xef\x45\x7e\x95\xff\x22\x75\xd5\xf5\xf6\xfe\xf9\x65\xfd\xf6\x6b\xc0\x35\x6f\x7e\xfb\xe6\x53\xd1\x7f\x9b\xb6\x05\x68\xaf\x4f\x71\xf2\x73\x96\xd5\x79\xf4\x1c\xc1\x06\x07\x07\xf5\xfb\x9b\xfe\xe7\x6f\x3a\x46\xae\x6f\xee\x68\x53\x88\xe7\xb7\xb4\x3b\xd7\x1a\x14\x22\xb7\x8f\x4c\x60\x47\x69\xb4\x5d\xca\xbd\x7a\x5f\x6c\x11\xfe\x02\xa4\x5e\x98\xfa\x7f\x37\x87\xb6\x03\x75\xed\x5d\x16\xcd\xd0\x25\xc2\x7d\xfe\xa9\xaa\x61\xf3\xd0\x25\x54\xb4\x42\x8a\x3e\x15\x94\x73\xcb\xd4\x3d\xbd\xac\x28\x2a\xd5\x79\x48\x6c\x79\xbf\x5e\xcd\x16\xe6\x57\xd8\x0d\x66\xb8\xf0\xbd\x8c\x6a\x1c\x2b\x59\xde\x37\x88\x73\x14\xdf\xa6\x20\x7e\xa1\xa4\xbe\xe2\x0f\x51\x3c\x9d\x2f\x66\x49\xf2\xa6\xc6\xd4\xc6\x5d\x5a\x28\x63\x32\x3f\x7d\x53\xff\xa3\x4f\x0a\x06\xb9\xc8\xef\xd5\xd3\xf5\x12\x03\xe9\x5f\xf9\x76\x43\xd7\x31\xf2\x48\x6c\xf2\x28\x02\xe9\x14\x73\x29\x02\x75\x8f\xf9\x78\xbe\x3c\x18\x68\x98\x85\x30\x55\x76\xe9\x01\xd3\x4d\xc8\xce\x3e\x60\x82\xb9\x78\xc7\x26\xe9\x0d\x0a\xc5\x33\x13\x99\x68\x96\x6d\x73\xd9\xca\x72\xfb\x81\x71\x89\x88\x8a\xa7\xfc\x70\xff\x6d\xbd\x7c\x84\xda\xd8\x57\xd6\xa5\x39\xe2\x04\xa4\xf9\x93\x6a\x3b\xdb\xa7\x69\xd6\x41\x0f\xab\x18\x0f\xfa\xfd\xca\xe8\x07\x91\xa7\xb6\x93\xf9\x0a\x4e\xd2\xa7\x14\xed\x24\x30\x5f\x7a\x82\x12\xac\x9c\xcf\x93\x85\xa8\xf0\x84\x67\xae\xfa\x1b\x89\xc4\x41\x26\x38\x4a\x50\x64\x75\x5b\xa9\x6c\x2c\xcd\x6b\x3c\xa5\xe1\x7b\xa6\xfa\x4c\x8e\x72\x5a\x31\x9b\x25\xf1\x59\x93\x6f\x9b\x0d\xbd\x56\xd7\x3d\x7f\x53\xd4\xdf\x8b\x2e\x62\xb0\x77\x3c\x56\xd1\x49\xf7\x19\x1e\xbc\xdb\xd2\x3a\x33\xcc\x3c\x6e\xf6\x17\xe1\x14\x34\x7d\x84\x2a\x78\x13\x0f\x2f\xab\xe8\x0e\x6d\xf9\x07\xd6\x2f\x13\xc6\xd9\xa2\xec\xb4\x04\x20\xf6\x20\x6d\x47\xc6\xaa\x65\x77\xb3\x21\xda\x30\x3a\x84\xc0\xc8\x30\x7e\x64\xfa\xbd\xea\xaa\x87\x0a\xd8\xe0\x25\x8f\xbe\x55\x20\x53\xd2\x6d\x05\x3f\x63\x48\xaf\x68\x3e\x9b\xed\x9f\xa3\x4c\xb5\xf7\xd0\x6c\x5f\x30\x57\x62\x59\x6f\x09\x1c\x2c\x2e\x35\x6a\xad\x89\x13\x26\x9b\x69\x60\xff\x7a\xdc\x35\x3f\xf2\x88\x49\x96\xc7\xe5\x69\x02\x6b\x8f\x88\xbf\x21\x65\x66\xbf\x75\xb2\x94\xc9\x12\xcd\x7e\x95\x0b\x13\xc8\xf6\xd0\xe0\x67\xbe\x86\xc7\xdb\x62\x49\x6e\xd6\x4f\x28\x1f\xa3\x76\x14\x85\x2f\xc7\x0c\x73\x96\x2c\xff\x0f\xd2\xf5\x8e\xf2\x15\x51\x04\x00\x01\x00\x00\xff\xff\xe3\xaa\x5e\x6f\xb6\x3f\x01\x00" +var _dist_bundle_js_gz = "\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x00\x0e\x40\xf1\xbf\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xc4\xbd\x79\x77\xdc\x48\xf2\x20\xf6\xb7\xd7\x5f\x82\x55\xa3\x29\x01\x5d\xc9\x22\x29\x4d\xf7\x74\xa3\x94\xac\x9f\x44\x89\x12\xbb\x25\x52\xf7\x45\xb2\x39\x60\x15\xaa\x0a\x22\x0a\x28\x01\x09\x1e\x22\xb8\xaf\x7f\x7b\xef\xda\x5e\xdf\x7e\xf6\xda\xde\xfd\xf9\xd8\xf5\xed\xf5\xfd\x6c\xaf\xed\x7d\xcf\xf3\x49\xb6\xfd\x01\xfc\x15\x1c\x11\x79\x20\x81\x42\x51\xea\x99\xd9\xe7\xf7\x24\x56\x22\xef\x8c\x8c\x8c\x8c\x88\x8c\x8c\x6c\x8d\xf3\x78\x28\xc2\x24\x5e\x09\x1c\xc1\x62\x96\xba\x97\x26\x26\x71\x7c\x96\xb9\x97\xe1\xd8\x69\xc5\xfb\xfe\xa1\x0c\x09\x0a\x9d\xfa\xe9\x4a\xce\xdb\x3a\x6b\x9b\x73\x71\x31\x0f\x92\xf1\x4a\x1a\x7c\xcc\xc3\x34\xe8\x74\x54\xa0\x8f\x65\xb2\x4e\x27\x77\xd3\x40\xe4\x69\xbc\x92\x43\xa5\xad\x75\x17\xe3\x43\x1d\x17\xaa\x38\xac\x75\xc8\xe3\xe0\x6c\xe5\x41\x9a\x26\xa9\xd3\xde\xf2\xe3\x38\x11\x2b\xe3\x30\x1e\xad\xcc\x92\x51\x1e\x05\x2b\x37\xdb\x5d\xbf\xdb\xbe\xd9\x76\xfb\x62\x9a\x26\x67\x2b\xc3\xde\x30\x19\x05\xbc\xfd\x64\xef\xfe\xab\xc7\x0f\x8e\x76\xf7\x5e\x1e\x6d\xef\xbd\xda\xbd\xdf\x66\xc3\x2b\xac\x2f\xe2\xd8\x77\x7e\x19\x9c\xcf\x93\x54\x64\xde\xe5\xd5\x55\x1f\xc7\xb0\xbf\x7e\xd8\x1b\xfa\x51\xe4\x44\x3d\x95\xc4\xf4\x68\x9c\x40\x0e\x30\xe6\x94\x71\xe3\x70\x3f\x38\xec\xab\xae\x26\x4e\x3c\x88\xbd\xc0\xbd\x62\x11\x2b\x4b\x06\x4c\xc2\xee\x4a\xe5\xc2\x26\x75\xe2\xd5\x18\x46\x82\xd5\x85\x5f\x02\x2f\xe6\xf3\xf5\xbe\x7f\x27\xed\x45\x41\x3c\x11\xd3\xbe\xdf\xed\xba\x89\x93\x22\xd0\x4d\x17\xae\x9c\xcb\x0d\x6f\xdf\xee\x6d\x3b\xcf\x82\x95\x4c\xa4\xe1\x50\xb4\x09\x8a\x82\x07\x4e\x3b\x0d\x7c\xf8\x76\x59\x6c\x3e\x56\xd3\x24\x17\x41\x0a\x71\x29\x8f\x7b\xcf\xf1\x83\x25\x10\xba\x1f\x8c\xfd\x3c\x12\x14\xd1\x87\xcc\xbd\xb5\x30\x1d\x42\x2e\x0a\x0e\x93\xd9\xcc\x8f\x47\x6d\x39\x3f\x21\xa7\xc8\x2c\x19\x9e\x04\x58\xb9\x2f\xbf\x73\x11\x46\xf0\x95\x71\x5d\x64\x9e\xc4\x41\x2c\xb2\xb5\xbb\xf3\x79\xef\x43\x76\x0e\x69\xf9\x42\xda\x56\x12\xc7\xc1\x50\xa8\xf4\xe1\x62\xfa\xd4\xd7\x89\xd1\x42\xe2\x8b\x40\x88\x30\x9e\x64\x2a\xc3\x5c\x66\xf0\x09\x26\xd9\x1a\x0d\x14\xa2\xc7\x3c\x4a\x60\x9a\x5f\x88\x24\xf5\x27\x41\x2f\xcf\xc3\x51\x7f\x5c\x14\xce\xbc\x17\xfb\xa7\xe1\xc4\x17\x50\x6a\x28\xbb\x81\xad\xd4\xf3\xf2\x31\xf7\x7b\xaf\x5e\xed\xdc\x77\x5c\x97\x85\x3d\x80\xb6\xc9\x5d\xa2\x8b\x7b\xa9\xf1\xb8\x97\x05\xf1\xc8\x69\x63\x49\x48\x77\xaf\x74\x99\x00\xd1\xb9\x5d\x41\x30\x55\x04\x6a\xcb\x92\x28\xe8\x45\xc9\xc4\x09\xa0\x78\x7a\x1a\xa4\xdd\xb6\xb7\xd2\xee\x06\xbd\x59\x90\x65\xd0\x11\xa8\x86\x20\x3f\xe5\xa2\x37\x84\x69\x14\xc1\x83\x28\x98\x01\x0c\x9c\x94\x5d\xc6\xfe\x2c\xf0\xda\xfe\x7c\xde\x66\x73\x5f\x4c\xbd\xf6\x5a\x9b\x4d\x61\xb6\xa2\x20\xf5\xb2\x2b\xb6\xb4\x84\x19\x85\xce\x9c\x43\x67\x97\xe6\xce\x14\xac\xcb\xec\xd1\xb5\xd9\x85\x2f\xf2\xcc\xf4\xc8\x93\xc3\x2a\x0b\x0f\xaf\x2b\x3c\x84\x49\xaf\x17\x5d\xf3\x20\x16\x3a\x1c\x5d\x5f\x47\xc2\x2e\xad\xfe\xb9\xfd\xb8\x97\xe6\xb1\x33\x65\x71\xef\x51\x98\xc1\xac\x5e\x3c\x86\xf9\xc5\x09\xa8\xcc\x84\xe8\xa5\x30\x6b\x41\xea\xd4\xab\x0b\x58\x9c\x47\x91\xcb\x46\xc9\x30\xc7\x88\xde\x71\x32\xba\x80\xd9\xb8\x62\x97\x0b\x98\xe6\xdd\xda\xf8\x9a\x59\x8b\x05\xbe\xbf\x65\xcd\x2b\x01\x92\xbe\x63\x4b\x10\xdd\xbb\x75\x6b\xbd\x9e\x66\x2d\x12\x48\xbe\xc5\xae\x59\x06\x90\xfe\x0d\x53\xab\xd7\xbb\x75\x7b\x83\x95\x2b\x15\x3e\xa9\x28\x2d\x54\xef\xd6\x6f\xd6\x19\x51\x04\x6f\xe3\x3b\x68\xb0\x42\x1c\xbc\xdb\xeb\x57\x87\xec\x96\x4d\x61\x90\xbc\xb9\x97\x2d\x2b\x02\xf6\x89\x06\x6a\x36\x0a\x80\x54\x03\x31\x93\xbf\x3d\x7f\x36\x1a\xc8\xa0\xb3\x7f\xd8\xb0\x5e\x82\xde\xdd\x5c\x24\x51\x18\x9f\x04\x29\x4f\x1d\x00\xad\xd7\x4e\x8e\x3f\x20\x5e\x9a\x2a\xe3\x81\xd0\x94\x14\xb3\x78\x0b\x65\x1c\x31\x0d\x33\xbb\x72\x5c\x2b\x01\x37\x11\xc2\xbd\x0c\x7a\xaf\x60\xd4\x3d\x3f\xcb\xc2\x49\x2c\xf3\x0b\xf7\xaa\x6f\x7a\x31\x4f\x13\x91\x60\x7b\xfc\x12\xd7\xa3\x48\xf3\x21\x60\x8b\x17\xb0\x3c\x8d\x32\xaf\xb5\xce\x82\x99\x1f\x46\x18\x10\x67\xa1\x00\x18\x61\x10\xb6\xa9\x37\xb0\x2f\x25\x67\xf8\x81\xb4\x77\xfe\x34\x85\xb1\x9e\x53\x36\xc0\x3b\xc0\xb4\xc0\x3b\x4d\xc2\xd1\xca\x3a\x1b\x46\xd0\xf6\x2e\xa1\x37\x60\xb0\x98\x45\x4f\xfd\x14\x30\x5b\x27\xcf\x7c\x31\x9c\x56\xa3\x84\x3f\xb9\x97\x87\xd1\xa8\x8c\xc1\x21\x7b\x36\xde\xea\x7d\x45\x70\x1c\x51\x6f\x12\x88\x47\xa6\x66\x07\xa9\xbe\xe8\xcd\xf1\x03\xf2\x02\xb9\x5f\x07\x42\x0f\x93\x10\x42\xc0\x07\x8a\xaf\xb7\x97\xcd\xb0\x1f\xc2\x16\x43\x40\xcb\x60\xab\x0c\x0f\x81\x4e\x53\x65\x2f\x01\x1e\x0e\x52\x65\xf9\x15\x9c\x0b\x87\x76\xed\x76\x20\x97\x07\x4c\x11\xcf\xdd\xb6\x8f\xbf\x32\x8b\x3f\xc1\x21\x3a\x6e\xa7\xe3\x64\xbd\x30\xdb\x8a\x92\x0c\x30\xd3\x71\x07\x29\x7f\x02\xcb\xb9\x37\xf3\xcf\x9d\x74\x75\x83\xad\xbb\x5e\x0a\x6d\xb2\xa4\x37\xcf\xb3\xa9\x33\x74\xfb\x41\x04\xfb\x17\xd5\x1d\x8b\x50\x5c\xc8\xaa\x17\x93\xd7\x21\x3e\x95\x7d\x8d\xe4\xa0\x11\x28\xe1\xf8\xe2\x85\x48\x31\x9f\x2a\x11\xb9\x57\x54\xc2\x54\xa0\xb7\xe5\xa4\xf7\x21\x09\x81\x1c\xb7\x71\xfb\x36\x25\xbd\x06\xb2\xac\x21\xfa\xa4\x9c\x19\xc7\x05\x3a\x31\x8f\xfc\x61\x80\xeb\x01\xd3\x25\xb5\xa0\x2c\xcf\xa9\xd8\x6b\x3f\xa2\x14\xa8\xbe\x29\xcd\xb3\x71\x92\x18\x0c\x84\x27\x55\xa5\x6a\xde\x8e\x01\x76\x31\xaf\x46\x49\x36\x45\x62\xad\x44\x5d\x97\xb5\x11\xe1\xe2\x89\xb5\x4c\x34\x2f\x45\x75\xc6\x00\xa8\xd6\x86\x8e\x12\x66\x24\xc1\xa8\x9c\x47\xd8\xae\x00\xd5\xfd\x78\x88\xc5\x83\x1e\xe2\x0e\xcc\xa0\xa9\xa6\x27\x92\x17\xd4\x86\x23\x77\x9f\xd4\x60\xd9\x4b\x83\x9a\x80\x1e\x09\x4f\x7b\xc7\xf8\x05\x63\x32\x0c\x8a\x55\xf6\x8a\x55\xf0\xd2\xab\xad\x53\x85\xbb\xe5\x92\xd0\x75\x08\xd8\xa3\x17\x12\x89\x35\x0c\xac\x88\x5e\x59\x33\xec\x06\xd4\x96\x35\x63\x4b\x1a\xb3\x56\x5b\x43\x6b\x56\xaa\x6a\xce\x8a\xe9\xd9\xf8\x70\x49\xd4\x81\x0a\x61\x48\x11\x09\xfa\xa6\xa0\x21\x16\x14\xa5\x3e\x2a\x94\x82\x12\xac\x08\xd8\xb3\xd4\x28\x4a\x18\x2f\x19\x44\x49\x1f\x1a\xc6\x50\x26\xaa\x21\xdc\x8d\x87\xd3\x24\xb5\x26\xee\xb2\xa4\x5e\x54\xc2\x7c\x96\xa4\x4b\xd6\xa4\xbe\x2c\x0a\x26\x51\x5f\x7f\xca\x2e\x5f\xb1\x80\x96\xa2\x45\x75\x71\xc3\x90\x78\x43\x5d\x70\x62\x83\x1e\x29\x65\x05\x7c\xc1\x52\x04\x5c\x7e\x89\x41\x6b\x9e\x2f\x4d\x92\x1d\x81\x44\x9c\x5f\xfa\xc7\x00\x31\xd8\xae\x9e\x04\x62\x9a\x8c\x6c\xf0\x90\x40\xd0\xd6\xe9\xed\x2b\x26\x09\xbe\x67\xef\x63\x25\xd9\x44\xfc\x5f\x11\xae\xe8\x4d\xfd\x6c\xef\x2c\x7e\x9a\x26\xf3\x20\x15\x17\xd0\x51\x58\x83\xc1\x7e\x7c\x08\xdc\x7f\x5c\x72\xdd\x01\xf4\xe0\x5c\x00\xa3\xe0\x35\x8d\x51\x94\x7b\x08\x2c\x09\xab\x4f\x57\x48\x94\xcc\xf6\x92\x4a\x16\xba\x1f\x02\x05\xae\x35\xdb\xb6\x76\x9e\xb6\x3b\x80\x55\x6f\xed\x44\xf6\xd6\x69\x27\xf4\x80\xf1\x8b\x2e\x24\x6d\xf0\xd3\x09\x71\x29\x40\x7d\xa8\x15\x9f\x87\x56\xcb\x38\x09\x89\x1e\x8b\x6f\xd7\xc1\x43\xe6\xf7\xb2\x1c\x7a\x41\x93\xca\x53\x36\x02\x0a\x2f\x82\x95\x4a\x17\x58\x75\x0f\xf5\x61\xe8\x2c\x04\x90\x44\x51\x38\xcf\xc2\xcc\xab\xf3\x0a\x66\x6f\x95\x1b\xcd\xa6\x20\xc2\x86\xfc\x14\xe7\xf1\xa0\xdd\xeb\xb5\xbd\x98\x05\x1c\x58\xde\xfc\x58\xd2\x32\x07\x36\xbd\x55\xbd\x31\xb9\x5d\xa8\x1f\x40\x0e\x38\x19\x9c\xef\x8d\x6b\x53\x08\xd4\xeb\x6e\x9a\xfa\x17\xe5\xf8\x7a\x2a\xa3\x6b\xda\x55\x11\x48\x96\xcc\x8c\xc3\xde\x97\x72\xdd\xa5\x7e\xba\x19\xf7\x63\xd8\x87\xa0\x36\x9a\x6e\xa0\xa5\x25\x11\x95\x81\xd5\x8d\x2b\x96\xcd\xa3\x50\xdc\x8d\x47\x5b\xfe\x1c\xa2\x82\xc5\xae\xb4\x80\xbe\x46\xc9\xb1\x1f\xb9\x52\x22\xb5\xe4\xd7\xdf\x51\xe1\xe7\xc1\x24\x38\xff\xdd\xca\x2c\xcf\xc4\xca\xd4\x3f\x0d\x60\x77\x01\x39\x76\x72\x73\x65\x1c\xf9\x93\x95\x0c\xc5\xa8\xb2\x8f\xd0\x43\xd8\xa6\x13\x90\x02\x71\x03\x0f\xce\x83\x21\x6c\x4b\x7d\x37\x95\x7b\x99\x0d\xaf\x04\xf8\x5a\x1a\x25\x2c\x41\x95\x1c\x83\x54\xeb\x92\x44\x47\x09\x5d\xfc\x36\xc3\xd5\xab\x6f\xb1\x22\xac\x80\xd6\xb0\xda\x04\xb8\x9a\x6c\x89\xf0\xce\x1e\xb1\x64\xec\xf2\x6c\x1a\x8a\x20\x9b\xc3\xa6\x44\x23\xf2\xd6\x0e\xb2\xee\x1a\x6b\xc4\xd3\x65\x4c\x97\xdc\x38\x43\xe0\x68\x53\x6c\x8b\x57\x3f\x8b\xc2\xfa\x7e\xf9\xe4\x31\x00\xdf\xb0\x15\x4b\x77\x69\x21\xd3\xb9\xdc\x94\x35\xf5\xac\x16\x69\x2c\x51\x14\xed\x36\xb5\x70\x57\x54\x98\x00\x26\x8c\xf8\xaf\x76\x3c\xcc\x90\x39\x86\x14\xc4\xfb\x01\x10\x87\xb2\xb9\x5a\xf9\x05\x26\x42\x15\x87\x52\xa6\xb9\x6c\x91\x17\x58\xd6\x5a\x15\x8e\xb1\x06\xa2\x69\x39\x5b\x36\x4c\x1f\x13\x71\x53\x30\x1f\x40\x46\x5d\xea\xc2\x16\xae\xf4\xa5\x5d\x56\x7d\x04\x92\x84\xd9\xda\x0c\xb5\x1d\xfe\x68\x54\x2b\x64\x93\x52\x56\x72\x07\x94\x8b\x18\x03\x8a\xa9\xe1\x0c\xf0\x9f\x6a\x3c\x6a\x7d\x02\x33\x9a\x0e\xd2\x1e\xad\x13\x40\x44\x0f\x70\x3f\x03\xbc\xd7\xdf\xb0\x08\xa0\x3f\xd3\x70\x8c\x4c\x8b\xbb\xba\x01\x8b\x34\x24\xe2\xd3\xe9\xf8\x0a\xe5\x0d\xa0\xea\xe0\x56\xdd\x3f\x04\x09\x5e\xb2\x7d\x2b\x6d\x0d\xba\x34\x98\x25\xa7\xc1\xff\x2f\x03\xf2\xd5\x7a\x24\x7a\x68\xc6\x06\x83\x53\x3a\x35\x39\xbc\xfe\xea\x46\x0b\x78\x60\x1c\x25\x96\x04\x9e\x33\x67\x1b\x86\x8f\xfd\x05\x23\x9d\x2c\x4c\xf6\x52\xf4\xd4\xb5\xc8\x75\x01\xdb\xd3\x32\x2c\xa1\xbe\x61\x23\xdd\x1a\x8c\xba\xd8\xb0\xa1\xbc\x98\x21\xa0\x28\xc2\xb9\x1d\xbd\xca\x97\xe2\x5d\x49\x16\xac\xb5\xdc\x50\x6c\x49\x29\xd9\x6f\xcd\x7a\xd6\xf9\xa6\xc0\xe6\x5f\xa5\x9c\xc2\x14\xbb\x44\xfc\x2b\x41\x01\xe5\x88\x12\x9f\xb8\x18\xd0\x20\x51\x68\xdb\x6f\xdf\x69\x93\x9a\xaf\xbd\xd9\x66\xba\x26\xd3\x37\xa8\xab\x7d\x67\x0d\x33\x40\xf2\xa1\x25\x65\x54\xaa\xb6\xbb\x44\xfb\x86\x59\x98\x6a\xdf\x69\x4b\xe5\x5d\x50\x27\x05\xd0\xd1\xfd\xc3\x7e\x85\x71\x09\xdc\xa0\x89\x71\x11\x6a\x51\x74\x6f\xf2\xf6\xcd\x2e\x6e\x6b\xdd\x9b\xed\x9b\xe5\x90\x4a\xfc\xb8\xba\x82\x0d\x76\x81\x31\x5c\x42\xf9\x7f\x11\x8d\x57\xa3\x6e\xa0\x70\x92\x19\x55\x9b\x8c\x73\xa9\xe8\xb0\x07\x32\x24\x23\x30\x78\x96\x58\x25\x87\x2e\x2c\x49\x94\xc2\xb2\xc3\x8f\x80\x5d\x26\x8d\x9c\x41\x0e\x2a\x09\xec\xc0\x30\xc8\x32\x35\x28\x94\x74\xac\x32\x52\xf2\x41\x65\x9a\x26\xe3\x5a\x4a\xab\x51\x51\x6b\x03\xb8\x9c\x42\x43\x1e\xb0\xe4\x8a\x1c\xc8\xfc\x5b\x99\x5c\x1a\xb8\x31\xeb\x5d\x15\x97\x73\xb9\x0e\x53\xb5\xd1\x19\xb6\x1a\x93\x61\xdf\x49\xa1\x37\xbc\x7d\x74\x1c\xf9\xf1\x09\x2a\x66\x75\x0f\x74\x8d\x95\xa5\x61\x71\xfb\x86\xdd\x36\x13\x39\x10\x5d\xc2\xcd\x6e\x7b\x15\x56\x99\x87\x98\xbf\x30\xfa\xa6\x85\xa6\x70\x6b\x94\xbc\x54\x9c\xbd\x83\xd4\xbd\xfc\xac\xcc\x5a\x75\x07\xd2\xbc\x9e\x23\xb7\x3e\x23\x1b\x14\xc5\x6e\x3e\x3b\x06\xe1\xe8\xe9\xde\x8b\x9d\x97\x3b\xaf\x1f\x1c\xed\xec\x6e\xef\xec\xee\xbc\x7c\xa7\x90\xac\x51\x5e\x5b\x82\x69\x98\x57\x72\x17\x0b\xeb\x77\x6d\x7f\x7d\xf5\x3b\x7f\xf5\xd3\xdd\xd5\xf7\x87\x65\xd0\x3b\xfc\x6a\x0d\xd6\xc7\xda\xfe\x8f\x07\xd9\xc1\x7a\xfb\xe6\xe6\xc1\x1a\x3f\x38\x5f\xdf\x58\x3d\x38\xdf\xd8\x3e\x38\xff\xed\xf6\x21\xf0\x28\x31\x5f\x73\x06\x5e\x7b\xff\xc7\xf6\xe1\x57\x83\x76\x71\x73\xff\xc7\x9b\x10\xb8\x59\xc0\x6f\x9b\xdf\xd9\xfc\xdd\x41\x76\xd8\x75\xd7\x70\x96\x7b\x59\x92\xa7\x43\x20\x5b\x90\xff\xe0\x20\xfb\x8a\xe3\x9f\x76\x37\x36\xf1\xee\xa0\x6d\x10\x08\xd0\x19\xfa\xfa\xe0\x7c\xee\xec\x63\xfe\x36\x10\x01\xa7\x75\x7f\x6f\xeb\xe5\xbb\xa7\x0f\x5c\xf8\x92\x71\x50\x43\x57\x7f\xa4\xac\x5d\xb4\x99\x55\x1b\x24\xb8\x5f\xb5\x89\xaa\xd0\x47\x61\x8a\xdd\x71\xd6\xa0\x2d\xf8\x42\x55\xb0\x9d\xdf\xae\x35\x55\xc5\xb1\x97\x6b\x03\x53\x4f\x49\x82\x58\x7b\x12\xc2\x62\x87\xe5\x83\x90\xdd\x9a\xfa\x28\x1a\x05\xe9\x03\xd4\xb3\x84\x41\xa6\x18\x39\xa7\x13\x1f\x67\xf3\x7e\xd1\xf9\xd5\xc6\x37\xeb\xf0\x13\x09\x0c\x53\x70\x22\x83\xb7\xe0\xef\xc7\x3c\xa1\x8f\xdb\xbf\xa1\xbf\xdf\xf5\xdd\xb5\x49\xc8\x48\xc7\xd4\xac\x98\x62\x66\x1f\x35\xd3\x8a\x9c\x2d\xec\x99\x40\xce\x50\x16\xc0\x7d\x44\xf0\x54\xb3\xb9\x7a\x17\xf4\x41\xf4\x5a\xa7\x7d\x73\x7f\x03\xb6\x23\xb1\x7f\x1b\xb5\x52\xad\x96\xd8\xbf\x75\x88\xc7\x04\x15\x26\x58\x28\x26\xb8\x3f\x2c\x75\x27\xd4\x27\x5c\x02\xc0\xb7\xd3\x50\x2f\x76\x93\x51\x90\x39\x43\x54\xc8\x23\x85\x54\x82\x53\x08\x5b\xad\x8e\x72\xac\x15\xae\x34\xc0\x58\x08\xcf\xc0\x58\xee\xd2\xfe\xaf\xb8\x6a\xbd\x85\x5f\x01\x11\x4f\xee\x68\x79\x42\xeb\xa5\xaa\x9c\x75\x3f\xfa\x7c\xaf\xa2\xa6\x5e\xe9\xbd\x1e\x84\xac\x25\xe5\x9a\x39\x17\x94\x1e\xcc\xe2\xaa\xc9\x2e\x7a\xe5\x2e\x47\x05\x57\xcd\x8f\x39\x7f\x0a\x37\x93\x7e\xd2\xe5\xb7\xf4\xc4\xa4\xfb\x09\x4e\x0c\xfc\x74\x37\x0e\xfb\x7e\xa7\x13\x2f\x00\x0f\x7b\x2a\x21\x07\x50\xcb\x9a\x72\x94\x83\x70\xb2\x72\xa4\x86\x1a\x5a\xd0\xaf\x08\xdb\xa8\x74\xb6\x96\x5e\x85\xb0\xd8\x33\x76\x29\x90\xf8\x09\xa6\xf7\x17\xd4\x65\x3d\x4e\xce\x82\x74\xcb\xcf\x48\xa5\x29\x15\x93\x5e\x7a\x65\x14\x75\x65\x8f\x9a\x08\xe0\x62\x6b\xe5\x00\x54\x63\x65\x55\x7a\xf8\x5f\x54\x91\x81\x55\x59\x4d\x13\xc9\xc4\x2c\x4b\x08\x26\x95\x03\x06\xe5\x17\x6e\xd1\x6a\x5b\xf5\x74\x72\x45\xa9\xc2\x94\xc2\x77\xa9\x00\x05\x69\x0b\xfd\xb4\x66\xa0\xd6\xd5\xc6\xe1\xb0\x72\xfb\x6f\x9b\x19\x69\x6d\x98\x8e\x2d\x34\x6d\xf4\xce\xbf\x40\xc4\xbb\x62\x46\x0d\xbd\x2c\xa7\x6a\x7a\x71\x38\x66\x8a\xbf\x6c\x34\xd7\xf4\x5b\xea\xb4\x17\x5a\xd0\x73\xff\xc7\xd6\x8f\xb3\xa1\x6a\x5f\xa2\xaa\x5c\x82\x3a\xd7\x9d\x6e\xd4\x0e\x34\xa8\xe2\x20\x5d\xb6\x33\x3b\x3f\xc2\x56\x7a\x70\x76\xe8\xfe\x99\x73\x70\x76\xb9\xc1\x36\xbe\xbe\x72\x69\x57\x86\xbd\x6a\xff\x60\xb5\xef\x75\xf8\x41\xf7\xe0\x06\x3b\x38\x3b\xe8\x1d\x76\xff\xcc\xd5\x3b\xf2\x3e\x6c\xe0\xb0\x8d\x1f\xee\xaf\xf6\xba\x32\x08\xfb\xfa\x61\xd7\x73\x06\xad\x65\x49\x07\x6b\x07\x6b\x2e\xa4\x1f\x8c\xba\x07\x6b\x03\x17\xb7\x69\x8c\x19\xd0\xf6\x8d\x75\x9e\x9d\x41\x23\xf0\x95\x00\x4f\x60\x0a\x1e\xf4\x0e\x56\x0f\xbf\xb2\xbe\x57\x0f\xd7\x80\xcc\xad\x1d\xf4\xa0\x44\x18\xc3\xa0\x63\x3a\x18\xf4\xa3\xc2\x2c\x24\xf8\xc4\x0f\x5a\x17\x09\x48\xd2\x01\x66\x9b\xa7\x61\x16\x64\xc5\x7c\x9a\x88\x64\x92\xfa\xf3\xe9\x45\x01\x7c\xd7\x48\x66\xcf\x8a\x71\x92\xc7\x23\xaa\xa9\x08\x67\xb3\xe4\x38\x8c\xc2\x00\x82\xf1\x28\x47\x80\x42\xc1\x99\x1f\xfb\x13\xc2\x63\x2c\x87\x8c\x3b\xc6\x8a\x60\x38\x8d\x93\x28\x99\x5c\x14\xc3\x29\xb4\x20\x66\x7e\x56\xe0\x51\x62\x1e\x03\xea\x14\xa3\x30\x0d\xb0\x0f\x17\x45\x00\x2d\xc9\xea\xd1\x5c\x60\x4e\xf5\xa0\x1a\x3f\x14\x39\x30\x62\x33\x3f\x3d\x09\xf0\x34\xb0\xc8\x92\x28\x97\x3d\x3a\xf5\x65\x81\xac\x38\x06\xf6\xd3\x0f\x31\x90\x40\xda\xc7\x3c\x28\x8e\x25\xd3\x0f\x4d\x01\xdd\xc2\x0d\xab\x18\x46\x81\x1f\xcb\x40\x02\xcb\x03\x03\xc9\x6c\x8e\xc7\x82\xc5\x08\x64\xe6\x61\xea\x0b\xe8\x8d\x3f\x4b\xe2\x51\x56\xd0\xf8\xc3\x61\x56\x4c\x93\x68\x84\x67\x90\x45\x14\x4e\xa6\xd4\x3e\x6c\x59\x22\xc6\x9a\xe7\x11\xf0\x86\xd4\xa3\x1c\xf6\x36\x1a\x6b\x0a\x9d\xc0\x98\x53\xe8\x3c\x6c\x4a\x59\x01\x3d\x84\xca\x61\xe8\x7e\x1a\x50\x6f\xa0\x49\x3f\x86\xef\x34\x27\x60\x8f\x92\x19\xf5\x1b\x8f\x01\xb3\x60\x54\x8c\xa9\x19\x00\x76\x94\x20\xac\x8a\x89\x1f\x45\x01\x00\x67\x92\x87\xc0\x62\x53\x77\xc2\x91\x7f\x51\x9c\x84\x88\xb4\x71\x11\x07\x00\x7d\x3f\x2d\x92\x93\x30\xf6\xcf\xfc\x02\x80\x19\xce\xa1\xde\x14\x3a\xe0\x47\xf8\x7b\x1a\x06\x67\x59\x01\xb2\xf8\x49\x36\xf5\x0b\xa4\x07\x11\xa4\x63\x97\x93\x54\x14\xd9\x45\x26\x82\x19\xf4\x73\x12\xc4\xc3\x8b\x02\x58\xdd\x28\x04\xd4\x00\xfa\x92\xfa\xc5\x90\xd0\x02\xfa\x3c\x1e\x07\x01\xe2\xcb\x28\x81\x1e\xfb\x04\x85\x00\x0f\xc2\x83\x22\xc0\x91\x52\xf7\x61\xba\x8b\x71\x2e\x8e\x93\xa8\x38\xf1\xf3\x31\xf4\x2d\xca\xcf\x73\xe8\x3a\x0c\x30\x83\x49\x05\xb8\xfa\xd9\xb4\x98\xe5\x59\x90\xcf\x0a\xc0\x94\xe4\xc2\x97\xb8\x86\xbd\x9c\xfb\x61\x8a\x3f\xd4\xa7\x64\x18\x02\xb2\x12\x54\x2f\x0a\x68\x46\x24\x49\x01\xb8\x04\xd8\x87\x10\x3e\x0d\xa2\xe2\x34\xf4\x3f\xc0\x28\x4e\xc3\x08\xa4\x07\xf8\xc9\x10\x6d\x4e\x13\xea\xd9\x29\x54\x3c\x09\x0a\xc2\x6c\x89\x06\x08\x7d\x98\x53\x00\x98\x3f\x2f\xd0\xa4\x06\x47\x11\x0f\xa1\xf7\x48\x1d\x8a\x09\x4a\x20\x00\x59\xe8\x19\xe2\xf0\x24\x29\x60\x0e\x3f\xf8\x34\xd1\x6a\x39\x00\xfc\x12\x84\x5a\x12\x01\xac\x45\x82\x33\x20\x92\x93\x0b\xe8\x56\x92\x00\x94\xcf\x90\x84\x14\x67\x49\x7a\x02\x90\x0c\xd2\xa4\xf0\xd3\xb9\x5f\xf8\x59\xe8\x03\x44\x61\x16\x8f\xc3\x13\xc0\xc8\x88\xd0\xf2\xd3\x27\x04\x2f\xf4\x23\xca\x8f\xa1\x33\x09\xae\xca\x64\x5e\x8c\xfd\x74\x56\x8c\x43\x80\xd0\x24\x1c\xc3\xbc\xe7\x69\x0e\xd8\x3f\x4e\x8a\x0f\xc9\x71\x06\xd3\x7d\x16\x16\x27\x29\x20\x08\x88\x57\xf0\x27\x9c\x25\x05\x9e\x34\x14\xb0\x4a\xf2\x02\x17\x23\xfc\x01\xf0\xa0\x99\x41\x31\x47\xbc\x9d\x63\x2a\xe0\x94\x28\x3e\xce\x01\x36\x69\x08\x1d\x4c\xf3\x69\x5a\x64\xc1\x39\x74\x1e\xa4\x1d\x84\x57\x80\x7f\x12\xe8\x3f\xc0\xed\x0c\x97\xf3\x59\x78\x12\x16\x9f\x92\x38\xc0\x25\x05\xfd\x1e\xc1\x7f\xec\xf0\x31\xae\x23\x40\x88\x04\x31\x18\x97\x6a\x31\x49\x4e\xa1\x83\x02\xba\x36\x2b\x66\x00\xc5\x38\x10\x45\x12\x47\x45\x92\x4e\x70\xf9\x17\x73\x18\x1e\x76\x58\xc0\x74\xe5\x31\xb4\x01\xe1\xf3\xf3\xf3\xe2\xfc\xe2\x13\xcc\x4d\xe1\x8f\x00\x52\x85\x3f\x06\xcc\x2b\xfc\xb0\x80\xf9\xf6\x67\x85\x1f\x17\x3e\x00\xef\x23\xc0\x0f\xa0\x57\x40\x8b\x7e\x5e\xf8\x67\x85\x7f\x5e\xf8\x9f\xa0\x47\xc5\xf1\x71\x71\x0c\x5d\x82\xde\x8d\x8b\xe3\x49\x71\x3c\x85\xee\x15\xc7\x1f\x8a\xe3\x59\x71\x1c\xc3\xe2\x2f\x8e\xa1\xd3\x40\x05\x00\xe4\xa7\xc5\xf1\x59\x71\x0c\x28\x8d\xdd\x2f\x86\xc3\x62\x08\x78\x30\x2e\x86\xb0\xec\xa7\xc5\x30\x2c\x86\x27\x30\x05\xc5\x70\x56\x0c\x91\x14\xc2\x82\x2c\x86\x79\x31\x3c\x2d\x86\x67\xc5\xf0\xbc\x80\xb5\x30\xfc\x04\x74\xa1\x18\x7d\x28\x46\x27\xc5\x68\x06\x2b\xb5\x18\x7d\x2a\x82\x61\x01\x4b\x21\x00\xfc\x4f\x61\x09\x14\x30\xe6\x20\x87\x69\x2b\xc6\x1f\x8a\xf1\x49\x31\x86\x29\x4c\x8a\x71\x0a\xcb\xb6\x98\x1c\x17\x93\x51\x01\x88\x38\x19\x17\x93\x49\x31\xc1\x89\x05\x54\x2b\x26\xb3\x62\x12\x17\x93\x79\x31\xf9\x08\x54\xa6\x00\xca\x32\xc1\xe9\x2e\x26\x67\x05\x90\xc8\xe9\x49\x31\x9d\x15\xd3\xb8\x80\x99\x9a\x8a\x62\x0a\x48\x30\x2a\xc2\xa0\x00\x00\x03\x9c\x61\x69\x86\x49\x11\x7e\x2c\x60\xb1\x84\x59\x11\x8a\xe2\x43\x50\x7c\x98\x01\x8e\x14\x1f\xe6\x05\xe0\xd8\xc9\xa4\x38\x99\xc2\x94\x14\x27\xb3\xe2\x24\x2e\x4e\x20\x32\x2d\x4e\xce\x8a\x13\xa0\x18\x9f\x00\x77\x8a\xe8\xb8\x88\x86\x80\x3a\x45\x74\x52\x44\x69\x01\xb8\x1b\x09\x58\xa8\x45\x74\x5a\x44\xb8\x54\x8b\xd9\xb0\x98\x8d\x00\xad\x8a\xd9\xa4\x98\xc1\x72\x05\x14\x8b\x8a\x19\x4c\x31\xae\xe0\x02\xf0\x76\xf6\xb1\x98\xa5\x05\x90\x8c\x99\x80\xc5\x5c\xcc\x4e\x8b\xd9\x59\x31\x3b\x2f\x80\xc8\xcd\x3e\x01\x02\x16\xf1\x10\x70\xa1\x88\xc7\x05\xe0\x54\x1c\x16\x80\x12\x30\xfb\xf1\xbc\x88\xd3\x02\x70\x35\xfe\x54\x00\x02\xc1\xea\x98\x03\xa2\x8e\x8b\x39\x20\xcb\xb4\x98\x03\xaa\x46\xc5\x1c\xe2\x63\xc0\x9d\x02\x70\x73\x0e\x7b\xc8\x59\x31\xbf\x28\x3e\x22\x4d\x2b\x00\x9f\x80\xf8\xc1\x92\x48\xcf\x8a\x0c\xa8\xd8\x71\x91\x0d\x8b\x6c\x04\xc8\x5c\x64\x40\x7f\xa7\x40\xd7\x8a\xec\x43\x91\x9d\x14\x19\x10\x8e\x59\x91\xc5\xb0\x56\x8b\x0c\xb0\x1d\xc8\x49\x5e\x64\xa7\x45\x76\x0e\xb4\xae\xc8\x3e\x15\x62\x58\x08\xc0\xca\x71\x21\x26\x85\x98\x16\xe2\x43\x21\x4e\x0a\x11\x15\x62\x56\x88\x18\xd6\x73\x21\xe6\x40\x65\x0a\x21\x0a\x71\x5a\x88\xb3\x42\x7c\x2a\x72\xbf\xc8\x27\x45\x7e\x52\xe4\x59\x91\x5f\x14\xf9\x27\xd8\x79\x8a\xd3\x21\x50\xf9\xe2\x14\xe8\x4d\x58\x9c\x02\xf1\xc9\x8b\xb3\x71\x01\x94\xf6\x22\x28\x2e\x44\xf1\xc9\x2f\x3e\xcd\x8a\x4f\x67\xee\xc1\xf1\x1a\xf3\x61\xbb\x3e\x58\x35\x1b\x74\xb7\xf3\x67\xbf\x3a\x58\xfb\x35\xff\xcb\x47\x8e\x5b\xdc\xbc\xf1\xd5\xc1\xfe\xc1\xe1\xa0\xe5\xb1\x5e\x1f\xb6\xf1\xcf\xe4\x3b\x5c\x6b\x96\xd0\xdb\x4c\x0b\xd2\x96\xac\xdd\x66\x5a\xe6\x67\x89\x0e\x84\x4d\xd9\x94\xdc\xed\x94\xe2\x7b\x59\xa0\x26\xba\x3b\xbd\xc1\x1a\x09\xef\xe9\x17\xe7\x5c\xd2\xb6\x96\xf7\x41\xe6\xb4\x14\x10\xcb\x44\xfc\x21\xc8\x74\xf7\x02\x10\x05\x83\xa7\x78\x30\x36\x4c\x40\xe6\x8e\x94\x0d\x02\xc9\xf9\x3f\x3a\x3d\x77\x80\xfc\xd2\x1f\x74\x6c\x43\x4c\xe0\x6b\x1f\x37\x57\x3c\x37\x94\xc2\xcc\x93\x4a\x24\xaa\xd6\xc9\x6c\x61\xe1\x40\xb0\xb4\x21\x28\x0f\x36\xb4\x3d\x45\x59\xbb\x62\x31\x2d\xfb\x2c\x96\xb0\x90\x91\x0c\xce\x86\x2c\x62\x73\x59\xd3\x18\x24\x54\xa5\xef\xda\x02\x62\x8f\x8d\x4b\x63\x8b\x86\x02\x68\xec\x30\x96\xc5\xc8\x84\x0e\xad\x29\x62\x36\x96\x0d\x1a\x0d\xde\x18\xea\x43\x6e\xf7\x85\x48\xbb\xd3\xee\x18\x84\xf8\xb1\xfc\xd2\xe2\x69\x80\x22\x5e\x63\x9b\x35\x21\xd5\xee\x80\x52\x0a\xb0\x39\xcf\x8b\x62\xc8\xc6\x1c\xed\x7f\xe0\x0f\x19\x60\x74\x3a\x2d\xdb\x34\xa0\x28\x42\x1d\x23\xf7\xdc\xc2\xd7\xdf\xc8\xa9\x17\x45\xab\x61\x16\x7a\x61\x46\x61\x39\x78\x6c\x75\xee\x9a\x53\xcc\x3c\x8a\x8c\x85\x09\x15\x7b\xe4\x67\xaf\xe2\x63\x3f\xc2\x8d\x7d\xa4\x04\x23\x10\x11\x02\x9c\xf9\x4e\x07\xcd\x07\x94\xf2\x02\x0f\x63\x95\x0a\x60\x75\xc3\xc5\x2e\xbb\x80\x68\xa1\x1b\xd9\x36\x11\xbd\x07\xd8\x4d\xe7\x72\x56\x9a\x96\x80\xd4\x2d\xa5\x89\xf0\xaa\x34\xdb\x89\x5d\x54\x8f\xc2\x94\x31\x6a\x80\x8e\x33\x36\x5c\xb4\xe9\xb4\x2b\x7b\x29\xa1\x50\xaf\x4e\x01\xe7\x11\xd9\xf5\x79\x89\xaa\x16\xf5\xe7\x0a\x15\x46\x7c\x2e\x6b\x50\x1a\x86\xeb\xd7\x80\x4b\x1a\x25\x98\x80\x11\x75\x69\x54\xed\xd2\x55\xb5\x4b\xaf\xd2\x85\xd1\xc1\x4c\xc0\xdf\xb9\xaa\x1a\x32\x48\x0c\x68\xb5\x32\x13\x09\xed\x01\xfb\x77\x1a\xe8\x94\xf9\x67\x6c\x3e\x14\x82\x5d\x1a\xfc\xf3\xc6\xcc\x60\x9f\x37\x95\xb2\x97\x17\x5d\x5d\xb1\xeb\xe7\xb0\x41\x79\x1c\x10\x38\xee\x0a\x27\x28\x27\x93\x6c\xb8\xdc\x36\x1d\x77\x2b\x35\xb7\x1a\xaf\xb3\x76\xe0\xac\x4d\x5c\x52\x1f\xe9\x08\x17\x23\x12\x1e\xa3\x1a\x47\x56\x51\x14\xa4\x20\xea\x74\xd2\x32\x82\xac\xb9\x37\x13\x85\x78\xad\x75\x35\xa4\xd6\x86\x14\x4b\xab\x34\x62\x89\x34\x1a\xc6\xa7\x98\x63\x19\xe5\xda\x07\xf1\x52\x52\xae\xa9\x9f\x6d\x03\x66\x97\x19\x55\x86\x6b\x04\xc6\x35\x98\xb7\xf0\x05\x4c\xe3\x2c\xf8\x5c\x76\xaa\xff\x4d\x92\x8e\x50\x41\x76\x77\x0c\xa8\x57\x6b\xc8\x43\x4d\xf3\xe1\x57\x03\x5d\x01\xc8\x91\xd6\x12\x5c\x66\x08\x21\xf4\x52\x56\x99\x5f\xe9\xfe\xc0\xca\x53\xc7\xde\xb9\x42\xa6\xfb\xc0\x45\xef\x26\xe2\x11\x30\xf1\xba\xe9\xbd\xf4\x7e\x22\xe8\x60\x62\x79\xde\xbb\xe2\x71\xe0\x67\x62\x2f\x0e\x74\xef\xed\x02\x61\xb6\xb3\x00\xdf\x12\x4b\x61\x89\x0e\x5a\x1b\x20\xe8\x5f\xb1\x7a\xff\x1a\xb1\xca\x5a\x6f\x55\xc0\xba\x68\x70\x50\xd1\xb6\x29\xfa\xda\xfe\xe0\x9f\xfa\xd9\x10\xd0\x5e\x78\xed\x16\xe0\x5e\xa7\xd3\x3e\x3d\xb6\x23\xae\xd8\xe7\x00\x50\x3b\xa2\x51\x38\xe6\xb4\x02\x18\x63\xa7\x23\x35\x9b\x0d\xb8\xd1\x13\x20\x5e\x10\x98\xe9\xe0\xb2\x34\x0d\x69\xf7\xda\xb0\xe4\x9b\x9a\x5d\x84\x65\x63\xdb\x2b\x01\x34\x3b\x68\xe9\x96\x97\x63\x8d\xec\x42\xe0\x7a\xb0\x22\xd8\xf5\x53\xd1\x70\x68\xd3\x6a\x05\x6a\x78\xd7\xad\x11\xdd\x86\xa5\x09\x92\x0b\xef\x4f\x73\xa6\xf7\x59\x85\xa1\x65\x60\xb8\x4c\xd7\x66\x91\x52\x69\xbe\x60\x0e\xf3\x96\x57\x6b\x1d\x67\x35\xe6\xb1\x46\x4b\xdb\xd1\x82\x36\xcd\x82\xc4\xb5\x5a\x3a\x2c\x2c\x75\x8b\x54\xcf\xb2\x31\x50\xbe\x7a\xef\x17\xab\xc3\x5c\x22\xf1\xd4\x11\x79\xbd\xd0\x75\x40\x92\x79\xad\x61\xa9\x8d\xf1\x0f\x1d\x98\xda\x40\x95\xda\xb4\xb2\x9b\x2e\x53\x9e\xda\x99\x3e\x3f\xd4\xa9\x10\xf3\xcc\x5b\x5b\x53\xc5\x7a\x20\xfc\xae\xa9\x71\x2f\xab\xa9\x79\xfc\xed\x3f\x6b\x2c\x66\x81\x02\xf6\xdb\xeb\xc1\x00\x6b\x59\x6e\xab\x86\xe1\xa5\xde\x69\x25\xa1\x23\x95\x83\x83\xb5\x70\x61\xb7\xd6\x05\xe4\x76\xa1\x53\xa1\xb2\x39\x5e\x0e\x18\x5d\xaf\x9a\x86\x66\x25\x7c\xa1\x83\x4b\x0c\x0f\x20\x4b\xc5\x50\xa5\x91\x5b\x50\xc4\xba\xce\x5e\xd4\xa2\x4d\xa7\x8a\xc2\x29\x6b\xe7\x34\x11\x30\x0f\xed\xae\xb2\x4f\x5e\xc8\xcf\x5b\xeb\x64\x55\xb7\x74\x46\xab\xd6\x07\xc8\xfe\xb8\x8b\xdc\xfa\x5a\xc7\x9f\xcd\xfb\x6b\x13\xd6\xee\xb4\xdd\x6b\x26\xf5\x9a\xca\x96\x43\x00\x6d\x2f\xb9\xcd\x23\x55\xf3\xc8\xc9\xc5\xa3\x42\x56\x67\xa4\x6a\x25\x5f\x69\x4c\xa0\xcc\x81\xb6\xa9\x46\xbb\x9f\x97\x29\xac\x30\xe0\x9a\x5e\x44\x3e\x5a\xc2\xa1\x79\x4a\xa5\x44\xe3\xb9\x79\x55\x58\xa9\xe2\x19\x23\x5b\x8f\x6b\x3a\xfc\x05\x35\x36\xe2\xa3\xac\xb8\xa1\xd7\x0d\x15\xb6\xd7\x90\xa7\x6b\xe2\xf8\x08\x32\x81\xe2\x72\xd7\xd9\x2a\xf2\xde\x72\x59\xd1\x5d\x96\xab\x43\x76\xbb\x7a\xd9\xc3\xba\x03\x28\xed\x6a\xa1\x7f\x47\x52\x8b\xc9\xed\x8f\xa2\xb8\xbc\x92\xf3\x70\x34\xf3\xcf\x1f\x87\x19\x2c\xc9\x20\xd5\x79\xec\xa8\xa2\x90\xb7\x18\xae\x4c\xc5\xa9\xd5\xf3\xc5\x8b\x24\x41\x99\x31\xb1\x32\xc6\x64\x68\xd0\x98\x2d\xb4\xb2\xd5\xef\x90\xc0\xf6\xa9\x4e\x9b\xad\x02\xbe\x35\x17\xb2\x73\x08\xbe\xab\xf2\xb6\x49\x0c\x82\xfe\x03\x1c\xe7\x83\x99\x24\xc0\x18\x51\x5a\x9c\x6a\x80\xa8\xeb\x19\x95\xa4\x0a\x34\x4c\x86\x91\xbc\x65\xf7\xc4\x4e\xdc\xa8\x96\xcc\x82\x6a\xb2\x3d\xcd\x68\x32\x84\xc0\x00\x7e\x7b\x13\x58\x9e\x30\xdb\xf5\x77\x11\xb9\xa5\xd5\x29\x52\x26\x65\x75\x1a\x4b\x53\xd3\xe3\x60\xc5\x5f\x99\x83\x7c\x80\xe8\xb4\xa2\x40\x57\x5d\x82\xd5\x8e\x6a\xab\x2b\xbb\x43\x01\x8c\x9d\x2f\xb0\x80\x20\xe6\x26\x52\xc0\x35\xf2\xa5\x41\x89\xca\x27\x5a\x1c\x32\x75\xfd\x0d\xc1\x0b\xa8\xd8\xb2\xd3\x7b\x94\x04\x83\x71\x16\x63\x5d\xcd\x32\x57\x62\xf5\x69\x3b\xc1\x43\x70\x63\xf5\x0c\x72\x1d\x13\xf6\x95\x06\x02\x86\x02\x8e\xe8\xd7\x81\x74\xf3\x55\x3c\xf4\xf3\xc9\x54\xb0\x95\x3c\xce\xe6\xc1\x30\x1c\x87\xc1\x68\x45\x75\x75\x85\x5a\xec\xdd\x74\xaf\xe8\x32\x85\xdd\x8b\xfd\xe0\x90\xf9\xc0\x2f\x6b\x59\x67\x03\x21\x90\x62\x44\x76\x16\x92\x0c\xae\x7b\x64\xec\x02\x86\xc0\x08\xaf\x6c\x78\xd6\x45\x0e\xb7\x7f\x9c\x06\xfe\x49\x9f\x52\x6e\xd9\x29\xcc\x1e\x50\x25\xdb\xed\xa5\xd9\xac\x8f\x5b\xa6\x8c\x42\x36\x0f\x0d\x03\x12\x5e\xef\x14\xcb\x48\xd0\x25\x2b\x6a\x27\x41\x11\x3f\xe7\x1b\xfd\x64\x33\xef\xe7\xdd\xae\x9b\xed\xe7\xab\x1b\x87\x16\x6c\xf3\xc3\x7e\x6c\xdb\x9a\x67\xea\x86\x0d\x8a\x7d\x38\xf4\xcb\x3f\x55\x2b\x58\xcf\x90\xc7\x8a\x56\xa1\xe4\x39\xd4\x75\xe5\x7c\xdd\x14\x1d\x42\xde\x5a\x7f\x8c\xe8\x59\x41\x5f\x7f\x34\xd2\xf8\xcd\xab\x14\x0e\xf1\x38\xa1\xdb\xc9\x29\x70\xbd\x8b\x8b\x28\x52\xc5\xac\xb5\x64\xc8\x94\xfb\x25\x58\x5f\x41\x5d\x00\x83\xee\x87\x62\xe5\x71\x61\xc1\x52\x2d\xe3\xd1\x7a\x10\xef\x20\xea\x86\xdd\x41\x19\xf6\x44\xb5\x3e\x40\xc2\x41\x75\xc9\x40\x0c\x14\xa8\x46\x28\xbb\x0b\xd7\xab\xc5\xf3\xfd\x3a\x42\x8b\xc3\x85\x3c\x82\x2d\x36\x50\x5b\x90\xd8\xc4\x99\x9f\xc6\xc1\x48\x83\x13\x50\xc0\x59\x24\x2c\x78\x9b\xa1\x81\xf6\x79\x8b\x39\x59\xd2\xe9\x24\x9b\xeb\x0a\x44\x56\x33\xea\x16\x41\x82\x4a\xaa\xc6\x1e\x00\x6b\xc3\xf4\x5d\xda\x40\xce\xa0\x13\x27\xa3\xc0\x5d\xc1\x74\x3c\xff\x47\x52\x98\x85\xc7\x51\xb0\x62\x13\xf5\x95\x19\x6c\xae\xe9\xc5\x4a\x04\x6b\x66\x65\x14\x08\xd8\x37\x82\x51\x6f\xe5\xd7\xa3\x15\x0d\xfb\x6c\x05\x90\x08\xe3\x5e\x01\xc2\x07\xb2\x54\x9d\x4e\x3b\xee\x8a\x48\x80\xf8\xa0\x05\x08\xe4\x8a\x42\xc8\xd6\x6b\xd7\xa7\x4c\x13\x04\xd6\xb0\xe1\xe9\xbe\xa3\x64\x03\x54\xb2\xf2\xe9\xb8\x15\xcb\xdf\x2a\x86\x27\x31\x5f\x82\xf0\xb5\x6c\xc3\x80\x7f\x6e\x8f\x97\x8c\x86\x2e\x8f\xf7\x5f\x61\x05\x02\x6e\x27\x08\x5d\xd1\x7c\xd9\x84\x48\xe4\x1f\xb4\x86\x08\x65\x38\x10\x50\x73\xe5\x4c\xe7\x57\xc6\xf5\x3d\xea\x69\xec\x36\x6c\x4b\xd5\x9e\x36\x2c\x6d\xdc\xa0\x7c\x96\xfd\x31\x0b\xbc\x55\x5d\xe1\x75\xd4\x77\xad\x29\xe9\x37\x6f\x13\xe6\x9e\x25\xd0\xb1\xd5\x0d\x86\xb7\xf2\x44\x51\xc0\x66\x51\x2e\x72\xd2\xab\xe9\x61\xa0\x4a\x4e\x5d\xbe\x59\x58\xa1\x36\x35\xa9\x8e\xbe\x42\x50\xaa\x49\x64\xb2\x5c\x2a\x62\x4b\x5a\x9d\x71\xbf\x9f\xad\xae\x6e\xae\xf7\xf1\xfa\x4b\xbc\x9f\x1d\xca\xbe\x61\xc8\xf4\x07\xfa\x66\x7f\x4a\x8d\x61\xc2\x33\xb9\xc3\xe0\xbc\xaf\x1b\x9d\x9f\x04\x03\xda\xe7\xeb\x31\x0f\x1c\x1d\xe2\xeb\xac\x79\x54\x2e\x6c\x69\xca\xbc\x3d\x61\x1b\xee\x1f\x35\xc8\xe5\x2b\x44\xe6\xbe\x1b\x45\xcd\x6c\x95\x62\x68\x16\x66\xbc\x3e\xbf\xad\x6b\x7a\xa7\xf3\x22\x0b\x59\xdf\x04\x2b\x54\x19\x76\x86\x3a\xa5\xc5\xdb\xd2\x4b\xa7\xbc\xaf\x6e\xbd\x2e\x32\x15\x38\x8b\x82\xae\xb0\xd9\x7d\xae\x83\x46\x6a\xda\xac\xc5\x6d\x83\xc1\xba\xb2\xb9\x2c\x47\xbd\xbe\xea\x1c\x71\xc5\xfe\x37\x73\x49\xc4\x14\x2d\xa3\x2b\x12\x27\x71\x10\x7d\x73\x19\x79\x59\xe6\xfd\xd8\xc8\x32\xe5\x7d\xbc\x6b\x80\x56\x9d\xfe\x68\xf9\xac\x5b\x96\xfe\x56\x35\x0b\xbb\xcf\x20\x5d\xdc\x6a\xeb\x5b\xe8\xc2\x06\xaa\x59\x18\x6f\xff\x10\xfb\xa3\x7b\xb1\x95\xe4\xb1\x68\xa2\x57\x86\x0a\xf2\xa0\xec\x88\x09\xee\x0b\xec\x85\xfd\xe9\x0e\x36\x3c\xfb\x5b\x81\xc8\x5b\xbf\x92\x22\xdd\x6f\xae\x15\xe9\xae\xf4\xb5\x45\x2d\xec\x5c\x5e\xf5\x53\xe0\x52\xce\xc5\xcb\x70\x78\xc2\x17\xa4\xf8\x76\x1e\xcb\x8b\xfc\x23\x40\x29\xb5\x65\x9d\x29\xcb\x76\xf9\x8b\x5b\xe2\xce\x6c\x16\x8c\x42\xbc\x2e\x2a\xbe\xa4\xc4\x93\x5c\x90\x69\xd2\xde\xb1\xf4\xf2\x00\x04\xf2\x0b\x4a\xa1\xbd\xc6\x13\xe9\x19\xc3\xc4\xc1\xae\x47\x9b\xba\xc6\x1a\x5c\x36\x81\x5e\x94\x0d\xb2\x77\x43\x97\x51\x0f\xa0\x2e\x3a\xef\x1f\x12\x7f\xa7\x98\x1a\x6e\xdc\x3f\x54\xbd\x43\xb4\x47\xe1\x29\x9e\x89\x11\x8b\x5b\x1f\x8a\xb3\x00\xc1\x54\x23\x44\x3f\x2d\xc9\x62\xd0\x83\x15\xf0\xc0\x07\xa9\xc1\xee\x64\x80\x9e\x10\xca\x7b\x0a\x61\x2f\x91\xb5\xa2\x7f\x0b\xbc\x27\x11\x1e\xe7\x22\x40\xcb\x3d\xe0\x32\x2b\x83\x33\x07\x32\x89\xbe\xc3\x45\x59\x9d\xf6\x45\x90\xb5\x59\x3b\x4e\xda\xe6\xa6\x20\xea\x89\x35\xc6\x0d\x9c\x25\x60\x74\xda\xca\x05\x49\x7b\xc1\x37\x0e\x9e\x02\xc8\x13\x69\x84\x15\x08\x62\x9c\xcb\x4a\x60\x0f\xa1\x4b\x9e\x1c\x4f\x14\xdb\xea\xbc\x74\x55\x00\x56\x49\xf5\xc4\xc8\x17\x3e\x2a\x24\x7a\x99\x48\x50\x5b\x32\xf7\x27\xbe\x04\x14\xd3\xfd\xdf\x5c\x77\xf5\xc9\x54\x6a\x2e\x7f\x41\x06\xc0\x6c\x54\x60\x55\x87\xac\x46\xc3\x16\xb1\xc3\xa9\xb6\xce\xda\x5f\xb5\xd1\xc3\x84\x5d\x1c\xaf\x17\x86\xb3\x20\xc9\xf1\x70\x65\x1d\x1a\xa0\x5e\x88\x50\x44\x80\xf2\xc7\xc0\x30\x64\xb8\xbd\xa4\x3d\x15\x44\x36\x28\xed\x05\xf1\x29\x12\xbe\xb4\x07\x44\xf9\x94\xcc\xad\x89\x09\xc3\x08\x4b\xda\x88\x29\x1a\x98\x2e\x0a\x8c\xc7\xf4\x5b\x63\x5b\xca\xa8\xca\xee\x84\xd1\x24\x77\x63\xe0\x18\xc6\x05\xec\xab\xbd\x24\x17\xae\x99\xaa\x71\xea\xbc\x2b\x61\xb6\x82\x6e\x93\x94\xfd\x1a\xac\x25\x54\x22\xf5\x86\x67\x23\xbb\x16\xa3\x35\xa2\xb4\xe9\x28\x4c\xbf\xa8\x0d\xca\xd9\xd4\x82\x24\x3b\x5f\x2f\xba\x0d\xa9\xe0\xb6\xbd\x30\x6c\x5d\x90\xba\x4b\x1b\xb4\xec\x63\x49\x44\x18\xbc\x41\x80\xd8\x44\x4b\x7a\x13\x58\x94\x56\x5c\x14\x16\x99\xb0\x95\x3c\x66\x1f\x26\xa1\x5c\xa0\x96\xa4\x95\x36\xe7\x86\x5d\x51\xbb\x4c\x58\xdd\xd0\x2b\x61\xbd\xa2\x75\x92\xbd\xc7\x8a\x5a\xd6\xd5\xe0\x99\xdc\xbe\xb4\xbd\x7d\xca\x1d\xe8\xcf\xba\x0b\xec\x5d\x52\x5e\x2d\xee\x76\xd3\x3b\x49\x5f\xde\x2c\x4e\x2b\x37\x8b\xf5\x75\x7d\x68\xd4\x56\x5d\x31\xeb\x2c\x56\xd5\x81\x2d\xe0\x1a\x4b\xf1\xec\xaa\x1f\xaf\xae\xf6\x5d\xba\xa6\x8c\x7f\x7a\xa7\x7e\x94\x9b\xcb\x40\xcd\x4a\xad\x05\x17\x11\xc1\x20\xf0\xe4\xda\x0c\x06\xed\xb6\x17\x74\xdb\xed\xb2\x60\x56\xd1\x4c\xa2\x0e\x71\x0b\xa4\xa7\xbb\xc2\x81\x55\x61\x32\xe5\xb5\x1b\xf4\xc8\xd4\xa6\xf6\xa8\xe3\x3b\xc8\xa8\x99\x03\x36\xa3\x8c\x04\x46\x60\x73\x75\xa3\x6f\x5d\xbd\x32\x75\x0e\xeb\x75\x9a\xea\x60\xc8\xbf\xb4\xb2\xa8\x72\x3a\x87\xf0\x1b\xa6\x21\x9a\xb6\xfa\xe4\x2b\x48\x06\xdd\xa2\x50\x67\x80\xab\xaa\xf6\xb2\x82\x79\xc3\x08\x71\x5e\x4d\x35\x21\x2f\x2b\x02\x06\x3f\xb1\xc7\xee\xf7\xb5\x1f\x95\xd4\x49\x60\x96\x58\x48\x0e\x04\x00\x0b\x0c\x33\x99\x19\x6b\x92\x65\x3d\x18\x5b\x13\xf1\x48\xe0\x9d\x61\x93\x34\xb5\x92\x5e\x57\x93\x46\xd6\xbc\x1f\x1c\xb4\xbb\x1f\xab\xc9\x33\x8d\xcd\x25\xda\x06\xa5\x68\x12\x0f\x50\x2a\xf1\x1c\x21\x11\xb9\x1f\x0f\x92\xd5\x55\xaf\xdb\x4d\xee\xa4\x6a\x44\x21\x60\x5d\x42\xbb\x62\x08\x6b\xc1\xf8\x6d\x4b\xae\x16\x91\xf9\xd4\x46\x24\xd8\x01\x16\x74\xb1\xb0\x26\xad\xec\x13\x2b\xfb\xc6\x37\xeb\x9b\xa8\x22\x0c\x36\xf9\x77\x9d\xce\xc6\x6d\xf8\x28\x8a\xdb\xb7\x38\xfe\x40\x1a\xfd\x7e\xfd\x5b\x15\xf8\x66\xe3\xeb\x6f\x29\x00\xb9\xbf\xdd\xf8\xee\x16\xec\x29\xdf\xde\x5a\xbf\x45\x65\xbe\xbd\xa5\x4a\x41\xe0\xb6\x0e\x7c\xa7\x02\xdf\xfe\x56\x56\x78\xeb\xd6\xb7\xb2\x82\x6f\xbe\xbe\xf5\x5b\x4c\xb4\x10\xfd\xe2\x5a\x44\x97\xd2\x1c\x5d\x62\x22\x94\x57\x0b\x93\x58\x6d\xe9\x4a\xe0\x0d\x4c\x3d\xc0\xef\x90\x97\xb7\x93\xc3\xb2\xf6\x07\xb5\xda\xa1\xea\x0a\xf9\x80\xaa\xe1\xdb\x97\xf5\x13\x21\x51\x68\x85\xc4\x84\xe5\x5c\x0c\x84\x93\xb1\x94\x05\xae\x97\xf5\x51\x4a\x43\x77\x39\x20\xa6\xc7\x3c\x67\x3e\xb4\x1b\x1e\x72\xa3\x10\x5b\xf1\xcb\x76\xb7\xaa\x5e\x83\x48\x22\xb5\x16\xaf\xb8\x13\x77\x3a\x13\xa7\xb2\xfa\x05\xde\xc9\x32\x6c\x72\x59\xd5\x71\xb5\x2a\x53\x8b\xc0\x35\xfb\x85\x75\x9c\x5b\x53\xff\xa6\x8a\xaf\xcf\xa9\x7a\xfd\x25\x94\xf6\x1b\x51\xab\xd3\x69\xdd\xc8\xe4\xaf\x13\xd8\xea\xde\x89\xd4\x08\x57\xe2\x8c\x53\x1c\x62\x52\x82\x4c\xea\x4f\x03\xd6\x3e\x3a\x82\xfe\x85\xf1\xd1\x51\x1b\x2a\xaa\xc4\x9f\xa5\xfe\x7c\x1e\x8c\x30\x45\x17\xbe\x8b\x47\x15\x86\x59\x82\x1d\x11\x37\xb2\xb2\xaf\x66\x9f\x93\x02\x40\x59\x83\xd2\xa7\x43\x94\x72\x15\x06\x51\xb0\x57\xec\x6b\x61\x5e\xf7\x01\x2f\xb6\xd5\x16\xc4\x17\x55\x05\xa4\x5c\xc7\xc2\x96\x0c\x31\x1b\xe6\x13\xd8\x2a\x12\x34\x20\x72\x5d\x47\x8e\xc3\x08\xa8\x16\xd5\xd6\x32\x39\x91\x90\x01\x4f\x1b\xd4\x2b\x14\xfe\x49\xa0\x6b\x78\x91\xe9\x58\x32\x93\x57\x39\xcb\x1e\xdf\xa8\x9e\xf5\x59\x7d\xd4\x17\xac\x2b\xed\x30\x2d\x29\xea\xea\x98\x34\x25\x9c\x38\xf5\x51\x5b\x1e\x63\xec\x81\x07\x83\x1b\x64\x4b\x41\xfd\x4d\xcd\xe8\x6d\x50\xc8\x68\x0b\x0a\x8b\x80\xa1\x2c\x16\x4c\x16\xa0\x44\x19\x6c\xf8\x08\x6c\x57\x58\xed\xda\x40\x5a\x84\x1b\x65\x31\x10\xc3\xb2\xb1\x2e\x5b\xc2\x2e\x10\xf2\x2e\xf8\x42\xeb\x1a\xa4\x25\x64\x40\x64\x36\x63\x85\xa5\x1b\xd4\xa6\x74\x5d\x6a\xe4\x03\x7d\x61\x38\x89\x51\x7f\x6e\x8a\x7c\x05\x65\x1a\xf8\x85\x58\xd4\x27\xcf\x40\x5f\xf2\x18\xd2\x57\x94\x5c\x73\x7a\x41\x3c\x8b\x9d\x45\x7c\x74\xfb\xd6\x7d\x65\x3d\x0d\x31\x5f\xdf\x14\x30\xbf\x17\x68\x50\x68\xc8\x5b\x75\xfa\xa5\x0f\x29\xbc\xa0\x21\xe8\xe2\x61\x10\x8f\x80\xf6\x85\xab\x09\xcb\x9a\xa6\x2d\xe7\x47\x99\xe3\x37\xe0\x29\xba\x2a\x8b\x07\xa1\x97\x00\x70\xa2\x26\xbc\x9b\xf3\x68\x10\x19\x31\x99\x8d\x61\x69\x4c\x91\xc6\x06\x74\x46\xd2\xf7\x91\x74\xe5\x9b\x63\xa0\xb6\xc3\x2e\xf0\x9b\x9a\xba\x8d\x10\xda\x33\xa0\xbd\x43\x24\xc7\xa3\x3b\x73\x45\x8e\x4f\x79\xb4\x3f\x3a\x64\x13\x7e\xda\xd3\xad\xb0\x0b\x3e\x71\x66\x6c\x08\x94\x99\x3d\x80\x78\xdc\xf2\x10\x7c\x0f\x38\xbf\xe7\xce\xf8\x85\x51\xc4\xb5\x2e\x68\xd6\x21\x7e\xdb\xc5\x2b\x46\x61\x9c\xc3\xd4\x49\xbd\x1a\x4c\xcf\x55\x36\xc8\x60\x07\x9e\xee\x8f\xbb\xdd\x43\x3e\xd3\xb4\x67\x5a\xce\xdb\x23\x61\xce\x65\x8f\x50\xa2\x02\x0c\xb8\xbc\x2a\x93\x5f\x8b\xba\x6f\x85\xa9\x2f\xa9\x66\x45\x6d\xa2\x8a\x56\x48\xef\x1b\xab\x28\xd0\x43\xd2\xa3\x00\x35\x44\xa6\xf1\xc8\x5b\x5e\xec\x53\x73\xb1\x16\xed\xe7\x59\x79\x70\x65\x4a\x33\x9b\x86\x7e\x14\x36\xe3\x56\x2f\xef\xd4\x9b\xe5\xda\x07\x8a\xa9\xe0\x9d\xb0\x04\xd3\x41\x60\x66\x99\x66\x91\x8a\x63\x61\x7e\x39\xc5\xb3\xf3\xad\xcc\x91\x8e\x1d\x41\xfc\xf3\x70\x81\x4d\xb3\x2b\xdc\xb9\x94\x02\x4a\x4a\x94\xa8\x62\x29\xeb\x7f\x28\xaa\x3c\x3a\xd6\x06\x78\xbd\xc0\x63\x03\x0b\xb5\x17\x02\x91\x18\xc4\x28\x81\x13\xd4\x91\x62\x60\x60\x0a\x35\x1a\x82\x36\x58\xf7\x6c\xa6\xe9\x99\xd5\x7d\xd3\xdb\xfe\x22\x07\x4f\xb5\x07\x78\x32\x84\xb5\x83\xb8\x89\x74\x50\xc8\xda\x01\x2c\x2d\x4b\x80\xb9\x51\xe9\x71\x95\x51\x27\xa0\x90\xbb\xb0\x6d\xdf\x49\x61\x7b\x56\x6c\x8c\xd0\xf2\x45\xc3\x6e\xfd\x5e\x7c\x19\xf3\x4f\x0c\x10\x8b\x61\x7a\x5b\xe8\x83\xae\xef\x36\x50\x9d\xef\x17\xea\xaa\x31\xfd\x5f\x52\x49\x50\xf7\xe7\xd5\xd4\x21\x92\xc1\x5a\x56\x7d\xe5\xb1\xad\x39\x30\x2c\xf9\x8c\xeb\x6b\x5c\x64\xfb\xd4\x9d\x68\x82\x98\x40\xbf\x2d\x0c\x97\x98\xa3\x78\x3f\xdf\xba\xc3\x5d\x12\xdc\xcf\xb6\x41\x53\xa2\x5b\x48\xc8\x0f\x59\xd9\xfd\xd2\x07\x70\x29\x3c\xc7\xd7\xb0\x75\x50\xf5\xd3\x4c\xf2\x76\x7d\xad\xcf\x42\xd4\xee\x27\x9b\x68\x93\x9d\xf2\xc4\x74\xd2\xda\x95\xea\xfe\x25\xeb\x55\xbe\x68\xac\x32\xa5\xe3\xb9\x25\x55\xfa\x8a\x4d\x62\xa9\x2e\x43\xb0\xac\xa0\x24\xf4\x28\xa4\xdb\xf2\x01\x01\x10\x81\x90\xdc\x09\xfb\x2e\x30\x0c\x0e\x0c\x1e\x6f\x9e\x27\x16\x0c\x2c\xb9\x2f\x5b\xa8\xbd\x5e\x71\xa2\x2a\x5e\x5d\xc5\x8a\x13\x5c\xec\x9f\xaf\x36\xff\x62\x14\x6b\xc0\xb0\x75\x8d\x61\xd6\x3a\x1f\x56\xcc\x47\x1b\xb5\x18\x03\xe1\x59\x48\x1e\x59\x03\x5b\x28\xd4\xb2\x54\x1f\x9a\xc6\xa6\xc0\x89\x82\x9c\x6f\x2d\xdc\x79\xed\x0a\x46\x90\xa3\x3e\x81\x9c\x7a\xeb\x0d\x7d\x8a\x37\x17\xd0\xa7\xab\xd9\xf4\xd4\xf4\xa4\xe5\x48\x69\x26\xaa\x4e\x00\x82\x7d\x1f\xc5\x91\x18\x84\x11\x74\x94\xcd\x7c\x79\xda\xe4\xe4\x28\x8f\x0c\xf0\x6f\xe6\x65\xb0\x80\x33\x5c\x14\x4d\xfd\xce\x8a\xc2\x97\xce\x6c\xd0\x92\x0d\xdd\x74\xe7\xee\xd5\xe2\x4a\x1f\x7f\x76\xcd\x9c\xc1\x1c\xbb\x24\x9b\xab\x28\x1f\x97\x51\x28\x97\x51\x68\xe4\x27\xa4\x6f\xfd\x64\xe0\x64\x9c\x5c\x2a\x6c\x47\x89\x0f\x92\x94\x0b\x42\x13\xac\xb2\xe7\x29\x0a\x55\x00\xbc\xfd\xec\xd0\x3b\x72\x3d\x5f\x12\xc3\xec\xb0\x41\x92\x9a\x1a\x98\xc6\x24\x77\x09\xe0\x74\x2f\xaf\x6c\xad\x10\x09\x74\x71\x4d\x1f\xa4\x64\xe9\x18\xc4\xb8\xbe\xd8\x0f\xb1\xfa\xd0\x54\x6f\x4d\xd9\xa8\x79\xc0\xa2\x86\x77\x0a\xd5\x69\x54\x88\xc6\x7c\x0e\x92\x0a\x4e\xcd\x13\x16\x34\xc1\x71\x56\xbf\x8c\xa3\xb0\x47\x9b\x68\x5b\xa7\xd2\xe9\xa0\x69\xbe\x40\xbe\x3d\x47\x61\x68\xf0\x5e\xd7\xe4\x95\x2a\xa5\x3d\xdf\x72\xde\x9b\x0e\x5e\x21\x0d\xf1\x1a\x55\x6f\x83\x47\x90\xd6\x6d\xb7\x5d\xef\x83\x0c\xe0\xf1\x5d\xa9\x40\x30\x28\x2f\x2f\xd2\xa8\xc9\x53\x37\x66\x60\xee\x92\x01\x39\x20\x66\x09\x6c\xac\x64\xdc\xd7\x88\x5a\x46\xe3\x42\xa8\x4e\xdb\x66\x29\x0d\x4a\x57\x5b\xc4\xd4\x62\x72\x4e\xdc\x58\xc6\x1f\xe0\xe0\x58\xcb\x28\xeb\x68\x0f\x55\xb6\x2e\x97\xca\x39\xbd\x16\x16\xf1\xfa\xca\x90\xf3\x67\x58\x7e\xd8\xe2\xef\x3b\x1d\xf8\xfb\x09\xed\x9b\xa2\xa2\x48\x4c\x5b\xdb\x02\xf8\xc6\xc1\x31\x6a\x38\x87\x30\x4c\x2f\x81\xc5\x79\x79\x45\x3a\x21\xbe\x95\x3a\xd1\xe0\xf2\xca\xab\xb4\x49\xa8\x95\x31\x58\xa5\x01\x9e\xad\x03\x7a\xe1\x8e\x03\x38\x0a\x21\x54\x09\x94\x48\x36\xe7\xa1\x46\x88\x39\xd2\x33\xd4\xce\xec\xcf\x0f\x51\x93\xa1\x31\x16\x3e\xcb\x53\x04\xad\x29\x57\x8e\xd3\x00\xef\x9d\x7c\xf0\x5e\x78\x4f\x63\x17\x9a\x34\x7a\x59\x04\xec\x65\x86\xe8\x74\x8a\x1f\xd2\xd6\x2b\xa0\x99\xb8\x02\x96\xc9\x92\x54\x2d\xda\x84\x77\x4a\x0c\xfa\x94\x74\xc9\xf2\x88\xf8\xd0\x77\x5e\x97\x87\x77\x99\xad\x07\x0e\x94\x65\xc1\x11\xfb\x88\x0e\xee\x52\x34\xca\xb7\x31\xe2\xa2\xe2\x93\xc9\x66\xef\x98\x3e\xac\x29\x69\x99\x72\xb1\x29\x35\x28\x13\x74\x51\x9b\x71\x9f\xf3\x04\xdd\x1a\xa3\x3a\x51\x1d\x31\xf0\x5b\xeb\xeb\x9d\xce\x3d\x64\xcf\x40\x6e\x30\x2b\x2b\x87\x09\xf4\xf9\x43\x01\x85\x50\x48\x06\x7a\xa4\xc5\x83\x6e\x37\x34\x1b\x5e\x44\x0b\x97\x26\xb1\xd3\xc1\xb3\x8e\xa8\x5c\xab\x73\x3e\x34\xd3\x21\x68\x3a\x20\xd5\xe2\xf1\xd3\xaa\x8f\x62\x1f\x28\x6f\xe4\xde\x59\xc7\xeb\x34\x3a\x61\x71\xf7\x7c\xb0\x14\x02\x34\xf8\xb3\xb4\x34\x48\x5b\x79\x2a\xf3\xd6\x69\xd1\x09\xe2\x36\x11\xa2\x18\x19\xac\x04\x55\x49\x38\xd5\xcb\x19\xac\xad\x5f\xd0\xe8\x8b\x85\x46\x65\x7b\x8a\x9d\x4b\xe5\xe6\x98\x5e\xd3\xda\x71\xa5\x35\xb3\x7b\xca\xa1\x5b\x47\x0a\x84\x9e\xe6\xac\xb4\x85\xbc\x1d\xc5\x5d\xa1\x3b\xad\x52\xb7\x74\x3d\x43\x50\x7a\x22\x5d\xf7\xba\xa8\xbf\x67\xeb\x9b\xd2\xf5\xf2\x6a\xbc\x99\x40\x64\x82\xfe\x47\x53\xde\x44\xbe\xd2\xa2\x00\x4e\x67\x90\x78\xdd\x54\x16\x24\x46\xaa\x0b\x6c\x0f\x52\xfc\x4d\x64\xed\xd3\xcd\xcd\xcd\x75\x16\xc3\x5f\xb2\x59\x8b\x49\x41\x88\xa2\x9c\x68\x18\xf8\xf3\xca\xc0\xf7\x0f\xaf\x1d\xb8\x1e\xad\xf1\xaa\x13\xd4\x06\x7e\x54\x1f\xb8\x61\x6b\xaa\xb5\xc5\x2c\x2c\x05\x44\xf5\x3d\x70\x40\x12\xc7\xd7\x2d\x58\x6b\xc3\x55\x6e\xc7\xa1\x76\x8b\xd7\x3c\xb3\x6a\x2f\x59\x05\x27\x55\x27\x20\x25\x3f\x07\x6b\x0f\xbe\x33\xc9\x2b\x97\xac\x43\x6e\xf4\xc8\xa7\x40\x74\x3b\x1d\xc0\xa1\x5c\x5b\x34\x00\x14\x81\x20\xe7\xc0\x0a\x6c\x85\xf0\xe3\xc2\x60\x21\x2a\xe7\xd0\x66\x4e\x7b\x8d\x7e\x1f\x84\xe4\xfb\xdc\x9e\x4e\x6d\x15\xd1\xe5\x11\x34\x37\xbc\x13\xf5\xdd\x0c\x58\x48\xe4\x27\x80\xfa\xca\x85\x86\x1b\xb5\x8e\x34\x4b\xcc\xa2\x66\x4f\xcc\xe6\xd8\xb4\x70\xf0\x98\x97\x68\x67\x49\x73\x71\x29\x95\x1a\xff\x10\xf7\x74\x62\x04\x13\x60\x19\x80\x80\x27\xae\xf4\xc1\x2d\x6d\x65\x16\xa7\xfd\x65\x43\x7b\xb2\xa9\x44\x36\x15\x96\x87\x0b\x21\xd2\x13\xc5\x7b\x25\x8a\xf2\x08\x7a\x14\x04\x78\xae\xf4\x33\x0d\xed\x55\xaf\x2c\xa9\x71\xbe\x0d\x2d\x02\xfb\xb4\x31\x4b\x90\x5b\x59\x5e\x54\xb3\xbc\x6c\xc8\xb2\x7b\x3d\xd7\xb2\x54\x7c\x22\xfe\xe5\x65\x48\x0c\xe0\xe7\xc4\xa7\xfb\x35\x16\x86\x66\xa8\xc1\x9c\x0e\x55\x49\x95\x8d\xc2\x47\x1e\x11\x50\x9c\xd8\x42\x6f\xe9\x2a\xd3\x2c\x5a\x02\x6c\xb8\x34\x19\x47\xde\x1a\xa5\x1b\x54\xac\xa7\x87\x3c\x1c\x84\x6a\xb7\xc2\x63\x40\xef\x08\xd6\x87\xc5\x17\xee\x54\x78\x17\xa9\x90\xb6\x4f\xff\xd6\x5b\xf2\xec\x61\x0d\x62\x37\xd6\x84\xf2\xd3\xac\x77\x4b\x54\x78\xa9\xee\x2f\xb0\x64\x2d\xee\x97\x87\x29\xf2\xc3\x4a\xcb\xec\xb4\x4c\x1f\xc1\x07\x3a\x20\x06\x78\xae\x8a\x97\xc8\xf0\x24\xd3\x3b\x91\xbd\xdc\x89\x4d\x47\xcb\x11\x9c\x34\x73\x5f\x92\x57\x62\xc4\x33\xd1\x8e\xf9\x11\xd6\xe0\xc7\x3e\x1a\xbe\x56\x78\x22\xe0\x88\x3e\x0d\x86\xfc\xbd\x27\x59\x22\x60\x72\x1e\x13\xe7\x05\x45\x21\x6b\x64\xb2\x0a\x64\x9f\x20\x6b\x04\x59\x23\x99\x35\xc7\xac\xc2\x55\xcb\x7c\x8e\xcc\xd5\x7b\x7c\xbe\x05\x7f\xa6\xf8\x45\x77\x99\xa7\x9d\x0e\x3e\x27\xd4\x9a\x1b\x7e\x89\x0e\x8f\xd9\x50\x16\x1b\xf1\xf9\x72\x85\x3e\x9b\xf1\xb1\xa5\x8d\xaa\xa5\x62\xed\xa3\xa2\x98\x99\xdb\xd3\xce\x08\x10\x48\x29\x41\x81\x26\xce\x06\xc2\x7c\x09\x03\x1e\xda\x0a\xa7\x96\x31\xf8\x35\x0c\xdb\x69\x49\x3c\x4e\x0d\xc3\x76\x5a\x65\xd8\xf0\x53\xf4\x17\x98\x35\x21\x87\x37\xe1\x4e\x36\x18\xa7\xde\x28\x75\x6b\xd3\x64\xb1\x79\xc9\xdc\xa1\x72\xf4\x3b\x29\xa7\xf6\xae\x35\xb5\x1a\xcf\x0d\xe3\x83\xdc\xb5\x44\x1a\x3d\x96\xd0\xf4\x5b\xd1\xf2\x56\x02\x0b\xd7\x47\x5a\x2e\x19\x1f\xa4\x3f\x03\x7c\xe9\x08\x71\x6b\x1f\x25\xc0\x43\xaf\x55\xc2\x9e\x1e\x8a\x2a\x01\x83\x95\x61\x45\xba\x0e\xb5\x1f\x60\xae\x7e\x59\x9f\x2b\x49\x7c\x59\x4b\xae\xee\x7b\x6b\xb6\x2b\x3f\x64\x73\x7a\xd1\xa9\x3f\x84\x45\x9a\x38\x11\x9b\x43\x1e\xef\x88\x35\x6d\xd5\xe8\x11\x70\xc8\x61\x51\xce\x59\x04\x70\x6a\xad\x2b\x6b\xd5\xa1\xe9\x56\x69\x36\x6e\xc0\xf4\xf8\x97\xec\xc7\xda\xb7\x9d\xfa\xae\x6d\xc6\xaf\x6c\x73\x19\x64\xe8\xe9\x51\x8e\x12\xe2\x1b\xc0\x81\x18\x61\x0c\x3d\x1e\x26\x74\xc4\x87\x49\x4f\x52\xa7\x14\x22\x1a\x2c\x98\x0c\x71\x4a\xd0\x48\x02\x0a\xd9\x68\x9f\xba\x57\xd6\xab\x53\xdb\x78\x5d\x41\x4a\xc4\xb1\x32\x24\x20\x8d\x0d\x90\x5d\x79\x44\x0d\xcc\x31\x09\xbb\xd4\x66\x7f\x79\x9b\x0a\x81\x48\x12\x28\x07\xf9\xa1\xb6\x79\xa0\xb5\xed\xc0\x94\x8e\x6b\x3d\xc6\x8b\xe4\xa8\xaa\xc4\x0b\xbf\xde\x75\xb9\x76\xc8\x9b\x02\x9a\xf4\xd1\x99\x49\x6b\xdd\x6e\x73\xbb\x01\x95\xcf\xc8\x78\xde\xe6\x25\xf0\xca\xaf\xa4\x29\x6a\x50\x4e\xa8\xe5\x1d\x51\xce\xa4\x60\xfa\x95\xb3\x53\xcc\xaa\x99\x6f\x58\xbd\x29\xad\x63\x69\x00\x8d\xa1\x7b\x52\x34\xf3\xd9\xb6\xa2\x9c\x6e\x5f\x33\x35\xfe\x21\x9d\x3e\x48\x56\x05\xf5\x20\x19\xe2\x64\xd4\xc8\x40\x0e\xc9\x27\xe4\x10\x95\xd8\xad\x10\x08\x77\x53\x96\xa2\x68\xc9\x4c\x9c\x0f\x07\xf8\x37\xf7\x72\x74\x08\x6d\x14\x25\x43\x97\xee\x6f\x19\x88\xdc\x5b\xa0\xdb\x1a\x01\x32\x43\x75\xf0\xe8\x18\xf7\xda\xcc\x10\x1f\x34\xfb\x35\x2f\xb3\x21\xc3\x27\x8f\xaf\x7d\x48\xd0\xdc\x16\xe9\xb5\x22\x5a\x6b\x43\x96\xa3\x86\x0b\xc5\x58\x3c\x4d\x69\xea\x78\xd4\x07\xfa\x0b\x74\x3e\x67\xcd\xac\xdd\x63\x62\xed\x80\xec\xdf\x40\x67\x9c\x83\xa1\x37\xc4\x83\xb1\x21\xee\xc8\xde\x7b\x8b\xfb\x83\x1c\xf0\x0b\x39\xb6\xf1\x2f\x26\x51\x6e\x10\x96\xe7\xc8\xeb\x68\x97\x9d\xb9\x21\x90\x91\xcb\xe6\x03\xea\x3c\x08\xd5\xd0\x4f\x09\x04\xcf\x21\xe9\x6c\x80\x57\xbf\xa0\x2d\x84\xa6\x79\xdd\x21\xb2\x76\xbd\x47\x36\x9a\x97\x98\x51\xc1\x4a\xdc\x46\x8f\x3c\x3a\xa7\xb6\x0e\x5a\xaa\xfe\xe2\x4b\x56\x67\x6c\x09\x44\x42\x5a\xf1\xa4\x6a\xf1\x29\x7c\xb5\x54\x50\x42\xdb\x89\x84\xb4\xb3\x3f\x47\x4e\x45\x73\x47\x61\x7f\x66\xd6\x75\x88\x3e\xc0\xcd\x63\x36\xd6\x99\x4d\xed\x56\x7a\x77\x98\x39\x7b\x99\xe3\x7e\xe5\x88\xd5\xa0\x8b\x7e\x2d\xca\x73\x9a\xca\xca\xd1\x55\x55\x29\x1b\xb1\x2e\x31\x88\x02\xb0\x02\x40\x0a\xc6\x23\x06\x54\x94\x4a\x4e\xa1\x42\xe0\x3e\x36\xb1\x63\xa5\x31\x00\xd7\x70\x03\x29\x4b\x48\x61\x49\x90\x9b\x91\x55\xa1\xa4\x2c\xe1\x56\x8d\x3e\xcb\xf7\x6c\x80\x77\x91\x52\x96\x2d\x9e\x29\x29\x4b\x6c\xa2\xe0\x16\x43\x2d\x28\x67\x09\x29\x67\x55\x08\x5e\xe2\x1a\x1b\x2c\x34\xc0\x02\x02\xd9\x2d\x4f\x5f\x2c\x7e\xf2\x87\x26\x13\xdc\xeb\x45\x4e\x4d\xeb\x59\x2b\x06\x60\xb4\x5a\x16\x38\xde\x55\xb0\x81\xb8\x5f\xd2\x40\x54\xe4\xa2\x14\x95\x11\x19\xce\x73\x48\x5a\x08\xa9\x98\xb8\x97\xd1\x5b\x4b\xb0\xdd\xe4\x08\xf6\x87\x40\x45\x10\xd1\x3d\x87\x14\x11\x68\xf3\x01\x2b\x64\x68\x69\x23\x4a\xbd\x66\x24\xd7\xe8\x9c\xec\x42\x22\xd2\x41\x7b\xc4\x2b\xf9\x0b\xca\x89\xb1\x25\x37\x29\x22\x90\xef\x8f\x91\x1a\xcf\x6d\x1d\x05\x4c\x52\x2e\x97\xd5\x1c\x3a\x55\x55\x58\xc0\xb2\x66\x73\x52\x58\x38\x78\x86\x84\xba\xdd\x86\xbc\x86\x77\x1f\x5a\x67\x68\x9f\x95\x0f\x16\x8f\x3e\xd4\x36\xd5\x70\xec\xf1\xac\xaa\x9d\xe8\x57\x9e\x33\x9a\xc8\xd7\x46\x34\xbf\xb6\xa0\x0c\x11\xcd\x8a\x59\x04\x23\xca\x23\xb0\x05\xcf\x33\xe3\x8c\xd7\x47\x43\xcf\x0c\x11\xd5\xef\x61\xf3\x2a\xc1\xef\xe1\x49\xdd\xdd\x74\x82\xab\x62\xf1\xec\xe0\x46\x6d\x69\xe0\xfb\x5b\x96\x44\x42\x26\xca\x0b\xf7\x59\xd1\x56\x5f\xda\x11\xed\x64\x9b\x80\xeb\x04\x2b\x3c\xab\x31\x5d\x4c\xbb\x09\xa0\x3b\xea\xb6\x48\x05\xe5\xc4\x03\xb1\xc9\x7d\x4f\x6c\xfa\xf8\xcc\x56\xd8\xdd\xf0\x12\x1e\x96\x24\x42\x05\xde\xca\xce\xec\xe1\xd3\x02\x65\x17\xdf\x5a\xd2\x3c\xac\x55\xfb\xa9\x14\xe9\x05\xb8\x26\x41\x91\xf4\x00\xa8\xdb\xa8\xd4\x25\x4f\xc1\x9a\xab\x03\xfa\xe3\x24\xdd\xd0\x5d\xbb\x45\xa7\xf2\x0e\xf2\x6d\x4a\x61\xca\xe9\xca\xa8\xef\x4a\x26\x3f\x2a\x8a\x54\x9e\x8a\xcf\x79\x36\xc0\x2d\xaf\x6a\xaf\x69\x54\x89\xb0\x09\xa4\x38\xd4\x21\x0c\x75\xd8\x9f\x0f\x12\x9e\xc3\x58\x43\x9e\xeb\x21\x1e\x65\x30\x55\xf7\x33\x6b\x78\x46\x49\xbd\x54\x3b\xa9\x8a\xee\xf9\x34\x19\x4d\xa3\x2a\x55\xc6\xea\x76\x67\x6c\xae\x73\xd6\x77\x0b\xfb\xd1\x1b\x25\x60\x00\xb0\xf5\xdd\xcd\x85\xdc\x15\xaa\x52\x96\x90\xba\x2c\x59\xea\x37\xcd\xa5\x2c\xcd\x4d\xb5\x1c\x22\xa2\x2c\xf9\xf5\xb2\x92\xc8\x18\x2c\x29\x4b\x5c\x5d\xbd\x98\x95\x5b\xdd\xfe\xb2\xdf\x19\xb2\x4e\x74\xed\x0d\xd4\x37\x1b\x96\x6d\x3c\x1a\xa4\x8b\x0a\x8f\xb8\xa6\x1b\x78\x9e\x95\xf7\xd6\x53\x28\xad\xd5\x48\xa2\xe4\x60\x50\x80\xef\x66\x2e\x89\x11\x59\xdf\xcd\x91\x19\x22\x21\x42\xd1\x45\x32\x5a\xcc\xf7\xe3\xfd\xe4\xf0\x50\x6a\x9b\x28\x81\x54\x28\x90\x19\xb5\x70\x10\x0b\x3f\x9a\xa6\xe4\xd6\x01\x70\x43\x17\x2b\x07\x39\xda\x32\xcf\xee\x67\x82\xfd\xcc\x30\x3e\x2f\xfb\x39\xc4\x7e\xfa\xdd\xdc\x25\xbd\xb1\xdf\x77\x87\xfa\xb8\xc7\x2c\xb1\x08\xb6\xf6\x6e\x37\xbb\x93\x63\x62\xd4\xcd\x70\x18\x99\x19\x06\x91\x25\x8c\xc7\xc3\x22\x2a\x69\x75\xd9\x22\xaa\x71\x5a\xd9\xfa\xeb\xf8\xa5\xa4\x3c\xd8\x18\x5c\x75\xec\x90\xf2\xd3\x14\x75\xfc\xec\xb6\xcb\x80\x09\x8b\x5d\xb7\x26\xe6\x59\x87\x56\x04\x61\xb5\xa4\x49\xe6\x0a\x60\x8d\xe5\x0c\xb7\x00\x7a\x00\x2a\x56\x7b\xc2\x03\x6c\xcf\x62\xa8\x63\x6c\x1a\xf3\x0a\xbc\xd1\x4a\x9f\xa4\xa1\x2d\x37\x60\xeb\xf8\x3a\x6d\x62\xbd\xb4\xd4\xb4\x70\xa3\x38\xb6\xee\x0b\xaf\x93\xa4\x74\x0b\x8d\xc2\x95\x3a\xb7\xf2\x08\x9e\xd8\xbc\xdd\xe9\x1c\xa5\xce\xd2\xab\xd2\xd6\xc7\xed\x43\xe9\xff\x0c\xe8\x15\x15\x6b\x50\x29\x95\x99\xc5\xea\x2d\x29\xa8\xa6\x1c\x68\x4c\x19\xbf\xba\x2a\x56\x2b\x4d\x88\xd5\xd5\x43\xf6\xb5\xba\xeb\x24\x36\x6f\x7d\xb6\xde\x8d\x43\x3a\x41\xaf\x54\x79\x58\xa1\xca\x84\xe1\xc2\x6c\x07\x65\x4e\x54\xab\x82\x0c\x08\x13\x11\xda\x0f\x11\x5b\x90\x4e\xd2\x86\x8b\x40\x4a\x30\xc2\xad\xac\x62\x39\x39\x48\xbd\xc0\x6d\x5a\xf3\x72\xdc\x7e\xea\x34\x9e\x98\x87\x8d\xb3\xb9\xb8\xe9\x1f\xf9\x4e\xee\xa3\xb8\x45\xc6\x5f\x66\x71\xb5\xdb\xb4\xfb\x23\xdb\xc6\x11\x7f\xe4\xb9\x41\x23\xde\xf8\xd7\xe2\xcd\x07\x5c\xa0\xe6\x0e\x18\x3d\x81\xdc\x30\x18\x5d\xef\x1e\x5e\x8c\x1c\xc4\x9e\xb0\xea\xcf\xae\x5f\x58\x09\xa1\x56\xac\x94\xf1\x30\x67\x64\x51\xa4\xce\x9e\x4e\x91\xe9\xf3\x15\xf7\x4b\x3b\x7d\x08\x1b\xdf\x0c\x58\x58\xa9\x14\x6a\x21\x08\x42\xb5\x0a\x5d\xad\x64\x23\xe5\x5a\x2c\x0f\x24\x41\xfe\xbb\x1b\x5a\xe7\x2b\x81\x93\x43\xff\x76\xe8\xc8\xa5\x9f\x72\x63\x46\x3e\x93\x7d\x10\x36\x2d\xce\xd3\xaa\x28\xa8\x3d\x11\x96\x46\x05\x4e\x39\x1f\x5b\x8b\x4b\xec\x98\x6f\xb1\x73\xa4\x5f\x5b\x6e\xff\x18\xc9\xe6\xf9\xfe\xb1\x7d\x4d\xff\x98\x96\x1d\x9e\x7a\x9c\x73\x20\xea\xe7\x52\xf3\xc1\x42\x8a\x10\x18\x81\x7b\x89\xcb\x46\x45\x71\x2a\x47\xf6\x9c\x47\x3d\x72\x75\x82\x8e\xa2\x83\x94\x1d\xf1\x0b\xc8\xf5\x9c\x86\xba\xb5\xca\x8f\x0c\xd5\xdc\xdc\x92\x05\xce\x80\x19\xb8\x81\x47\xf3\xd2\x60\x72\x0f\x09\xee\x70\x75\x0b\x29\xed\x53\x3e\x02\x31\x8c\xa2\x5f\x40\x10\x03\x20\x8d\xee\x40\xf0\x5c\xc6\x9e\xe8\xd8\xf3\xbe\x28\x20\xbc\xeb\xdd\x67\xa2\xc3\xff\xb2\x33\x1a\xdc\xf7\x76\x5d\x36\x43\xc3\x27\xfc\x7e\x52\xbc\x04\x60\xfe\x25\x6c\xef\x2e\x37\x40\xdb\x61\x4f\xd9\x09\x7b\xc1\xce\x00\x68\x7b\x06\x43\xee\xda\xfd\xe7\xcf\xd9\xdd\x2b\x5a\x08\x8f\xf9\x18\xd1\x66\x5a\x3a\xb5\x94\x0e\x6c\x1e\xef\x3f\x38\xa4\xb7\x0f\x00\x22\x2f\x10\x22\x19\xc0\x03\x24\xe3\xfc\xce\x79\xf9\xfc\x93\x0e\x82\x04\xce\x16\x16\x60\x34\x98\x14\x05\xe1\x78\xb9\x0e\x1f\xb3\x73\xb9\xfe\x80\xd5\xef\x9c\xb0\x31\xfc\x7d\xc2\xa6\xf0\xf7\x25\x1b\xc1\xdf\xa7\x6c\x06\x7f\xf7\xd8\x29\xfc\x7d\xc1\x26\xbc\x05\x8d\x50\x0d\xec\x01\x37\x77\x45\x2c\xbb\xdd\x61\x5a\xe5\x50\x03\x4b\x33\x25\x78\x17\x68\xf7\x26\x5e\x09\x6e\x1d\x67\xa5\x5e\x44\xbd\x50\x04\x1c\xf4\xaa\x79\x78\xd2\x7a\xd6\x6f\xa5\xed\xc5\x78\x9e\x7f\xea\x03\x5a\x66\x99\x93\xac\x99\x07\xfd\x5c\xe3\x7f\x26\xb1\x98\x82\x28\x2d\x59\xd0\x92\x50\x39\x35\xe3\xa3\x6c\x11\x49\x73\x8c\x1f\x96\xb4\x23\x42\x84\xcd\xba\x43\xdc\x70\xf3\x3b\xc3\xbe\x1b\x01\xcb\xc9\x53\xed\x53\x42\xea\x3c\x20\x0e\xf7\xff\x12\x95\xbb\xa5\x54\xb8\x30\x03\xc9\xc0\x2f\x41\x1f\xaa\x69\x66\x91\x9c\x81\x90\x60\xef\x57\xe9\xa0\x25\x9d\xcc\x17\xd6\xa0\x51\x78\x76\x5e\x92\xce\x38\xaf\x6a\xf0\x97\x9e\x98\x4b\x2d\x0c\x3e\x29\x66\x9f\xbe\x0e\x35\x12\xef\x16\xf7\xf1\xa0\x32\x91\xf4\x87\x0d\x57\x51\x53\x53\x32\xed\xa2\x73\x5f\x0b\x89\x29\x48\x88\x49\x5f\x67\xbd\x92\xe2\x20\x76\xe3\x11\xa9\xf6\xa7\x7c\xbf\xec\x31\x6a\x55\xa9\xd7\xb4\xd4\xc7\x9d\xce\x18\x0f\x6e\x51\xe6\x7b\x99\x3a\x53\x36\xc6\x17\xa9\xa6\xb8\x9d\x66\xf0\xf3\x1d\xa0\x3a\xfe\x55\x68\x90\x0d\x72\x10\xce\x8d\xe0\x00\x2b\x37\x5b\x1d\xc2\xca\x45\x31\x1e\x84\x9b\x27\xae\xd4\xd3\xc3\xa4\x4c\x51\xe5\x39\x25\x9f\x25\xb4\x43\x8e\x50\xc2\xd8\xa5\x53\x0a\x58\x9c\xbb\x50\x62\xba\xff\x1b\x7d\xb1\x75\x90\xa7\xc6\x4c\x60\x0a\x02\xae\xfd\x45\x40\x9a\xc1\x5a\xdc\xce\xbc\xd7\x66\x29\xce\x9c\x11\xa4\x59\x66\x44\x69\x5d\x45\x26\xd5\x63\xc4\xb9\x05\x25\xe7\x26\x4a\x9c\x6a\x11\xb0\xf3\x16\x1f\xe2\x7d\x03\xa0\xf9\xc3\xcd\xbc\xa6\xd3\x46\x65\x9e\x62\xe3\x2e\xe5\xda\x44\x9b\x21\x5c\x9c\xfb\x12\x7a\x11\x3f\x62\x29\x29\xc5\x92\x41\xea\x8c\x01\xb2\x40\xd6\x52\x67\xce\xc6\x44\x15\x1a\xb5\x68\x28\x98\x27\x86\x31\x9b\x82\xcc\x34\xc5\x83\x74\x07\x6b\x9d\x1e\xb2\x16\x54\x06\xd4\x64\x0e\x9b\xca\x18\x78\x1f\xaa\x4b\x0f\x8a\x2e\x5b\x10\x38\x97\xe7\xd1\x5a\xef\x96\x45\x0d\xa6\x86\x1a\xd4\x24\x9d\x1f\x3c\xfa\x79\xa7\x44\x8a\x6e\xc0\x81\x36\x48\x31\xe3\xa1\x67\xa4\x03\x74\xaa\x0e\xfd\xa7\x5f\xbc\xb7\xac\x2e\x8e\x62\x94\x0a\xca\x22\x6f\x4d\x91\x16\xef\x06\x03\x98\xea\xae\xf0\xf0\x46\xcf\x40\x1f\x8a\x79\x56\x03\xdf\xcb\xb6\x85\x30\xa5\xa0\x42\xbc\xb7\xb6\x68\x5a\x37\x5a\x32\xbb\x52\xef\x8e\x6f\x5a\x9b\x09\x26\x0b\x38\x94\x46\x2d\x82\x07\x73\x0c\x13\xd9\x4a\xaa\x93\x4b\x13\x0a\x73\x49\xc7\x16\x63\x33\xc7\x53\x9e\xed\x8f\x0f\x81\xe8\x96\x67\x49\x53\x79\x7e\x24\xd3\xd1\x5a\x1c\xa6\xe9\x94\x66\xab\x3f\x52\x08\x30\x22\x04\x38\x65\x33\xc4\xdf\xd4\x99\xb1\x53\x08\x34\x23\xc0\x88\xb2\xcf\x3a\x9d\x19\x4c\xdf\x29\x4e\x1f\xe6\x36\x53\x4c\x87\x18\xa3\xb2\xab\x73\xa0\x06\x73\x5e\x79\x41\x96\xf3\xa9\xcc\xa6\xbc\xe4\xe2\x9b\x9e\xf6\x73\xae\x17\x78\x8f\xad\xfc\xc6\xce\x4f\x5a\xfc\x02\x88\x92\x5d\x4b\x28\xef\x70\xd5\xa2\xd0\x97\xa9\xd3\xc0\xc9\x4e\x3a\x9d\x49\x4d\x0b\xd3\x90\x0b\xda\xb8\xb0\x73\x5d\xb8\xd7\x9d\xc6\xcc\x6a\x9b\x54\x3c\x78\x91\x79\x4f\x33\x64\x1b\xf1\x84\x7c\x99\xca\xce\x26\xb8\xea\xb3\xef\x38\xf1\x20\xd9\xcc\xbd\x7c\x33\x01\xd2\x82\xe6\x89\x30\x2b\xf8\x13\x22\x07\x97\xf0\x1c\x35\x1e\xa8\xe0\xb4\xf4\x83\xa7\xe4\x80\xa0\xb4\x22\x91\xee\xa3\x8f\xfd\xe1\x49\x51\x3c\xf1\x0d\xe1\xe7\x78\x0a\xf3\xc4\x1f\xcc\x62\x2f\x61\xe9\x20\x51\x85\x3c\x6b\x47\x98\x54\x6a\x0a\xb9\xb9\xd8\x58\x14\xcf\xcc\x56\x1a\x72\x64\x14\x9f\x41\x0d\x5e\xc8\x82\x41\xa8\xeb\xb1\x7a\x74\xb1\x54\x46\x1d\xc4\xe5\x16\xb1\x68\x70\x48\xa6\x0b\x59\xf8\xc9\x68\x32\x42\xba\x9e\x20\x17\x79\x1b\x6f\x58\xe0\x95\x50\xee\x5b\x2e\xa7\x28\xf6\x39\xbe\xb5\xd1\xf6\xc4\x6a\x35\x09\x2f\x5e\x40\x2c\x5e\xc6\x10\x2c\xe8\xfa\x6e\x3d\x51\x95\x0b\x48\x56\x66\x62\xb5\xd4\x2e\x5c\xd2\x5d\x0f\x2f\x60\xf8\x98\xb2\xcd\x72\x93\xf9\x9d\xb9\x5d\x6e\x04\x3e\xe9\x91\xd9\xc2\x41\xdb\x6f\x05\xa0\xd8\x82\x95\x3c\x6c\x2b\x95\x43\x60\x02\x34\xde\xf4\x72\xd4\xbb\xb8\xda\x07\x2c\x3d\xa0\x3b\xcf\x05\x7d\xc3\x6f\x45\xb7\xbd\x55\xe9\x8d\xbd\x56\x16\xcd\x25\x2d\xf5\x9d\x8d\xda\xd2\xc6\xfe\xa3\x0f\xf5\xc2\x18\xec\xeb\x73\x0b\xac\x97\x5d\xbf\x9a\x20\xa1\x08\x70\x6a\xa8\x1f\x69\x59\xfa\x4d\x54\x99\x18\x86\xd4\xe9\xea\xe4\x44\xc8\xf4\x50\xfd\xfa\xea\x37\x53\xbf\xb9\xfa\x1d\xaa\xdf\x48\xfd\xce\xd5\xef\x58\x78\xda\x6c\xea\x38\x1f\x8f\xcb\x57\xc6\x65\x3b\xf1\x00\xba\x92\x00\x7e\x33\x48\xbf\x10\xc1\xde\x78\x9c\x05\xc2\xdc\xf0\x71\x35\xad\xaf\x51\x6f\x59\x58\xf7\xf1\x7b\x4f\x61\xa7\x8c\xd5\x7e\xef\x8f\x44\xf9\x1c\x5c\xd8\x8b\xfc\x4c\xec\xa8\x39\x33\xe1\x06\xc3\x90\x73\x33\x5b\x31\x39\x31\xa7\x7b\xe9\xc0\x18\xb5\x60\xce\x31\x13\xbe\x06\x95\x0d\xe4\x3e\xe5\xc9\xa8\xfb\x01\x3e\x34\x23\x4f\xf0\xcd\x02\x7f\xef\x6b\x5b\x86\xbe\x55\x90\x0e\x03\x5b\x67\x42\xfa\xd8\xa5\xf7\x92\x29\xea\xbe\x89\x29\x8a\x5d\x34\x74\x60\xdb\x19\x9d\xbf\x36\x19\xf1\x3d\xaf\x4a\x94\x01\x47\x3f\x9d\xe6\x88\xe4\x6e\x86\xbe\xd3\x37\x57\x37\x00\x75\x7f\xbd\xc1\x39\x3a\xc1\xda\xb4\x0e\xf8\x8e\x52\x4b\x9b\xd9\xda\x0b\x2b\x2e\xe8\x2a\xf6\xbc\xa2\xaa\x5a\x4e\x5d\x39\x32\x4b\x87\x75\x86\x07\xbd\x74\xce\x24\xf0\x10\x53\xde\x4a\xb2\x2e\xb3\xa4\x12\x8f\xcb\x13\x91\x10\x4f\x6d\xc5\x21\xaf\x38\x50\x3c\xb3\x5d\x38\x2e\x78\x66\xc4\x6b\xbc\xf6\x60\xee\x66\x9b\x76\xe1\x27\xb6\xf8\x1e\x28\xd7\x80\xe4\x81\x11\x19\x81\xcd\x75\x4f\x99\xec\x5a\x06\x53\x69\x45\xe1\x8f\xdc\x67\x4a\x0f\x04\x22\xed\x2b\x70\x37\x38\x29\x76\x80\xca\x81\x58\x07\x6c\x69\x58\xf8\xc5\x5e\xf1\x02\xcd\xd3\x3b\x27\xb8\x5f\xa5\x9d\x13\xd2\x45\x77\x76\xe4\xd7\x0e\x72\x00\xce\x10\x6d\xe5\xdd\xfd\xdf\xe2\xf1\x09\x88\xd8\xf4\xf1\x2d\x72\x6f\x80\x37\x9b\x1c\xb2\xa6\x9b\x3e\x9e\x44\xf9\x18\xe2\x3b\xc8\x26\x27\x9b\x1c\xc0\x81\xea\x79\xe8\xf1\xce\x26\xda\x95\x01\x37\x8e\xd6\x6c\xfa\x72\xd9\x1d\xae\xb0\x0a\x18\x67\x63\x1b\x82\xa6\x9f\x9d\x27\x74\xf8\x78\x0b\x55\x7d\xb7\xa0\xdf\x05\x74\xe7\x09\x30\xcb\x7b\xda\x78\x05\x5f\x3a\xac\xf1\x11\xb7\xd1\xb6\xfb\xf6\x21\x9f\x0d\x02\xe4\x19\x46\x4c\x00\x4f\xec\x7a\x20\x1d\x8f\x5c\x16\x40\x18\x52\x2e\x1c\xcc\xc2\xde\x50\x34\xa5\x6b\xf4\xc3\x2a\xbf\x06\x4e\x05\xda\xc5\xca\x20\x88\x7f\xa0\x88\xd0\x95\x7d\x63\x55\xf6\x8d\xae\xec\xeb\xb2\x32\x48\x77\x51\xbc\x44\x18\x8d\xa8\xfb\xbf\x3d\xe4\x54\x00\x16\x01\x82\x16\x62\xbe\xd5\xbc\x3f\x06\x07\x02\xfe\x78\xb0\x2f\xe0\x07\xc3\x0f\xc8\xa9\x93\xbf\x3b\xa4\x02\xdf\x21\x04\x50\x6e\x40\x5a\x2d\x4d\x1f\x70\x42\x79\x62\x1f\x69\xef\xa9\x09\x0f\x94\x2d\xe9\xf2\x73\xa3\xcb\xab\x8a\x49\x59\x28\x8f\xb9\xc3\x15\xc9\xbe\x38\x89\xd6\xbd\xba\x0d\x67\xa7\x4f\x2b\x68\x85\x6e\x70\x94\x4e\xe8\x7a\xf3\x4b\x27\xa6\x73\xc5\xda\x79\xe8\x0b\xad\x62\x5b\xb8\xd8\x84\x3a\xaf\xcc\x18\x28\x90\x63\x35\x4e\xd7\x58\xfb\xa9\x75\x26\x4c\x47\x4f\xe4\x32\x02\xcf\x80\xf1\x2a\x07\xf6\xdd\x3b\x6a\x30\xeb\xdb\xa5\x05\xa4\x0e\x2e\x0d\xc5\x23\x96\xef\x94\x9c\x84\x96\x56\x59\x2d\xfe\x1e\xc4\x78\x6b\x43\xb4\xf9\x39\x57\x5e\x8c\xa9\x30\x87\x0d\x5b\x1b\x3e\x56\xe1\xc4\xd5\xcb\xd5\x75\x02\xb4\x0c\x74\x48\xf3\xb8\xb8\x6a\x66\x75\x81\x90\x56\x0c\x57\x4a\x53\xbf\xd4\xbe\x84\x14\xf3\xb7\x44\x5f\x2b\x67\x06\x29\x4a\x1a\x86\xaa\x95\x64\xdf\xc7\xb5\xa9\x88\x9c\x43\x96\x6b\x45\x11\xf6\xe2\x24\x7e\x00\x64\xea\x6e\x3a\xc9\x3a\x9d\x2d\xa2\x2e\x5a\x6f\x4f\x36\x89\x99\x41\x20\x20\x13\x28\xbc\x39\xf2\x2c\x7e\xc8\x90\xbc\x97\x9d\x1c\xba\xe5\x99\xe7\xd0\xa0\x94\x75\x8c\xb0\x63\xd3\x36\x7d\x3d\x62\xff\xd0\x43\x82\xa9\x77\xc8\x81\xbc\xc8\x17\x78\x1f\xd1\x65\x87\x97\xf8\x95\x3b\xe5\x27\x76\x0d\x95\x9c\x96\x39\x57\x85\x82\x56\xf8\x6e\xd8\xe7\xd4\x05\x60\x4f\xdd\x57\xb7\x2f\xf6\xd2\xa5\x60\x75\xf7\x9c\x21\x0e\x56\xae\xf1\x5a\x2d\x3c\x36\x5b\x8e\xe0\xb0\xe5\x9b\x1d\x48\x5d\xf9\x10\xe8\x82\x0a\xb8\x3b\x3c\xda\xdf\x60\x1b\xf6\x21\x6b\xed\xb0\x73\x5d\x9f\x9b\xa0\x8e\x06\xb5\x42\x68\x92\x43\xa7\x9a\xca\x5d\xc1\x47\xb9\xc2\xd2\x2e\x2f\x59\x3b\xcb\xac\xf2\x55\x05\x15\xf4\x7d\xb4\xea\x3d\x00\xe2\x81\x69\x1e\xcb\x8b\x69\xa1\xbc\x98\x16\x12\x0d\x90\xe6\x9b\x4d\x24\xe0\x43\x6a\x29\x9c\x02\xac\x69\xf1\xe0\x01\xea\x0d\x8c\xde\xdd\x3e\x84\x08\x88\x60\x93\xe6\x96\x6c\x57\x60\x59\x54\x2c\x71\x2f\x50\x65\x7c\x66\x1d\x13\xb0\xd6\x06\x6b\xad\x33\xa8\xcf\x86\xf5\x76\x9d\x23\xb4\xcd\xed\x35\x2f\x31\x70\x1a\xa7\x81\x4e\x2e\x36\x5c\x46\x50\x5c\xdf\x44\x73\x0b\x00\x30\x3a\x1e\x2b\xcd\x83\xfe\x04\xd5\x0b\x9e\xae\xd2\x64\xaf\xeb\xa6\x96\x34\xf6\xe8\xba\xc6\x24\xb7\x25\x9b\x54\x8f\x9a\x0b\x54\x98\xa3\xe8\x7e\x9b\xa8\xa1\xbc\xff\x49\xd7\x13\x02\xcb\x73\x84\x6a\x32\xed\x6e\x58\x60\x7b\xfd\x0b\x9a\x92\x6c\xd0\xea\xc6\x42\x9b\x74\x68\x28\x5b\xd5\x77\x01\xab\xad\xda\x1a\xcb\x37\x96\xc6\x52\xb1\xc8\x0d\xb0\x4c\x06\x78\x59\x49\x73\x45\x2d\x8b\x8a\x1a\xf8\x12\xdd\x45\xcc\x4d\x5c\x66\x5d\x57\xa8\x82\xf2\x53\x6d\x7c\xd2\xc0\x66\xe1\x82\x73\x65\x30\xda\xf5\x90\x05\xc5\xeb\xbc\x0f\x7d\xbc\x0e\x84\x0d\xd3\xf3\x4b\xea\xfe\xa1\x42\xa3\x06\xb8\xdb\xc3\x66\x56\xda\xcb\x7c\x01\x56\xd6\x40\x26\xc8\xfc\x2b\x1d\xc8\x9b\x08\x55\x60\x3d\xb4\x25\xb6\x86\xaa\x84\x2c\xd5\x5a\xaf\x16\x7b\xf6\xa5\x38\xb4\xba\xd1\x68\xb4\x11\xbb\xe8\xe6\x20\x1e\x00\x29\x4c\xbb\x31\x83\xda\xd1\x64\xc9\x7a\xfd\x48\xd1\x22\x69\x11\xe2\x6a\xd3\x0d\xad\x76\x46\x7b\x8f\x01\xfe\xf5\x3d\xbf\x05\x7f\xdd\x41\xe8\x95\x2e\xa9\xb4\x1f\x2a\xcb\xb0\xc4\x86\x29\xad\x6b\x7b\x41\xbc\xad\xd2\x32\x74\x36\x22\xc9\xe5\x82\x06\x1d\xad\x1b\x81\x2e\x4f\xe4\x59\x55\xc8\x79\x52\xa1\x9d\x96\xce\x1d\x69\x28\x52\xb8\x4c\x52\xb8\xcc\x25\x1b\x3a\x73\x8b\x4c\x5d\x5c\x82\xcd\x52\xd7\xbd\xc9\x37\x6e\xa9\xdb\x55\x10\x09\x7c\xc2\x95\x75\xc3\x5b\x9b\x4c\xae\xa3\xc9\xa4\xbc\xcb\x31\xc8\x4b\x4a\x3e\xc7\x6e\x8d\x79\x8a\xa7\xbb\xc6\xd8\x89\xae\x74\xd0\x9d\x39\xbc\xd0\xc1\x9c\xf1\xe0\xa1\x70\x50\x7f\xea\x85\x0e\xea\x53\xdd\x3b\xeb\xca\x23\x26\x8f\xfb\xab\xab\xc2\xe8\xe9\x52\xa2\xff\x63\xc7\x99\x62\x89\xa9\x2c\x81\x9b\x82\x2a\x54\x1a\x3d\x5d\xa1\x96\xdb\x8c\x69\xae\x43\x7a\x1e\xe6\x96\x5d\xc9\x67\xd1\x2c\xa0\xa3\x5c\x1b\xd3\xbf\xff\x05\x38\x26\xa9\x4a\xb3\x81\x50\xec\x26\xdc\xa9\x22\x1b\xb0\x95\x64\x22\x97\xa2\x5f\xff\xee\x86\x8d\x77\x89\xc2\x39\x44\x79\x55\xb1\xf2\xe4\xb4\x80\x7c\xa1\x27\x3d\x3b\x0d\x12\x44\xbe\x26\xa7\x67\x64\x3f\x2d\x55\xde\x89\xa2\x02\x74\xe9\xd4\xca\x96\x34\x90\x80\x20\x31\x1e\x46\xea\x27\xf7\xf8\x70\x4f\xcb\x70\x44\x46\x4c\x2a\xf7\xf9\x75\xc0\x5b\xc2\xcf\xb4\x69\x3f\x16\xc8\xaf\x55\x0d\x96\xaa\x28\x4b\x17\x69\x58\x88\xa7\x93\xe4\x30\xac\x34\xa4\x44\x6f\xb3\x0d\x57\xb1\x84\xf5\xd6\x00\x99\x76\x92\xb7\x9e\x85\xcd\x1b\x99\x1d\xdb\x01\x50\xf2\x19\x1a\x2d\x2f\xbd\x2c\x21\xd4\xc6\x87\x40\x2a\x7d\x08\xa4\xca\x87\x80\x5a\x54\x2e\x2b\x7b\x0d\xc4\x17\xbd\xe4\x02\xf4\x9b\xae\xc6\xa4\x76\xe7\xb7\xeb\x74\x21\x49\xbe\x88\x01\xf8\x82\x4d\x4b\x4e\x4b\xaa\x78\x00\xba\x98\x55\x21\xa7\x61\x52\xdf\x20\x4f\xf1\xd8\xba\xd4\x95\xca\x93\x70\x7d\x66\xa8\xa8\xa2\xa7\x8c\xd1\x12\x3a\xcf\xae\xc0\xd7\xff\x43\x2a\x24\x2a\x5f\xab\x93\x8c\xc8\xcb\x03\xfe\x2f\x83\xc8\x17\x70\x5c\x4b\xd8\xa0\xfc\x4f\xd0\xc0\x22\xcf\xd5\xd8\xd4\xf0\xba\xa6\xfe\x38\x8e\xab\xca\x6f\x45\xbf\xa0\xa1\x3f\x9c\xdf\xaa\x9e\x11\xcf\x93\xd2\x0c\xed\x5d\xec\x2c\xf2\xd2\x36\xb2\x8c\x6b\xc8\x12\x2e\x76\x31\x2c\xbb\xd8\x3e\x4e\x12\x7c\xf1\xba\x72\xc5\x5d\x5e\x41\x10\xd2\xaa\x03\x50\x5d\xcd\x4e\xea\x4a\xb3\x02\xbc\xeb\x0f\x3c\x88\xba\xbb\x85\xa6\x1e\x9a\x9a\xe2\xf6\x3d\x8b\xa5\x31\x52\x8b\x2b\x0e\xcf\x27\xe4\x43\x33\x0f\xa8\x11\x89\x19\x6c\xb4\x03\xf4\x00\x07\xb3\x4d\xf6\xc2\xf6\xde\x3e\x4d\x1a\x04\x1d\x27\x28\xc5\xdc\x4e\x07\xda\x21\x1f\x22\xdf\xe3\x51\x1f\xd9\x3f\xa7\xea\x66\x87\xda\xbd\x71\xcb\xe3\x94\xe5\x51\x6c\xdd\x7d\xb0\x35\x91\x33\x9b\x54\xd0\xed\xea\x8f\x36\x50\x2b\xab\xef\x34\xf9\xd3\x0a\x47\x12\x6f\xd2\xc1\x45\x4c\xbe\x2a\x50\xef\x30\xf4\x85\x73\xa1\x6e\x7e\x7b\xb1\xd1\x9c\x0e\x00\x3c\x69\x15\xcf\x27\xd5\xce\x2c\xf0\x34\xe4\xd0\x06\xd0\x29\x20\x67\x3e\x78\xcf\xa4\xd2\x17\x6d\xa3\x91\x38\x95\xeb\xe5\xc9\x82\xd5\x76\x85\x7a\x93\x7e\x09\x1b\x45\x5f\xa2\xb0\x14\x51\xa1\x00\x3b\x98\x4b\xca\xfd\xfd\x43\xb7\xa6\x7b\x92\xde\x60\x48\x71\x43\x7a\x28\x4f\x8a\x9f\x21\x14\x01\xf9\x13\x5f\xf5\x68\x10\x41\x1f\x24\x96\xfa\xda\x36\xad\xb2\xdd\xc4\xad\x57\x8e\x27\xcc\x4a\xd4\x6c\x87\x7e\xd9\x34\xa8\x5c\x0c\x39\xbe\x26\x9f\xa5\x3e\xb7\xd6\x18\xf4\x85\xfc\x8d\x59\x9a\x6b\x2b\x55\x2a\x14\xc8\x49\x91\xb2\xae\xae\xb9\xb3\xb3\xca\x1d\x55\xd1\x99\xe9\xf7\x5f\x2b\x6a\x24\xe3\xc7\xe2\x2e\x3a\xf1\x00\xc8\x85\x15\xcf\x77\x89\x27\x80\x33\x95\xa0\x45\xf3\x85\xd4\x4e\x35\xdb\x60\xdd\x59\x9e\xa5\xa5\x4e\x96\x7a\x38\x33\x1c\x40\x55\x79\xe2\xd4\x5d\x9b\x95\x26\x3b\x15\x7f\x6c\xf2\x54\x07\x95\x2b\x69\x70\x1a\xa4\x59\x03\x28\xd4\xd3\x1b\x62\x9a\xe6\x15\x2f\xb8\xe6\xd8\xdc\x94\xbc\xb2\xc0\xf6\xc4\x02\xb7\x0d\xe8\x8a\xc3\xd6\x97\x56\xa6\x67\xf1\x82\xef\xbc\x45\xff\x6c\x96\x62\x35\xb9\x9e\x81\xc5\x9b\x54\xf2\xd1\x28\xd2\x64\xb9\x8c\x2e\xb3\x7c\x8e\x0d\x7a\xfa\x05\xdb\x1d\xf9\x69\xa1\x57\xcb\x48\xe1\x65\x39\x71\x41\x99\x0e\xa8\xe5\x22\xc3\x3b\x58\x14\xad\x60\x4d\x36\xb9\xc6\xd2\x8e\x21\xef\x92\xbe\x2c\xc5\x1b\x23\xe5\x5b\x8f\xd8\x31\x60\x02\xbd\x89\xde\x6a\xe1\x83\x9e\x63\x2c\x75\xb7\xb5\xfe\x53\x6d\x83\x20\xf6\x8e\xf5\x31\x48\x93\x11\xb9\x68\x36\x57\x57\x9c\x92\xd9\xf3\x60\x78\x44\x64\x2c\xfd\x6d\x63\x73\x22\xf6\x9e\x9b\x53\x17\xab\xfc\x42\xf1\xfb\xb6\x83\x62\xe9\x9d\x4f\x55\x64\x54\x06\x86\xf0\xc3\x50\x07\xb8\xbd\x97\x7a\x64\xbb\x66\xe5\x31\xe0\x81\xbd\x0f\xed\x2c\x10\x8d\xc5\x02\x5b\x76\x81\x93\xa4\x72\xb6\x45\xbd\x7b\x45\xdb\x8f\xa5\xb0\xac\x55\xda\x7c\x80\xda\x78\x19\xa8\xd3\x91\xe0\x51\x4e\xc8\x3c\x3a\xee\x7f\x1f\x6b\xe0\x5a\x2a\xcb\x3f\xbe\x0d\xe5\x9c\xcc\xdb\x5a\xd6\xc6\xab\xda\x58\x25\x38\x2a\x3b\xe8\x2d\x3b\xff\x87\xc6\x99\x8e\x63\xef\xf1\x17\xcd\xf4\x76\xb5\x39\xaa\xed\x51\x0d\xb4\xf7\x16\x58\x64\xd9\x88\x1f\x7b\x9f\x4c\x23\x98\x87\x9a\x49\xd9\x6f\x80\x76\xb1\xfa\xee\x79\xe7\x76\x15\x09\x1e\x2d\xa9\x34\xfb\x85\x95\x56\x10\xe5\xf5\x2f\x47\x7b\xeb\x24\xc1\xf2\x83\xd5\x12\xea\xdb\xa6\x9c\x6f\xec\x55\xd1\xc4\x57\x5f\x2a\x9a\xd6\xaf\x99\x3c\x9a\xa5\xb2\x0e\x2b\xe5\x4d\xec\x48\x71\x1a\x57\x8c\x1c\xf9\xa7\xc4\xb6\xf3\xd3\x86\x9b\x20\x7a\x4b\x7e\x5c\xde\x6e\x4b\x0c\x2d\xb3\x76\x76\x2a\x69\x9a\x5d\xee\x53\xad\xc2\xc3\x29\x78\x53\x47\x04\xec\x89\x2d\x3a\x6c\x24\xce\x0e\x7d\x6f\x01\x5c\x50\xf2\x46\x3d\x46\xc3\x39\xf3\xc7\x2f\x21\xef\xe8\x66\x0c\x2d\xa3\x54\xaa\xa5\xb2\x6b\x9c\xa0\x3c\xf6\x7e\xf8\xe7\x42\x06\xdf\x7d\x56\x78\xf6\xe5\x71\xf5\x80\x6e\xf5\x59\x9e\x1b\x16\xc4\x52\x69\x01\x69\x63\x4f\xdd\x2a\x88\xee\x25\x28\x47\x0e\x97\xda\x8b\xb7\x27\x54\x0a\xa3\xbd\xc2\x4b\x19\x6d\xb7\x1e\xbd\x90\x18\x82\x44\x6e\x5f\x14\x7d\x68\xc1\xd6\xa0\x7a\xdf\x78\x15\x92\x17\x0e\xe8\x50\x9a\x4e\x78\x85\xb9\x58\x80\xc6\x95\x10\xad\xae\xd5\x36\xb3\x99\x67\x48\x6c\xf4\xce\x2a\xc7\x9d\xd2\xb8\xd3\x6b\x3d\x56\x94\x38\x95\x54\xd0\x09\x11\x07\xf9\x60\x29\x10\xa8\x63\xa8\x23\x0f\x84\x2e\x88\x90\x0e\x2d\x62\x1b\x0e\xa9\x02\x40\x5c\x07\xc0\xdc\x02\xc0\xb3\x2a\x35\xda\x6d\x22\xf4\x37\x54\x9e\xe6\x6b\x57\x4b\x13\x9a\x6d\x5f\xf1\x6e\x5f\x40\x0e\xd6\x8c\x64\x10\xf0\x63\x40\x4a\xde\xa5\x53\xb1\xf5\x12\x16\xba\x57\xab\xab\xc1\x9d\x8d\xc1\x92\xf7\xaa\xb4\x5f\x1b\x4b\x65\x5a\xdf\xec\x96\x62\x56\xa0\xb5\x0c\xa2\x9c\x38\x75\x00\xb6\x8e\xb6\xe9\x64\xf5\x7b\x22\x2f\xac\xd7\xfe\xd8\x38\xff\xde\x16\x38\xfa\x7f\x12\x28\xa5\x06\x4a\xe9\xd2\x3b\x5c\x00\x16\x20\x6f\x68\x1e\xd3\x0c\x18\x39\x4e\x66\x5f\x19\xf9\xbe\x22\x1a\x3d\xa1\x9b\x7b\x35\x02\xbf\x79\x4b\x2f\xdd\xda\x0e\x08\x08\x7d\x01\x22\xde\xf7\x89\x6d\x3a\xef\xf6\xe3\x82\xef\x1a\xa5\xaa\xb4\x89\x13\xf2\xd2\x5b\xa9\x32\xb4\xde\xf2\x94\xbe\xf0\x16\x1a\xdd\x18\x34\xb2\xa3\xde\xc3\x9a\xd1\x88\xa8\xbc\xad\xf0\xa4\x78\xf9\x87\x0c\x41\x84\xd7\x0e\x41\xd0\xa5\xf8\xea\x10\xe2\x50\xe3\x54\x33\x32\xa9\x49\x23\x00\x3c\x6d\x44\x18\x85\x35\x66\x67\xaa\x5c\x40\x88\x2b\x3d\xb2\x1d\x4a\xa7\xbf\xa0\xe1\x17\xbf\xbc\xe1\x74\x69\xc3\x89\x69\xb8\xec\x0b\x0a\xeb\x9d\x4e\x9e\x39\x63\x97\xe5\x14\xc8\xd1\x14\x77\xcc\x61\xeb\xb4\x4a\x3a\x46\xf2\x5d\x75\x9e\x65\x8e\xbb\x1a\x91\xf9\xcc\xfa\x26\xa7\x5b\xe0\x30\x7d\xba\xb0\xea\xfd\xb4\xaf\x2a\x51\x76\xb5\xcf\xe4\xe5\x69\x7d\xc5\x07\x4f\x04\xd8\xb8\x28\xd0\xe5\x4c\xc6\xe7\x72\xe0\xea\xaa\xda\x98\x8f\x32\x27\xa9\x28\x5d\xc2\x4a\x37\x55\xc5\xce\x69\x51\xcc\x5a\x4a\x15\xf7\xa5\x2d\x94\x2a\x4b\x47\x79\x14\x2c\xb1\x29\x92\x75\xcc\x49\x0a\x65\x53\x7e\x8a\xe6\xdc\x20\xb4\x4c\xd0\x2d\x0d\x39\x70\x92\x30\x98\x74\x3a\xad\xb1\xf4\x79\x02\xb5\x4f\xa0\x81\x11\x37\xd3\x36\x5b\x75\xa2\xd5\x11\xee\x0d\x00\x1c\x72\x44\x36\xeb\xfb\x03\x27\x27\xf7\x39\x04\x21\xb4\xd5\x89\x6a\x3d\x75\x3d\xec\x67\x8e\x23\x0f\x6d\xdb\x34\xbf\xd3\x19\x0f\xc6\x9c\x06\xee\x41\x5f\xf0\x1c\x00\x6f\xc7\x28\x18\xe1\xed\xac\x98\xfc\xe1\xe1\xdb\x8a\xd5\x1a\x59\xcb\x2f\x8a\x3a\x00\xd8\x90\xb8\x25\xba\x6e\x44\x57\x08\xc6\x6c\x0a\xdd\x59\x87\x01\xc2\xea\x3c\x55\xd6\xf4\x5f\x44\xd3\xe8\x0a\x8a\xd2\x75\xd2\xbb\x79\xad\x75\x6d\xc7\x0c\xb5\x40\x55\x1b\x72\x3a\xc9\x0e\x0e\xfa\x38\x21\xb3\x10\x1f\x5f\xbf\x81\xd6\xda\x33\xff\xfc\x8d\x1f\x0a\x34\x56\x86\x11\x20\x89\x8e\x7b\x2a\x8e\xae\x21\xb8\xd0\x9b\xb6\x50\x0f\x2a\x53\xae\x41\xdc\xd3\xdf\xde\x69\x69\x83\xd0\x1b\xa2\x5a\x00\x2f\x4f\x58\xe6\x08\xa1\x4d\x9f\xc8\x0b\xe2\x06\xb3\xb5\x67\x16\x1e\x84\x95\xdd\x52\x79\x4c\xb4\x49\x8c\xa5\x8f\x0e\x17\x0f\x4a\x98\xa8\xdc\xca\x29\xbd\x44\x2e\x10\xf7\x15\xfb\x70\xe5\x4a\x9e\xae\x60\x6b\x2f\x43\x77\x99\x13\x46\xab\x8e\xd2\xca\x06\xd5\x89\xf4\xc2\x4c\xe3\x1e\x41\xaa\x2e\x01\x2c\x85\xcc\x53\x3e\x47\x9b\x5a\x6a\x46\x4b\x03\x7e\xfd\x90\xe4\x79\x2a\xcc\xf2\x3f\xf7\x51\x89\xeb\x47\x45\x6e\x39\xbe\x70\x4c\xc3\xf0\x3a\xe6\x26\x80\x55\xd4\x78\xb1\x47\x2c\x61\x6e\xac\xee\x2a\x03\x77\xe8\xc1\x70\x1a\xa0\x93\x82\xa5\x2c\x4c\xfd\x20\x2d\x25\x47\xe3\xa5\xbf\xa0\x14\x1f\x5c\x77\x12\x7d\x1d\x31\x58\x32\x6c\x93\x3b\xc3\xdc\x2c\x44\xcb\xf7\x52\xf1\x48\xdd\x20\x7d\xd7\x30\xec\x6d\x51\x9f\xec\x97\x76\x42\xf5\x28\xc7\x2f\x71\xfb\xb9\x30\xbf\xad\x25\x5d\xb3\xe0\x3d\xb7\x17\x1b\x71\x4e\xf6\xa2\x19\x87\x25\x3f\x5e\xd3\x61\x03\xd9\xc0\xdb\x9e\xe3\xda\xe6\x6d\xb3\x1e\xbb\x6a\xb3\xab\xea\xe0\x3f\x5b\xe5\xf4\x9a\x2a\xef\x37\x55\x39\xb2\xaa\x6c\xe4\x5b\x2a\x55\xec\x5c\xc7\x3b\xce\xfe\x28\xb8\x5b\xd6\xc7\x36\xe0\x2b\xd7\x47\x4f\xcd\x46\x2e\x11\xb2\x85\xa2\xc9\x2f\x20\xdd\x1a\x81\x68\x53\x1b\xa0\x07\x19\x4f\x53\xe9\x94\xb7\x15\x91\x96\x34\xb7\xd5\x32\x54\x1b\xa4\x8f\xa4\x4e\x92\x31\xd9\x10\x65\x90\xcf\xee\x09\x9d\x1b\xe8\x31\x7c\x28\x8a\x8e\x57\x15\xe1\x4b\xe7\xe4\x09\x53\xbc\xc8\x3d\x1b\x70\x93\x2a\x29\x2e\x0d\xaf\xf7\x40\x02\x64\xc4\xc6\x29\x74\x40\x9f\x53\xfb\xb6\xf3\xff\x8b\xb0\x54\x84\x28\xb5\xd2\x1f\x7e\x6e\x84\xfe\x6e\x1a\xcd\x2b\xdf\xc7\xfa\x98\x52\x7b\x40\xb6\xba\xf0\xc0\x4c\x8a\xe9\x7f\xb3\x6a\x4b\x29\xac\x74\x2d\xf8\x6e\xaf\x55\xcd\x96\x85\x88\xa7\xa4\xde\xd4\x62\x8c\x51\x86\x2b\xe5\x6f\x69\x3d\xca\xf9\xa7\xea\x93\x4d\xc7\xf6\x8a\x0c\x68\x6f\x2e\x0a\xfa\xdd\x28\x0a\xf9\x46\x8f\x5d\xfa\x87\x6a\xe9\x73\xbb\xf4\x62\xee\x77\xd5\xdc\xcf\x2b\x6d\x75\x3a\x1b\xf4\x86\x20\x3e\xec\x8c\x2f\xf9\x76\x3a\xf5\x0a\x8c\xbe\xb7\xad\x9e\x69\x6c\xa3\xa2\xb7\x5a\xe7\x91\x5e\x42\x35\x87\x77\xeb\xfd\xea\xd5\x93\xba\x3a\x5c\x19\x92\x92\x7a\x99\x4e\xb3\xf0\x47\x76\x00\xbd\x57\xaa\x97\x6c\x5d\x77\xd0\x12\x5e\xab\x59\xb9\x72\x66\x61\x12\xbd\x99\x7a\x2d\x2a\xdc\x46\x1f\x43\x9d\x0e\x99\xca\xd3\x4f\xe9\x9e\x8c\xbc\x4a\xaa\x13\xd6\x78\xa0\x8e\xd0\xf5\x1c\x36\xa9\x37\x93\x81\xf6\x4d\xe9\x7a\xad\x96\xa5\x9f\x7a\xb2\x38\x1f\x8b\xca\x75\x7d\x87\xaf\x3a\x57\x0f\xab\x70\x7d\x69\xd5\xd4\x30\xae\xda\xc3\x5f\x7b\x16\x2a\x5e\xe3\x88\x1c\xf8\xb5\xea\x2b\x62\xd5\x5a\x9e\x5a\x00\x55\xd6\x78\x74\xb9\xcf\x76\x9e\xfa\xa5\x70\xde\x40\xfb\x17\x65\x8e\x91\xa0\x79\x52\x66\xbc\x13\x02\xec\x33\x03\x7b\xe3\x7a\x2f\x23\xd7\x7b\x7e\xe5\xb2\x91\xef\x1a\xcf\x7b\xd2\x57\x89\x2b\x7d\x81\x84\xae\x74\x41\x82\x16\x4c\x74\x30\x88\xe7\x83\x87\x8c\xdc\x82\x50\xed\xe6\xa6\xb9\xf4\xc0\x85\x2c\xb4\x4d\x00\x5e\xd8\xd3\xb4\x13\xd2\x3c\xd1\x15\x4a\xeb\x44\xc1\xce\xa2\xf5\x3d\x40\x7d\xed\x29\x7b\x36\x48\x32\x79\x65\xa5\xbc\xe8\xe2\x7a\x0a\x89\xd5\x65\x16\x44\x6b\x1b\xc6\xf7\x17\xeb\xb5\x6f\x72\xec\xd8\xd3\xbe\x70\x0d\xa4\x89\x22\xbc\xad\xd6\x7f\x72\x3d\x45\xf8\xbe\x9a\xfb\xae\xdd\x5c\xc3\x29\xd0\x62\x05\xa2\x86\x33\x8f\x17\xdb\xb3\x00\x3f\x40\xc0\xbf\x2d\xb3\x3b\x9d\x0f\x62\xbf\x2c\x7f\x58\x2d\xfc\xca\x6e\xbe\xe9\xfd\x06\x4b\xef\x6f\x61\xf8\x35\x7a\x58\xf5\x9a\xd5\xfe\x61\xdd\x08\x7c\xdb\xee\x27\xb9\x85\x7f\x5b\xd3\x6e\xdc\xab\x6d\xd5\x1f\x32\xfb\xe8\x78\x89\x16\x6b\x40\xaf\x3d\xa4\x8c\x16\x8a\xeb\x59\x22\xfc\xa3\x66\xc2\xa8\xfc\xe5\x0b\xbc\xaf\xb0\xc8\x3d\x0a\x65\x08\x1f\xbb\xec\xfb\xcc\xdc\xc9\xb6\x37\x9d\xd7\x8b\x7b\xd7\xc2\x61\xd2\xd3\xb8\x6a\x9c\xf3\xe6\x0b\xca\xbc\xa8\x95\xf9\x54\x2b\xf3\xcb\xf5\xd4\xe5\x69\x0f\x6b\x72\x93\xfc\x71\xb1\x53\xa6\x04\x7b\xd9\x50\xe0\x87\x3f\x65\x8f\x94\x93\x66\x4b\x75\xfe\x05\xdd\xa9\x38\x68\x7e\x68\x23\xd4\x6e\x13\x42\x3d\xab\x32\x49\x80\xb5\xa5\x3b\xd7\xea\x69\xe9\x8d\xcf\xe9\x99\x6a\xb7\x53\xe5\x35\xec\x92\x2c\x33\x5f\xde\xda\x49\xad\xe7\x39\x12\xf9\xbc\x21\xde\x9f\xef\x0b\xd3\xb4\xcf\x72\x77\xe0\xef\xe7\x87\xda\x24\xd3\xc3\x0f\x8e\xaf\x74\x50\xc0\xf8\x42\xb1\x24\xf4\xb7\xcd\x98\xbc\x7f\xd8\xdf\x93\xdb\xb6\x13\x70\xba\x4e\xe1\xd6\xf7\x7c\x81\x0c\x5c\x6d\xc7\x7f\x95\x35\xdd\x1d\xe9\x74\x50\x97\xd0\xb7\xaf\xfa\xd8\x77\x68\x96\xfb\xa6\x8e\xc9\x79\xbb\xf6\x4d\x43\x6f\xdc\x86\x52\x5f\x8f\x3e\xd6\x36\xe5\xe5\x5d\xa1\x3c\x17\xa6\xdd\x76\xdb\xb4\x91\xc9\xc7\x52\xe4\xb5\x14\x64\xdb\x01\x77\xaa\x97\xbe\xd1\xe5\x48\x52\xb9\xec\x03\xfb\x16\x5e\x7e\x51\xb0\xd3\xab\xd6\xb2\x1b\x7c\x5f\x23\x22\xe5\x15\x28\x7b\xcd\x3d\x6d\x3a\x4a\x49\xd5\xeb\x44\xf4\x75\xe5\xda\xea\xc0\xef\x4d\xad\x0b\xb3\x20\xfd\x50\x35\xeb\xbc\x95\x0c\xdc\x60\xe5\x45\x67\x22\xef\x4a\x47\xc7\x74\x3b\xec\x22\x76\xd4\xb5\xa0\x52\xab\x65\xaf\x82\xa7\xbf\xf0\xfc\x30\xf0\x9b\x2e\x9a\xe4\x0b\x17\x8f\xb4\xa3\x42\x61\xd9\xfd\xc4\xf4\xac\x12\x9e\xb5\xec\x87\x0c\x2d\xbc\x0f\x1b\xec\x7c\x84\x5f\x3f\x6b\x50\xfb\xf4\xe5\x95\xd7\xc4\xd0\x0f\x68\x04\x25\x15\xf0\x68\xd8\x9f\xb5\x48\xf5\xab\x53\x6a\x1f\xfe\x18\x87\x27\x8d\x97\xb1\xa4\xf0\x02\xe4\x23\xc4\xa3\xa7\x54\x6f\x82\xf6\x2e\x91\xfa\x8d\xc7\xc2\xe4\xdb\x35\x50\x9a\x3b\xeb\x44\x58\x39\xe6\x42\x87\x16\xea\xf5\x32\x63\x28\x55\xb9\xf4\x1c\xf3\x64\xa0\x4e\xc6\x41\x94\x0c\x71\x3f\x84\xed\x0c\xfa\x81\xb7\xf3\x43\xcb\x97\x93\x72\xe7\x5f\xe2\xa9\x93\x34\xbc\x62\x52\xf5\xda\x29\xfd\x97\x2e\x3e\x13\x91\x58\xef\x25\x4b\xff\x94\xea\xdd\x95\x52\xd7\xb7\x90\xa3\x4e\x33\x7d\x7f\x39\x25\xac\xe8\xdc\xd5\x2c\xb0\x44\x8b\x9e\xa5\xd3\x6d\x54\xb3\x26\xc0\xe6\x6a\xb1\xd2\x7a\x0e\x0a\x2f\xe7\xb1\x80\x6f\xb8\xde\x62\xaa\x20\x0b\x43\x41\xf2\x39\x5d\xc7\xa4\x67\xae\x04\x47\xc2\x83\xa2\x26\x9e\x91\xd1\xc1\xf4\x00\x22\xb1\x96\x75\x3c\xe5\x91\xc7\x55\x31\x30\xd6\xbf\x06\xc9\x48\xfc\x7a\x43\x4f\x08\xba\x8c\xd5\xcb\x0b\xef\x6f\x76\x43\xe9\x40\xd6\xf2\x54\xdb\xde\x08\x56\xdb\x5d\xc7\x09\xf1\xf9\x1e\xa3\xc6\x43\xff\xee\xc2\x2c\xc0\x37\xf5\x8d\x2a\xb3\x61\x18\x70\xb2\xfc\x21\x9b\x46\xf5\xa0\xf3\xba\xdb\x13\xc9\xab\xf9\x3c\x48\xb7\x7c\xb4\x85\xea\x06\xca\x57\x90\xad\x4a\xcd\x97\x55\x92\x06\xa4\x8c\x71\xf6\x04\x1b\x5b\xf9\x87\x66\x5a\x54\x66\xd1\xe5\xca\x7b\xd1\xe2\xb9\x7f\xcc\x1b\xdd\x3f\xa2\x17\x34\x3a\xe3\x2f\xdf\x09\x01\x42\xb3\x5a\xde\xe2\xdc\xc4\x9b\xcd\x55\x23\x23\x98\x4c\x4b\x4b\xd6\xdc\xe9\x07\x86\xd3\x1e\x94\xfd\x9f\xa0\x13\x11\xfb\xed\xaf\x79\x73\xe1\xdd\xa6\xc2\x2f\x04\x6b\x1f\x1c\xdc\xe8\xb4\x2b\x35\x8c\x17\x60\x80\x9e\x55\x6a\x20\x40\xfd\xe1\xa2\xa3\x27\xc5\xf4\x25\x1c\x30\x20\x75\xd7\x6e\xc1\x16\x35\x44\x15\x23\x08\x45\x78\x83\xcf\x52\xf3\x0c\x53\xa7\xdd\x66\x19\xf9\x03\x34\x3e\x9e\x42\x98\xc4\xae\x05\x88\x69\x9d\xee\x95\xe3\x31\x6e\xa8\x6c\x59\x66\xb4\x3c\x7f\xd0\x35\x25\x2c\xb5\xd8\x02\x5d\x5d\x30\x5a\x07\xa2\x96\xd5\x10\xf3\xd4\xb7\x4f\x07\x01\x3b\xe8\xbd\x06\x03\x29\xb6\x41\xef\xcd\x07\x75\xd0\xc4\xfd\x51\xb2\x22\x7e\x7d\x4b\x7a\x24\xa6\xcc\x00\x1b\x81\xce\x4e\x03\xf8\xee\x9f\x4d\xc3\x28\xb0\x9c\x54\x58\x70\x98\x2c\x19\x97\xfd\x20\x4d\x0d\xe3\x4a\x0b\x39\xcb\x03\x42\x13\xb2\x5d\xf8\x4e\xcd\x57\x89\x08\x66\x80\x1e\x22\x78\x11\x08\x01\x72\x12\x3d\x16\x7d\xa4\xfd\x90\x10\xed\x50\x7e\xeb\x98\xe9\xc6\x3c\x76\xe0\xdf\xe5\x15\x3a\x38\xc0\x4b\xca\x2c\x8a\x95\x1a\x19\xdd\xc8\x95\xc9\x71\x2f\x9c\xe1\x5d\xdb\x0c\xf2\xe8\x20\xe6\x95\xee\x75\x72\xbc\x5c\xff\x10\xbd\xa1\x0f\xf1\xc8\x0b\x1f\x5b\x45\x57\x1b\x22\x48\xe7\x09\x76\xa8\x28\x9e\x02\xb6\x73\x7c\xe8\x73\xa5\xcb\x57\x6e\xb6\xd9\x8c\xff\xe0\x3b\x4e\xdc\x0b\xb2\xa1\x3f\xa7\x74\x57\x39\x84\xe8\xb6\x8b\x76\x77\x6c\x7f\x38\x63\x60\x9a\xce\xc5\xe0\x39\x50\xfd\x6a\x36\xac\x00\x8d\x17\x54\x13\x56\xda\x8d\x36\x6b\x4f\xda\x74\xee\xb3\xb6\xf6\xab\x15\x19\xff\xea\xf9\x63\x0e\x85\xda\xe6\x4b\x1f\x05\x99\x08\xaf\x1d\x25\x23\x3f\x9b\x96\xa0\xa4\x94\x6c\xbf\xdd\x5d\xe9\x76\x5f\x89\x6e\xfb\xb0\xed\x76\xdb\x07\x71\xbb\x5f\x2e\xc6\x59\xd5\x17\x26\xba\xed\x41\x26\x56\x4f\xb9\x74\x1d\x01\x4b\x69\x0a\xc8\xa2\x56\x0c\x3e\x62\x60\xca\xef\x08\x36\x92\x47\x6f\x21\x6a\x5f\x21\x5b\xfb\xe6\x4a\xf7\x20\x3e\x3a\x0a\x9c\x76\x37\xee\xb6\x5d\xfc\xba\x09\xa3\xf1\xe9\x89\x0d\x9d\xa7\x0f\xdd\xe8\xfa\xdd\x76\x1f\xb3\x2a\xc0\xd2\xae\xe0\x98\x2a\x1c\xe7\xe8\x48\xac\xf0\x15\xa8\x07\x38\x4b\xd7\x5d\xe1\x9c\x58\x90\x95\xc1\xca\xcd\x9b\x2b\xde\x0a\xa4\x9a\xca\xe7\x3c\xef\x1a\x52\x87\xd7\xb7\x4d\x23\x7d\x79\x12\x87\xfe\x95\xd3\xd0\x3f\x8e\x82\x3e\x9e\x53\xc2\x7c\x9e\x85\x62\xba\xe2\x24\xc7\x1f\xdc\x95\x4b\xec\xcc\x14\x41\x73\x05\x21\x74\x9c\xe0\x64\x83\xa9\x19\xe3\x14\x08\x16\x10\xab\x69\x39\xea\x11\xc4\xdc\xd8\x68\x97\x11\x33\x8a\xe8\x53\x59\xc3\x1b\x41\xc7\x1d\x68\x0c\x15\x42\x08\x78\xd5\x8e\x33\x19\xb4\xdb\xf4\xfc\xdc\x4a\x51\x50\x07\x60\x8c\xf8\x20\x1f\x36\xdd\x6d\x63\x77\x61\x64\x6c\x05\xc1\x02\x50\xb9\x09\x25\xc2\x41\x1b\xbf\x03\xf8\x3e\x52\x58\x07\x35\x40\x6e\xe8\x26\xa5\x60\x15\x77\xd3\xd4\xbf\x28\x79\x8f\xde\x87\x24\x8c\xa1\xce\x92\x44\xa7\x21\xbe\xa0\xbc\x72\xb9\xa2\x00\x0e\xc5\x94\xd4\x62\xf8\x33\x68\xce\x5d\x41\x18\x78\x6d\xd9\x1d\x00\x8a\xde\x64\x8f\xe6\x00\x1e\x09\xce\x0b\x7e\xe6\xdb\x8f\xa2\xa9\x2c\xaf\x7d\x67\xc8\x4e\x4d\x09\x00\xa9\x6b\x84\xec\x08\x5d\xaa\x02\xc9\xba\x50\xf8\xca\xa7\xec\x49\xe8\x5c\xe8\xa3\xb1\x0b\x4d\x7f\x2e\x2c\x3d\x72\x8d\x33\xd4\x2a\x37\x45\xf6\xdc\x81\xb4\x9a\x4b\x6b\xf7\xbc\x35\x9a\xe2\x0b\xf2\x0c\xdf\x7e\xef\xa2\x6b\x72\xda\x51\x99\x4e\xcb\x89\x96\xb2\x21\xfd\xa0\xd3\x79\x7b\x27\xda\x5a\xd2\xae\xa1\xeb\xa6\x89\xe6\x0e\x60\xc3\x1e\xb5\x80\x8c\x47\xa5\xea\xe3\xcf\x56\x7d\xfd\x98\xd6\xcd\x80\xca\x98\xa1\x6e\x89\xa2\x2d\xe5\xf5\x35\xbc\x9e\xc5\xe9\xdd\x05\xfe\xeb\xb1\xe6\xee\x40\xbc\x41\xee\x97\x9e\x05\xd6\x9c\x56\x3b\x0b\x80\xa9\xf2\xb5\x3f\x2d\x7a\xcf\x57\x45\x78\x61\x9f\x8e\x49\x70\xd5\xc9\x44\xb3\x08\xd1\xf4\x99\x8e\x49\x92\x59\x98\x65\x28\x28\x50\x3a\x48\x8e\x3d\x1d\x83\x2e\xa7\xa4\x9b\x76\xc9\xe6\x59\x3b\x1a\x6c\xf2\x8b\x77\xed\xa4\xe0\x9d\xae\xda\xda\xd2\x8d\xcd\xac\xbc\xd0\xa7\x6e\x6b\x1a\xc8\x64\x6e\xc9\xb5\xea\x8b\x34\x2b\x79\x37\xc1\xd8\x93\x90\xde\x2d\xc0\x26\x55\xfe\x0c\x28\x70\xe0\xa7\xe8\x6d\x4a\x8d\x9d\x0c\x03\xaa\xf5\xa1\xb8\x15\xf6\x26\x51\x72\xec\x47\xf4\x7a\x0e\xec\x04\xa1\xf6\x06\xe4\x68\x77\x40\x21\x0a\xbb\xb8\x98\x81\x8a\xe3\xfb\x0f\xa5\x63\xa0\xf5\xfe\x90\x87\x32\xd3\xdc\xed\xbb\xe8\xd7\x8d\x18\xb2\x7e\xce\x73\xd3\x8e\xec\x71\x34\xc8\x3c\x58\x35\x57\xfa\x8e\x64\xc9\xba\xc1\xf6\xe6\xb6\xb8\x72\x1a\x46\x6e\xf2\xad\xad\x36\x84\x4e\x92\x33\x1b\xc7\xae\x72\x5c\xca\x9c\x00\x00\xeb\xcc\xa2\x99\x6f\xbb\x68\xe2\xdb\x4e\x05\x3b\xaf\x60\xd8\xd1\x67\x19\x99\xca\x86\x1d\xf4\x66\x3e\xf9\x8a\x2a\x8a\x13\x54\x07\xd8\x97\x65\xce\xa8\x1f\x22\xbd\xa8\x9f\xf9\x1d\x2d\x5e\xf7\x19\xfa\xca\xe3\x94\xca\xfa\x24\x94\x36\xa2\x28\x8b\x3d\x42\xd5\x84\x75\x40\xf8\xe4\x0b\xbb\x48\x07\x4c\x4f\xc9\xbd\xc5\xac\x2e\x12\xbc\xb4\x61\xb4\x48\xf5\x02\xab\xb9\xbd\x0a\x38\x2d\xd5\xbf\x1d\xff\x2a\x76\xd4\x79\x97\x2d\x9a\xbd\xf0\x2b\xea\x2c\xfd\xda\xe8\x29\xd9\x59\x56\x72\xee\x9a\x31\x95\x32\x99\x26\x28\xb4\x72\x95\xb7\x11\x7d\xb8\x00\x92\x96\xb9\x15\xb2\x1b\x4b\x37\x4a\x0e\xbe\x0d\xa6\xdd\xfb\xbb\x84\xc9\x2d\xd4\x1f\xe0\xc1\x1f\x0a\x5f\xf2\x52\x8d\x7c\x20\x8a\xca\x48\x0d\xac\xbe\x49\x06\xbb\xb8\xf2\x46\x42\x07\x29\x6c\x58\xbe\x16\xa5\xce\x52\x7d\xeb\x2c\xb5\x4d\x57\x4c\x94\x81\x8b\xe3\xa3\xd9\x00\x46\xb8\xda\x7f\x78\x86\x3e\x50\x69\x00\x11\xc7\x77\x5e\xd0\xf0\x68\x3f\x42\xe7\x32\xd1\x21\x9f\xa3\x35\x96\xed\x20\x19\x23\x1b\x0e\x89\x6b\xc6\x09\x31\xaf\x5e\x6f\x21\x5b\x3a\x64\x13\x35\xe5\x5d\xb8\x85\x62\xae\xc6\xa5\xf6\x55\x14\x54\x24\x2f\x5c\x4f\x71\xa5\x8a\x8a\xac\xc7\x3c\xb2\x91\xc9\x3c\xcb\x68\x44\x3e\xb5\x00\x2b\x05\xef\x9b\x97\x77\xa2\x80\xbb\x52\x16\xda\xfb\xf6\x4d\x19\x63\x2c\x6b\x9e\x71\x48\x2c\xeb\x02\x26\xcc\x13\x6e\x09\x20\x36\x50\x8d\xa6\xd7\x72\xef\xfb\xb6\xf7\xfb\x23\x9e\x66\xb5\x37\xe7\x77\x30\x83\x75\x8c\x61\xe3\xa3\x7e\xe1\xd6\x3a\xb7\x68\xc4\xf8\xfa\x13\x33\x5a\x47\x63\xe1\xff\xe3\xcf\xea\x17\x8c\x9c\x5f\x4a\x11\x1b\x4a\x78\xd0\x87\xdc\x0b\xf2\x7f\x5d\x3f\x8b\x6e\x5a\x33\x07\xc5\x7d\x77\x0d\xef\x93\x03\x51\x40\x8b\xd6\xc6\xc7\x54\x50\xca\x29\x5d\x83\x59\x67\x23\xf6\x22\x22\xf7\x66\x1b\x9b\x4a\x78\x32\x6e\x22\xd4\xbd\x50\xd5\x2a\x54\x8e\x8a\x06\xb6\x9b\xa9\x37\x3a\x8c\xf2\x6e\x43\xb6\x19\xf4\xdd\xdd\x6c\x33\x1d\xa0\x6a\x98\xe3\x13\x3a\x1e\xbd\xa3\xb3\xa8\x58\xfb\xe0\x97\x87\x2d\xdd\xae\x30\x4e\x60\x31\xba\x2b\xae\x02\x80\xec\x5b\xd1\x03\x09\xdf\xcf\x23\x91\x39\x3f\x88\xde\x1e\x1d\x29\x3a\x00\x3d\x06\x29\xf3\x70\x78\x02\xb1\xec\x31\x9e\x89\xfc\x20\x85\xe4\x6d\x1f\x36\x2a\x62\x01\xd9\x3d\x0c\xde\x07\xfe\x9f\x3d\xc2\xd0\x83\x34\x4d\x52\xf6\x1a\x83\xdb\xaa\x07\xec\x0d\x7e\x3d\xf1\x81\x57\xfe\x84\xa1\x5d\x3a\x09\x63\x1f\x31\x2c\x9b\x62\x3f\x60\xf8\x79\x30\x79\x70\x3e\x67\xef\x30\xfc\x82\x8e\xaf\xd8\x43\x0c\xe3\x79\xb6\xac\xf6\x19\xfa\xc9\x29\xd7\x26\xbb\xe1\xf3\x8f\xf6\xf7\x5b\x9f\x3b\x6f\xb1\xc8\x19\x6c\x5e\xc9\x19\xa0\xc2\x5b\xbf\x37\x4a\x86\x84\xdd\xec\xbd\xcf\x5f\x5b\xb9\x7b\x22\x51\xad\x7c\xef\x73\xc0\x4a\xcd\x59\xc0\xb0\x33\x7e\xc3\x47\xc3\xa1\xbd\xb3\xf8\x69\x9a\xcc\x83\x54\x5c\x30\x91\xe1\xed\x6e\x4a\x31\x05\xd3\x0c\xda\x3a\x62\x49\x86\x1b\x73\xfb\xc7\x76\x77\xee\x3b\x71\x56\xf2\xe9\x6b\x3a\x67\x61\xf8\x57\xb7\xf7\xd5\xc0\x19\xf0\x83\x83\x03\xc7\x2d\x56\x60\x62\x57\x7a\x5d\x15\x71\xe8\xae\x4d\x90\xaf\x87\x1c\xb8\x9b\xdf\x80\x9e\x84\x19\xdf\x05\xd6\x21\xd3\xd0\xbe\x47\x1e\x07\x51\xed\x97\x31\x9f\xd2\xe0\x6f\x98\x75\x3a\xa4\x19\xcc\x50\x5f\x44\x7b\x30\xe4\xf0\x33\x96\x65\xfc\x8d\xdf\x1b\x06\x61\xc4\x72\xac\x62\x18\x01\xc7\xf1\x32\x9c\x05\x49\x2e\xd8\x90\x12\xc7\x51\x02\x70\x8d\xa8\x2a\xf8\x0b\xd0\x9c\x04\xe2\xa9\x06\xd1\xde\x18\x7d\xb7\x65\x6c\x9e\xf1\x67\xf2\x35\x29\x36\x26\x08\xcc\x15\x54\x76\x32\xd4\xfd\x07\x29\x4a\x3a\x6c\x4a\xb5\x4c\xb1\x25\x10\xab\xa1\xe4\x34\x63\x23\xfc\xca\x02\xa1\x5b\x9d\x51\x4d\xd2\x1e\x80\x9d\x52\x81\x53\xcc\xf2\x0a\xa4\x85\x6f\x69\x88\x50\xee\x34\x63\x13\x4a\x9a\x60\xd2\x9b\xc0\x3f\x79\xe2\xcf\x21\x7e\x92\xb1\x8b\xcc\xb6\x0b\xc3\x1d\x5c\x22\x36\x64\xc6\xa3\x0a\x52\xc5\x7d\xf3\x1b\x5d\x91\x50\x3e\x32\x85\xa3\xe0\xb3\x01\x0b\x77\x1d\x56\x10\x24\xa9\x8d\x3d\x05\x42\x65\x94\x11\x80\xf2\x0f\xa8\x61\xf8\x0b\x88\x86\x84\x55\x56\xf4\x20\x63\x5b\x94\xb0\x45\x30\x1a\xa6\x01\x20\x3c\xc4\x6f\x65\xec\x18\xfb\x18\x66\xdb\x61\x1c\xc2\x1a\x38\xa7\x5c\xe7\x94\xeb\x24\xb8\xc0\x37\x80\xce\x33\xf6\x9c\x60\x3d\xf3\xcf\xd9\x91\x0c\x85\x31\x3b\xa3\x9c\xf0\xf7\x9e\xdf\x8b\x09\x57\xcf\x32\xf6\x84\x22\xe1\xef\x27\xdf\xd4\x89\x06\x0e\x19\x7b\x89\xcd\x90\xba\x71\x07\x50\x79\x8f\xaa\x49\x7d\xc0\xf2\x19\x7b\x4a\xd9\x77\x1f\x3c\xbc\xfb\x72\xe7\xf5\x83\xa3\x9d\xdd\xed\x9d\xdd\x9d\x97\xef\xd8\x0b\x8a\x7f\xba\xf7\x62\xa7\x1a\xbf\x4b\x85\xe7\xc9\x99\x73\x8b\xdd\xbe\x85\xaf\xd3\xde\x87\x66\x33\xf8\xdd\xc1\x5f\x7a\x44\xe7\x24\xe3\x17\xd9\xe0\x22\xeb\xdd\x7b\xf7\xf2\xc1\x8b\xa3\xa7\x0f\x9e\x1f\x3d\x78\xfc\xe0\xc9\x83\xdd\x97\xde\x3a\xbb\x6b\x55\xf0\xf5\x6d\xac\xe0\x71\xc6\x27\x0a\x0b\x61\x92\x5e\x65\xa5\xc7\x31\x54\x46\xb7\xac\x29\x7b\x95\x59\x1e\x26\x79\x0b\x4f\xe6\x7b\x6f\xc2\xf8\xf9\x4b\x5a\xe1\x30\x56\xed\x38\xf2\xb9\xcb\x54\x5e\xf2\x33\xc9\x17\x4e\xb4\x61\x2d\xa3\xcb\xca\x3e\x22\x01\xe4\x04\x48\xf0\x0d\x34\x82\x79\xab\xe7\xe7\xbe\x5a\xf8\xdb\xa9\x3f\xc1\x5f\xc7\x35\xe6\x31\x25\x57\xa7\x4a\xb6\x36\xae\x54\x3d\xd6\x79\x16\x6f\x8d\xb3\xba\xcc\xba\xe1\x56\xca\x56\x72\xaf\xc3\x8e\x49\xb7\x1d\x16\xf5\x4b\xfc\x52\x0a\xd2\xde\x16\x30\x37\x4a\x0f\xe3\x1d\x0b\x66\x69\x7e\xbc\x73\xc1\xb4\xd6\x00\xc4\x6d\xa6\x54\x47\xde\xe5\x11\xba\x82\x25\xb2\xfb\xa1\x82\xfd\xe5\xd1\x89\x53\x22\xb1\x49\x97\x7b\x8d\xf4\x86\x79\x29\xac\x53\xb5\x58\x2b\xdd\x71\x61\xf4\x2b\x29\xe8\xfd\xbc\x54\xc5\x04\x66\x23\xb8\xc2\x95\xb1\x9d\xf1\xc7\x59\xf9\x7c\xa1\xcd\x3e\x3e\xce\xc8\x50\x92\xa4\xdc\xe0\xca\xdb\xf3\xfb\x3e\x3a\x06\xfd\x3e\x26\xda\x74\x6a\x97\x2a\xfd\xc6\xa2\x77\xd4\xc7\xda\x93\x2d\x20\x1b\x29\x0a\x4f\x32\x97\x7c\x96\xc5\x5f\x9d\xa0\x27\x63\xb5\x6c\x85\x14\xad\xcc\x79\x12\xc4\x5e\xa0\x1d\xf6\x3a\xde\xe5\x0c\xa9\x6d\x15\x17\x50\x5c\x79\xe2\xd5\x42\xde\xd4\x91\x45\x4e\xb1\x48\x8a\x12\x92\x2e\x70\xaa\x5c\x92\xe2\xb5\x34\x0f\x18\x6f\x69\xac\x4e\xf0\xb9\x97\xf1\xad\x0c\x49\x58\xa5\xef\x9a\x52\x40\xd9\x77\x28\xaf\x94\xa5\xd8\xa3\x1a\x78\x6c\xe0\xa0\xcd\x29\x66\xde\xf1\xd9\xeb\xca\x14\x4a\x0b\x60\xf4\xfe\x6e\x6c\x1f\xca\x09\x2c\xf5\x95\x64\x1f\x1f\xf2\x0f\xab\x4e\xb2\x2a\xd4\x41\x52\xc2\xc2\xcd\x75\x9a\xe3\x6e\x37\xd8\xe4\xaf\x8c\x0a\x56\x8a\x70\x41\x59\xe3\x76\x46\x75\xd1\x24\xbe\xc9\x78\x9c\x3a\xf6\x24\x92\x0e\xdc\x9c\x89\xc6\xee\x00\xaa\xc3\xbb\xf9\xf4\x12\xe0\x06\x30\x95\x9f\x3e\x5f\x84\xcc\x83\xd5\x6b\xac\xb2\x20\x32\x6a\x2e\xfb\xd8\x5c\x94\xce\x46\x21\xf9\x87\x8c\x67\xa9\x93\xc6\x2e\x7b\x47\xa1\x84\xcc\x16\xd8\xc3\x65\xa5\x06\xeb\xde\x86\x69\xe7\x6a\xf1\x76\xd3\xfe\x3e\x9a\x27\x62\xc3\xcf\x32\x7e\x06\x18\xb8\x90\x83\x66\xfd\x9e\xef\xe2\x8c\xe0\x96\x04\xa8\xcd\x6e\x64\xfc\x81\x9d\xf7\x7a\x0b\x18\xdb\x7c\xe6\x23\x19\xc0\xf4\x25\x09\x01\x7c\x7f\x1e\xf2\x86\x5a\x96\xda\xe6\xb5\xde\x67\xda\xa2\x48\xe2\xdc\xdb\x8c\x3f\x69\xec\x49\x93\x0f\x59\x62\x1d\xaf\xfa\x78\x0e\xb8\x76\xbe\x86\xf6\x76\xf8\xf8\xef\x4b\xdc\x4f\xc9\x0b\xd5\xcb\xc6\xce\x54\x2c\x9e\x54\xb3\xef\x33\x1e\x55\x31\x57\x79\x20\xaa\xf8\xc9\xac\x7a\xb4\xc4\x05\x4c\x12\xc5\xde\x18\x56\x2f\xee\xbe\x52\x6b\x1e\xd1\x69\x00\x32\x0d\x96\x1f\x9a\x78\x10\x70\xbc\xb0\x12\x65\xd4\x6e\xec\x91\x87\xce\x2b\xf8\x61\xdf\x67\x3c\x4d\x9d\x39\xa0\x40\x90\xf3\xf3\x85\x5e\x04\xae\x6e\xcc\x36\x20\x88\xeb\xa7\x54\x4b\x1c\x4e\x57\x4d\x09\x8a\xa2\xc9\x48\x17\x66\x94\xa6\x18\xb0\x98\xdc\x6a\x7a\xd2\xa7\xe4\x79\x26\x2d\x8f\xae\xbc\xfb\x29\x13\x39\x76\x72\x1b\x8f\x71\x72\x1e\x2e\xa2\xa6\x39\x5e\x07\xba\x9f\x3c\x4e\xce\xf4\x69\x1d\x48\x03\xf8\x0a\xdd\xd2\xc3\x3c\x61\x0e\xf3\x3c\x41\x46\x02\xd7\xd5\x4e\x75\xb5\x57\xa5\x26\xb6\xd6\x10\x4c\xe4\xb7\x2d\xfe\x32\x73\xee\x8a\x6e\x7b\xfd\x5b\xf2\x5c\x3a\xf3\x79\x73\x4d\xcd\xfe\x2a\x81\x02\x79\xf2\x05\x4a\x7c\x79\x32\xe0\x0f\x48\x89\x22\xcf\x85\x00\xb5\x9f\x94\x2a\x9a\x8d\x6f\xbc\x0d\xd4\x10\x48\xe4\x49\x3e\xdf\xe7\xa3\x25\x7d\x66\xe1\xe7\xcb\xae\x28\xcd\xf3\x97\x00\xd1\x7a\x46\xcb\xb6\x22\xf9\x80\xce\x65\xad\x07\x8f\x26\xd5\xb4\x78\x49\x9a\x8d\x71\x7c\xc2\x1e\x59\x75\xec\xb7\x47\x41\x14\x88\xa0\x7d\xc8\x5f\x8b\x4a\x0a\xd2\x15\xfe\xa6\x16\x07\x82\x04\xff\x54\x8b\x83\x1d\x88\x7f\x14\xec\x9d\x1d\x87\x84\x8d\x3f\x03\xce\x5c\x5d\x2a\xe0\x8f\x04\xca\xe3\x63\xe0\x10\xf8\x8d\x04\x83\xe9\x05\x7f\x4b\x81\x2c\x0b\x27\x31\xff\x3e\xc3\xb0\xe0\x7b\x18\x77\x1c\x80\x30\x11\xf0\xf7\x14\x06\xf1\x87\x7f\xaf\x43\x77\x61\x8a\x83\x50\x7d\xfc\x10\x5c\x70\x81\x1f\xda\x5b\x3f\x7f\xe2\x33\x21\x55\x24\xfc\x41\x42\xc1\x3c\x3e\xe1\x8f\x53\x0c\x02\x8f\xe6\x0f\x05\x7f\x25\x3f\xc8\x15\x88\xe0\x2f\xa9\x40\x92\xc7\xe2\xde\x05\x7f\x83\x7d\x90\xfc\x16\xbf\x47\xf5\xe6\x29\x74\x33\x36\x41\xf2\x76\xcf\x53\xfc\x1e\x05\xc7\x50\x6a\x18\xf0\x44\x7e\x49\x89\x93\x3f\x52\x5f\x30\xcc\x50\x06\x23\xff\x82\xfb\x14\x0c\x51\xde\x09\xb0\xcc\x07\xec\x03\xba\xdd\xe7\xdb\x3a\x24\xab\xbe\x57\xf9\x7c\x83\x27\x8c\xfc\x91\x8e\x93\x9f\xaf\xf1\x73\x1c\x02\x1c\xde\xa8\x10\xc2\x74\x17\x47\x3b\x06\xd6\x4b\x04\x31\x7f\x97\x96\x1f\xf7\x83\x60\xce\x1f\xca\x88\xe4\x8c\x67\xa1\x0a\xc9\xf6\x72\xfa\x4c\xd2\x07\x30\x47\xfc\x6e\x52\x7e\xc8\xe4\xc7\x2a\x66\x27\xe6\x9f\x42\x1d\x94\x49\x1f\xd5\x37\x88\x95\xfc\x87\x32\x2c\x13\xdf\x51\x84\x5a\x0b\x19\x7f\x88\x9f\x93\x34\xc9\xe7\x00\xe4\x4f\x08\x64\xd2\xc7\xc2\xc7\x47\xf9\x11\x8a\xd0\x8f\xf8\x8d\x94\x3e\x04\xba\x4a\xa1\x92\xfc\xad\x8c\x39\x05\xf1\x8c\xdf\x08\x65\x38\x39\x09\xf8\x2b\xec\x17\x8a\x24\x3c\xc8\x55\x68\x07\x5d\x07\x33\xbc\x2d\x30\xe7\x1f\x12\x19\x78\x8d\x44\x3d\xe3\xef\x65\x3c\x30\xba\xf0\xf1\xd4\x2f\x3f\xb4\x3c\xcc\x5f\x50\x64\x30\x4b\xc2\x4f\x01\x1f\x52\xf6\x20\x9d\x04\x5c\x60\xed\xb3\xf0\x1c\xd0\x69\x17\xb3\xc4\xc1\x04\x71\x23\xc2\x1c\xc9\x2c\x14\xfc\x7b\x0a\xe1\x94\xce\x31\x34\xf7\x43\x14\xa3\x7d\x0a\xa6\x34\xa8\x71\x58\x7e\x48\xe0\x4c\x4d\x0c\x8d\xf1\x21\x82\x00\xf5\x12\x5c\x50\xb9\x28\x87\xe0\x36\x8e\x40\x0b\xa6\xfc\xc4\xb7\xbe\xf6\xc6\xfc\x2e\x7d\x23\xb5\x0b\x12\x15\xba\x0b\x04\x1b\xc3\x20\x46\x41\xbf\x1f\x63\x06\xc0\xe3\x74\xc2\x47\x21\x05\x91\xf7\xe5\xaf\x29\x07\x0c\xf3\x14\xf8\x63\x19\xce\x00\x9d\x31\x94\x4d\x41\x1a\x07\xec\xfa\x44\x1f\x48\x84\x78\x42\x41\x60\xdb\x61\x9e\xde\x95\x61\x5c\x81\x0f\xe9\x73\x0e\x2d\x8c\xf8\x0c\x1b\xc0\xa7\x20\x78\x96\xa8\x90\xc2\xad\xca\xa7\x44\xde\xa1\x8e\x93\x9f\x91\xfc\x9c\xf3\x2d\x0a\x4c\x81\x7c\x08\x88\x3e\x0d\xe5\x57\xce\x8f\x29\x3e\x44\x99\xe9\x15\x8e\x49\x24\x24\xc5\xf2\x0f\x94\x23\x79\x1a\xc1\x4a\x97\x8c\x3d\xdf\xa6\x28\x18\x7f\x06\x98\x38\xe3\x29\x66\xcf\x63\x84\xf0\x3c\x91\xc1\x8f\x7c\x2c\x43\x9f\xc2\x39\x9f\x62\xf0\x54\x22\x48\xe2\x9b\x30\xa0\x51\x88\x5f\x67\x53\x58\xaa\xfc\x19\x66\xc2\xd3\x4e\x10\xf7\xf9\x8c\x3e\x52\xe8\xed\x04\x9b\x3a\x07\x52\x7a\x8a\x51\x58\xdb\x44\x05\x54\x5f\x2e\x88\x5c\x01\x41\xa2\x35\x47\x8b\x6c\x98\x44\x11\x26\x11\x6e\x22\x2d\x4a\xb2\x40\xa6\x04\x66\xed\x05\xd5\x85\x17\x9c\xc3\xfa\x1d\x49\xca\x88\x97\xf7\x01\xf5\x02\x49\xe1\x66\x01\x74\x69\xa4\x16\x56\x62\xb5\x99\x05\xd4\xc8\xae\x84\x6b\x18\xc9\xc9\xc5\xb1\xe7\x01\x8e\x7e\xd7\x77\x04\x0a\x36\x48\x6a\x51\xac\x13\xfc\x8c\x08\x20\xc8\x9e\x11\xee\x41\x20\x36\xd1\xe7\x3c\x14\x7e\x84\x8b\x21\xa3\x64\xf4\x32\xcd\x2f\x42\x1d\x24\x9a\xf2\x40\x51\x41\xa0\x8b\x3c\xc7\x5c\xd0\xd7\xec\x0d\xc0\x8a\x0f\xe9\x8b\x44\x44\x1e\x95\x61\xa9\x12\xe3\x73\x8a\x81\x25\x0d\xcb\x8e\xc8\x0b\xd2\xf7\xfb\x3a\x24\xcf\x7a\x3e\xa5\xea\x13\x29\xfc\xeb\x50\x7d\x3c\xf6\x01\x5b\x77\x12\xeb\x4b\xe6\xfe\x98\x5a\x51\x58\xe2\x8d\x2e\xf1\x86\x66\xf1\x44\x16\x49\xa1\xf4\x0f\x98\x15\xf7\xb0\x67\x44\x4d\x46\x20\x06\x87\xb0\xc0\xf6\x7c\xa2\x2d\xc3\x28\x1f\x21\x89\x48\x98\x79\xb6\x85\x3f\x23\x12\x84\x5a\x69\x29\x34\xf3\xad\x50\x45\x20\x1e\xde\xa0\xb9\xc9\xee\x49\x93\x2d\x7e\x2c\xd3\x50\x83\xc8\xcf\x65\x58\x5d\x50\xe1\xcf\xd5\x27\xc0\xfc\x82\x1f\xa9\x8f\x8f\x39\x50\x88\x33\xf5\x81\x3a\x03\xfe\x44\x7e\x48\x6d\x09\x7f\x2b\xab\xd7\xca\x47\xfe\x52\xa6\x3e\x41\xf2\xc5\x9f\xca\x8f\x5d\x7f\x97\xbf\xd0\x41\x11\xc2\xd2\xde\x55\x5f\x48\x20\xee\xeb\x30\xf2\xdc\x7c\x47\x7e\x29\x2c\xdd\x93\x5f\xf6\x22\x7a\x2f\x1b\x54\x53\x75\x22\x33\x48\xb5\x1f\xbf\x2b\xbf\x90\xeb\x1f\xc9\xd1\x3f\x96\x31\xaf\xb4\x49\x15\x7f\x15\x12\x35\x3e\xf6\x8f\x09\x99\x52\x44\x26\x3c\x61\xe3\xef\x53\x15\x52\x67\x6d\xfc\xfb\x94\xc8\xf0\x39\xff\x21\x23\x12\x0b\x9b\x16\x06\xe2\x64\x2b\x89\xc7\x40\x7e\x04\xbf\x4f\x04\x37\x81\x3d\x72\x47\x86\xce\x40\x74\x24\xca\x39\xe2\x63\x49\x61\x47\x8f\x83\x31\xd0\x53\xf5\x21\x57\xce\x48\x11\x5f\xd2\x2d\xf1\x99\x2f\x69\x22\xaa\x45\x7c\x49\x14\x47\x39\xd0\xb6\x7b\x89\x09\xcb\x62\x8f\x64\xc4\x1c\xf6\x7e\x7e\x2a\x33\x66\xb0\xa1\xf3\x98\xc2\x79\xbc\x13\x43\xc7\x04\xac\x48\xfe\x1c\x97\x19\x2e\x8d\x8f\xb4\xe0\x62\x20\x66\x34\xd8\x24\x27\x12\x39\x0b\xf8\x0f\x9a\x58\x06\x0a\x9d\xc3\x32\xa2\xc4\x5a\x9f\x22\xf1\x8d\x1c\x2a\x1e\xe6\xfa\x53\x2e\xa2\x09\x91\x3b\xa5\x79\xe1\x17\xf4\x95\x86\x33\xe0\x65\x55\x88\xc6\xbe\xa5\xbf\xe4\x28\x8e\xe5\x27\xa0\x0b\x3f\x97\xf4\x4f\x2d\xc3\xe7\xbe\x21\x03\x3b\x23\xfe\x81\x28\x5c\x92\x02\x05\x39\xc2\x20\x70\x4f\x72\x2d\xfa\xf1\x85\xec\x3d\x3a\xcc\x05\xac\x50\x6b\x61\x04\xfc\x21\xce\x88\xe4\x06\xa2\x51\x24\xe1\x87\xc1\x54\x42\x6e\x8a\x3b\xc1\x0f\x69\xb9\x8a\xf4\x22\x22\xac\xba\xa7\x08\xcf\x82\xb2\xa0\x34\x42\x7e\x1a\xdb\xe9\xf2\xad\x6a\x8b\x49\x4d\x0f\xd1\x98\x1b\x4f\x07\x62\x64\xb6\x03\x14\xff\xd1\xf4\x11\x40\xe6\x03\x88\x02\xfe\x46\x6d\x98\x9a\x25\x95\xb1\x0d\x42\x63\xf5\x6c\x4b\x7b\x71\x0c\x06\x0d\x1e\xdc\x4a\x9d\xd0\x9b\x04\xcf\xf1\xa0\x65\xef\x4d\x52\x71\x8a\x07\x22\xb7\xe8\xbd\x7e\xf0\xfc\xc5\xce\xde\x2e\x3f\x63\xef\x85\xb3\xdf\x46\xce\xb4\xcd\xda\x8a\x41\x85\x10\xb1\x8e\xfa\x57\x3e\x98\xc4\xda\x8a\x25\x28\x43\x32\xe1\xb0\xe2\xf3\x05\x7d\x1b\x56\x1c\x33\xa0\xa6\x81\x1a\x91\x6c\x1f\x94\x06\x36\x07\xfe\x9a\x2d\xb5\x52\x41\x69\xf4\x26\x38\xdf\x46\xbf\x7c\x9c\x3f\xea\x5b\x72\x01\xba\x4e\xb4\xb2\x97\x2f\x09\xe3\x10\xd5\xdb\x02\xf4\xa2\xd4\xd1\x91\x6c\x90\x7c\xce\x65\x14\xa1\x77\xa4\x0c\xa1\xe8\xd4\x62\xc8\x61\xa2\x3e\x3a\xaa\x94\xe6\x78\x94\x58\x14\x29\x5a\xfb\x1e\x1d\x8d\xc2\xf4\xe8\xe8\xce\x3a\xcb\xd4\xb1\xa0\xae\xc2\xa3\x17\xb9\xe8\xf5\x62\xec\xa7\x27\xe8\xbd\x2e\x3d\x78\x7a\xc6\x4a\x0e\x7a\xc9\x78\xdb\x47\x47\xed\x6e\xd0\x6d\x6f\x21\x67\x0f\x61\xbc\x18\xde\x6d\x4b\x08\x2d\x05\x00\x1a\x8d\xeb\xd7\x5c\xe5\x9b\x07\xc3\x8c\x1c\xd9\xa1\x1e\x54\xd9\x49\xda\x90\x41\xdd\x55\x52\x19\x9c\x86\x1f\x3e\x6a\xdf\xa7\x97\xed\xc5\xe0\x48\xba\x63\xf0\xc2\x6e\x4a\xda\x2c\x7d\xf5\x0c\x0a\x9e\x86\xc1\x99\x04\x9f\xf5\x45\xa0\xf3\x15\x3c\x90\xd0\x78\xa9\x84\x01\x08\x91\x49\x09\xb2\x41\x5b\x3d\xbd\x85\xc7\x8f\x96\xaf\x49\x56\x19\x5d\x57\xe5\x6a\x3c\xf7\xa5\xb1\x18\xd7\x84\x00\x0a\x48\xb3\x5c\x15\x36\xd6\xa4\x90\x8c\x57\x81\xde\x5c\x61\x7a\x48\xa9\x56\x95\x25\xf6\xc2\x66\x0c\x33\x88\x3b\xc2\xb2\x19\xa4\xd9\x05\x61\xd9\x1e\xe8\xd2\xa9\xab\x74\x01\xe0\x0e\x12\xb4\x5e\xa2\xe8\x52\x40\xb7\xab\x24\x0d\x68\x19\x39\xdf\x65\x2d\x13\x7a\x51\xcb\xd0\xa8\x6c\xfc\x17\xb5\x6c\x9a\x23\x5e\x1e\x1a\x23\x66\x72\xd9\xca\x1c\xe8\xb5\xec\xc9\xb5\x0c\xab\x74\xf0\x2a\xf6\x1e\xc5\xcb\x17\xea\x42\x9b\xe4\xbf\x11\x9b\xad\xca\xfc\x52\xe0\x6d\xee\xaa\x12\x1c\x9d\x3d\xbf\x3a\xd3\x96\xa4\xd9\xd0\xdd\xd2\xe8\xea\x54\xaa\x5d\x6e\x2b\x67\x98\xaa\x36\xcb\x22\xd2\x36\xcc\xc7\xd7\x93\x62\xde\x0a\x54\x34\x22\x6c\xa5\x4d\x25\x9f\x34\x22\xd5\x17\x34\x65\xdf\xf7\x08\xd4\x77\xbd\x09\x29\xd3\x54\x5b\x08\xcc\x95\x89\x75\x8f\x8e\xd6\x95\xb7\x86\xf5\x4d\xbd\x1f\x68\xe9\xc5\x59\x0d\x94\x93\x4f\x04\x4f\x79\xfd\xae\xe9\x4e\x97\xd6\x3c\xc9\xa3\x7a\xf4\x6e\x12\x97\x22\xbd\xb3\x2a\x5c\x2f\xa6\x8a\xe9\x14\x1e\xef\x29\x54\xfa\xa9\x25\x9c\x25\xb3\x46\xcd\xaf\xc3\xd8\x60\xc3\xb4\x8a\x55\x6e\x44\x18\xcb\x60\xbc\x68\x15\xf2\xb5\x1f\x9d\x81\x47\x2b\xae\xc0\xf5\xe6\xde\x58\x93\xea\x2f\xf4\xc2\x5a\xd9\x62\x17\xbd\x54\x2c\xb8\x1b\xf5\x2d\x0f\x1f\x59\xcd\x4e\x84\xe5\xbc\xd5\x5a\xe2\x54\x15\xdf\xf0\xad\xb8\x5f\xc5\x77\x39\x3b\x9d\x56\x4e\xaf\x66\x43\xc0\xd8\xa2\x45\xf8\xaa\x0d\x2a\x6a\xf1\x5d\x45\xfd\xec\x66\x65\xcb\xa5\x49\x9a\x57\x96\x83\x9c\x36\xcb\xf7\xaf\x31\x08\x89\x99\x8f\xa6\xcb\xfa\x51\x70\xe0\x1e\xd4\xbb\xba\x37\x90\xb4\x6b\x3b\xb0\x68\x90\x7a\x96\xcb\x57\x36\x35\xce\x34\xc6\x50\x5e\xba\x93\x46\xb3\xb0\xa2\x98\x56\xad\x59\xa8\xfc\x88\x57\x62\xd1\x46\xb6\x62\x07\x83\x04\x7d\x64\xdb\xbd\x1c\x27\xd2\xf0\x65\x7f\x7e\x68\x4c\x5e\x44\x49\xc4\xa5\xbf\x59\x7c\xc5\xe0\xca\x9e\x7a\x62\x4e\xe6\x25\x75\x91\x2e\x95\x81\xbc\xa0\xb9\x2a\xf2\x11\xb4\x29\x62\x33\xf0\x93\x4d\xc3\x31\xa6\x21\xd7\x89\x3f\x74\x48\xdd\xc6\xa7\x99\x64\x4a\x95\xcf\x90\xf0\x7b\xe6\xa3\x4f\x84\x54\x22\x0c\xd6\x53\x60\xe9\x42\x15\x31\x78\x13\xb8\x03\x20\xce\x73\xa0\x57\xd8\xa3\x36\x4b\x64\x01\xec\x45\x01\x7d\x28\xea\xb9\x2b\x58\x16\x2c\x60\x99\xe5\x34\xc6\x18\x7c\x00\x42\x54\x71\x0b\x96\x50\xe9\xc8\xc2\x78\x24\x56\x6b\x12\x37\x9a\x26\x53\x1b\x33\xeb\xc8\xb9\x2d\x50\x47\x92\x69\x6f\xd4\xc8\x10\x6d\x54\x3c\x10\x95\x68\x6a\x8e\xc7\xa2\xc2\x61\x4a\x25\xe3\x79\x95\xed\x04\x92\x8b\x5a\xa1\xe7\xd5\x58\x60\xe0\x40\x14\x39\xaa\x46\xea\xb6\xce\xaa\xd1\xda\xc8\x82\x3f\xa9\x65\xcf\xd1\xa3\x9b\x9d\xef\xfb\x17\xc0\x72\x8a\x7a\x37\x41\xb4\x5a\x88\xe3\x2f\xeb\xbd\x94\xaa\x08\x3b\x0e\xb6\x9e\x4a\x1e\x62\xe8\xed\x08\x22\x20\x55\x1e\x3b\x58\xa8\x45\x92\xe6\xea\x80\x50\x0b\x51\x1d\x38\xd6\xf3\x97\xc8\x9e\xeb\x88\x9d\xf1\xf6\xed\xde\xad\xde\x7a\x9b\x3d\xe1\x1b\xec\x25\xbf\xc5\xf6\xf8\x6f\xd8\x53\xfe\x2d\x7b\xc1\x37\xbe\x61\xbb\xfc\xf6\x2d\x76\x9f\x7f\xf3\x1b\xb6\xc3\x37\x6e\x7d\xcb\x4e\xf8\xad\xaf\xbf\x61\x77\xf9\xed\x75\xf6\x98\xb7\x7b\xbd\x5e\x9b\xbd\xe2\x1b\x5f\xaf\xb3\x0f\x98\x7b\x9b\xaf\xb3\x7b\x50\xcd\x23\xa8\xe6\x35\x6f\x83\x08\x0b\x1d\x0c\x46\x2b\xbe\x39\x88\x6c\xb3\x37\xc8\x1b\x4a\x6b\xff\x23\x8b\xb3\x46\x1e\xf1\x13\x6f\xef\x4b\x65\xca\x8a\x11\xf7\x0f\xdb\xec\xa3\x1d\x0d\xa4\x19\xa2\x7e\x28\xa3\x94\xe8\x0f\x91\xef\xca\x48\x54\x00\x40\xcc\xc3\x32\x86\xa4\x7b\x88\x7a\x56\x46\x69\xa9\x1e\x62\x6f\x94\xb1\x4f\xfc\x39\x44\xbc\x2d\x23\xa4\xe8\x0e\x71\xef\xcb\x38\x29\xad\x43\xdc\xf7\x65\x9c\x94\xd9\x21\x2e\x10\x65\xe4\x8b\x00\x73\x09\x3b\x86\xd0\x0b\x22\x63\x2b\x52\x99\xa5\x40\x6c\x2a\x6a\xa3\x95\x56\x3a\x90\x92\x58\x29\x64\x9a\x72\xfb\x96\x06\x47\x58\x4f\x52\x56\x2b\x90\xe4\x5b\x49\x3b\xda\x2c\x06\xe2\xb3\x6a\xfc\xc6\x37\x3a\x21\xaf\x26\x94\x8d\x0c\xad\x84\xd2\xc2\x06\x12\xa2\x7a\xc2\x56\x04\xd2\x9f\xd2\x51\x40\xfa\xbc\x96\x5e\xb6\x35\xae\xa5\x94\x8d\x81\x2c\xbd\x76\x70\x8c\xd6\xfe\x07\x78\xbf\xe2\x66\x7f\x6d\xc2\x46\x14\xe7\xa8\x48\x17\x6f\x52\x1c\x74\x21\x7e\x06\xf1\x10\x1b\x1c\x38\xbd\xaf\x06\x07\x6e\x81\xe5\xc4\x81\xeb\x42\xea\x41\x2c\x8b\x9e\x42\x96\x0e\xd0\x48\xe8\x57\x11\x89\x62\x22\x8a\x8f\x79\x22\x8a\x5f\xdd\xfe\xae\xf8\xd5\x77\xdf\xb8\x98\x65\x02\x59\xf6\x3b\x77\x36\xdb\x37\x7f\x77\x08\x9f\x17\x40\x45\x68\x42\x9d\x53\xa1\x8c\xa4\x5d\xf6\xc0\x44\x4e\xca\xc8\x2d\x28\x78\xe7\xd7\xab\xce\xfe\x41\x76\xf0\xe2\xb0\x3b\x70\x7f\xbd\x09\xe5\x8f\x29\xb6\x16\x79\x4e\x91\xbc\x16\xfb\x1c\xc7\x75\xe3\xe0\xd2\xd9\xff\xf1\xe0\xe0\xea\xf0\x2b\xe8\xe7\xc1\x41\x4f\x7d\xb8\x5f\xb9\x07\x57\x90\xe9\x08\x33\x9d\x7d\x75\x63\x8d\x9d\x41\xe8\xc7\x83\xec\x2b\xbd\xa4\xf6\x57\x0e\xe2\x83\xf4\x40\x1c\x76\x0f\xce\xd6\xd8\x13\x4c\x5d\xdf\x3f\x7f\x7b\xb8\xc6\x5e\x52\x4e\x0d\xe0\x5e\x77\xb0\x55\x9e\x42\x1d\x1c\x42\x55\x7b\x38\xe6\x83\xf3\xe1\xfa\xea\xc1\xf9\xe8\x1b\xf8\xff\x2d\x06\x02\xf8\x3f\x86\xc0\x18\x62\xc6\x18\x33\x1e\x23\x44\x9e\x22\x98\x6f\xfc\xe8\xae\xb1\x17\x58\xac\xf7\x55\x77\xf0\xe3\x8d\xcb\x2b\xc7\x2d\xf6\x0f\x0e\x0f\xd6\x0e\x0e\x30\xd3\xae\x81\xd0\x8b\x12\x42\xf7\x69\xe2\x70\xa7\x38\x38\x5e\x63\x3b\x58\xfa\x26\xf5\x39\xbf\xb5\x7e\xeb\x5b\xfa\xfb\x9d\x2c\x7e\x22\x16\x77\xa7\xf6\xfe\xdd\xd5\xf7\x07\xb2\x97\xd4\x4d\xd9\x4f\xec\x28\x2e\x2d\x48\xf7\x57\x3f\x1d\xc8\x3e\x53\xa7\x65\xaf\xa9\xdb\xdd\xb6\xde\xd2\x54\xaf\x40\x8c\xba\xbc\xc5\xae\x9c\x01\x47\xf1\x54\x74\xdb\x6e\x41\x72\xea\xa0\x8d\x1f\x32\xdc\x2d\xf6\xd7\x57\xbf\x83\xb2\x74\x95\x09\x35\x1d\x77\xa1\x95\x95\x7f\xe1\x5f\x3c\x18\xff\xdf\x7f\xf1\xff\xfe\x93\x7f\x5a\xef\xfa\x3f\xfb\x7b\x3f\xfd\xb3\xbf\xf8\xbb\x3f\xff\xf4\xd3\xcf\x3f\xfd\xf9\xcf\x3f\xfd\x95\x9f\x7f\xfa\xab\x3f\xff\xf4\xd7\x7e\xfe\xe9\xaf\xff\xfc\xd3\xdf\xf8\xf9\xa7\xbf\xf9\xf3\x4f\x7f\xeb\xe7\x9f\xfe\xf6\xcf\x3f\xfd\x9d\x9f\x7f\xfa\xc7\x3f\xff\xf9\x3f\xf8\x7f\x7e\xfa\xa9\xcd\x1e\x0b\xbe\xdf\x26\x54\x87\x36\xac\x55\x0e\x5f\x48\xb9\xe0\x87\xc8\x15\xfc\xda\x0b\x5d\x7f\xaa\xc5\x8d\x9f\x86\xaa\xb6\xcd\xda\x96\x61\xb5\xc6\xe4\x47\x59\x1e\xed\x26\xe1\x47\x92\x34\x08\x48\x3a\x06\x01\x09\x1e\x08\x00\xc1\xc2\xbf\xd2\x3c\x8a\xb5\x8f\x50\x6d\x62\x59\xfa\xc1\xa7\x36\x81\x84\xa0\xd6\x93\x4a\x25\x0a\x69\xfc\x90\xd7\x31\x16\x7a\xf0\x61\xec\x2d\x21\x5c\x52\x0d\xfd\x61\x53\x0a\x15\x57\xf6\xdc\xa2\x08\xf0\xa5\x48\x24\x4a\x73\x64\x8f\x89\x51\xc6\xd4\x0b\xd8\xa9\x57\x74\x8d\xfc\x03\xd9\x88\x7d\x10\xfb\x89\x38\xe4\xf0\x13\xca\x1f\x5f\xfe\x64\xf2\x27\x97\x3f\x43\xf9\x13\xc9\x9f\xb9\xfc\x19\xc3\x4f\x0b\xb6\x33\xb1\xff\x89\xbe\x3f\xd2\xdf\x54\x26\xfe\x40\x7f\xdf\xd1\xdf\x87\xf4\xf7\x19\xfd\xbd\x41\x7f\xdf\xd2\xdf\xf7\xf4\xf7\x7b\xfa\x1b\xc8\x62\x42\xfe\xc4\x58\xb5\xb4\x78\xd8\xa6\x6e\x6e\x53\x23\xdb\xd4\xc8\xb6\x6c\x64\x9b\x1a\xd9\xa6\x46\xb6\xe5\x28\xb6\xe5\x28\xb6\xe5\x28\xb6\xe5\x28\xb6\xe5\x28\xb6\xa9\xd5\x6d\x6a\x75\x9b\x5a\xdd\x96\xcd\x6d\xcb\xe1\x6d\xcb\xe1\x6d\xcb\xe1\x6d\x9b\xe1\x6d\x53\xff\xb7\xa9\xff\xdb\xd4\xff\x6d\xd9\xdb\xed\x4a\x37\xef\x41\x37\xb5\xe3\xb0\xd6\x06\x53\x8e\xc0\xbc\x75\x66\xdc\x85\xb5\x36\xae\xd8\x23\xc8\xd5\xfe\xfd\x4f\xc0\x8f\xde\x85\x49\xf9\xfd\x9f\xeb\xc0\x5f\xd1\x81\xbf\xaa\x03\x7f\x4d\x07\xfe\xba\x0e\xfc\x05\x04\x7c\x0c\xfc\x47\x3a\xf0\x1f\xeb\xc0\x7f\xa2\x03\xff\xa9\x0e\xfc\x43\x1d\xf8\x9b\x10\xd8\xc2\xc0\x7f\x06\x81\x21\x06\xfe\x35\x08\xdc\xc7\xc0\x7f\x07\x01\xd4\xfe\xfd\xfe\x6f\x41\xe0\x01\x06\xfe\xb6\x0e\xfc\x1d\x1d\xf8\x97\x74\xe0\x3f\x87\x00\x22\xef\xef\xff\x0b\x1d\xf8\x2f\x75\xe0\xbf\xd2\x81\x7f\x19\x02\x3b\x18\xf8\x57\x74\xe0\xef\xea\xc0\xbf\xaa\x03\xff\x35\x04\x42\x0c\xfc\x37\x3a\xf0\xdf\xea\xc0\x3f\xd6\x81\x7f\x1d\x02\xbb\x18\xf8\xef\x21\x80\x2b\xf6\xf7\xff\x06\x04\xf6\x30\xf0\x6f\xea\xc0\xbf\xa5\x03\xff\xb6\x0e\xfc\x3b\x3a\xf0\xef\xea\xc0\xff\x80\x17\xf0\x30\xf0\x3f\xea\xc0\xff\xa4\x03\xff\xb3\x0e\xfc\x2f\x3a\xf0\xbf\xea\xc0\xbf\x07\x81\x57\x18\xf8\x7b\x3a\xf0\xef\xeb\xc0\x7f\xa0\x03\xff\x1b\x04\x72\x0c\xfc\xef\x3a\xf0\x4f\x74\xe0\xff\xd0\x81\xff\x10\x02\xef\x30\xf0\x7f\x42\x00\x97\xe5\xef\xff\xa9\x0e\xfc\x0d\x9c\x53\x02\xd9\x3f\xc2\x79\xa2\xd0\xdf\x87\xd0\x4b\xa4\x38\xbf\xff\xbf\x48\x5c\xc1\xd0\x3f\x80\x50\x96\xb5\xaf\xd8\x6b\xc4\x9b\x0e\x7c\x75\x80\x08\xf4\x21\xe9\x0e\x86\x23\x81\xc1\x4d\x0c\x4e\x30\x78\xb3\x7d\x13\x82\xb8\x5d\x63\xfc\x4d\x8c\x87\x6d\x1b\xc3\xbf\xa3\xf0\x77\xdf\xf4\xa1\xae\x37\x54\x17\xd5\x03\x91\x90\x48\xf5\x78\x50\x25\x93\xf5\x78\x50\x25\xd3\xf5\x78\x50\x29\x53\xf5\x78\x50\x27\x53\xf5\x78\x50\xe7\x15\xfb\x84\x75\x19\x86\xd5\x43\xc7\x7c\x44\x26\x21\x74\xc5\x3e\x62\xe2\xc1\x01\x64\x85\x3f\xb2\x3f\x58\x9e\xee\x1d\xe2\xac\x1e\xa0\x1e\x09\x89\x9d\xdc\x21\x10\x6e\xf4\xab\x22\xbe\x53\x11\xdf\x41\x3b\x3f\x08\xfe\x09\x56\xab\x54\x5a\x48\xa2\x76\xd8\xe9\xc8\x40\x8b\x73\x12\xb5\x3a\x1d\x12\xb8\x94\x09\xfa\x40\xfe\x92\xd0\xc5\xde\xd9\xc5\xe3\x43\xb2\x3d\x6a\xc5\x96\x61\x58\xcc\x1e\xda\x59\x04\x64\x11\x28\xd8\x59\x59\x04\x7b\x26\xf8\x3b\x88\x7d\x28\x2a\xde\xbf\xca\xc7\xc5\xfb\xad\x67\xa2\x28\x9e\x09\x75\x71\x0c\xfa\xf5\x0c\xb2\x3e\x13\x3d\xd3\x4f\xf5\x0d\xd2\xc8\x98\xbe\x40\xfc\x86\x91\x3d\x13\x52\x4f\x70\x43\xf0\x87\x54\x7f\x2f\x38\x27\x13\x54\xce\xa9\xc1\x77\x82\xbd\x05\x5e\xc1\x71\xfb\x0d\xf6\x56\x52\xa5\xd3\xd0\x23\x99\xd0\xf3\x67\xa3\x4e\xa7\x0c\x0f\xf0\x9e\xc1\x11\x7f\x2b\x98\x8c\x6b\xb8\xdf\xf9\x16\xc4\x7b\xd7\x93\x23\x1d\xdc\x10\x03\xc7\xea\xd0\x5b\xe1\x52\x69\x48\x96\xbf\xaa\xb6\x2b\xb7\xf4\x52\xea\xda\x1f\xac\x49\xeb\x24\xe1\x33\x90\x3f\x5e\x53\x0e\x84\xd0\x00\xff\x34\xa6\x4a\x78\xea\x19\xbe\x44\xf5\xd9\xe5\xd5\x21\xfb\xc6\xdb\xaf\xdb\x34\x95\x16\xd0\xa4\xe2\xbb\x06\x7e\x16\x88\x14\x64\xf6\xdb\x69\xe0\x0f\x51\xfd\x90\xb8\xde\x02\x78\xd1\xbe\x4c\x43\x25\x71\x02\x47\x65\x46\xf7\x55\xbd\x9d\x78\x2c\xcf\x44\x13\x27\xed\x3d\xc7\x78\x60\x8d\x08\x1a\x4d\xf6\xb8\xd2\x88\x07\xb6\xf7\x2c\x73\x2e\x47\x61\x06\x92\xde\x05\x9a\x5e\x03\xc1\x54\xf5\x80\x5c\x90\x26\x73\x44\xc3\xcc\xbb\x9c\xfa\xf1\x28\x0a\x5e\x0c\x53\x90\x8c\xbd\xa0\xf7\x54\xa7\x90\x0d\x0b\x64\x0c\x80\xef\x19\xdd\xc3\x53\xd7\x17\xa8\x90\xb7\x73\x48\x6b\x46\x9d\xe7\xee\x68\x44\x56\x1d\x7e\xf4\x28\x40\x75\x5f\x53\xd6\x40\x9e\x08\x2f\xcd\x40\xe7\xaf\x1f\xf3\x30\x0d\x46\x4c\x9d\xc3\x05\xe9\x17\xe5\x0e\xd5\xd8\x1e\x63\x6f\x83\x49\x18\xdf\x4b\x84\x48\x66\x7b\xe3\x31\xf0\x44\x4d\x5d\x49\xe2\x1d\xab\xc8\xe2\xc8\x71\x48\xb0\xcd\xbe\x98\x87\x31\xf4\xe1\x3e\xf4\x1c\xed\x5f\xaa\x35\xc1\x62\x66\x61\x66\xd7\x83\x1b\xb3\x9d\x05\x1d\x9a\x30\x34\xe2\x90\x00\x7e\x21\xa0\x8e\xff\x8f\xbc\x77\xed\x8a\x1b\xc9\x12\x45\xbf\xcf\xaf\x00\xcd\x1c\x4a\x6a\xa2\xd2\xa4\xed\xb2\xab\x94\x25\xb3\x30\x50\x5d\xdc\xb1\x8d\xc7\xe0\xae\x99\x43\xd1\x94\xc8\x54\x82\xc6\x99\x52\xb6\xa4\x84\x62\x80\xff\x7e\xf7\xde\xf1\x7e\x28\x49\x57\xf7\x9c\x3b\x67\xdd\xe5\x65\x52\x8a\x97\x22\x76\x44\xec\xd8\xb1\x9f\x28\x07\x6d\x7f\xaa\x9b\x3d\xd4\x08\xfb\xdc\x16\x0d\xcf\x6b\x43\xbd\x1c\xe3\x34\xd2\xec\x99\x99\x5c\x85\xfe\x91\x5d\x15\xdd\x01\xd7\xbe\xc2\xbc\x36\xf5\x36\x9f\x3d\xbb\x46\xf6\x63\xff\xf8\x0e\x8e\xdf\x0f\x26\xe5\x8d\x50\x87\x76\xc0\x64\x35\xe1\x0f\x1d\x28\x95\x75\x07\x3b\xfc\x6e\xe7\x91\x46\x70\xc4\x05\x13\x54\x3a\xf5\xae\x20\x84\x83\x71\xb9\xe2\x5f\x7b\x2d\xee\xae\xc8\x4b\x8d\x3c\x67\x21\x3d\x7b\x0e\x37\x17\xbf\xaa\xbb\x7c\x03\xad\x7b\x2b\xbc\xff\x23\xac\xca\x90\xe0\x47\xe9\x7e\x6c\x96\xba\x2e\x67\x93\xa6\x50\x7e\x96\xa8\x0c\x1a\xf6\xc4\x70\x3d\xea\x92\x67\x46\x51\x6b\xab\xa8\x18\x77\xf7\x7c\x5d\x1c\x4f\xf7\x45\x4b\xe9\x8a\xd6\x5b\x02\x35\xda\x21\x88\xfe\xf2\xc0\x10\x4c\x20\x05\x92\xc5\x9f\xa0\xd8\x3d\xb5\xd3\x0e\xab\x49\x5a\x85\x67\x17\xe5\xb8\xd0\x2b\x3e\x89\xa7\xf5\x42\x36\x09\x10\xba\x29\xeb\x65\x1b\xca\x70\x10\x48\x2f\xbe\xe8\x44\x87\xc5\x0d\x46\xb6\x50\x8a\x46\x05\xcd\xfb\xc8\x48\x83\xa8\x82\x5e\xfc\x52\xce\x66\x9f\x0a\x00\xdf\x4d\xe1\xac\x7f\xed\x77\x13\xb1\x24\x79\x52\xe2\xad\x6d\x66\x64\xe5\xe3\x8c\x0c\x55\x9e\xfd\xd4\x50\x49\x1d\x56\xc7\x1d\xd8\xa8\xf2\x92\xb2\x66\xb7\x49\x0b\x7f\xfd\x09\x79\x6a\xd1\xb7\xae\x74\x53\x6e\x4e\x56\xef\xd6\x7e\x8b\x5c\x46\x00\x78\x8e\xf6\x50\x5c\x99\xca\x06\x9d\x4a\xff\xa9\xa9\xe7\x6a\x7a\xe2\x0e\x55\x5c\xf5\x2b\x97\x4b\x29\xc8\x1e\x94\x93\xcf\x8b\x89\xb5\x21\x51\x24\xdf\xbb\xd4\x08\xac\x4e\x9a\xa0\x9f\x7a\x3e\x8f\x59\x6e\x0f\xec\x99\x7d\x8f\xf2\x6b\x13\x21\xa0\xe1\x3e\x29\xe0\xcb\xb5\xcf\x95\x57\x43\xfb\xcb\xf4\x9d\x4e\xb7\xd4\x58\x1d\x7e\x1b\x93\xba\x68\x37\xaa\xba\x83\x87\x8d\xbc\xba\x83\xda\xd5\xd5\x06\xb9\xf5\xa8\xab\xd9\x1d\xfc\x29\x36\xa8\x99\x41\xe4\x40\xc4\xeb\x90\x0d\xf6\x7b\x6f\xbb\x09\x99\xf0\x14\x0a\xa9\x2c\x1c\x34\x60\xd8\x0f\x70\x74\xc4\x40\xd7\xcc\x4a\xb5\xc7\xfd\xbd\x15\x00\x52\x60\xa3\x05\x4a\xc9\xb9\x5c\x76\xc5\x69\xdd\x01\x6e\x75\x7b\xd6\x23\x61\x0b\x60\x9e\x3f\xf5\x4f\x3a\x61\x6f\xdd\x8f\x9e\x36\x57\x8e\xbf\x95\xb5\x1f\xcd\x6d\x7e\x50\xdf\x56\x7d\xcd\xb5\x08\xeb\x81\x07\x85\x1f\x8d\x4c\x17\x8e\x8f\x2c\xb8\x06\x03\xd8\x82\xd0\x31\x99\x52\xc6\xc5\x33\xfb\x73\xd6\xc6\x46\x37\x42\x2b\xb2\xff\x84\xce\xf8\xab\xed\x15\x25\x58\x2d\x8e\x87\xfc\x77\xf4\xdc\xf0\xad\x5f\xd4\xdd\xf9\x68\x37\x64\x9f\x28\xab\x26\x18\x03\x4a\x07\xbe\xef\x37\x9a\x9b\x63\xae\xfb\xcf\x1f\xd6\x66\xfa\xac\x2a\xfb\xcb\x8d\x9c\x3d\xe1\x1f\x35\xb9\x77\xd4\xb4\xfe\xca\x2f\xfa\xd6\x79\xcf\x0c\xc3\x7a\x97\x04\xe0\xcf\x41\x8a\xc7\xc6\x5e\x26\x55\x14\x3f\xb9\x4a\x85\xec\xdd\xaa\x84\xc2\x9d\x06\x0a\xe9\x15\x0c\x5d\x98\xe7\x55\x7e\x25\x4a\x88\x43\xac\xf5\xf1\x05\x8d\xc0\x3a\xe9\xb6\xb6\x4c\x3e\x5f\xdc\x57\x8c\x9f\x3d\x9c\x24\x02\x12\x46\xf3\xfa\xcc\x4b\x57\x61\x00\xdf\x3e\x39\x83\xa7\x2b\x42\xce\x00\xcc\x9a\xc4\x9b\x37\xcd\xd6\x97\x76\x9c\x2f\xa1\x78\x97\x85\x09\x51\x39\x2d\x21\xc8\xc9\x58\xa3\xe1\x03\xa4\x50\x7e\x4d\xdf\xac\xb1\x1b\xbe\xed\xa7\xd4\xcc\xac\x95\x97\x88\x51\x27\x45\xb3\x7c\x6e\x42\x54\x84\x07\x16\x8f\x84\x02\x88\x9b\x00\xb7\xc9\x6b\x3a\x04\x2f\x97\x80\x65\xf5\x10\x4e\xba\xbb\x59\x11\xa2\xec\x9f\x24\x41\xeb\x9b\xa2\x41\x25\xec\x7f\x4f\xa3\xeb\x72\x32\x29\xaa\x48\x25\xfd\x47\x1a\xf1\x39\x8a\x1e\xc5\x07\x79\x1d\xe7\x63\x4a\xdb\xe6\xfe\xb6\x9c\x74\xd7\x69\x34\xdc\xd9\xf9\x5f\x11\x13\x9f\xd6\x08\xa1\x48\xb6\xa3\xc5\xef\xd8\x96\x73\xab\xe0\x3b\x3d\xd0\x7b\x81\x03\xd2\x55\xf0\xdc\x8d\x2e\x67\xf5\xf8\x0b\x72\x77\xe0\x08\xc6\xd6\x61\xd3\x4f\x8a\xc6\xbd\x24\x74\x26\x2e\xf6\x10\xce\x9f\xfa\x70\x15\xc6\x9d\xee\x3f\xdc\xbe\xed\x69\x13\x10\x56\xd2\xdf\x64\x93\x85\x5a\xe4\x86\x4d\xab\x3a\xc9\x56\x7c\x8d\x47\x67\xf6\xcf\x40\x63\xcf\xa1\x6f\xcd\xc1\xa2\x26\xfb\x91\xc3\x1b\x52\xd5\xe6\x30\x43\xf7\x39\xf2\x3e\x77\xaf\xef\x92\x66\x27\x65\xe2\x6e\x28\x11\xed\x97\x01\x35\xca\xd5\x82\xeb\x11\xe5\x97\xb8\x48\xa8\x78\x68\xad\xc6\x78\x69\x14\x1b\x9d\x0a\x85\x30\xf3\xa3\xd9\x31\xfe\x85\x79\x5d\x77\xd7\x6a\x48\xbf\x90\xde\x4d\x23\xbf\x56\xfb\x15\xba\x7a\x71\xb2\xc8\xc7\xba\x8c\xee\x91\xb1\x98\x63\x6e\x91\xe7\xd5\xbe\xa4\x9d\xbd\x4e\x03\x5c\xeb\xd6\xa9\x6e\xaf\xf3\xe8\x91\xad\x5c\xc8\x06\x68\x7b\xae\xdd\xdc\x62\x19\x35\x35\xd4\x4c\x13\x1b\x8a\xb8\x40\xe9\xf0\x87\x9d\xc7\x73\xf6\xda\xe6\x47\x19\x86\xe3\x74\x1d\xd7\xfc\xa3\x8a\xf3\xaf\xbe\x5f\x51\x5e\x06\x32\x13\x2e\x52\x6a\x74\xbb\x4c\x4e\xbc\x3a\xc7\x5f\x06\xc6\xdc\x91\x9a\xb1\x67\xf5\x39\x5c\x2e\x28\x9a\x7d\x69\x6a\x34\x11\x85\xbd\xb5\xd5\xc4\x70\xc8\x94\x32\x90\x02\x8c\x45\xfa\xcc\xe1\xbc\xac\x67\xb3\xf2\xf2\xd9\x6d\xde\x54\x28\xde\xc2\x55\x6d\x65\x94\x15\xd9\xcc\x63\x38\x0b\xa0\x74\xee\x11\x92\xe5\xb8\x4d\xe1\xd3\xb3\x12\x2f\x22\xfe\x05\x4f\x90\x41\x06\x87\x4b\x23\x56\x62\x93\xa0\xee\x4b\x08\x67\xd4\xd8\xcf\xe8\x7f\xb5\x1b\x62\xef\xb6\x1b\x79\x53\x90\x0b\x8f\x06\xce\x9d\xa2\xd9\x00\x44\x3a\x2d\xaf\x96\x4d\x4e\xc0\xa2\x5b\x01\x2c\xdd\x8d\xf6\xba\x5e\xce\x26\x74\x75\xb8\x2c\x36\x78\xbb\xc5\x24\x62\xe2\xfc\x51\xf2\x5d\xb3\x4b\xd0\x83\x91\x9e\x98\x12\x26\x26\x38\xe6\x74\xf8\x7a\x87\x05\xc0\x94\x0e\xbf\xff\x01\x66\xf2\x07\x77\x26\x85\x3b\xee\x3e\x00\x3a\x40\x3f\xfc\xbd\x18\x2f\xb1\xf2\x61\x75\x53\x36\x75\xc5\xa3\x86\x60\xe0\x2f\x38\xd3\x61\x5d\x23\x86\x11\x5e\x9d\x86\x0c\x4d\x77\x4c\x68\x21\xab\x33\xda\xcf\x2b\x1c\xf6\xb2\x2d\x36\x7e\x2e\x5b\x18\xe3\x1d\x99\xf8\x6c\x08\xfb\xa0\x8d\x7c\x03\x9a\xc1\x49\x95\xd8\x33\x1b\x32\xce\x4e\x1d\x5c\x1b\xe5\x63\x1b\x1c\xb5\x0d\x8e\x60\x37\xd3\x57\x2f\x59\x2f\xc8\x00\x34\xc3\x9d\x5e\xd8\x0c\x9e\x29\x8e\x19\xc1\xe4\x7e\xcc\xcd\x18\x04\xe3\x73\x9e\x7f\x29\x3e\xc2\x11\x96\x56\xc4\xf0\x33\x99\x89\x98\xf5\x33\xee\x73\x3f\x8b\xac\xac\x88\x88\x3e\xad\x03\xd9\xc2\x63\x0c\x9a\x31\x04\x72\xaf\xea\xb7\x08\x5d\x2f\xe3\x91\xa9\xce\xf4\xd9\x24\x8b\x35\x86\xfd\x1f\xc8\xc2\xd2\x47\xac\xee\xef\xba\xb5\xb1\xb0\xaa\x6d\x0d\xc9\x6d\xc1\xaa\x6a\x96\x54\xd5\xcd\x21\xaf\xac\x6d\x14\x54\x95\x05\x44\x5c\x22\x59\x56\xe1\xd9\xce\xb2\x69\x70\xd9\x98\x93\x9b\x0e\x9f\xe3\x4a\x18\x7e\xc5\x4a\xc0\xa3\x79\xff\x7f\xee\x72\x80\x9b\xc5\xbe\xd1\xc5\x00\x01\xa5\xba\xeb\x61\x1f\x99\x43\x66\xc2\xb1\x9b\x9d\xe8\xd1\x04\x6b\x62\x4e\x5f\x4d\x6b\xb0\x5e\x6d\x33\xb7\xaf\x05\x13\x1e\x5e\x03\x46\x66\x5f\x7d\x01\x31\xaf\x2a\x4f\xef\xa9\xf5\xb8\xd6\xea\x79\xbe\x06\x8e\xe5\x3a\x1b\xc2\x6c\xdb\xc2\xb3\x80\x4e\x55\x8b\xe8\xef\x24\xbe\x9f\xe6\xb3\xf6\xae\x6f\x43\xa2\x03\xb4\x5d\x83\x39\xf5\x23\x3a\xbd\xfd\xe6\xcd\xc6\x3c\xbf\xa3\xf3\xe5\x3a\xbf\x29\x00\xa9\x46\xdf\x6c\x77\xdb\xdf\x44\x1b\x78\xa4\x7d\xa3\xe3\xfa\x32\x52\x5f\x36\xb1\xa8\x22\x13\x58\x6f\x6f\xd3\x57\x78\x92\x0c\x5f\x3c\x4d\x14\x70\x8d\x5b\x38\x9f\xc5\x79\x9a\x37\xf9\xbc\xcd\x04\x8d\xfa\xb7\x25\x5a\x2f\x56\x3e\xb5\x31\x7c\xb9\x1a\x80\xfe\xb1\xe4\x42\xb3\xf6\xb7\x6a\x89\x1a\x8b\x74\x2a\x73\xe2\x91\x74\x15\x73\x17\x93\xc3\x6e\xf9\x84\x65\xf6\xba\x83\x62\x01\x2b\xab\xf6\x76\x5a\x2b\x4a\xec\x4b\x76\x5e\x7f\x51\xf3\x6b\x2d\xe4\xe7\xe4\x20\xd7\xdc\x9c\x01\xe4\xf1\x74\xa5\xa7\x77\xb4\xdd\x86\x8d\x39\xcd\xac\x01\x57\x7e\x8e\xc9\x1d\xe0\x79\xf2\xb8\x0e\x93\xf2\x62\x49\xdc\x5c\x1b\x06\xf1\x13\x1c\xdf\xb5\xeb\x22\xb7\xf6\x73\x35\x0f\x7e\x59\x0e\xa1\x6f\x06\x14\x27\x98\x72\x79\x12\x8f\xa9\x00\x5f\x08\x7e\xfa\x1f\xf4\x09\xc5\xf6\x39\x2b\xcf\x13\x9a\x1f\x9d\xdd\xc7\x7c\x0c\xcf\x87\xe4\x86\x0a\xc1\x2b\xce\xf2\x27\xa3\x40\x8f\x54\x42\x9f\x71\xf6\xea\x0d\xf6\x56\xdf\x0a\x76\x2b\x21\xe0\x15\xc6\xb5\x44\xb0\xd3\x77\x58\x83\x5e\xcb\x31\x3c\xa7\xba\x6d\x30\xba\xac\x94\x28\x7f\x27\x9f\x50\x26\x1e\xcc\x03\x78\x90\xad\x8f\x47\xbe\x7b\x1a\x8f\xb8\x8e\x90\xd0\x4b\x78\x09\xc9\x68\x7c\x0a\x9b\x62\xdc\x71\x9f\x24\x35\x06\x6a\x28\x4d\xf7\xab\x32\xaa\xa0\x30\x17\x2b\x06\xdc\xcc\x83\x04\x26\x30\xaa\x51\x3e\xb0\x6e\x05\x5b\x5b\x4e\x42\x3c\xe5\xcc\xa1\xeb\xec\x1e\x3d\x8b\xa5\x53\x72\x30\xc6\xa0\xf7\x75\x23\xee\x9f\x6f\x0b\x40\xb1\x65\xdd\xa4\x9b\x9b\xd3\x41\x28\xe3\x71\x94\x67\x59\x36\xa3\x4f\xef\xc6\xd7\x83\x5b\x58\xe3\xa7\xc6\x09\x07\x28\x7e\x0a\x48\x92\x4d\x05\x7e\x84\x07\x42\x8d\x09\xa5\x74\xd7\x19\xff\x79\x78\x98\x0e\xa6\x0d\x7a\x15\x8a\xfe\x14\x25\x29\x34\x24\x66\x0b\xf2\xe5\xbc\x05\x1a\x57\x99\x5b\x5b\xea\xd1\x2b\xe5\x55\x44\x0e\xd9\x3a\x55\xb1\x1c\x87\xd0\x24\xe3\xfe\x75\xa8\xa7\xd1\x33\x0a\x0f\x10\xeb\x9e\x23\xd8\xd0\x05\xe1\x66\x96\x2d\x09\x12\xfc\x79\x4c\xcf\x7c\x7a\xe6\x99\x5d\x7c\xb4\x40\x03\xf1\xcb\xb6\x9e\xc1\xea\x8d\xe7\xe8\x24\x76\x9e\x2d\xc8\xad\x78\x0c\x94\x54\x92\x40\xaf\x09\x3e\x8b\x01\x00\x7d\x4e\x96\xf6\x50\x8c\x3b\xbb\x12\x59\x13\x86\xb0\x1f\x8b\x2f\xc6\x3c\x75\x3b\x43\x08\x8e\xae\x39\xbc\xb9\x2f\xb9\x05\xfa\x09\x68\x60\x9d\x7e\x54\x69\xa2\x34\xec\xef\xad\xad\x3d\x81\x85\xe9\x37\xee\x8c\x9a\x09\x1f\xb5\x7c\x95\x9e\x3f\x62\x73\xab\xb6\xf1\xb7\x43\x18\xac\xf9\x41\xe5\x4b\xb9\x48\xd8\x37\xa7\xd7\xc5\x46\x55\xb4\xa8\x64\x4f\xf8\x60\x03\xbf\xbb\x01\xf7\xca\x68\xa3\x6c\x37\xc8\x5b\x75\x75\x05\x78\xa3\xe0\x69\xd4\x4a\x81\xd7\x4b\xb8\x31\x97\x70\xe9\x84\x04\xd8\xbf\xba\xd6\x37\x02\x32\xac\x60\x7c\x46\xa4\x6b\x9e\x1b\xee\x3e\x2d\xbe\xd6\xd1\x4e\x09\xd4\xe8\x19\x5f\x78\xf2\x6d\xce\x78\xd2\x39\xfb\xe6\x3f\xea\xe5\xc6\x58\x5f\xd7\xf0\xfb\x98\xc3\x3b\x81\x97\xdc\x39\xac\x75\x48\xce\x2b\x12\x75\x51\xd7\xbf\x61\x62\xae\x99\x6a\x28\xbb\x49\x8c\x59\xd8\x85\x2f\x75\x2c\xfa\xf1\x43\xdd\xfd\x04\x68\x9e\xe3\x37\x20\x57\x96\xad\xa2\x55\xc4\x70\x7e\xe4\x59\x70\x76\xcb\xbe\xa1\xd2\x93\x51\x8b\x45\xd8\x43\x8b\xd0\xb1\x7b\xe4\x7e\x64\x01\x20\xf3\x5b\x9d\x2a\xf6\x5a\x4f\xb7\x54\xeb\xb2\x5c\x94\x30\xa7\x2b\xd9\x0d\x3f\x68\x52\x1c\xe8\xd2\x1a\xa8\x50\xab\xf8\xba\x71\x4e\x8c\x4a\x4f\x0f\xd3\xfe\xc4\x1a\xa3\x0c\xf4\x29\x3c\x48\xb3\x1f\x6a\x8c\xf1\x0d\x3f\xb6\x50\xbd\xc8\x68\xf6\x06\x3d\xe9\xdd\x18\x5e\x7c\xe5\xc5\x4e\x18\xd2\x9d\x29\xbb\xb2\x5c\xcb\x5d\xe5\x76\x29\x2c\x05\x24\x74\x75\xf9\x17\xc4\xc3\xf2\x68\x42\xdc\x11\x17\x99\x74\x52\x95\xa0\x4b\x69\x32\x05\x43\xa3\x24\x66\xb8\xb6\xa5\x58\x66\x05\xba\xf6\xba\x17\x9c\x34\x5c\x83\xe8\x6a\x4d\x73\x75\x10\x31\x14\x1a\x53\x19\xb4\x29\xc7\x05\x85\xf1\xf2\xf0\x10\xc2\x0c\xaa\x1d\x71\xf8\x87\xd0\x7e\xb6\xb9\x59\x04\x33\x98\x50\x06\x74\x10\x75\xe1\x63\xe5\x40\x41\x42\xcc\x6e\x51\x4c\x34\x25\x4b\xa8\x54\x20\x9e\x1e\xc5\xc1\xa7\x49\xe7\xb6\x9f\xd9\xb3\xe4\x64\xb3\xa2\xc6\xda\x67\xe6\x42\x89\x28\x5e\x89\x53\xc0\xda\x2f\x11\x46\x32\x71\x4b\x7c\x12\x47\x34\x05\xc9\xa0\xcc\x65\x57\xce\xda\x67\x78\xb1\x8c\xcc\xdb\xc7\x3d\xa7\x46\xa8\xa5\x16\x87\x44\xfa\x69\x4a\x3b\xa5\x66\x94\x03\x34\x08\x27\x37\xfa\x7a\x99\x3e\x7f\xc1\x56\xf5\x31\x7d\xfe\x1d\xeb\xe9\x61\xfa\xfc\x15\xb3\xfb\x97\xbe\x78\x15\xa6\x64\x7c\xee\xd1\xab\xd5\x64\x0c\x77\xa1\x27\xa3\xb7\xf3\x10\xd1\x7c\x11\xd2\x02\xc5\x4d\x2f\x5f\x6c\xbf\x7a\xe8\xda\x8e\x6f\x37\x94\x09\xc8\x47\xa0\x1a\x3c\x13\x5e\x25\x63\xa1\xd3\xa6\x31\x8e\x18\xc5\x0b\xde\xac\xc9\xb9\x46\xa0\xce\x46\x78\xb1\x3e\x26\x21\xde\xab\xb9\x68\xea\xaf\xe4\x10\x96\xe6\x22\x00\xe2\xf4\x17\x62\xee\xf1\xaf\x7e\xac\xf9\x82\xc6\x68\x2d\x06\xe7\x16\x26\xa7\x6e\x26\x76\x11\x5f\xf2\xc7\x05\x0b\x82\xa9\x08\xc4\x82\x9f\x98\xdd\x4b\x91\x99\x95\x8c\xe6\x94\x65\x9c\x18\x4a\x08\xc1\x8f\x58\x72\x93\xbf\xe3\x5b\xdc\x5b\x86\xab\x7d\xe4\xdd\xb6\x1a\x79\x18\x58\x4a\x19\x72\x5e\xe2\x04\xc9\x5d\x93\x9b\xca\x3f\xb3\x71\x29\x0a\xb8\x0c\xd5\xaf\xb8\xdb\x09\xc1\xf4\x53\x5a\x3c\xb8\xa6\x03\xd5\x3a\x7d\xdb\x0a\xc8\x68\xd1\x69\xab\x21\xbf\x62\x32\xc2\x5d\xd7\x3b\xce\x11\xd1\x95\x66\x83\x72\x76\x3c\xfe\xcc\xc0\x9b\x40\x53\x54\x66\xe0\x6b\x9e\xc0\x6d\x8b\x1d\xa6\x8e\xb8\xcc\xac\x5e\x9e\xe9\x8b\xd7\xec\xef\x66\x37\x7b\x42\x98\x75\xd9\xcd\xc8\x00\xe0\x6a\x0b\x3d\x5c\x46\x5d\x80\x23\xd3\x95\x45\x3e\x0a\xac\xf3\x44\x21\xbc\x99\xac\x2c\xf2\x6f\x78\x67\x09\x94\x00\xa2\x79\x8c\x0e\x95\x7a\x98\x93\x36\xab\x3a\x7c\x49\xb6\x3b\x1b\x1b\x77\xec\x80\xa2\x6a\x5f\x55\x5e\x5e\x54\x56\x83\xfe\xaa\x2f\x63\x0d\xd5\x00\x01\xe4\x2b\xaa\x63\x79\x51\x99\x83\x6a\xed\xba\x54\x1c\xab\x2a\x50\xae\xc3\x9c\x97\x85\x25\x83\x7c\x1d\xce\xe5\x13\x72\x3e\xe3\xac\xe8\x3f\x45\xe4\x71\x66\x86\x0a\x6d\x44\x6b\x32\xfc\xab\x92\x11\x72\x13\xb5\x18\xfd\xff\x26\x70\x66\x89\xd7\x0e\x5f\xf5\x29\x28\x8f\x4c\x87\xb2\xfc\xfb\xdb\x13\xa1\x35\x57\x71\x12\x73\x7f\x3f\xb6\x3e\x15\x03\x94\x93\xbb\x2b\x57\x2b\x9d\xe5\x42\xe7\xcd\xde\xa6\x2b\xeb\xf0\x83\x5f\x06\xd4\x49\x1e\x43\x5b\xf8\xc9\x8f\x62\xa9\x47\x7f\x5f\xfb\xf5\xca\xf8\xde\x92\x44\x73\xd6\x84\xf5\xd5\xbe\x55\xec\x56\xe5\xcc\x8c\xbe\xd5\x5b\xaa\x7a\xad\x79\xdd\xc7\xc0\x3f\x59\x96\x39\xdd\x4f\x2d\x84\x2e\x48\x21\xbc\x1b\x34\xb1\xd7\x57\xc6\xfd\x0f\xf3\xe0\x4b\x70\x58\xc6\x6e\x97\xe0\xd3\x49\x90\x05\xeb\xcc\x64\xfe\x34\x7e\x5d\x55\x44\x4d\xce\xea\x42\x34\x0f\xab\x8a\x70\x70\xfb\x25\x14\x58\xbd\xac\x75\x58\xc5\xce\x58\xe5\x21\x6c\xa4\xf9\xa3\x75\x0a\xf1\xd4\xd0\x88\x03\xad\xd1\x35\xcc\x1b\xb7\x57\x90\x26\xd0\x1d\xbb\x53\xea\xdf\xf8\x24\xca\xe1\xf3\x8b\x98\x78\xb3\xcf\xf4\x65\x88\x41\xe9\x13\xfa\x4f\x31\x2a\x3d\xd9\xb9\x8b\x1d\x8d\xeb\x25\xdf\x00\xf9\x25\x7c\x1f\xae\x31\x6d\xcd\xa3\xcd\x48\x56\x71\x07\xf4\x61\xa7\x65\x4c\x41\x1a\xbb\x47\xa6\xa1\xaf\x53\xa3\xc6\xf4\x54\xcc\xee\xe9\x63\xb6\x5e\x83\x26\x20\x8d\x9e\x48\xe5\x32\xb3\x73\xe8\x0a\x7b\xef\xed\xf1\xa7\xd3\x88\xc4\xb0\xfc\x13\x61\x19\x2c\x55\x23\xaf\xe9\xf2\x7e\x8f\x8e\xd7\xe1\xba\xe6\x15\xd7\xde\x6f\xb0\xf3\xc2\x51\xa0\xe9\xdc\xb9\x32\x9c\x1b\xa9\xe4\x92\x88\x44\xd8\xb1\x8d\xd9\xc3\xa4\xc0\xc0\x62\x32\x14\x59\x15\x62\x43\x62\xb4\x86\x50\x06\x06\xb3\x3b\xab\xcf\x19\xea\xda\x06\xb2\x05\xd3\xfd\xc7\x17\x5b\x5b\x78\xb8\xf3\x50\x0e\x79\x72\x5f\xc0\x1f\xe1\x38\x1f\xa5\xc6\x18\x57\xa0\xc6\x43\xb8\x73\x25\xdb\x86\xab\x20\x1c\x6a\xa9\x86\xca\x5d\x15\x19\x85\x9b\x15\xa3\xad\xfb\x47\xeb\xf3\x6b\x69\xac\x7e\x72\x5c\x53\x7f\x90\xf9\xe6\xe5\xc9\x61\xbe\x7c\x62\x98\x4d\x32\x2a\xb9\x8f\x31\x5b\x2e\x67\x2e\xbd\x74\xf8\xe2\xa9\xcd\xf2\xbc\x47\x99\xe2\xfe\xe3\xe7\x93\x9f\x53\xe1\x5f\xe7\xd3\xe1\xc7\x77\x7b\xfb\x87\x69\x24\xe4\xb5\x11\xfb\x78\xfc\x31\x25\x17\x3c\xe6\xf6\x15\x62\xc1\xe7\x2b\xa4\xf2\x83\x67\xc2\x51\xd0\xb3\x77\xf5\x98\x94\x6d\xf6\xf8\x3b\xa7\x9f\x43\xb7\x07\xe7\x26\xd3\xc2\x7d\x89\xc7\xf0\x18\xe7\x18\x32\x7b\x40\x1d\x15\xcf\xb2\xa3\x42\x11\x45\x6a\xea\x52\x68\x8f\xd1\x25\x40\xe2\xcb\x48\xd6\x82\x01\x14\xbb\x6e\xb9\x62\xf0\x3b\x2b\x06\x77\x49\xb0\x81\x90\x50\xb9\x7f\x3c\xe9\x73\xbc\x3c\x3c\xef\x91\x31\x3f\x31\xd2\xe4\x3e\xdc\x81\x00\xb0\x3d\xe9\x6e\x58\x06\x0b\x3d\xdd\x37\x75\x9c\x14\xa2\x72\xa5\xaf\xd5\x0a\x6b\x42\x8b\x7f\xc3\xc8\x53\x74\x9b\xa2\xdb\x2d\xc3\xb8\x90\x0e\x94\x5a\xd8\xab\x31\x22\x06\xea\x01\x49\xc6\xd9\x58\xb1\x88\x44\x82\xe0\x7d\xf9\x22\x59\x54\x8a\x73\x74\xa8\xbc\x01\xa4\xdf\x33\xbb\xf7\x96\x34\x0b\x41\xe3\x89\xa7\xcd\x73\x40\x6d\xf1\x1d\x32\x30\xb9\x5c\x76\x5d\x5d\x59\x94\xb0\x72\xb2\xb6\x09\xeb\x62\x5e\x74\xf9\xbf\x16\x77\x18\x5a\x25\x9f\x75\xe2\x69\xdc\x35\x33\xf1\x48\x6e\xa0\xe0\x39\x11\x91\xdb\x0c\xf8\x3b\x94\xeb\xf8\x77\x49\xae\xf6\x9f\x21\xad\x98\x9a\x0f\x70\xb7\xbe\x92\xf3\xb5\x14\x89\xa4\x69\xac\x98\x7c\xf6\xfc\xcd\xb2\x7a\xc5\xfc\xbd\x2b\xab\x2f\x7a\xde\x5a\xb6\xb4\x66\x2e\xa7\x13\x79\x5f\x29\x82\x8e\xc5\x24\x5a\xca\x2f\x75\x30\x99\x53\x72\x90\xc5\x6d\x5c\x19\xd1\x6d\xfa\xb5\xae\xf6\x81\x1a\xfe\x02\x09\x08\xdf\x75\x8c\x18\xdd\xbe\x44\x3c\x01\x35\x82\xf9\xa2\xe1\x0d\x7a\x72\x56\x8a\x1a\x3f\xb2\xb4\xad\xa9\x24\x39\xa9\xf3\x93\xd1\x91\x20\xdb\x6c\x88\x6d\x5d\x71\xe6\x35\x94\xc3\xb8\x84\x38\xa7\x13\xd9\xc7\x02\x15\x6c\x8b\x09\x66\xec\x60\x19\x11\x88\x9e\x6c\x52\x90\xe9\xc2\xcb\xa1\x16\xac\xb0\x80\xb2\xb4\xa6\x4c\x65\xfb\xda\xd4\x04\x97\xf4\xaf\x4e\xe1\x24\x38\xa7\xde\x6d\xed\x2e\xfb\xa2\xa0\x14\xba\xbe\xba\x6d\x4e\x6b\x2a\xb8\x3a\x7a\xd5\x85\xab\x77\xec\x28\x07\x23\x73\xff\x2c\x94\x81\x7e\x2e\x24\x8f\x5d\xde\x67\xbf\xba\x6f\x6e\xeb\xce\x22\xe0\xdf\x40\xc1\x41\x9f\x5a\x38\xc6\x0f\xbd\x37\xad\x1b\xd8\xfd\xb5\x52\x7b\x12\x20\x85\x59\x72\xb4\xa2\x4d\x80\x90\x26\x33\x5f\x5b\x06\x9f\x9e\x12\xb4\x9e\x6e\x4d\x9a\xc1\x14\x17\xd0\x57\xfd\x4e\x6c\xdc\x35\x13\xb8\xcb\xd8\xc9\xe9\x70\x27\x80\xb9\xf4\xce\x4e\x87\xaf\xd7\x94\xca\x33\x1b\xad\xa4\xc3\x97\xdf\x23\xde\xf3\x04\xf5\xff\x8d\x47\x82\xcd\xb3\xff\x9f\x7f\x26\x78\xdc\xff\xff\x46\xd8\x28\x3a\xac\x07\x2c\x02\x10\x02\x2c\x44\x9a\xab\x37\x40\xb4\xea\xd9\x00\x09\x82\xe8\x1f\x03\x88\x7e\xae\xe6\x1f\x03\x04\xbf\xf4\x18\x4a\x30\x74\xca\xad\x04\xcf\x57\x2f\x19\x1f\x1e\x30\x82\xb0\x92\x47\x4d\x76\xf8\xeb\xdb\xcb\x37\x28\xaf\xb2\x00\x9b\xaf\x0f\x58\x77\xe4\xe9\xf3\xef\x6d\x60\x7b\xfc\xba\x5e\x60\x9b\xed\xbc\x47\xc8\x10\xc0\x9f\x04\xa3\xfc\xb2\x09\x4d\x1f\x47\x5a\xec\xc7\xb0\xea\x52\xec\xe0\xaf\x5a\x40\xc1\xef\x17\x60\x1b\x7b\x90\xde\xb5\x5b\x5f\xa9\x2a\x83\xf6\x6a\xf4\x6d\xcc\x54\x83\x83\x3e\x17\xe7\x92\x90\xe8\xd8\x42\x71\xbb\x05\x31\xd1\x3c\x7a\x02\x6b\x56\xb2\x5c\x33\x17\x81\x9c\x61\x63\x20\x80\x76\x28\x14\xb7\x08\x32\xb5\x78\x33\x1b\x6d\x6f\xcf\xe8\xf2\x06\x44\xd5\xd9\xec\x1c\xc8\xa8\x3a\x6e\x25\x4f\xaa\xb5\x25\xf8\xad\xa3\xb8\x80\x1f\x60\xdc\x67\xfa\x52\xc5\x05\x97\x1c\x3e\xe1\x29\x34\x6e\x81\x34\x23\x37\xab\xd9\xb1\x25\x82\x6e\x63\xce\x64\x40\xfe\x95\x0c\xcd\x17\xb7\xd0\x47\x6c\x55\xf9\x3a\x85\x43\xcf\xaf\xd8\xa9\x8a\xbb\x4d\xdc\x89\x2a\x69\x15\x2c\x5b\x99\x65\x2b\x55\x16\x45\x57\xa6\xb4\x3d\xcc\x87\xf5\x6c\x3f\x30\x08\x2f\x72\x65\x37\xb3\x8c\xb8\xb1\x2b\x98\xbb\xb9\x9c\x48\x56\xe3\x3c\xf4\xb3\x9c\x51\x82\x8a\xed\xe9\xc6\x8c\x39\xcb\x4c\xad\x1c\xa0\x69\x77\x60\x0a\x97\x72\xfa\x66\x6f\xc6\x30\x7d\xe3\x84\x66\x6f\x79\x36\x86\x45\x7d\xd6\x62\xdf\x2a\xf8\x71\xfb\x06\xa3\xc4\x8e\x6c\x6d\x95\x71\x8e\x31\x90\x0d\xbe\x76\x6b\x6a\x1b\x5c\x4a\x2d\x05\xb9\xf0\x8a\x47\x69\x59\x78\x86\x0e\x61\x61\xf1\x88\xbb\xdc\xc3\xc3\x47\x62\x13\xb4\x16\x6e\x79\x78\x38\x01\x02\x1d\x1a\xba\xc6\x3f\x1f\x38\xc3\xe8\x80\x7e\x46\x5e\xa8\xcb\x66\x77\x1c\x6f\x2e\x1e\x1e\x22\x74\x0f\x0b\xc9\xb0\x95\x8b\xea\x66\xf0\xe1\xf8\xe0\xf0\xe2\xf0\xc3\x5f\xb8\xce\x88\x61\x66\x82\x12\xc2\x7c\x83\x4b\x54\x37\x64\x3f\x70\xba\x48\x3c\xb8\x51\x68\xc1\xd5\xc6\x65\x31\xce\xa5\xbe\x8f\x30\x63\x41\x66\x82\xb4\x56\xf9\x52\x2c\x3a\xac\xd8\xde\x55\x63\x6e\xec\x8e\x05\x85\x1d\xed\xc6\xe7\x4f\xef\xa2\x24\x9d\xc5\x0b\xe4\xdf\x54\x45\x31\x69\xa1\x79\xa2\x7c\x79\x97\x0c\x7d\xa2\xff\xd5\x3a\x32\x4a\xd4\x1f\x69\x60\x12\xe6\x0f\x0f\xa7\x28\xdf\x8c\x9b\xec\x86\x43\xf0\x08\xa6\xee\x09\x4c\x45\xa6\x57\x42\x5e\x0c\x87\xfb\xb2\xaa\xa4\x9f\x09\x34\x2d\x9a\x7d\x04\xa4\x05\x09\x9a\x23\x62\xe2\xaf\x0f\x30\x6d\x1f\x0c\xc6\xd6\xfb\x44\x80\x1f\xf9\xc3\x68\x4f\xbb\x37\x9b\xf9\x2c\x7a\x8e\xee\xc2\xad\x4b\xad\x50\x4b\x7f\x46\x73\x00\x6d\xdd\x21\x23\x1d\xc6\xc3\x13\x69\x21\x70\x6e\x21\x7f\x3d\x3b\x7f\x64\xf9\x64\xe2\x76\x03\xd6\x9f\x5a\x77\xfb\x82\x72\xf4\xda\x92\x76\xc7\x02\xc1\x20\xf3\xc5\x74\x04\xac\xf8\xe8\xca\x02\x23\xf0\x15\x3e\x5a\x0b\x18\x72\x90\xaa\x5b\xa8\xcc\x26\x95\x61\x9b\xa2\x25\x49\x1d\x05\x89\x0a\xc9\xd1\x6b\xeb\xe3\x1e\xb4\x02\x80\x62\xc7\x32\x8a\x10\x97\x88\xc1\xd7\x14\xd2\x92\x29\xc9\x0a\x03\x18\xe2\x47\x22\x46\x3d\xb6\x25\x0d\x49\x03\xc8\x4f\xab\x10\x16\x9c\xf3\x66\xf0\xf4\x4c\x58\xa2\x7b\xec\x19\x20\x84\x6f\x3e\x57\x68\xa7\xb8\xd1\xd5\x1b\x18\x23\x47\x68\x5c\x91\x82\x5c\x86\x0a\x72\x6f\xbe\x21\x3e\x1c\xdc\x9b\x49\xd8\x23\x06\xcd\x47\xc0\x3b\x7b\x2c\x02\x7b\x08\x7c\xdb\x60\x44\xa1\x95\x26\x38\x46\x87\x1c\xbb\x1d\x89\xa9\x1a\xd8\x69\x93\xdd\xe8\x9f\xa3\xed\x1a\xed\x1c\x57\x9a\xe3\xcc\x62\x89\x54\x94\xf7\xaa\xc6\xdb\xa3\x66\x0b\x7c\xb3\x7b\x48\x24\xb2\x82\x3a\xb8\x1d\xfb\xb0\xab\xac\x31\xe2\x1a\x3d\x50\x91\xd6\x56\xfd\x84\xb1\xcf\x5a\x7d\x33\x1a\xe8\xed\x1a\xd3\x5f\x0f\x75\x2f\x68\x36\x24\x5d\xa8\xaf\xd3\x07\x5e\xbb\xff\xf3\xb7\xe2\xc4\x79\x03\x17\x7f\x9c\x9c\x9b\xdd\x18\x40\x40\xee\x37\xe0\xd2\x99\xc6\x63\x32\x20\x94\xb6\x49\x1b\xb7\x79\xbb\xc1\xc9\xce\x89\x89\x86\x9b\x02\xf5\x40\xab\x5a\xa2\xe3\x6b\xae\x4b\x12\x51\xf4\x16\xc9\xb9\xd8\x23\xf6\x7f\x31\xa8\x2b\x7a\xb2\x83\x86\xc2\xa2\xf7\x8f\x10\xdf\xb3\xc9\xe7\x8a\xb7\x35\xd9\x20\x64\x08\xbf\x7a\x01\x6c\x6e\x70\xde\x74\xba\x11\x6d\xe3\x16\x31\xcd\x36\xdf\x63\x5c\x19\x33\xe1\x62\xb7\x17\xf0\x78\x69\x57\x32\x3a\x29\x1d\xa4\x95\x21\x5c\xb7\xf0\x2e\x50\x8f\x68\x38\xf4\x64\x0f\x87\x77\xbc\x90\x65\x25\x8f\x74\xff\x1a\xe3\xb6\xf9\x68\x0b\x4f\x0b\xe2\x77\x17\x42\x2d\x96\x6b\x1d\x3f\x32\x99\x61\x2e\xc0\xea\x29\xcc\x2e\xfc\xf6\x08\x22\xac\x16\xd1\x0f\x2a\x44\x2c\x78\x7a\x01\x31\x80\x52\x8d\xad\xad\x2a\x43\xad\x4b\x64\x23\x0b\xee\x4d\x48\x8d\x09\xe3\x07\x18\xd1\x62\xe6\xbc\x9b\xc9\x68\x1c\x73\xf2\xb0\x64\xdf\x7c\x10\xf3\xbe\x21\xe2\xed\x69\x3d\xdf\xc1\xc6\x7b\x00\xeb\x46\xbb\x84\x05\x72\x07\x0b\x93\xf4\x37\x05\x22\x22\x31\x14\x21\xa2\x0d\x24\x9c\x6e\xf9\x2a\xaa\xb0\x9c\xb0\x4e\x6d\x01\x43\x91\x50\x84\x8b\x48\x29\x28\xf2\xbd\x20\x59\x96\x6c\x06\xe4\xae\xc4\xce\x0f\x0f\x40\xc0\x5c\x67\x92\xc3\x42\xd4\xce\x24\x13\xec\x15\x7a\x9b\x67\xa5\x59\xf6\x06\x5e\x8d\xb2\x57\xf0\xaa\xca\x8e\x16\x62\x4f\xec\xc6\xcb\x6c\xd1\xaf\xc4\xb6\x99\xc7\x73\xe8\xe0\x35\xbb\x61\x13\x76\x85\x6a\x9e\xb3\x6c\xbe\xb2\xf8\xc2\x2a\x0e\xbb\x6b\x89\x84\x17\xd4\xe2\x63\xba\x23\xe5\xe7\xdf\x25\x7b\x25\x68\x23\x86\xfa\x48\xa3\x0f\xd9\x1d\x55\x38\xcc\x64\x24\x51\xd9\xe5\x6f\x25\x05\x99\x8c\xee\x48\x19\x3f\x5e\xb2\x43\xad\xb9\x6a\xc4\x70\x79\x78\xb8\x33\x05\x3a\xbb\x07\xdc\xf1\xe0\x11\xa0\x9d\x3b\x61\x7e\x75\x07\x3b\x21\x9e\x41\x7f\xaf\xac\x16\xcc\x92\x8c\xdf\xe5\x0b\xc6\xa5\x01\x70\x69\x51\xf7\x97\x52\xc9\xf3\x99\x20\x37\xe7\xf2\x96\x73\x23\xae\x36\x57\x8f\x09\xfd\x03\x5c\xbb\xb4\x55\xd9\x66\xf1\xa6\xe0\xa9\x09\x42\x89\x09\x22\x0a\xf1\x4c\x3e\xc3\x88\x84\x77\x1b\x0d\xcf\x02\x2c\x73\x60\xc4\xbd\xe1\x37\x2c\xb8\x5e\x1c\x0d\x8c\x8d\x0a\x1d\x07\x92\x09\x76\x01\x52\x52\x9c\xa0\xa9\xac\xf1\xcb\xd2\x7b\x9c\xc8\xb2\x84\x5d\x69\x61\x78\x65\xa4\x3f\xd7\x59\x83\x98\x20\x40\xf5\x1e\xe9\xcd\xdc\x48\x75\xe4\x06\x29\x10\xbe\xf7\xdf\x01\x66\x2c\x2a\xb4\x58\x08\x24\xc6\xb2\x13\x36\xbe\x50\xfc\x45\x01\x0b\x74\xad\x6b\x53\x31\x74\x5a\xd1\xb3\x79\x4e\x98\x5d\xf1\x54\x94\xa4\xdd\x11\x20\xea\xc5\x57\x10\x8d\x8d\x08\x2c\xe9\x8f\x26\x94\xbe\xf6\x80\xd0\xd7\x99\xbc\xc1\x5f\xc1\xb2\x3a\xb4\x78\x22\x8a\x57\xf6\x49\x30\x82\x7a\x94\x22\x2c\xcb\xb8\xa5\xe3\xe5\x70\x2d\x1b\xb9\x55\x95\x6c\xa3\x35\xb3\xe4\x1f\x31\x81\x73\xbb\x6b\x99\x42\x89\xc4\xfe\x7e\x72\x55\x91\x9e\x5c\xa7\xa7\xdc\x78\x6e\xb5\x03\x42\xa9\xe1\x92\x5d\xaf\xe5\x73\xce\xf5\x07\x06\xf5\xd6\x30\x92\x3b\x1a\xe0\x62\x13\x2a\x66\x72\x45\x04\x7a\xd1\x18\x8a\xae\x8a\xaf\x15\x50\xe3\xd1\x5a\x76\x12\x2c\x3d\xe6\x67\xa6\x36\xce\x48\xf3\x1f\x30\xec\xda\x63\x3f\x8c\x9d\x23\x17\x95\x70\xab\x7e\x06\x7c\x68\xfe\xe2\x1d\x45\xf8\x16\xbb\x4b\xc7\x98\x4d\x69\xc0\x1b\xcc\x74\x69\xbb\xa6\xaa\x1d\xf9\x37\x1a\x39\x10\x44\x70\xc6\xc5\x46\xa4\x26\xec\x88\x04\x71\x4b\x93\xc7\x36\xee\x73\x4c\x31\xeb\xd7\x9a\x5e\x7c\xa5\xd6\xf4\x94\x33\x42\xfb\xa5\xdc\xd7\xbc\x80\x54\xff\x6d\x9f\x1d\xcd\x4b\x9c\x97\xb7\x40\x29\xb5\x45\x23\x27\x1a\x4a\x4e\x78\x49\x49\xa5\xb6\xcf\x7e\xce\xdb\xeb\x77\x9a\x66\x9d\x7b\xf9\x9c\xdc\x34\x8a\xdc\xb8\x45\x3e\x71\xf4\x68\x14\xb9\xe2\x45\xb4\x7c\x42\xec\x55\xc8\xba\xe3\x59\xb4\xb6\x75\xea\xa1\x48\x95\x6e\x5b\x20\x69\x5f\x73\x7f\x29\x61\xb0\xd2\x42\x80\x5d\xf2\xe2\x88\x28\x8c\x64\x68\xe7\x77\x9e\xa1\x31\x2d\xa4\x7d\xf2\x15\xfb\x2e\x5c\x0d\x1b\x76\xcb\x53\x7e\x56\xf4\xf6\x7b\x9e\xb0\x4f\x08\x7c\x26\xc7\x7a\x6a\x6a\x04\xb6\xcb\x05\xb1\x38\x75\xa5\xe3\x80\xc2\xe0\xc7\x6c\xb1\x3b\x49\xd1\xfa\xe4\x04\x9e\xae\x69\x61\x1a\xec\xd1\xd6\xf2\x54\x0c\xd5\x2f\x60\x01\x8f\x8b\x16\xba\x99\x70\x65\x0c\xab\x0b\xe9\x6b\x66\x74\x33\xfd\x81\x05\x21\x9f\x0e\x87\x2c\xa4\x06\x65\xeb\x75\x68\x78\xa7\x43\xb2\x94\xd0\x33\x92\x0e\xc9\x3e\xc2\x9a\xb8\x74\x88\x9c\x6b\x13\xb6\xe9\x90\xbe\xbf\x42\x81\x81\xad\xb3\x50\xd3\xe7\xd4\x5b\x77\x36\xd3\x17\x94\xdc\xb3\x7a\xd3\x17\xcf\xd9\xca\xb5\x9b\xbe\x78\xc1\x56\xae\xdc\xf4\xc5\xcb\x90\x6a\x58\xdf\xec\xa6\x2f\xbe\x67\x72\x6e\xd2\x97\x61\xf9\xda\xd7\xab\x87\xaf\x70\xe0\xf2\x62\xc7\xf7\x25\x5d\x0d\x4c\x0d\x8a\xa7\x8c\x78\xaa\x01\xca\xeb\xbd\x52\x24\xc4\xc7\x5c\x4b\xf4\xf6\xa4\xc1\x4f\x35\x90\xcb\x67\x95\xe5\x0f\x94\x0a\xb6\x66\xb4\x62\x1c\xaa\xe1\x62\x5a\xfe\x53\x0d\xcc\x49\x7f\x02\x9d\x41\x61\x7b\x0d\x3c\x8d\xde\x70\x4c\xd6\xaa\x78\x1a\xdd\x55\x83\xf0\x32\x5e\x1b\x2b\x57\x03\xe9\x91\xee\xb4\x5e\xf4\xd5\x0e\x14\x31\x47\xe8\x62\x2b\x98\x4b\x85\x04\x5c\x74\xec\x01\x9d\xa4\x2f\xbe\xb8\x4d\x0a\x8b\xa0\x7f\xd8\x71\x03\x75\x53\x22\xc7\xc8\x62\xc2\x34\x76\xe6\xdd\xc2\x70\x5b\x94\x03\x0f\x32\x99\x63\xaf\x3e\x54\x25\x84\xd8\x3d\x62\xa1\xc8\x14\x65\x7f\x05\x0e\x59\x0d\xc0\xf4\xf9\x73\xb6\x62\xc3\xf8\xf6\x64\xb4\x53\xd2\xe7\x2f\xff\x4e\x33\x33\x6f\x1b\xa4\xcf\x5f\x87\xd2\x4d\xe9\x9f\x0b\xe5\xf4\xf9\x0f\xff\x27\xb0\xa1\x9e\xbf\xf4\xc5\x77\x88\x84\x3c\x55\xbc\xa0\x0a\x94\x88\x0b\x89\xca\x8d\x9e\x3d\x67\x50\x25\x8a\x6a\x3f\x3c\xd8\xd6\xd6\xc8\xdd\x2e\x78\xac\x73\xf4\xa0\xe6\xea\x41\x39\xba\x73\xa6\xe8\xf0\x85\xa7\x25\x67\x74\x53\x7d\x73\x52\x8c\xeb\x49\xf1\xf9\xd3\x51\x2c\x94\xe3\x24\x38\x06\xa8\xe4\x31\xc0\xa0\x7f\x5d\x1c\xfd\x73\x94\x9c\x0d\xcf\x1f\x1e\x30\x50\xac\xd1\x75\x49\x9f\x22\x5f\x48\x04\xb3\x7c\x16\x65\xdc\x87\x31\x10\x96\x1d\xd0\xa8\xbb\x9b\x3b\x69\xbc\x50\xec\x30\xc8\xdf\x2e\x38\xe7\xce\x14\x3c\xa2\x1c\x29\xcb\x5a\xc1\x2f\x8a\x25\xa3\x61\x3b\x1b\x4a\x21\xd2\xbd\xd0\x80\x17\xc1\x7c\x8b\xc7\xd1\x38\x68\x6d\xce\x1d\xd5\x99\x42\x3a\x34\x26\x23\xfd\xa2\x38\x7f\x78\x68\x51\x47\x91\x64\xe8\x74\x43\x25\xfb\x50\xa5\x18\xd6\x4f\x5f\x4a\x2d\x31\x8d\x5d\xc6\x9c\xbb\xb2\x39\x04\x62\xf6\xde\xbb\x6c\x5b\x97\x85\xb1\x34\xd6\x65\xd0\x11\x36\x7b\x78\x90\xa0\x86\x6a\xe4\x65\x50\xd6\xda\xed\x49\x8f\xa3\x6b\x58\xd8\x63\xfa\x42\xc4\x4a\x84\x9e\xd4\xa5\xcc\xbb\x0e\x20\x40\xa5\xe3\xa8\xae\xac\x72\x48\x82\x6f\xee\xd0\xf5\xdd\xbf\x3d\xdb\x3d\xcc\xc6\x7e\x48\x54\xcd\xce\x41\xbe\xde\x63\xc2\x76\xc8\x8c\x5d\x3a\xa5\x96\x83\xe0\x8d\x07\xc7\x11\xc8\x5a\x31\x14\xa3\x74\x78\x28\xc8\xed\x45\x48\x5a\x5d\xcf\xc5\xaa\x61\xde\xf2\x85\xfa\x59\x51\xc9\xd5\x6d\xc8\x77\xbc\xfa\x42\xc1\xd5\x6b\x42\x2e\x5a\x37\x5d\xf2\x9e\xb6\xdd\x8c\x16\xae\x53\xe3\xeb\x6d\x14\x41\x98\x5f\xc6\x7e\xdb\x8c\x10\xea\xf5\xf1\x47\xb6\x94\xee\xdc\x1c\x03\x82\xb4\x62\x32\x8a\xa3\x7f\x39\x8d\x7e\x34\xf1\xdc\x9b\xc8\xd2\x60\x5d\x08\xd5\x02\xeb\x8c\x79\x4a\xa1\xf6\xc5\x2a\x6f\x46\x6b\xa0\x8a\x27\x00\xe2\xa2\xbb\xbe\x1d\x1d\xf6\x1f\xe1\xee\xe8\x9a\x76\x74\x49\x1b\x59\x1b\x31\xad\xdc\xbe\xb9\xb7\x7d\x51\xa4\x88\xc1\x66\x87\xb0\x91\x9f\xd8\xbe\xad\xda\xbe\xcb\x3f\xb2\x75\x61\xe6\x89\x45\x10\xb1\xba\x77\xe3\x1a\x65\x10\xd7\xac\xb7\x69\xe1\x9e\xb4\xe6\xa6\x6d\xbd\x4d\xdb\xd7\xfd\xe0\x8e\x35\x7b\x17\xdc\xac\x6e\xf7\x83\x1b\xd5\x71\x63\x88\xf9\xc2\xbb\x2f\xe7\xf2\x3e\xb2\x28\x62\xd6\xae\x61\xb9\x3e\x06\x18\xcd\x38\xec\xf3\x9e\x6d\xec\xb4\x2e\x8a\x3c\xf5\x01\x6c\x54\x6c\x7e\xb1\x47\x73\xda\x90\x5f\xb9\x1b\x6d\xba\xc2\xd9\x90\xe3\x3f\xb4\x21\xfb\x9d\x80\x0d\x02\x24\x7b\xe3\xad\xef\x1a\xb6\x57\xcf\x0c\xcc\x14\x59\xff\x24\x72\xec\x43\x88\x01\xe4\xd6\x84\x01\xe7\x9a\x53\xad\x82\xa3\x43\x7e\x39\x70\xac\x43\x70\x0c\xd1\x74\x08\xbe\x35\xbc\x2a\x05\x62\x0e\xa1\xda\x50\x85\x0e\xda\x38\x75\x20\x24\xbb\x4d\xac\x54\x5a\x98\x84\x04\xfa\xe2\xd6\x8a\xab\x40\x20\x02\x6d\xc6\x6a\x6d\xc8\xe4\x5e\x07\x46\x9e\x39\x89\x4b\xc8\x62\xaf\x57\x3a\x51\xe0\x2e\x14\x48\xd0\xb8\x31\x53\x76\xe3\x80\xc5\xc8\x45\x82\x98\x98\xdc\x0c\xe2\xad\x4d\x63\xab\x5d\x54\x7e\x42\x2c\x06\xdd\x8c\xe2\xb3\xbf\x3e\xdb\xfd\xe7\xf3\xed\x24\x4a\xd2\xe8\x4f\x44\xaf\xa9\x7c\x8c\xf2\x9c\xe3\x9d\x35\xc2\x48\xa4\x54\xe2\xd7\x5f\xe1\x34\x83\xe1\xce\x90\x49\x79\xcf\xc5\x70\x3c\xd4\xb5\x08\x48\x19\xfd\x15\xbd\xee\x45\xff\x82\xd1\x14\x91\xb9\xa7\x14\x8f\x00\x4a\x52\xf4\x8f\x95\xd7\xf2\xa5\xf0\xb7\x96\xd2\x89\xdf\x10\x25\x83\x79\xd1\x5c\x15\x5c\x11\xf2\x6f\x1c\x93\x3f\x4b\x63\x8c\x96\xb9\xf7\xed\xff\xbe\xf8\x97\x73\xf1\xb4\xf3\xed\x0f\xf0\xf2\xa7\xe4\xe1\xec\x4f\x83\x38\xf9\x15\x83\x79\xfe\xba\xfd\x70\xff\xf8\xd7\x7f\xc1\x88\x9c\x6d\x7f\x9d\xdd\xf3\x3f\x9d\xed\x9e\xef\x62\x45\x2c\xb9\xcc\x9e\xfd\x8a\xff\x76\x1f\xf0\xcf\xaf\xcf\xe8\x07\xd2\xc7\x90\xbe\x1b\x0f\xb6\x93\x67\x40\x87\xdc\x3f\x22\xc9\xe7\xb9\x45\x09\x69\x79\xe0\xb3\xa1\x88\xf5\xc8\x2c\x25\xb3\xd4\xdf\xe1\x4d\x86\x55\x00\x12\x9d\x10\x86\x36\x03\x01\x70\x1e\x41\xbc\x4e\x8c\xcb\x85\x10\x9d\x6a\xe5\xf2\x66\xb5\x2b\x26\x72\xc3\x81\x93\x58\x9f\x75\xdb\xc3\x73\x38\x1c\x4a\x74\xf7\xaf\xb5\x30\x5c\xf7\x06\x59\x47\x22\x4b\x11\xd0\x5e\x71\x9b\xd5\x6a\x33\xe2\x66\x91\x47\x32\xb4\xe5\x42\x6b\x53\xb1\x88\x58\xb4\x1b\xc1\x29\x54\x0a\x31\xe2\xb7\xc3\x24\x69\x84\x60\xb7\x3b\x2b\xcf\xd9\x37\xef\x85\x6f\xa7\xe8\x9b\xed\x92\xdc\x33\x2a\xd7\x4e\xe8\x5f\x89\x0b\x7a\xbf\xd9\x2e\x20\xeb\x1b\x6d\x0f\x56\xaa\x06\x77\x18\x34\x29\x04\xb8\xd8\xa0\x80\x4d\x14\x51\x8f\x73\x79\x23\xe1\x9d\xc9\x48\xc8\xeb\x78\xb2\xc2\x4a\xbb\x71\x4e\xb5\xcf\xaa\xed\xed\x73\x26\x3b\x98\xb3\x48\xf6\x8e\xea\x6f\xfc\xf3\x06\xb9\x96\x0c\xf4\x0c\xdd\x1e\xd1\x78\xf2\xc7\x44\x81\x66\xc9\xe0\xa6\x93\xa8\x09\x77\xac\x85\x8d\x28\x63\x7c\x9a\xc7\x89\x21\x3a\x20\xe9\x71\x0b\x64\x0f\x5c\xb9\xa0\x09\x53\xeb\x27\xb4\xc8\xf4\x7c\x8c\x19\xde\xcf\x98\x52\xb2\x09\x2c\xb0\x4a\xfb\xfa\x92\x4a\x43\xa3\x8a\xdb\x71\xec\xd6\x31\x9c\x73\x49\x5a\x49\x19\x7f\x29\x54\x83\xcb\x29\x06\x40\xbf\x87\xb3\x00\xa0\xde\x62\xec\x20\xad\x72\xb3\xbb\x70\xb5\x92\x28\x10\xad\x22\x15\xb5\xa3\xc3\x26\xc1\x23\x58\xab\x1e\x05\x86\xe2\x5d\x1e\x1f\x99\x52\x4c\x5a\x3d\xf2\x67\x7f\xfd\xf5\xd9\x9f\x9e\x09\x98\xa3\x8f\x34\x67\xe8\x7e\x05\x28\xff\x2f\xbc\xc2\x76\xe7\x11\xd0\x7f\x6b\xd3\x17\x70\xbc\x58\xb8\x28\x7d\xf9\x62\xa5\x47\x8b\x17\xab\xdd\x8a\x2b\x5d\x55\xed\xb7\x04\x8e\x46\xa5\x39\x28\xfc\x97\x2c\x84\x62\x84\xe7\x10\xfa\xfe\x77\x49\x79\x2d\xf2\xab\xe2\xdf\x79\x24\x85\x87\x07\x19\xc8\x76\x20\x1f\x04\x8b\x41\x28\x57\xbe\x2b\xa6\x1d\xbb\x33\x6b\xfe\xc7\x9a\x35\x31\x18\xc8\x3f\xd8\xf7\xcd\xe8\x9f\x9c\x43\xf0\xef\x74\x21\xf2\x62\x95\xbf\x06\xc5\x99\xe0\xcc\xb5\xba\x19\x2c\xdb\xa2\xd9\xbb\x82\x86\x47\xd2\x4d\x10\xad\x35\xe9\x26\x28\xda\xab\x26\x0d\x2a\x26\x3c\x1f\x44\xc9\xd6\x56\x5f\xee\xcb\xc1\x4e\x94\x3c\x3c\xb8\xd9\xef\xeb\xcb\x72\x56\x6c\x9c\xe4\x53\xe8\x23\x2f\xb0\x69\x15\xd8\xbf\x6e\xea\x79\x11\xca\xe1\x2e\x56\xda\x8d\x8f\xd7\x14\x68\x60\xd7\xa6\x64\xb7\xb6\x22\x45\x29\x47\x65\xb5\x61\xe7\xe2\x5e\xf4\x8c\x17\x5f\x78\x2a\xe3\xba\x08\xe7\xe4\x02\x34\x25\x2b\x92\x9e\xd3\x97\x08\xcf\x97\xab\x3c\x80\x2b\x4c\xa0\xa8\xcd\x67\x84\xa4\x6c\x1f\x56\xaa\x14\xe9\x6a\x40\x36\x2a\x98\xd3\x77\x78\xe1\xf4\x25\x71\x24\x75\x63\xe9\x4b\xf4\xbc\xf1\x72\x95\xc7\x69\x41\x09\xa0\x21\xeb\xa4\x98\x95\xf3\x12\xce\x07\x8a\x8f\x3a\x21\x41\xea\x77\x8c\x04\xe4\xef\x30\x03\x85\x2b\xea\x0c\xe1\x29\xc3\xe2\x05\x1c\x8f\x1c\xa1\xfe\x25\x9f\x2d\x8b\x36\x73\xd6\x8c\x50\x9a\x6e\xf0\x5c\x47\x43\x6d\xce\xf1\x42\xe7\x6f\xe2\x63\x6c\xf8\x6c\x47\x78\xa8\x32\x9b\xde\xe5\x5e\x84\x53\x37\x1d\xcd\x36\x76\x80\x4e\x91\x36\xc7\xa3\xfc\x4d\x39\xda\xde\x2e\xf9\xa0\x80\x8e\xc5\xa3\x62\x99\xd1\x0a\xd2\x8e\x10\xa3\xf3\x0c\xe6\xde\x78\x87\xd7\xd4\xc9\xde\x1e\x22\x0d\x40\x15\x97\x49\x73\x56\x0d\x38\x96\x8d\xdb\x04\x72\x23\xad\xb6\x39\xce\x74\x96\x3a\x2a\x97\x09\xf2\x50\xbc\x8c\xe5\xf6\x10\x9d\xa2\x9e\x8d\xcf\xb3\xc6\xd5\x5a\x1f\x27\xbb\x67\xe7\xd2\x4b\x2e\x16\x49\xe4\xcb\x2c\x49\x67\x8a\xb4\x6b\xe0\xee\xc0\x01\xcc\x4d\xa9\x2c\x00\x23\x11\x8a\x84\x8b\xb4\x1d\x90\xf4\x4b\xa7\x62\xb7\x71\x75\x7f\x0a\x56\xf0\x88\xe3\x8b\xce\xce\xf1\x14\xa8\x93\x12\x89\x5b\x3c\xed\x65\x0f\xcc\x8f\x48\x15\x46\x3d\xea\x3c\x8b\xce\xa8\xe2\xd9\xce\x39\xec\x1a\xde\xc8\x99\x72\xa4\x3f\x3c\xdf\xad\xc5\x98\x87\xda\xbd\x3e\xdc\xc7\x6b\xa0\x0f\x65\xe4\x6f\xa0\x9f\x87\x3b\x78\x85\x8d\xa2\xed\x76\xb4\x59\xb6\x1f\xf2\x0f\x31\x3a\xb9\xac\x61\xcf\xe6\x5b\x5b\xcb\x8c\x7e\xda\x37\xd9\x0e\xfc\xfd\x11\xc0\xa9\x17\xdf\x6e\xcc\x3b\x7c\xd6\x22\x28\x03\x5d\x4d\xcb\xb3\x3c\x9c\x25\x21\x59\x2a\x48\xfe\x6b\x71\xd7\x86\xe0\x58\x48\x3d\xd8\x67\x7f\x05\x2a\x1e\x09\x5d\xa0\x7a\x9f\x01\x94\x9e\xc5\xbf\x9e\xc9\x84\x5f\xcf\x13\xa0\x59\x71\x05\x16\x80\x57\xf1\x84\xc7\x19\x10\x76\x6e\xca\x65\x82\x3b\xdb\x39\x52\x1b\x72\x91\x9e\x9d\x8f\xf0\x1d\x06\xc9\xaf\x05\x94\xa9\x0c\x0c\x96\x40\x0c\x72\x32\x29\x03\xe2\xa9\x94\x9f\x01\x38\x2d\x7f\xc4\x15\x06\xfb\x72\x94\x6c\x6f\x2f\xd9\x3a\xdf\x34\x8e\xe4\xb3\x87\x5f\x91\x0a\x07\x22\x26\x41\x4e\xad\xf1\x65\xe9\x3a\x51\x75\x08\xe6\x7a\xbb\x10\xf3\x99\xf3\x6d\x02\x94\xc7\x39\xe9\xbc\x9a\x00\x6e\x85\xfb\x9f\x47\xc3\xa0\xdf\xa1\x88\x61\xc9\x11\xd9\xc1\x3d\x93\xf1\x27\x23\xba\xad\x0e\x25\x2c\xd6\x2e\x2c\x53\x41\x19\x33\x03\x4b\x64\x9e\xba\x96\x91\x09\x4d\x93\x06\x0f\x5d\x97\x8c\xf4\x64\xd7\x78\x81\x2b\xb4\xc6\x39\x1d\x07\x63\x16\xf1\x38\x95\x76\xab\x90\xb1\x2b\x7e\xa9\x12\xaa\xe5\x74\xc6\x52\x0c\xd5\x32\x16\xaa\xf9\x02\xf5\xf5\x0b\x73\x71\x59\xa8\x21\x07\x0b\xba\x09\x69\xe3\x24\xa8\x55\x53\xfb\x20\x2a\x76\x2d\xd4\x4c\x13\x92\x16\x84\x0a\x60\xfd\x8a\xd5\xf3\x05\xf6\x42\x5c\x23\xcb\x0e\xb0\x58\x26\x79\x42\xa3\xe5\x9b\x16\xd0\x6a\x9b\x08\x94\x97\xc3\xbe\x03\x04\x67\xec\x1f\x20\x87\x6b\x34\x6e\xe9\x60\xfd\xc3\x4e\xa5\x9b\x64\x5c\xb2\x99\xda\x6e\x15\x05\xbb\x02\xfa\x22\x46\xaf\xc9\xda\xf1\x19\x92\x7a\x78\x2a\xf5\x7b\xb2\x5f\x71\x2a\x29\x2a\x79\x07\xcf\x1d\x75\xd2\xd9\x9b\xb9\xe6\xae\xe0\x60\x4d\xbc\x5d\x4e\xa7\x45\xc3\x1d\xfe\xa0\x72\xb0\xf0\xd9\x04\x50\x30\x15\x8a\x0f\xe0\xf4\x17\x05\x8e\x4e\x8e\x55\x19\xb9\x5e\xc9\xfe\x21\xc2\x4b\xbb\x07\x60\x58\xca\xee\x14\x62\x1a\x9a\xf1\x15\x79\xe5\x2f\xee\x33\xc5\xda\xd1\x94\x7b\x07\x3b\x2b\x33\x38\xda\x3a\xa7\x48\xce\xc5\x25\x14\x10\x06\x6e\xa4\x15\xdb\x66\xa3\x54\x2b\xc1\x9e\xda\x62\x9d\xa9\x1d\x19\x07\xc1\x66\x3d\x10\x50\x76\x2f\x74\x00\x46\x03\xe6\x71\x41\xd3\xcf\x48\xf3\xde\x4d\xdd\x46\x0c\x32\x46\x94\x01\xf9\x26\x06\xee\xc3\x13\xf6\x6d\x38\x34\x52\x63\x2f\xef\x1a\x7b\x39\x35\xd2\x81\x58\x12\x5d\xcf\xfc\x39\x50\x79\xbb\xea\x29\x6d\xe4\xd3\x48\xb9\x91\x45\x38\x8b\xa8\xd7\x9b\xc6\x9c\xca\xc5\xa0\x6f\xc1\x12\xdc\xa5\x0b\xee\x1c\xc0\xdd\x02\x3c\x05\xb8\xdb\x37\x39\x80\x3b\xe7\xe0\x5e\x66\x78\x4c\x8d\x6a\x74\x79\x20\xcf\x5d\x13\x76\x4b\x20\x5e\x00\x1c\x0a\x62\x35\x77\x49\x5d\x05\x77\xd0\x8b\x90\xb6\x06\xe1\x9b\xd3\xda\x23\x16\x34\x2d\xd6\xe1\xfe\xaf\xa0\x93\x8d\xb6\x39\x6c\xde\x54\xd0\xc9\x2a\x09\xc5\x1d\x47\xd3\x3a\xbc\xc3\xc2\x4f\x46\xce\xcf\x74\xec\x27\x26\x36\xbe\x8f\xf4\x95\x37\xd2\x8d\x22\x08\x52\x95\xed\x2d\xb1\x82\x1f\x41\x88\xaa\xce\x3a\xb4\x9f\x67\xe1\x16\xd4\xca\x2f\xb2\xb3\x42\x11\x52\x80\x8e\x7c\x09\xef\xa6\xc3\x98\xe0\x26\x4d\x0e\xac\xf0\x88\x1d\x69\x7a\xd5\x9c\xd4\x0e\x6f\x63\x3b\x80\x38\x1b\x09\xaf\xf2\x4d\x0d\xf0\xaa\xa5\xef\xf7\x06\x7d\x00\xb5\x59\x87\x73\x5b\x20\x1d\x82\x7f\x76\x25\x56\xc4\x17\xd6\x02\xc1\x29\x67\xb5\x40\xc0\x71\x52\xd1\x9a\x21\xf2\xbc\xe3\x48\x83\x0c\x74\x60\x9c\xe5\xdb\x78\x90\x6f\xa0\xc2\x16\x77\xb6\x63\x5c\xc2\xd1\x9d\x90\x44\xbd\x81\xc3\xf8\xe9\xb5\x0d\x33\x46\xbb\xf1\xec\x5c\x70\x2a\x3a\xc3\xdb\x2b\xa7\x91\xd1\x05\xac\xa2\x35\xcf\x1a\xda\x35\x9d\x12\xe4\xb8\x13\x60\x04\xf0\xe2\x44\x27\x12\xf0\x85\x4b\xc0\x87\x97\x5e\x79\xae\xdd\x31\x23\x3f\x49\xb1\x85\x1f\x39\x29\x65\xef\x3d\x9a\x3f\xde\x7e\x1b\xbc\x20\x2c\x33\x0c\xa4\x30\xc2\x8d\x96\xe9\x03\x8a\xf6\x5d\x97\x58\xd3\x23\x09\x8a\x2c\xc0\x48\x39\xe3\x40\x14\x1c\x5a\xa2\x85\x3d\x5a\x4c\x1e\x36\x5c\xd5\x0e\x45\x00\xfa\x40\x0a\xb4\xb9\xf1\x04\x75\xb4\xbb\x39\x4c\xc9\xa9\x8b\xe1\x92\x14\x55\x17\x4c\x0f\xa5\xb2\xf9\xbe\x74\x12\x27\xf0\x5b\xec\x4b\x4f\x02\x12\x91\x9f\x57\xe8\x32\x2c\x8e\x91\x71\x14\x4f\xeb\xf1\xb2\xc5\x08\xa3\xd2\x5b\xe8\x53\x8e\x5e\x85\x1f\x8c\x65\x57\xff\x84\x55\xd1\x49\x89\x54\xb0\xd5\xb1\x4a\x43\x1e\x23\xf5\x97\xd2\xe1\x77\xa8\x09\xf2\xd2\x93\x33\x58\x9d\x0c\xf0\x23\xc4\xfd\x1d\xe9\x5f\xc5\xa0\x14\x0b\x5e\x83\x12\xae\x2f\xbe\x70\xa2\x18\xdc\x14\x4d\x00\x0e\x40\xf1\xbf\x5b\xa2\x07\x33\x75\x5d\x51\x69\x70\x7f\x82\x8b\xcb\x8f\xd9\xf0\x79\x50\xb3\x24\xb6\xbc\xea\x68\x57\x3b\xc2\xff\x0e\x22\x20\x5d\x04\x27\x87\x17\x31\xd4\x4d\x06\xcf\x48\xd6\xb7\x5f\x13\x51\xd2\x19\xde\x09\x28\x1d\x29\xfa\x9c\xf8\x2c\x5a\xdc\xda\xc3\x10\x92\x1e\x24\x4f\xee\xaa\xee\xba\xe8\xca\xf1\x51\xb5\x58\x76\xd4\x8a\x76\xc2\x0d\xbb\xe5\x78\x4a\x5a\x16\xb9\x66\x20\x01\x58\x4e\x8b\xdf\x45\x51\xc5\x0b\xc1\xbe\x47\x92\x89\xf5\x1e\x27\x07\xb2\xe4\x3b\xa0\x8e\x98\x2e\xbe\x2f\x9e\xb3\x85\x70\x88\x49\xa6\x2b\xfb\xd7\x79\xb3\x8f\x33\x3d\x4b\xd8\x14\xce\xba\xae\x5e\xbc\x2b\x6e\x8a\x19\x0f\x3c\x74\x9d\xdd\x5f\x16\xb0\x53\x0b\xea\x5b\x7a\xbf\x80\x7b\x4b\x31\x81\xcd\x54\xc2\xd4\x92\x00\x88\xb3\xfc\xef\x2f\x97\x97\x97\xb3\x62\x92\x2e\xe3\xfb\xba\x7a\x6b\x54\x21\x55\x6b\xe8\x7f\xbe\x00\xf8\x07\x0a\xec\xf3\x0c\x51\xee\x11\x99\x19\xa8\xfb\x5d\x8d\x4b\xb4\xd9\xc7\x88\x18\x0b\xc2\xab\x9c\x1d\x78\x58\x4d\x18\xa5\xc1\xa4\x7c\x6c\x8a\xb6\xe5\x6f\x08\x0d\x6a\x8d\xbf\x7e\xcc\xdb\xae\x40\x5d\xfc\x09\xb7\x41\x99\xa3\x78\xfb\x26\xbb\x27\x77\x3a\xdc\x90\xe1\x5a\x32\xa4\x79\x74\x4b\xd7\x97\x9b\x3c\x2e\xc8\xf0\x3e\x11\x4e\xc1\x0a\xe1\x14\xcc\xea\x40\xca\x71\x55\x3d\xb8\xbd\x2e\xc7\xd7\x58\x7e\x09\x28\x77\x26\x50\xee\x68\x8e\xa7\x62\x9e\x2d\x4c\xf7\x60\x76\x97\x53\xa8\x82\x57\xd4\x49\xde\xe5\x14\x20\x61\xb1\xb5\x35\x97\xd5\x79\x2d\x61\x10\x9b\xf2\x44\x72\xd3\x76\x1f\xea\x13\x8d\x3b\xe5\x83\xf6\x3e\xa8\x3a\x2c\xba\x0a\xcb\xa5\x81\xdb\x04\x9c\xaf\x93\xe0\x7a\x10\xc5\x92\xc4\x6b\xc9\x9e\x0f\xf8\x1e\xef\xfc\x23\x52\xf2\x1c\x35\x4e\x64\xff\xf3\x6c\x82\xc9\x82\xa4\xba\xc9\x08\xb7\x7c\x44\x7a\x6f\x12\x5f\x0f\x8c\xa5\x45\x30\x97\x27\xc6\x0d\xb5\x97\xe5\x72\xfe\xca\x41\x3e\x86\x65\xbc\x9c\x01\xf5\x7f\x7a\x5b\x7f\xc4\x45\x78\x20\x8c\x6e\xe0\xb2\x74\x93\xb0\x1b\xdb\x7b\xda\x0d\x47\x53\xce\x4e\x4d\xbf\x23\xcd\x39\x6f\x9f\xa6\xaf\x48\xfd\xad\x9f\xf7\x1a\xde\xa3\xe9\x90\xeb\xd5\xf1\x2d\x9a\x0e\x5f\xbf\x46\x44\xe8\x89\x2e\xfb\x10\xa1\xc5\x8e\xdf\xee\x34\xaf\x1f\x40\xfc\x19\x23\x95\xee\xc3\x28\xe3\x04\x72\xda\xe5\x25\x27\x3c\xe3\xa1\x74\x11\x09\xc8\x7d\xb6\x9c\x57\xfb\x84\xd6\x61\x85\x4d\x67\xc5\xef\xf2\xf7\xcf\x4d\x7d\x2b\x9f\x4f\xae\xa1\xde\x17\x7a\xab\xab\xee\x17\x1e\x66\x17\xde\x66\x70\x66\xed\xcf\xf2\xf9\x42\xbe\xfc\xac\xb2\x00\x2e\xe3\xb2\xbb\xa3\xc7\x06\x8d\x30\xe8\x01\x36\x7e\x85\x77\x39\x76\x5b\x22\x93\x16\x9f\xfe\x8b\x02\xca\xd2\x53\x5d\xcf\xe9\x1b\xe5\x6c\x76\xac\xab\x43\xa7\xeb\x2f\x85\x4e\x40\xb6\xe2\x59\xf4\x4b\x71\xf9\xa5\x44\x99\xd8\xbc\x85\x3f\xef\xeb\xff\x82\xbf\xc7\xd1\xf9\xc8\x24\x0f\x9a\x24\xa8\x00\x53\xfb\xa9\x08\xc3\x33\xb4\x47\x83\x1b\x18\xd0\x76\xb0\xeb\x65\x90\x13\xb8\x3b\xa3\x20\xfe\xaa\x41\x65\xcc\xd4\x78\x3e\x9a\xe7\x57\x05\xf6\x4f\x27\x29\x17\x79\x56\xea\x27\x40\x45\x79\x67\xa7\xed\xd7\x33\x8c\xf1\x03\x63\xb9\xe4\xd0\xb9\xe7\xbf\xbf\x50\x38\x63\x2c\x4a\xaf\x3c\xec\xb1\x7a\x75\x6b\xf1\x28\xd0\xb2\x2e\x7f\x73\x5a\xe0\x89\x4e\x3b\x3c\xd1\x6d\x0d\x85\x1b\xb2\x2d\x7c\x76\x5a\xc2\x24\xa7\x1d\x4c\x72\x5b\x21\x37\x95\xb2\x19\x7a\x71\xda\xf9\xa4\xe3\x39\xdb\x69\x6e\x4b\x18\x5b\xfd\x5e\x3d\x3a\xad\x40\x8a\xd3\xc6\x29\x62\x14\xd9\x02\x2e\xd3\xf4\x1e\xff\xaa\x52\xf8\xf2\x17\x2e\xf1\xf0\x17\x32\x95\x44\xa9\x98\xb7\x8e\x31\xe7\xa7\x7c\x5e\xce\x68\xe9\x21\x1b\xe5\xbe\x6c\x3f\x57\x65\x37\x03\x24\xf8\x81\x58\x01\x69\xc3\xda\x6b\x40\x18\x68\x22\x24\x59\x71\x40\x25\xa2\x09\x03\x20\x8d\xb4\x74\x1d\xc2\xe3\xfe\xf6\x84\x5b\x7d\xd4\xd8\xfe\xc9\x89\x6c\x53\x8b\x0a\x7a\x28\x81\x3a\x8b\xb9\xae\x04\x1c\xa6\x28\xe3\xa3\xb1\xe3\xc9\x8a\xf1\x96\x31\x63\x82\xca\x4f\x0d\x46\xaf\xc7\x1c\x62\x12\xc1\x8d\x42\x52\x1e\xd7\x77\x8b\xeb\xa2\x42\x87\x8f\x46\x3d\x41\x7b\xcc\x8b\x79\x4d\x2d\x22\x02\x39\xae\x66\x5c\xe7\x8b\x7f\x4e\x9b\x28\xe5\x21\x27\xde\xe4\x0b\x2d\x21\x2e\xf0\xb8\x6d\x7f\x9a\xd5\x39\x8c\xb0\x31\xc9\x10\xce\xf9\x47\x84\xdf\x2b\x44\xc3\x1e\x0d\x64\x75\xd4\x68\x45\xe6\x17\xa4\xf1\xe6\xf8\x56\x1d\xcb\xa0\x1f\xef\xf3\xe6\xcb\x72\xf1\x53\xcd\xf7\x4f\x1b\x90\x13\x1b\xb7\x79\xf2\x5b\x52\x24\x14\x40\xc3\x73\x33\x23\xb5\x08\xf0\x16\x2c\x58\xb4\x0d\xde\x8c\xb7\xb3\x16\x72\xb7\xa3\x34\x62\xf0\x8c\x82\xde\x06\xde\x46\x91\xf6\x98\x23\xe2\x32\xa0\xc5\x1a\xc1\x39\xd4\x1b\xad\xa5\x50\xf0\x11\x6a\x16\x43\xbf\xef\x9b\x32\x91\x77\xd0\x3a\x2e\x19\x89\xdc\xe9\xb6\x3c\x25\x48\x64\xd2\xf6\x7a\x09\xb3\x91\x34\x90\x9b\xe5\x9a\xa7\xdf\xc2\x15\x68\xc5\x52\xc5\x8b\x12\x3a\xb1\x49\x64\x37\xc6\xe4\x9a\x25\x21\x71\x86\x90\x88\x6c\x50\x9b\x51\xf4\xf8\x18\xd0\xca\xb2\x56\x6b\xfa\xf2\xd5\x53\xe7\xa1\xbf\x50\xd3\xe1\x4b\x3a\x45\x43\x2b\x15\xf2\x48\x47\x29\xb0\x4e\xd3\xe1\x2b\x3a\x94\xfd\x65\x0a\x07\x2a\x55\x72\x0c\x5f\x5e\x7a\xc2\xce\xfe\x9b\x06\x0f\x4b\x81\xb7\x3a\x44\xe0\xad\xe1\x61\xe5\x42\xb8\xc7\xe7\x69\xa6\xba\x12\x27\x4e\xc8\xbf\x8c\xf6\xb6\xec\x3a\xd0\x14\xfb\xce\x90\x01\x8f\x6a\xdb\x0b\x73\x51\xfd\x6d\x59\x2c\xc3\x71\x32\x74\x87\x9c\x77\x32\x9a\x77\xfa\x67\xbf\x9a\x25\x64\x2d\x75\x99\xb7\x8b\x4a\xde\x0c\xaa\x0e\x74\xe5\xf4\x6e\xcf\x0c\xc1\x61\xd9\x53\xea\xa6\x58\xe7\x7c\x6f\xc4\x45\x2d\x80\x09\xc4\x1d\x9d\xe4\x7f\x42\x82\xe5\x76\xa4\x17\xbe\x7a\xcb\xfa\xac\xac\x6a\x7b\x3b\xc1\x4d\x2a\xec\xdc\x88\x69\xa5\x3e\xb6\xc3\x3a\xf5\x48\x91\xb7\x61\x53\xfa\xe1\x4a\xd6\x98\x60\xb8\x56\xc8\x3b\xb6\x57\x9f\x5a\xe5\xbe\x8e\xc9\x5a\x1c\x57\x00\x1a\x64\xd7\xa8\x23\xe6\xa9\xab\x05\xbc\x24\xda\x8b\x26\x7d\x4d\xa6\x2b\x9e\x94\xfe\xa5\x27\x8d\xee\xa5\x0c\x15\xf7\xe2\xe4\xf0\xdd\xe1\xfe\x29\xd7\x05\xa9\x80\x28\xc7\x2d\xf3\xf0\x10\x1d\x7d\xf8\xf8\xd9\x49\xc5\x9b\x72\x39\x2b\x78\x22\x2e\xc1\xa0\xa6\xf1\xef\x06\xf9\x7d\x3a\xe0\x4a\xe5\xec\x23\x86\x5f\x3f\x5c\x4d\x62\x77\x09\xbb\x1c\x5c\xd2\x8b\x88\x00\xd3\xa2\x97\x69\xd7\x76\xe1\x6e\x20\xd6\x3d\xbf\x55\xe1\xa2\xbc\x1b\x08\xb3\x38\x4a\xfa\x37\xcc\x8c\x13\xcf\x75\xd8\x71\x06\xfd\xc8\x3a\x76\xec\xea\xf1\x4b\xc5\xf7\x26\x31\x3d\x83\x41\x05\xc0\x95\xc7\x83\x49\xd1\x53\x98\x1d\xf3\xb5\xf0\x51\x98\x37\xa8\xba\xad\x1b\x37\x17\x00\xf6\x9e\x2e\x35\x54\x77\xb7\x92\x31\x71\x55\x8d\xa5\xac\xa1\x8a\x12\xb3\x64\x37\xce\x51\x56\x1b\x73\x89\xa6\xca\x7b\x3b\x5b\xc2\x39\x93\x9b\x43\x1c\xdb\x43\x3c\x81\x09\xba\x41\xb4\xc8\x3e\x48\x56\x14\x4c\x8a\x71\x50\x1c\x14\xed\xb8\x29\x17\xb0\x54\x6d\x1e\x92\x81\x5e\xa2\x1b\x4e\x01\x48\xb9\x22\x67\x42\xa9\x93\xe6\x58\x16\x60\x5f\x12\x1f\xa4\x0b\x51\x4c\x42\x6b\x61\xf4\x75\x26\x40\x3b\x29\x66\x45\x57\x6c\x1c\x8b\x9e\x7a\x90\xf6\xdb\xb0\x21\x0e\xa3\xa4\x9f\x0f\x2e\xfc\x17\xd2\x0d\x0d\xef\x20\x2d\x57\xd9\x18\x85\xb7\x57\xfa\x60\x6d\x33\x96\x44\x04\x95\x1d\xa1\x22\xf7\x09\xf4\xed\x04\x80\x28\x18\x64\xaa\xd9\x69\xdf\xb4\xd2\x7d\x2d\x30\xab\xd7\x7d\xb3\x3a\x43\x0f\xae\xe1\x59\x9d\x99\xb3\x3a\x31\xd5\xaf\x36\x45\xb9\x13\x00\x1b\x65\xf3\xd5\xb4\xb5\xa5\x72\xe0\xf6\xfd\x79\x61\xbf\x1f\xd4\xb7\xd5\xc3\xc3\xe6\xf1\xc3\x83\x00\x33\x7c\xed\x44\x2a\x53\xc0\x28\x25\xf0\x3f\x1a\x5f\x9d\x1b\xc8\x21\x88\x05\xe2\x08\xb6\xe8\xf8\xcb\x65\xfd\xbb\x46\x05\x80\x31\x9a\x7c\x52\xd6\x3a\xc5\x68\xf1\xa6\x77\x43\xa0\x57\x5a\x0d\x39\x9c\x96\xab\x1e\x06\xd8\x9d\xc9\x00\x9b\x2d\xaf\xca\xea\xe7\xe5\xa5\xb6\xe5\x0e\x30\xc6\xf6\x57\x92\xc3\x97\xd2\x02\x3b\x1f\x77\x02\xdb\x68\xf3\x6d\x75\x15\x97\x9c\xb2\x4f\xd2\xde\x9b\x12\x4e\xb8\x65\x6e\x31\xd1\x96\xdc\x65\xab\x98\x2d\x62\x45\x69\x9b\x6e\xc9\x5f\x7b\x9f\x5d\x39\xac\xaf\x53\x0c\xea\x4e\x8e\x84\x9e\xe6\x7a\xdd\x22\x53\x4b\xb8\x1d\x72\x19\x5e\x46\xde\x6a\x5e\x97\x5a\x69\xcc\x40\x48\x4c\xcf\x05\xd3\xcb\x94\xe9\xb5\xcd\xcc\xe5\xc4\xf4\x5a\x63\xa1\x05\x89\x3c\xb1\x15\xfb\x94\x1d\x64\x9b\xc3\xd1\xbe\x49\xe1\xc7\x07\xd9\x27\x5c\x53\xb4\xcd\x91\x59\xb4\x82\xc7\x98\x04\x94\xe9\xb0\xcc\x9b\xef\x13\xe9\xbf\xcf\x6b\xfe\x08\x9b\x2f\x71\x20\x7f\xb8\xf5\x1f\x44\xeb\x5f\x28\xf8\x4e\xc0\x85\xc5\x07\x44\xb0\xda\x8e\x3e\x21\xda\xde\xba\x5b\x9c\xa0\x9e\x0b\x20\x64\xf4\xb5\x61\x1a\xdc\x23\x0f\x7e\xcf\xe2\x1b\x9e\xae\xe2\x1b\x36\x92\x6f\x58\x32\xe2\x1c\x22\x7b\x62\xf7\x60\xb7\xcc\xda\x34\xcf\x96\xe9\x05\xbe\x1e\xc1\xeb\x34\x05\x3a\x1f\x63\xd2\x5e\x27\xe9\x9c\xcb\xb8\x4a\x0c\x8f\x5a\x4a\x41\x6f\x29\xe2\x15\x73\xf6\x23\x25\xce\xc2\x87\xf7\xd8\x60\x9b\x3d\x71\x86\xcf\x12\x36\x7b\x7c\xcc\xf1\x74\xe2\xad\x5b\xf7\x80\xbd\xa7\x59\x66\x6a\x67\xa7\xaf\x76\xfe\x28\x23\xcd\xda\xd3\xe9\x90\xdb\xdc\x3a\x5b\x3a\x1d\xbe\xe0\x24\x94\xbb\xa3\x81\x92\x12\xce\x00\xbc\x0d\x0d\x59\x2f\x3c\x66\xdc\x77\x9e\x22\x5f\xe0\xb2\xbe\x43\xb2\x12\x6e\x84\x80\x9d\xfb\x54\xd7\x1d\xe7\x6c\xf9\x2b\x09\x88\x55\x4f\x1c\x82\xdf\xf1\xd4\xf6\x56\x90\x76\x0e\xe3\xf6\xca\xe1\xa8\x9e\x74\x79\x23\x39\xbd\x30\xa3\x63\x27\x67\x14\xac\x84\x6c\xd8\x50\x15\x48\x0f\x57\x10\x51\xfc\x42\x75\x78\x96\x1b\x3c\xdb\x3a\x1f\xae\x0c\x94\x83\x51\xf9\x00\xe8\xc8\x32\x46\x3e\x80\x17\x9c\x2b\x34\x5c\x42\x50\xa9\xd4\x3e\xa5\x90\xc8\x52\x6c\xa9\x1a\x4b\x46\x56\x79\xfc\x94\xec\xae\x2a\x03\x35\x27\x76\x31\xce\xe1\xd6\x49\xef\xe1\x22\x5a\x50\x5d\x9d\x86\x28\x36\x95\xfe\x66\x1d\xde\x3a\xba\x48\x32\x69\x53\x79\x45\x80\x35\x21\x83\xf9\xb4\x38\x0d\x0a\xaf\x66\x63\x8a\x36\x28\x5f\xd5\x35\x8c\x4a\xd1\xed\x57\xf9\xac\xc1\x35\x1b\x27\x3a\x12\x6b\xe0\x20\x6d\x7b\x0f\xcc\xe5\xca\x03\x73\x6c\x1c\x98\xb4\x2d\x54\x87\x74\x2c\x56\xb5\xc9\xcc\x75\x23\x8e\x50\x11\x91\x55\x74\x92\x7c\x7a\x54\xdd\xde\x18\xc9\x76\x72\x2d\x30\xb5\x0f\xcb\xeb\xec\xec\x07\x36\x7c\xc1\x9e\xbf\x66\x2f\x9e\x9f\xb3\x49\xf6\xfc\xf9\x0f\x6c\x8e\xce\x59\x0d\x09\x95\xf7\x19\x25\xa8\x62\x37\xd9\x26\xc6\x2f\xef\xc3\xf4\x5b\x5b\x3d\xc7\x48\x4f\xc6\x8f\xd9\x70\xc8\xae\xb2\xdc\x39\xc0\xef\xf8\x99\x76\x28\x24\xa1\x7a\xa7\x3c\x7d\x9e\x4f\xe9\xcc\xb6\x6b\xb9\xe7\x7a\xa0\xcc\xea\xf3\x5d\x2d\x3e\x16\xd8\xbe\xcc\x5c\xe8\xcc\x5a\xce\x4c\xef\x19\x66\x2f\xea\x73\xe1\x0d\xca\xc4\x1c\x5f\x3f\x38\x5e\xef\xa9\xe1\x51\xa9\x3f\x3a\x40\xaa\xfc\x0f\x18\xa2\x40\x5b\x5f\x3f\x46\x51\xf1\xa9\x41\xf2\x62\x7f\x74\x94\xbc\xf6\x1f\x1c\xe6\xe3\xa8\x34\x54\x12\xc4\x4e\xcc\xfc\x23\x48\xe1\x23\x7e\x3b\x78\x78\x50\x09\x67\x8b\x38\x01\x70\x39\xcd\x1c\xa0\x24\xad\xd7\x8f\x16\xc7\x49\x4c\x7b\xf0\x32\x50\x1b\x7f\x65\x55\xe6\x20\x34\xa9\x32\x1c\xaa\x02\x70\xd2\xd6\x51\x5c\x6e\x85\xb2\x19\x59\xa5\xfa\xb6\x4b\xb8\xe2\xd8\xbe\x45\x55\x1d\xae\xa2\xaa\x72\xb6\x14\x74\x11\x5b\x20\x41\x34\xdf\x1d\x93\x71\x58\x7a\xb7\x8b\x67\xcc\x32\x21\xbf\xe5\xee\xb9\x97\xa4\x4d\x4f\x26\x2d\xc6\x84\xdd\x40\xce\xdd\xc3\xc3\x18\x0e\x11\x3f\x1b\x3e\x91\x79\x4d\x6e\x6d\xdd\x41\x9d\x45\x76\x27\xe1\x1a\x27\x02\xc9\x40\x5f\xc8\xab\x64\x09\xc4\x1c\x2c\x2f\xde\xdd\x69\x36\x33\x28\xb6\x31\x8d\x43\x02\x07\xae\x82\xf1\x94\x4b\x39\xe1\xea\xdc\xae\x26\xdc\xa6\x80\x80\x6d\xa6\xed\xfe\x3f\x5a\xbe\x19\x3a\x39\xd2\xe1\x8e\x4d\x9d\x79\x18\x1d\xe8\x37\xfa\x62\xcf\xb9\x91\x0e\x5f\x7d\xe7\xd3\x64\x9e\x32\xe9\x0a\x01\x29\x5d\xd0\x81\x36\x68\x8b\xa6\xe3\x3a\x03\xb4\x9a\xc8\x2f\x21\xaa\x9f\xb4\x67\x95\x88\xa3\x2c\x04\xa3\x92\x61\x7b\x40\x5c\x68\x23\x72\x04\x8e\xef\x3d\x9c\xf3\x25\x79\x90\xe2\x3b\x55\x3a\xfc\xca\x9f\x38\xfd\x5a\x8f\xdb\x8b\x3a\x9a\xe8\xe9\x23\x8b\x3a\x5d\x03\xaf\xd7\xcb\x5d\x7b\x6c\x70\xdd\xd6\x05\xb2\xee\xd1\xe1\x07\x23\x5f\x74\x54\x0c\xa6\x65\xd3\x72\xd7\x56\xa3\xa4\x50\x2e\x1e\xe1\x35\x36\xf3\xe8\x36\xa0\x95\x6f\x07\x80\x36\x8a\xe6\x40\xe9\x77\xc8\x13\x11\xda\xcb\x17\x88\xb0\x78\x0b\xd2\x37\x0f\x0e\x8d\x34\x7a\x3a\x52\xe9\x11\x62\x17\xc5\xad\x9f\xdd\x7d\xe2\x1a\x6b\x58\x06\x9d\xa1\x72\x51\x4c\x8a\xa2\xfd\xd5\x45\x18\x8f\x35\x66\x80\x2e\x6d\x98\xe0\xf9\x09\x42\x3f\x30\x6a\xee\x6f\x64\xc9\x8f\xe8\x31\xff\x99\x65\x3b\xa3\x9c\xa2\x28\x8c\x66\xdb\xdb\x28\x43\xc9\x89\x5b\x81\xa2\x91\xc1\xfb\xe3\xbf\x1c\x5e\x1c\xfe\xfb\xd1\xc9\xe9\xd1\x87\x3f\x3f\x3c\x18\x39\x9f\x0e\x29\x0f\x7d\xde\x73\xe0\x2c\x80\x14\x40\x55\x06\xa2\xe2\x81\x76\xc9\x51\x15\x1a\xfa\x85\xfd\x36\xd7\xce\x02\xbd\xd9\xca\xcc\xa3\x83\x11\xed\xb4\x65\xb6\x24\x8d\xf6\xe5\xd9\xf5\x79\x86\x7f\x88\xe5\x8e\x0f\x50\x3e\x9b\x42\x5f\xc7\x94\x22\x7c\x99\x4c\xf9\xc2\xe3\x3a\x10\x06\xa0\xd0\x7d\x21\x87\x0f\xea\x39\xd2\x35\x4e\x0e\x7b\x0e\xc3\x9c\xff\x28\xfd\x87\x8c\xe6\x30\xd4\xf1\xd9\xfc\xdc\xec\xa4\xb9\x04\x30\x4f\x6b\x3b\xde\x08\x18\xdd\x9c\x8f\x6e\xa0\xa2\xa0\xae\x39\x34\x04\x89\x5d\x0e\x8e\x3e\x9c\x1c\x7e\x3a\xbd\x78\xbf\xf7\xe9\x5f\x3f\x7f\x4c\xab\xd8\x04\x00\x9b\x9c\xe5\x83\x39\xf5\x8c\xe0\x73\xce\x90\x6e\xa2\x47\x4b\xd3\xc3\x81\xb8\xdb\xca\xf2\x4c\x03\xee\xfc\xcc\x80\x77\x7f\x7b\xa7\x87\xff\x7e\x7a\xb1\x7f\xfc\xe1\xf4\xf0\xc3\x29\x20\x67\xab\xb9\xdc\xdc\x27\x4e\x3d\x63\x7e\xd3\xa0\xec\x4a\x6c\xf6\xf4\xbb\xef\xd8\xea\xad\x0e\x18\x6d\x1d\x7c\xe5\xb1\xee\xbf\xf3\xbc\x82\xac\xa1\xd4\x11\x17\x5b\x5d\x42\x11\x90\x0d\xe9\x92\x6d\x35\x78\xff\xfe\xf3\xc9\xe9\xc5\xe7\x93\xc3\x8b\xbd\xd3\xd3\x4f\x47\x6f\x3f\x9f\x1e\xa6\x43\xa6\x12\x3f\x7e\x3a\xfe\x08\xf3\xf8\x1f\xe9\x73\xf6\xf3\xde\xc9\xc5\xc9\x11\x06\x75\xf8\xe9\xa7\xc3\xfd\xd3\x93\xf4\x25\x25\xbd\x3d\x3e\x7e\x77\xb8\xf7\xe1\xe2\x2f\x7b\xef\x3e\x1f\xa6\xdf\x53\xda\x87\xcf\xef\x0f\x3f\x1d\xed\x8b\xb4\xe1\x2b\x4a\xfc\x78\x7c\x72\x74\x7a\x84\x50\xb4\x72\x5f\xf2\x2a\x00\xde\x4f\xef\x8e\xf7\x0e\x0e\x0f\x9c\x16\xe1\x70\xe0\x66\xd1\x40\xd2\x4b\xee\x32\x0f\x58\x13\x34\xe1\x15\x45\xca\x82\xfb\x7b\xc6\xd8\x16\x50\x71\xaf\x03\x38\x5d\x2e\x3b\xe2\x50\xf2\x9c\x96\xe7\x7c\x34\x18\xbf\x3c\x63\xc9\x33\xde\x2f\x3b\xa2\xea\xde\x17\xdd\x75\x3d\xa1\x2c\x40\x6b\x65\xbb\xbf\x6c\xbb\x7a\xae\x1a\xdc\xda\xca\x07\x17\x5e\xea\x4f\xa2\x67\x52\x30\xe6\xd7\xd3\xdb\x69\xcc\xc5\xb5\xf7\x4d\xbc\x99\x43\x39\x38\xfb\xab\x49\xde\x4c\xb0\x43\xbe\x11\x18\xfa\xe1\xb0\xcb\xa0\x78\x15\xee\x90\x9c\x3f\x33\x86\x75\xff\xae\xbe\x95\x8a\x3b\x23\xc2\x5f\x44\x00\xb4\x6d\x09\x54\xa9\x55\x71\x76\x9e\x8d\x81\x54\xf3\xbf\x21\x30\x58\x09\x4d\x8f\xfa\xab\x2f\xb0\x3a\x65\x5b\xd0\xc5\xfe\x2c\x78\x18\xcf\x70\xe6\x4c\xb4\x69\x00\x1e\x93\xdb\x80\xc5\x5b\x0b\x19\xa9\xf8\x88\x3d\x1f\x58\x63\x19\xa8\x81\x11\x54\x52\x65\x8f\x3f\xcd\x3a\x3e\x86\x39\x00\x1f\x6e\x85\xaa\x2f\x58\xbd\x8a\xa7\xac\x1e\xf8\xcb\x1f\x41\x2c\xca\xcb\x96\x03\xc5\xe5\xc6\xc0\xd2\xd0\x8d\x93\x72\x52\x1c\x4e\xa7\xb0\x4c\x5b\x5d\xd8\xdd\x31\xa2\xec\x5b\x6e\x6b\x40\x84\xac\x5d\xd8\x5a\xf9\xa2\xf4\x07\x38\x51\x61\x8f\x07\x4a\x5b\xfb\x48\x94\xe6\x5a\x44\x37\x45\x7f\xad\xf0\x36\x14\xd5\x8f\x6f\x8a\x66\x56\xe7\x93\x62\xd2\xdf\xc9\xbe\x9d\x8a\x1e\x5c\x36\x83\xa0\x7e\x78\xd8\x0c\x81\x14\x2b\x84\xd2\xa9\xb8\x07\x53\x6a\x7e\x33\x04\xc0\x6d\x91\xec\x8c\x59\x26\xf7\x8e\x09\xee\xec\x64\x8c\x26\x2c\x9c\xee\x8f\x0e\xf4\x22\xb8\xf8\xb0\xf7\xfe\x30\x8d\x90\x3a\xfe\x96\xcc\x9e\xcb\x49\xc4\xec\x8d\x97\xde\x93\xa3\xa8\xd0\xde\x10\x59\xd6\xd2\x97\xc5\x8d\x65\x2f\x92\xec\x95\x8d\x89\x2e\x0c\x8d\x34\x59\x1f\x93\x6c\x18\x89\x14\x73\x90\x22\xc9\x04\x8c\x48\x0a\xad\x13\x91\x15\x86\x17\x66\xae\xc0\x73\x29\x6a\xea\xbb\xb9\x16\x82\xd6\xf6\x24\x3b\xa3\xee\xc7\xd5\x48\x53\x90\x25\x1d\x50\x17\x82\xd4\x5c\x59\xfe\xac\x3b\xe7\xac\xee\x42\x86\xa1\xda\xdc\x79\x54\xcc\x34\x23\x40\x9a\x54\xa6\x51\x40\x0c\x98\x94\xb1\x26\x43\xbf\x1c\xca\xa9\xc2\xc3\x43\x4c\x7e\x3a\xd0\x26\x19\x6e\xa9\x88\xac\x31\xad\xd2\xfa\x46\x8e\xb7\x67\x58\xa8\x68\x89\x52\xc1\x1f\xfe\x28\xfd\x7a\xa0\x72\x5f\xed\xea\x73\x05\xcf\xfa\xd5\xea\xf6\x3d\x0a\x9c\xc2\xf7\x06\x46\x3b\x72\xf7\x48\x71\xbe\xb5\xb5\x29\x73\xac\x6d\x82\x39\xdc\xb2\x16\x85\x1b\x4d\x2f\x0a\xc1\x72\xc3\x37\xb2\x89\x9e\x2d\x85\x85\x78\x6c\x51\x93\xde\x30\x0e\x59\xad\xcd\x52\xb4\xe3\x7c\x41\x04\x3b\x4c\x87\xf0\x95\xa9\xaf\x4a\x21\x85\xb1\xdc\x53\x18\x2b\x43\x0a\x63\xa8\x03\xb0\xfd\x4d\x16\x7d\x83\x5a\x63\xad\xa7\xd4\x75\x74\x10\xf2\x5d\x91\xc7\xcd\xc0\xdb\xfd\xc9\x36\x6f\x0b\x9a\x62\x4e\x2b\x3d\xeb\x87\x02\x64\xaf\x3e\xc1\xd1\xbe\xc8\x2d\x03\x70\xe3\x26\x88\xd4\x8a\xed\x38\x05\x8d\x88\xbc\x43\xd4\x58\x9d\x81\xa9\x5e\x73\x8e\x76\x76\xeb\xb8\x4c\xd2\x1c\xfe\xc0\x40\x3b\x3e\x50\xd5\xac\xb7\xd9\xd0\xd6\x4a\xac\xb0\xdd\x28\x82\x6a\x85\xae\x96\x7a\xda\x6a\x41\x00\x09\x4b\xcb\xa7\x40\xd4\x85\x40\x04\x7b\xe9\xde\x80\x87\x43\x0c\xf0\xfd\x5f\x26\x28\xb3\xaa\x8d\xd8\xec\x31\x7e\x33\x11\x01\x9d\x50\x9b\xc0\xed\x1f\x41\xdc\x88\x6e\xee\x1d\x5e\xf0\xdd\x02\x25\x72\x1a\x0e\x81\xf9\xe8\xce\x59\x14\x6d\xd7\x96\xfd\x7b\xe3\xd1\x38\xd0\xc9\xc6\x3d\xd6\x3a\xb4\x8e\x8f\xb6\xc9\x08\x0c\xe5\x7f\x35\x46\xaf\xc1\x97\x1a\x4e\x26\xae\x31\x17\x98\x0a\x92\xd6\xf1\xc9\xa8\x77\xe5\x4d\xcd\xcc\x4e\x9d\x3e\x77\xbc\x7f\xc4\x47\x0c\x81\xe1\xeb\xd7\xf1\xca\x49\xaa\x56\x4c\x52\x95\xe0\x47\xb8\x40\xff\x69\xc8\xbb\x43\x0b\x02\xdf\x0a\x92\x15\x82\x3b\x13\xab\xa6\xe7\x14\x88\xb5\xf2\x02\x49\x32\x7b\x27\xa9\x3e\xc7\xcb\x3e\x4d\x11\x3c\x96\x4f\x4d\x51\x68\x66\xac\xbb\x63\x2b\xee\x8e\x06\x82\x4c\xbf\x23\x3e\x59\x10\x3d\xa6\x43\x9e\xb9\xb6\x9e\xe2\x77\x6b\x5b\x44\x99\x6e\x7c\x0c\x55\x7f\x66\xb8\x46\x21\xf3\x41\x03\xad\xf7\xaa\x11\x1b\x1e\xd7\x88\xc7\x81\xde\xf1\x39\xe6\xd4\x08\xbe\x98\x2f\xba\x3b\x79\x7e\x5b\xec\x2f\x5e\xf2\x97\x26\x5f\xf4\x71\xbd\x9e\xfd\x35\xfe\xf1\xec\xaf\x1b\xbf\x3e\x7b\x73\x8e\x3e\xc0\xc6\x19\xa7\xd2\x38\xeb\xe3\x5b\xea\x6f\x84\x9e\xc1\x7a\x78\x21\xb6\xdb\xc6\xd8\xd0\x25\xd6\x57\xb2\x4e\x7a\x16\xdb\x19\x2d\x7e\xd4\x91\x36\x91\xd9\x11\xe3\xc5\x07\xb9\xd5\x95\x7a\xca\x51\xa6\xde\xa1\xf7\x36\x36\xc3\x93\x1f\xff\x10\x7f\x06\x1f\xf0\x9a\x84\x05\xc5\x7d\x84\xa2\x17\xed\xd0\x87\x3a\xee\x3c\x0e\x56\xff\xcc\xdf\x5d\x7c\x23\x4d\xa8\x2d\xd5\xad\x39\xd6\x98\x60\x8d\x89\x5b\x63\x9e\x48\xf3\x96\xc9\xd9\xfc\x7c\x84\x7f\xb2\x1b\xd3\x01\xd6\xbf\x0c\x37\xd0\xc4\x1a\x4f\xc6\xed\x39\xfa\xf7\xfa\x26\x11\xfa\x34\x35\xb4\x46\x66\xc3\x68\xb4\x5e\x72\x20\xf0\x91\x5f\xc9\x91\x6f\x6f\x2f\x78\xf3\x77\xd9\x15\x8e\xe5\x0e\x3f\x6f\x5c\x81\xed\x77\xb8\x87\x01\x7e\x9a\x67\xdb\x77\xd6\x6e\x85\x64\x76\xe7\x6d\x09\x48\x6c\xe3\xcd\x69\x60\x3c\x6c\x8a\x83\xb8\x63\xe4\x78\x58\x39\x38\x69\xe3\x6b\x0a\x66\x25\xf5\x3f\xdb\x78\xaa\xd5\x42\x95\x63\x13\x36\x05\x54\xf7\x14\x5f\xd1\xde\x1a\xf6\x52\x60\xa4\x6f\xd8\xc6\xd1\x75\x37\x9f\x45\xe4\x24\xa8\xcb\xaf\x08\x13\x5a\x37\xec\x44\x48\xf0\xe1\x28\x04\xd8\x9d\xed\x9c\x8f\x0a\x9b\x89\x46\x1f\x16\x6c\x50\x52\xe6\xf0\x22\x67\xaf\x56\x72\x0e\xee\xa3\x74\xf8\x92\xfc\x73\xdb\xdb\x08\xf0\xc3\x90\x79\xbb\x28\x1d\xbe\x7a\x1e\xe6\x28\xad\x36\x13\x32\xcc\x08\xa4\xcc\xb5\xc9\xce\xaa\xf8\xfe\x53\xd1\x2e\x6a\xdc\x4f\x86\x46\x86\x94\x6a\x41\xf6\x49\x39\x5f\xcc\x8a\x70\xde\x69\xbe\x08\x67\x1c\x56\xe8\xa1\xa2\xc8\x6f\x7a\x2a\x72\xd5\xa1\x9e\x0f\x92\xb4\xa0\xa7\x9e\x23\x2e\xf0\x0a\x18\x56\x80\xe1\x02\x7b\x55\x3e\xbb\xc3\x58\x9e\xe1\x6c\xee\x6b\x8a\xbb\x9a\x22\x0d\x29\xbf\xd8\xb9\x6f\xbb\x6a\x4b\x23\xd6\x36\xe7\xf0\x64\xf5\x4d\xaf\xac\xbe\x76\x04\xee\x24\xe5\x93\xa2\x76\x4b\x20\x81\xe6\x5b\x1a\x03\xcb\xa9\x46\x65\x7f\x5b\x94\xbd\xcc\x4a\xdc\xce\x3f\xa1\x2c\x80\x6a\x62\x2c\x98\x71\x76\x3f\xa7\x96\x71\xfe\x52\x38\x43\x6c\x69\x28\x90\x89\xf7\x70\xfe\xeb\x12\x02\x70\xb6\x34\xb3\x55\x62\xc8\xe3\x65\xc7\x8c\x37\xa0\x60\xe1\xf2\x44\x1f\xa0\xb5\xb1\xf2\x03\xbc\xc4\x1f\xf8\xc0\x23\x20\xfb\x33\x1e\x27\x0c\xfe\x9c\x93\x3f\x49\x2d\x16\x1c\xaf\x36\xd2\xcc\xb9\x27\x20\x72\x1f\x65\x36\x0b\x08\x30\x87\xdd\x8f\xd2\xb4\xc9\x69\xde\x5c\xa1\x97\x37\xce\xa1\x16\xf7\xc4\xc4\x72\x1e\x29\xe2\x07\x5b\x1d\xe5\x9a\x9a\x76\xb3\x9e\xc7\xc9\x05\xb7\xa5\xe7\x4a\x0d\xc8\xe9\x4d\x16\x59\xa7\xe9\xa1\x69\xd6\xd9\x32\x9a\xd1\x22\x9b\xee\x4e\x65\x78\xd3\xbf\x94\xc5\xed\xc3\xc3\x54\x60\x2c\xee\xfc\x4c\x38\xa8\xa3\xc3\xe1\x9a\x4d\x46\xfe\xf0\x96\xdd\x2e\x20\xe1\x8e\x4d\xb2\x65\x68\x90\x5d\x2d\x87\xf8\xf0\xb0\x48\x52\x28\xba\x80\xa2\x1d\xaa\x6c\x68\xab\x4c\x3d\x82\x79\x76\xbd\x4b\x2b\xeb\xe8\x20\xbe\x4e\xd2\x28\x62\x70\x86\xa9\x94\x09\xa5\xc0\x21\x65\x8a\x31\x07\x7a\x49\xb0\x39\x4c\xc1\xe8\x8a\x4b\x62\x22\x4a\x9f\x61\x7a\x84\xc2\x6d\xea\x52\x76\x0d\x8f\x56\x27\xb3\x89\x08\xc2\x17\x68\x94\x96\x29\xbb\xc1\x46\x45\x47\xef\xcc\xb6\x8b\x8a\xc2\xfb\xde\xc9\xb6\x27\x74\xa2\x99\x6d\x5f\xa3\x02\xbf\x92\xa4\x6a\xbc\x66\xc8\x52\x31\xec\xd9\x9c\xdd\x24\x40\x1f\xec\x9c\x67\x57\xf0\x33\xc4\x73\x6e\x16\x70\x1d\xfe\x95\xe2\x55\x63\x47\xa7\xc3\x9d\x57\xac\x07\x03\xa4\x43\x1e\x4b\xc1\x46\x43\xab\x8d\x5a\xec\xe3\xe0\x7d\x89\xa1\xf6\x08\x03\x01\x12\x94\x1a\x0f\x5c\x90\x26\x15\x1b\xc4\x56\xac\xb1\x84\x54\x79\xe2\xc6\x11\x52\xb1\x54\xbf\x22\xe6\xd4\x6f\xbe\xd2\x0b\x0b\xe8\x72\x84\x32\x0c\x1d\x0b\x9e\x43\x06\x18\xef\x8b\x6a\x69\xa4\x2d\xee\xf4\xcb\x52\x37\x73\x50\x2f\x61\x14\x76\x57\x0e\x9a\xfc\xca\x7a\x31\x3b\xc4\xdf\x25\x5a\x53\x29\xbf\x97\x9d\x95\xa0\x11\x93\x4c\xc1\x9d\x6c\x25\xd8\xe3\x39\x80\x89\x55\x2f\x3c\xf8\xa8\x7c\x23\xcd\x5b\xf5\xa6\xad\xdb\x99\xa1\xa1\x66\xbc\x73\x55\x34\x23\xe1\xb3\x6e\xf8\x5d\x9d\xeb\xa1\x68\x1d\x35\x2b\xe5\x7d\x6d\xf4\x5c\x6e\x7e\x27\xc1\x1c\x0b\xa5\x18\xdf\xe0\xc6\xe0\xf2\xed\x13\x99\xce\xc8\x37\x1e\xff\x44\xbf\xda\x5a\xc2\x3a\x7d\x79\x39\x37\x00\xaa\x4d\xd6\x55\x4a\xbd\x1c\x5f\xf3\x10\x54\x76\x9a\x39\x55\x94\x60\x8d\x86\x52\x6c\xb8\xff\x72\x5d\x88\x36\x1e\xc9\x03\x9e\x75\xfe\xa5\x35\x93\x1b\x0e\x3a\x49\xea\x11\x6d\xda\x98\x3b\xb6\x54\x67\xbb\xd8\x1d\xb0\xb1\x5e\xe1\xc6\xf2\x8c\x6e\x8c\xbd\xe4\x5e\x84\x9a\xec\x7e\x46\xbe\xde\xbd\x40\xc4\xea\x7e\xe6\xb9\x8b\x8f\xfd\x34\x0a\x8e\xb9\x39\x4c\x30\x08\x09\xd2\xdb\xa6\x1e\x69\x31\x08\x39\x96\x17\x15\x1e\x1f\x91\x79\x60\x58\x6b\x50\xeb\xb6\xf1\x46\xb4\x8d\x1d\x0a\x37\xed\xd8\x68\xf0\xa2\xd8\xa8\x50\xe1\x97\xe8\xc1\x51\x5a\xfe\xfa\xe1\x35\x18\xb5\xf8\x6b\x86\x47\x15\xb0\x27\xb2\x4e\x45\xd6\x5c\x48\x4f\xc0\xf1\x28\x34\x30\x8d\x76\x42\x3e\x47\x7c\x7a\x1b\xe6\xf7\xd5\x3a\x1a\xbe\xae\x71\x82\xd0\x1b\xbb\x73\x89\x38\xca\xfc\x2c\xfc\x99\xd5\x32\xd2\x9e\x3c\x4e\x8e\xaa\xae\xd6\xf4\x9b\x30\x44\xdf\x53\xd9\x13\x4d\xc7\x99\x57\x66\x0a\xe0\xae\xd4\x1c\xcc\xeb\xaf\x76\x62\xd8\x65\x0d\x79\x0e\x84\x2b\x99\x3c\xa9\x10\x73\xd3\x01\x49\x7d\x7a\x5f\x4f\x96\x33\xe4\x9a\xf0\xb9\x2d\x92\x51\x8d\xae\x76\x9c\x3a\xe4\xbc\xd8\x4b\x45\xa3\x36\x27\xa9\x68\x8f\xaa\x63\xb4\xbc\x26\x88\x21\x9f\xa1\xfd\x88\xde\x53\x70\xba\xba\x38\x41\x7f\x28\xa6\xd9\x51\x83\xa7\x7a\x8b\x4c\x48\x22\xd7\x68\x28\x40\xa7\x69\xbe\xba\x78\xe4\x3e\x66\x9a\x81\xca\x18\x18\xe9\x82\x0d\x7f\x24\x5c\xb9\xf1\x60\x46\x76\x30\xda\xac\x10\xc1\x33\xc3\x45\x74\x44\x6e\xc9\xd3\x37\x66\x8d\x86\x93\xca\x2f\xba\x19\x7e\xf9\xf6\x2d\x17\x02\x05\x6a\x88\xac\x47\x46\x84\x28\x3e\x4a\xb8\x71\xc9\x37\xe0\xf4\x41\x5f\x16\x73\x69\x64\x3e\x73\x58\xa5\x27\x87\x01\x3a\x0d\x04\xb5\xe0\x68\x27\x8f\x37\xab\x87\x87\x80\x0b\x1c\xe5\x99\xba\x25\x76\x47\x8c\x3f\x14\xb4\xb9\x11\xf1\x33\x31\xf4\x67\xa8\x55\x89\xff\x48\x6c\x23\xa9\xc1\xad\xad\x8a\x62\x74\x72\xfe\xe4\xd3\xf5\xa0\x82\xb0\x0f\x33\xeb\xed\xcd\x66\xb2\x6a\x1b\x16\x3e\x71\x9b\x64\x51\x15\x5b\xa2\xda\x2b\xed\x29\x4a\x53\x5b\x08\xef\x45\x0b\x3e\x47\xb0\xa5\x76\x60\x3f\x29\x69\xd5\xf8\xcd\x72\xb4\x94\x12\xab\x19\x74\x73\x49\x0c\xcf\x99\x14\xa7\xcf\x06\xd6\x67\x54\xeb\x23\x54\xc4\x43\x83\xec\x9c\x2d\x12\xcd\xe8\xc8\xa1\x5b\xa6\x21\xa3\x35\x9e\x82\xac\xd8\xeb\x78\xc9\x78\xcc\x07\xd7\xbc\xd1\xb7\xb2\x85\xbe\x09\x47\x26\xf0\xe1\x31\x5a\xdb\x6f\x2e\xa1\xe6\xc5\xc5\x62\xd9\x5c\x59\xe5\x11\x5d\x60\x86\x31\x7f\x6f\xf3\x2a\x14\x97\xbe\xed\xa5\x58\x1d\x24\x97\xbe\x1a\xb2\x10\x8a\x4b\x39\x6b\xc2\x41\x70\xe9\xf0\x25\xd9\x5e\x04\xf0\x1b\xa0\xdc\x57\x41\x66\xc6\xab\xb5\xcd\x1f\x08\xeb\xe5\x4a\x13\xaa\xe0\x2b\x42\x20\xc1\x16\x96\x03\x43\x69\xa3\xed\xc2\xac\x8c\xab\x37\xe8\xde\x7e\x73\x29\x27\x1f\x6d\x84\xef\xcb\xb8\xb3\xe7\x34\x61\x66\x81\x4c\xfa\xd5\xed\x06\xfa\x42\x69\xab\x7d\xd4\x49\x19\x37\x31\xf7\x8c\x09\xb3\x82\xe2\x68\xdb\xe6\x81\x5c\xcd\xc2\x54\xf5\x6e\xf7\x80\xdb\x01\xd6\x5f\x9a\x9c\xf2\x8d\xa4\xdb\x80\x1e\x15\x66\x0a\x1f\x6f\x2c\x7a\x12\x79\x26\xc4\xa5\x77\x5d\xc6\x2a\x1f\xb5\x0d\xf9\x29\x94\x1e\x5e\x1d\x21\x2c\xb9\x7a\xb7\x3f\xb2\x1b\xd7\xb1\x9f\x4a\xb5\xf1\x9c\x46\x5f\xda\xb6\x15\x87\x02\x44\x0f\x12\x43\x21\x1a\x5b\x95\x0b\x17\x56\x3f\xfb\xc0\xe0\x13\x50\x19\x63\xa6\xd0\x20\xdc\xe4\x23\x18\xe1\x8d\xac\xe3\x95\x87\x2f\x93\xa7\xec\xbd\x98\x7f\x14\x88\xf7\x62\xef\xfb\xc7\x5e\x2c\x1d\xc8\x32\x3b\x89\xf9\x3d\x27\x8f\x75\xb0\xc7\x9b\x39\xf6\x8c\xfb\xd6\xd3\xca\xd8\xe4\xa3\x57\xfa\x98\x63\x15\xc6\xba\xea\x3d\x97\x7c\xed\xaa\xcd\xa1\xf6\x78\xd8\xef\xf8\xa2\x49\xa4\x5f\xe4\x02\x7d\xfd\x79\x2b\xb4\x49\xb6\xb6\x5a\xc8\x41\x97\xd0\x28\x5c\x8f\x37\xf1\x0d\xc8\x14\x4c\xab\x59\x47\x11\x97\x3a\x74\x04\xc7\x23\x71\x85\xe8\x8f\xa0\xea\xd7\xc4\x82\x32\x67\x8c\xb8\xb0\x94\xec\x87\xfe\x95\xe2\xd7\x11\xea\xbd\xb6\xd3\x8f\xae\x6f\xf7\x70\xbf\x1b\x3d\x99\xfd\x4e\x42\x56\x75\xa8\xa7\x31\x58\xa0\xe7\x7c\xaf\x2a\xe7\xdf\x06\x73\x05\x50\x38\x79\x15\x30\x67\xd6\x8e\x7a\x66\x0d\x4a\xe0\x41\xaf\x87\x28\xb0\x56\xc7\x65\x71\x3e\x52\x08\x4e\x39\x45\x10\x31\x01\xfb\x91\x8e\x03\xb8\xc4\xf3\x4a\x52\xe9\x6f\xa0\xf3\x85\xd1\x13\x10\xd1\x4e\x8c\x39\x66\xf2\xd0\x52\xad\xdb\x43\x57\x9b\xd6\x29\xb5\xec\xd1\xb9\x78\xb5\xbe\x4e\xb8\x65\x87\x36\x1f\xe8\x7b\x2f\x50\xad\x32\x45\xde\x40\xdd\x24\x7e\x51\x0d\x47\x9c\xb4\x9b\xc3\xdb\xaa\x5b\x1b\xd3\x1c\x77\x07\xc1\xba\xdc\xac\xdb\xae\x4b\x77\x5d\xcf\xe9\x81\x54\xe4\xbe\x90\x9b\x47\xd1\x4f\xe4\x24\x43\x25\x1f\x1d\xd0\xb1\x60\xfb\xea\x84\xd5\xab\x5d\x75\xee\x8c\xea\x1f\x2b\x15\xdb\x6c\x93\x28\x7a\x7d\x61\x3e\x81\x6e\x2c\x8a\x49\x0c\xd7\x06\x20\x91\xd0\xd7\x7a\x85\x4e\x50\x71\x7a\x84\x14\x18\xad\xf8\x30\xd9\x71\xb3\xa0\x34\xf0\x45\x70\x0e\xc9\xc2\x1b\x10\x49\x8f\xf7\x13\xd2\x28\x57\xd4\x28\xb5\xa1\x83\xb1\x3b\xd5\x08\x53\x37\x8e\x2b\x06\xf2\x2d\xc2\x6f\x21\x3e\x18\x78\x15\x1b\x12\xdc\x9f\x87\xe9\x9d\x41\x23\xa1\x00\x20\xab\x27\x01\xd9\x25\x66\xec\x83\x9d\x51\xf3\x63\xb7\x06\x24\x1b\xae\xa0\x8e\x1e\x55\x09\x9e\x80\x44\x15\x77\x15\x5e\x1e\xa5\x70\xbd\x13\x90\xd5\xb9\x23\x13\x4f\x98\x4e\x22\xe4\x38\x70\x48\x1a\x86\xde\xd8\x57\x40\xaa\x33\x1d\x39\x7c\x25\x5c\xae\x63\xcf\xf5\xae\x9a\xd6\x5d\x3e\x04\xae\xdb\xe9\xf7\xec\xe9\xf9\x32\xa7\x7d\xa1\x77\xce\xe6\x66\xa8\x95\x47\xce\x3c\x0f\x4b\x5d\xae\x7d\x1a\x60\x92\xdd\xf3\xab\x27\x27\xb1\x8d\xbb\xa8\x79\x50\x89\x45\x9b\xa1\xd3\xdd\x79\x36\x75\x04\x2c\x37\xe8\x1c\x0c\x50\x46\xd9\x62\x8c\xbb\xb2\xc5\xcd\x8e\xcf\x0d\xd7\x3b\x6c\x3a\x7c\xa9\x99\xba\x48\x63\x00\x5f\x89\x69\xd3\x19\x73\x2e\xd8\x69\xee\xa6\xa8\x2b\x77\xda\xf6\x66\xe1\xe2\xda\xeb\x4e\x1b\xb8\x41\x8c\x51\x17\x50\x17\x48\x17\x86\x16\xdb\x84\x01\x92\xe1\x28\x8e\xdf\x4d\x80\x5c\x5b\xd7\xf5\xa1\x8f\x79\xbf\x46\xb3\x1d\x71\x81\x58\x11\xce\x79\xbf\xe2\x94\x94\xeb\x65\x0e\x2d\x34\x89\x4b\x61\x37\x92\x5c\xe9\x76\x27\x03\xc9\xca\x9e\x0c\x24\x1f\x9b\x95\x28\xea\x27\xbb\xfa\x11\x7a\xc7\x6a\x42\x8b\x6e\x1a\x4c\xc6\x50\xa9\x8d\xbd\x12\xad\x82\x90\x40\xf7\x37\x1b\xa3\xa3\xcb\x8e\x35\xc7\xb6\xb5\xb5\x30\x58\x1d\x1e\xe3\x22\x4e\x06\x50\x1a\xbd\xd2\x2a\x93\xae\x58\x37\x8d\x32\xe2\xa2\x81\x81\x15\xae\x2f\x1c\x11\xdf\x02\x2f\xe5\x6e\x47\x3c\x7a\x4a\x46\x4a\x7b\xaa\x20\xab\x33\x0e\x7e\xe4\x1b\xc5\x55\x18\x88\xa1\x64\x0c\x63\x59\xb9\x40\xac\x7c\x20\x5a\x87\x46\x18\x8a\x6e\x9f\xb6\xb6\x4a\x1f\x1e\x1c\x7f\xd8\xee\x7a\x92\xfb\x6b\xd2\x2c\xf3\x3c\xf2\xe0\xe2\x59\x77\x0a\xb4\x2c\x08\x3d\xbe\xb1\x92\x15\x96\xf3\xa2\xb1\xfc\x4c\xce\x15\x33\x66\x3d\xd8\x67\xd1\xe3\xe8\x64\xda\xc3\x2c\xbc\x5e\xc1\x2c\x9c\x64\xb3\x81\xc7\xd5\x06\xd4\xb4\x18\x18\x97\x7f\x44\x4c\xab\x6c\x03\x01\x9d\xe8\x6c\x1b\x2d\x91\xfc\x74\xb5\x34\x2c\x5d\x7e\xa5\xd3\x54\xd7\x03\xc4\xd7\x31\x0f\x10\xdf\xac\xe3\xcc\x7a\x33\x18\x3e\x81\x8b\x46\x1f\x1e\x36\x85\xe7\x68\xed\xd9\xd8\x4d\xb1\x95\x82\xb9\x2f\x6c\xa9\x5c\x02\xd8\x9d\x3f\xff\x52\xe3\x8a\x6b\xd3\x90\x2f\x73\x9e\x27\x0a\x5a\xbc\xec\x36\xad\xd0\xcd\xf2\x66\x4f\xf4\x58\xc8\xf3\xa3\xda\x26\xa2\x21\x14\xf8\x22\xa4\xa9\x09\x59\xae\x85\xbe\x16\x78\xe2\x1c\x55\xfc\xab\xe9\x66\x15\xf0\x30\xf1\x6a\xb5\x36\x99\x54\x9e\xee\xd7\xf9\xed\xd1\x18\x43\xe5\x3c\xbd\x83\x7c\x7b\x0c\x96\x87\x0b\x48\x0b\x0c\xb8\x79\x9b\xf9\x9e\x1d\x05\x5c\xca\xdd\x7c\xd3\x28\x83\x8d\xbd\x6c\xcb\x32\x82\xe2\x98\xd8\xf9\x61\x13\x0a\xd8\x99\x6e\xc1\x3e\x53\x09\xa4\x00\x6b\x43\xdb\x48\xc8\xea\xd5\xe2\x21\x15\x1a\x7c\xa2\x6d\x39\xaa\xb2\xe9\xd6\x16\xa9\x48\xfd\x04\x8b\x0a\x0e\x25\xfb\x0d\x95\x94\xba\x45\xfa\xec\xd9\xed\xed\xed\xe0\xf6\xc5\xa0\x6e\xae\x9e\x9d\x7e\x7a\x76\xf2\x97\x3f\x0f\x87\xcf\xa6\xbc\xcc\x3f\xbf\xcd\xdb\x72\x7c\x42\xfc\x74\x78\x8d\x58\x34\x1c\x0c\x23\x8e\x69\xae\x91\xf0\x70\x55\xf7\xb9\xb3\x7a\xd3\x43\x7d\xd1\x76\x83\x4b\x58\x31\xf1\xb3\xbf\xc6\xa8\x71\xf7\x80\xc7\x78\xf2\x2d\x46\xf0\xbc\xa0\x38\x9e\xbf\x4e\x2e\x06\xbf\x7e\x7b\xfe\xa7\x7f\x79\x96\x30\x6d\x86\x95\x22\xf2\x28\x16\x82\x34\xe2\xcf\xe8\xe0\x59\xc9\x02\x73\xb2\x7d\xfb\xd7\xe2\x4e\xbe\x12\x89\xc1\x9f\x67\xb3\xfa\xf6\x27\x78\x3a\xa1\x25\x9a\x96\x0f\x2d\x4f\x3b\x6d\xf2\xaa\x25\xad\x85\xf1\x5d\x5a\x42\x9a\x6c\xab\xbd\xab\xc6\x88\x90\x96\x5d\x8d\x62\x61\xbc\x03\x8a\x1c\x48\xf9\x38\xcb\xef\x20\x13\x2e\x60\xb3\x8f\xb0\x6d\x30\xf2\x2d\x17\x8a\x40\xc2\x09\xba\x08\x56\x09\xd0\xbf\x13\xe8\x5f\xc9\xc8\x93\x15\xd0\x03\x39\x7c\x79\x8c\xbe\xf5\x8e\x0e\x30\x15\x9f\x38\xf3\x7e\xb7\x04\x4a\x6b\x5c\xcf\x5a\xe8\xdc\x0c\x1f\xa0\x21\xd1\xfb\xb1\x30\x45\x35\x5f\x0e\x27\x65\x97\x03\x85\x61\x24\x0a\xf9\x74\x49\x6f\x0d\xb6\x44\x1f\xab\xeb\x66\x22\x64\xb7\xe3\xa6\x6e\xdb\xe3\xa6\x94\x3a\x45\x0c\xc1\xaf\x9e\x8a\xd3\x12\x3a\x52\x32\x40\x21\x44\xdb\x4d\x4a\x21\x90\x85\x83\x2d\x27\x62\x06\xc1\x06\x1b\xbd\x42\x75\x70\xa0\xe3\x26\x4d\x7e\x75\xa5\x3b\x01\x30\x44\x02\x94\xbf\x00\xda\x9c\x43\x5b\xf8\xc3\x83\x20\x8b\x97\x43\x51\x88\xbf\x09\x4b\x15\xfe\xf2\xa1\xfe\x4b\x3e\x2b\x49\xee\xde\x52\x02\xbf\x6b\x61\x2e\x86\x1e\x7a\xcb\x7d\x14\x97\xec\x9a\xbb\xc5\x85\x87\x72\x32\x11\x93\x79\xdd\x14\x53\xfe\x61\x7c\x7a\x97\xcb\x09\x40\xad\xbb\x9f\xa4\xdc\x1b\x57\xf7\xe1\xdf\x96\xe5\x8d\xa0\xae\xc7\x72\x79\x94\x30\x2f\x6c\x96\x5f\x4a\xc9\xef\x4c\xd5\x47\x19\x2a\x7c\x69\x56\x63\x14\x69\xf8\xce\x3c\xaf\xca\x69\x41\x69\x73\xe8\x1d\x1c\x20\xbc\x33\x54\x98\xa7\x70\x1f\xc1\x22\xe1\x77\xf5\xf0\x8e\xae\x61\x58\xaf\x98\x94\xb9\xfc\xfd\x73\x53\x2f\x85\x98\x7b\xce\x61\xc1\x9f\xe5\x04\xcd\xd1\xf6\x13\x56\x1f\xff\x38\xec\x27\xbe\x82\x2a\x5a\x32\xa4\x6a\x64\x02\x0d\xb6\x8a\xa8\x07\x87\x22\x1c\x91\xf2\x05\x55\x07\xaf\xeb\xd9\x44\x4a\xd8\x17\x75\xab\xb4\x0d\x16\x4d\x31\x53\x12\x7c\x72\xad\x66\xf4\x09\xce\x9e\x09\x2a\x06\xd3\x47\x1b\x09\x9e\xa6\x00\x20\xa2\x66\x06\xa4\xd5\x33\x9c\x4b\x54\x2c\xa6\x75\x0b\x0f\x7a\xdd\xb6\x40\xb9\x5c\xd6\x02\x04\xed\xb8\x96\x6b\x83\x07\xa3\x54\x9b\xa4\x2d\xf2\x39\xfa\x31\xa6\x89\x6c\x49\x7c\x2f\x86\xd9\x5e\xe7\xaa\x0e\xfa\x45\xc6\x2f\xe0\x03\x14\x65\x2d\x7e\x06\x5e\x17\xb0\xe7\xf6\x71\x73\x89\x72\xcd\x58\x3d\x1c\xd4\x63\x98\x57\x78\xe0\x5b\x90\xdc\x3b\x00\x1d\x01\x63\x17\xc3\x23\x77\xb7\x42\x6c\x9f\x5f\x72\x47\x49\xe2\x8d\x56\x1e\x7f\x46\x2f\xcb\xe2\x51\x2d\x6f\xe4\xab\xe4\xa2\x15\xf2\x5d\x01\xfd\x5d\xa2\x3f\x71\x9a\xe2\xdb\x79\x3d\x41\xb0\x10\xf6\xc8\x17\xb0\x53\x29\xd8\xa9\xc2\x1f\xfb\x75\x83\xd4\x8d\x58\x7c\x5d\x31\x47\x2c\x07\xe5\xf1\xf1\x84\xe0\x84\xa0\xc0\x37\xb1\x57\xa4\x57\x41\x61\x20\xe1\x19\xa2\x4a\xdc\x28\xf1\x61\xc4\x5f\xbf\x1d\xf3\xf7\xc8\x40\x34\x11\x3d\x46\x6a\x67\x44\xb0\xd3\x22\x63\x6b\xd0\x19\xf0\x2d\xce\xf0\x4d\x44\x5f\xb2\x0c\x5b\xe1\x43\xf6\x98\x22\x7c\x1f\xab\xf7\xc8\xc6\x98\x3c\x57\xbc\x45\xd6\xd8\x45\x16\xbd\xf0\x1c\xae\x93\x42\xe9\x14\x93\x23\xd2\xb8\x96\x12\x61\x19\xdf\x45\x0a\xcb\x44\xf0\x80\xf3\x11\xe9\x1d\x1f\xe1\x13\xee\xdd\xc8\x5c\xc8\xdc\x5f\x20\x7a\x3c\x5f\x44\xe6\x72\x89\xe8\x99\xf0\x72\x24\x57\x4b\x04\xbf\x70\x78\x46\x72\xd1\xe0\x3b\xc2\xcf\xe2\xfc\x5d\xf7\x6a\xdb\xf7\x29\xe0\x22\xd1\xb3\xbe\x2f\xfd\xe4\x7e\x29\x8c\x32\x0a\x11\xd5\x44\x1c\x1e\xef\xca\xea\x8b\x0c\x9b\x23\xb3\x68\xf1\x61\x46\xe2\xf0\x02\xc9\x7d\x93\xdb\x10\x95\x86\xdb\x98\x95\x28\x55\x65\xdc\xfb\x63\xb0\x05\xd1\x95\x35\xda\xd0\x1e\xa7\x9c\x9e\x0e\x10\x7f\x14\xe8\x08\x02\x6b\xc4\x85\xd0\x81\xe3\x05\x12\xe7\xfa\x65\x34\x60\x40\xa1\xaf\x09\x51\x24\x11\x51\x7a\xb4\x76\x2a\xce\x94\x74\x91\xb1\xf4\xd9\x2e\xe3\xec\x1e\xf6\x52\xc7\x9d\xe6\x4b\xa7\x93\xf8\x5c\x4a\xff\xfa\xe2\xac\x81\x27\x5a\x4e\xf4\x40\x6a\x48\x18\x1b\x80\xab\x16\xa1\xcb\xf7\x59\x76\xff\xbe\xfc\x1d\xb0\xf7\xfd\x42\x7e\x31\xbd\xe7\x08\xc2\x9e\x7d\xc1\x34\x2a\x48\xe6\x3d\x3e\xe3\xae\x2c\xcf\x51\x5d\x41\x82\x12\x9f\x25\xfe\xc5\x67\x79\x0a\x4b\xaf\x9a\xe8\xa3\x85\x94\xba\xe2\xe8\x3f\xea\xe5\x06\x7c\xef\xa6\x9c\x14\x93\x8d\x7c\xe3\x37\xfa\xe0\x6f\x98\xb4\xd8\xe8\x6a\x48\xc1\xd3\x74\x63\x5a\x16\xb3\x89\x8e\x41\x5c\x6d\xfc\x26\x3f\xf5\xdb\xc6\x35\x5d\x32\x9b\xc1\xc6\x29\xc0\x1b\xca\xcc\x66\x1b\x0d\xd9\x3a\x40\x65\xec\xc4\xb7\x35\xf4\x82\xb7\x30\xd8\x38\x9a\x6e\x74\xd7\x85\x68\xaf\x85\xd6\xe0\xe7\xb2\xd8\x80\xe3\x09\x3b\xb8\x81\xeb\xfa\xb7\x89\x61\x22\xf3\xdb\x60\xe3\x18\x2a\x34\xb7\x65\x5b\xb0\x0d\x00\xda\x46\x51\xe2\xbb\xd9\x81\x1a\xde\xe4\x68\x7f\x1b\x60\x20\x5b\x49\x31\xad\x80\xdb\x3f\x04\x58\xe2\x3b\xff\x23\xc0\xb5\x2f\xfa\xf2\x87\x00\xa6\x54\xde\xda\x01\xc2\xec\x91\x84\x5e\x7f\x71\xd6\x9e\xa1\x20\xe5\x6c\xcb\xdd\x18\xf1\x06\xf3\xd2\xc5\xbe\x4c\xad\x0c\x6a\x7b\xdf\x9b\x21\xaf\x75\x63\xcf\x92\xa4\x56\xb7\x6f\xee\x66\xe7\x0b\x22\x8b\xbe\x71\x2c\x07\xf5\x15\x43\x28\xbd\xa6\x8c\xef\xe7\x3a\x53\x02\x2c\x64\x4b\xe1\x60\x8d\x74\x38\x0c\xbb\xd3\x78\xb5\x5a\xe9\xde\xc6\xeb\x52\xa5\x2c\xb6\x0c\xa0\xe8\x53\xc2\x36\x8b\x2e\xd9\x87\x80\x4d\x3a\x32\x63\xfd\xc7\x29\x6e\x75\x4d\xbe\x78\xcb\x79\x92\xae\xe0\x13\x3b\x9d\xf3\x60\x59\xc8\x2c\x5e\xc2\x55\x62\xa2\x0d\x52\x9a\x81\x5b\x95\x38\x56\x7e\x6c\xad\x11\xf7\x55\x3e\x03\x6a\x60\x66\xf3\x19\xd0\xa8\xa5\x2f\x0f\xa5\xfc\x4c\x45\xf7\xfa\x05\x76\xd2\xe7\x6a\x1e\x0c\xf0\x15\xaa\x8d\x8c\xb7\x95\x4d\x07\xac\xe4\x7a\xc1\x9d\x72\xaf\x9b\xff\x08\x25\x92\xd5\x2a\xd0\xff\xb4\x86\x29\x86\xab\xcf\x59\x7b\x76\x14\xa5\x65\x5e\xc0\x6f\x60\xab\x2c\x0c\x4a\x65\x61\x50\xdb\xb2\x3c\x19\xc9\xa1\x14\xa7\xe8\x28\xdf\xda\xda\xcc\x61\x77\x8c\x51\x85\x99\x0c\x10\xc4\x73\x86\x7e\x56\x03\xaa\xaa\x61\x36\x5b\x58\xc9\xd1\x53\x62\xb5\xb7\x88\x8a\xbb\x54\x24\xdd\x35\x4c\xd2\x06\x62\x6e\x1c\xa2\xc0\xde\x96\xcb\xfa\x0d\xde\xe1\x8d\x71\x5e\x55\x75\x87\x48\x15\xeb\x22\x6a\xd4\x8c\x30\xc3\x18\x2f\x53\x11\x17\x59\xe5\x47\xce\xb3\x65\xbf\x30\x0f\xc3\x51\xf3\x23\xb4\x4f\x9c\x14\xa5\x9c\xd5\x48\xc5\xac\x3a\x53\x79\x22\x12\x21\x7e\x7b\x33\x93\x5e\x73\xe5\xc7\x6a\xdd\x01\x52\x80\x29\x93\x8a\xeb\x4d\xc0\xf5\x20\xa1\xf8\x96\xf9\x39\x45\xe7\xd4\x1a\x5b\x9d\x1f\xfe\xfd\xf5\xda\xba\xa1\xe6\xbe\xb7\x23\xfe\x71\x18\xe0\x76\xe1\x2a\x0d\x32\x14\x2d\x1a\x2e\x48\x7b\x37\x21\xc7\x75\x32\x17\xf5\x22\xd6\xe1\x37\x79\xf7\xd1\x08\x8d\x55\x4a\x51\x00\x66\xa9\xa3\x70\x83\xb5\x13\xfc\x51\x34\x28\xbe\x5a\xf5\x7f\x15\x79\xff\xfd\x5f\x15\x40\x6b\x88\xd9\xcd\x1a\xf3\xbb\xfc\x43\xe8\x7e\xc3\xd5\x39\x14\x02\x1e\xf1\xed\xa6\xff\xdb\x75\xd6\xac\xf8\x76\xc3\xbf\x5d\x33\xa1\x57\x54\x9b\x5f\x97\xda\x55\xe8\xf9\xc3\xd9\x71\xda\x85\xb2\xea\x43\xd9\xdf\x07\xdc\x80\xfd\x7d\x28\x79\x1f\x72\xa6\x9b\x66\xb9\xd9\x8f\xd2\xf8\x28\x3a\x25\xea\x99\x79\x78\x37\x63\x10\x93\xb0\x5a\xc7\x93\x20\x59\x87\x7a\x43\x67\x8a\xa1\xfe\xfe\x08\xdb\x06\xde\x30\x54\x11\x7a\xcc\xb5\x3b\xcd\xe3\x77\xa0\x06\xd3\x10\xb5\x1a\x1b\x20\x89\x83\x4a\xeb\x7a\x62\xcd\xfa\x68\xd7\x5a\x69\x6b\x1a\xf4\x42\x31\x86\x04\xf9\x39\xf4\x97\xa1\x5e\x30\xba\x4c\x25\x35\x7a\x33\x40\xf7\x68\x68\x7b\x6f\x06\xbd\x48\x67\x40\x14\x15\x7b\x62\x9f\x52\x93\x18\x27\xa9\xbb\xad\x9d\xb4\x1a\xce\xb3\xa6\x70\x4b\x96\x6c\x5a\xde\xb8\x89\x79\x40\x55\xd1\x3b\x00\x5e\xaf\xd6\x22\x34\xb6\xab\x71\x8b\x3c\xc6\xf0\x91\x58\xc3\xb3\xc8\x0b\x29\x73\xd3\x31\x46\xf6\xa0\x40\x79\x3a\xb6\x78\x2a\x78\xab\x26\x07\x74\x7a\x5b\x76\x85\x59\xa0\xb5\x0a\x10\x1f\x51\x5f\x92\x78\x2a\x57\x7d\x38\x46\xfb\x2f\xc7\x41\xaf\xf6\x41\x3f\x13\x6e\x35\xcc\x64\xc1\x9a\x22\x03\x1f\x9d\x09\x43\xc6\x78\x4f\x8b\xcc\x4a\x32\xbb\x34\x35\xb3\x38\x65\x7c\x24\xf9\xe1\x5a\x12\x25\xfc\x3c\x9a\x52\xb2\x96\x64\x51\x3a\xf7\x5d\x71\x95\x8f\xef\x74\x27\xe7\x01\x83\xc5\x9b\xa0\x57\x45\xc8\xb8\x32\xef\x8f\x45\x33\xd5\xc1\x01\xbc\x2b\xe5\xa1\x91\x7e\x52\x34\x37\x45\xc3\x2d\xc5\xb9\x7f\x91\x7d\x23\x97\xfb\x6a\xd3\x43\xbd\x0c\x07\xe5\x11\xf1\x01\x26\xc5\xa2\x29\xc6\x82\xb0\x13\xb1\x01\xf0\x6a\x21\xba\x38\x9a\x0a\x39\x41\xcc\xa9\xb5\x8b\x6c\x6c\xcb\x8b\xd8\xad\x4a\xf9\x29\xc7\x2d\x7d\x37\xba\xc8\x26\x83\x5b\xa0\xe8\xf6\x2d\x67\x33\x17\x18\x44\xc0\xcc\x10\xc5\xe3\x5b\xde\x32\x86\x14\x98\xc3\x3e\x23\x29\x01\x0d\x24\x62\x11\xbf\xf2\x44\x6c\x3e\xe0\x4f\x09\xc6\x19\x90\x4b\x32\xbd\x9f\xe7\xe8\x72\x11\xfe\x32\x41\x3b\xa5\x2a\xe6\x1d\x50\x7c\x48\xe2\x61\x34\x6a\xd4\xa7\xc7\x21\xa5\x9f\x88\xdb\x04\x5b\x56\x01\x36\xbd\x63\x65\x55\x76\x25\x71\x96\x4c\x2d\x01\xeb\x2e\x30\xb0\x55\x08\x50\xf3\x9e\x8f\x98\x42\xd8\xa4\xf9\xc0\x78\x63\x16\x74\xd2\x0b\x66\xc1\x26\xbd\x65\xca\x56\x60\x0f\x43\xe6\x55\x14\xee\x4e\x4c\x56\x3a\x1f\xac\xc8\x5d\x55\xf3\xed\xdd\xd1\xc1\xea\xda\x58\x82\x71\x20\xa6\xef\xc5\xc3\xa9\x88\xe4\x9b\x1e\x0e\xec\x04\x23\x3f\x47\x7b\x3c\x6e\x84\x6e\x96\xd2\xc9\x6c\xc9\xa9\x69\xf5\xa5\x3d\x52\x73\x82\xde\x84\x33\x58\xd9\xd2\xa6\xe5\xb0\x9b\x0c\xcc\x57\x99\x27\xa1\x37\x1e\xd8\x09\x0c\xef\xca\x02\x83\xc0\x1d\xd4\x78\x63\x17\x17\xed\x02\x2f\xab\xe9\xa5\xe8\xbc\x86\xea\xef\xee\x7a\xd2\xbb\x43\xaf\x30\x8a\x60\xf0\x3e\x71\x2b\x2b\x10\xf5\x37\x22\x8b\xa8\x1c\x9d\x40\x8d\xba\xc0\x0d\x7e\xc3\x00\xf3\xea\x2f\xe9\x82\xd6\xf7\xcc\x64\xef\xab\x3a\x33\x51\xd0\x0f\x41\xc7\xcd\xd3\x49\x12\xbf\xf1\xb6\xdd\x69\x49\x1e\x47\x21\xb9\xf0\xc5\xc5\xa7\xc3\xbd\xfd\xd3\x8b\x83\xc3\xbf\x9c\x1e\x1f\xbf\x3b\xb9\xf8\xf3\xbb\xe3\xb7\x7b\xef\x2e\x7e\x3e\x3e\xfe\xd7\x8b\x8b\x60\xb0\xe2\xd5\x55\x04\x2a\xda\xda\x5a\xab\x98\x30\xa9\xa7\x41\x96\xcc\x3c\x61\xd2\x25\x33\x8f\x83\x74\xc1\x82\x67\x64\x5a\x31\x07\xf7\xa7\xd7\x8c\xab\x4a\xcd\x99\xc6\xe3\xe9\x0d\xb3\x50\x6e\xba\xff\x98\x8c\x4e\x65\x84\xe5\x2c\xda\x19\x0c\x9f\x0f\x9e\x47\x46\x6c\xac\x53\x8f\xbd\x6b\x1c\xcc\xe9\x77\x2f\x57\x19\x20\xac\xf2\xc0\x10\x0c\xb6\x65\x9f\xe2\xe9\x6b\xed\xc0\x58\xcf\x73\xfa\xfa\x3b\xb6\xe2\x04\x4f\x5f\xbf\x66\xee\xf9\x9d\xbe\xfe\x9e\x05\x4f\xef\xf4\xb5\xfe\x2c\x9e\xc3\xe9\xf7\x3b\x2c\x78\x08\xa7\xdf\x3f\x67\xbd\x47\x70\xfa\x83\xce\x54\x41\x2b\x7e\xf8\xce\x4d\xd3\xc7\x7f\xfa\xc3\x2b\xd6\x77\x62\xa7\xc3\x1d\x6d\x73\x6c\x1f\xd8\x90\xf5\xb2\xc7\x1c\xd9\x3d\xae\x21\x5d\x83\x81\x4e\xeb\x74\x38\x1c\x32\xff\xb0\x96\x9c\x9c\xe0\x59\x0d\x99\x1a\x3e\xf6\x51\x9d\x0e\x9f\x53\x73\xc6\x91\x0c\x57\x5a\x82\x9e\x3e\x91\xd3\xe1\xf7\x78\xc9\x7d\xbd\x5a\x07\xd8\x20\xff\x38\xb8\xf0\xa2\x6c\x12\x05\x4d\x80\x4c\xa9\xfd\xeb\x5d\x49\x41\x62\x04\x07\x26\x60\x56\x53\xfb\x4c\x1d\x8a\x06\xff\x01\x2e\xaa\xea\x73\x47\x07\x82\x83\x82\x6e\xd7\xb1\xa1\xa3\x03\xee\xa0\x2b\x6d\x94\x52\xac\x57\x20\xc4\x04\x08\x0d\x25\xfd\xe1\x75\xcf\xfc\xf9\x24\xf3\xfa\xda\x7b\x6a\x80\x4f\xdc\xe1\x85\x7d\x02\x9b\x24\xe4\x6a\x69\x72\x9e\x4d\xb7\xb7\xd9\xec\x0c\x1f\xc9\xc4\x4c\x3e\x5b\xee\x88\x5c\x86\x4c\xed\x51\xe2\x5c\x4f\xaa\xf4\xd2\x0d\x5b\x4c\x93\xea\x36\x99\x4c\x24\x1c\xd0\x44\xb7\x54\xa3\x79\x5f\xe0\x30\x0d\xe1\x84\x4b\x0f\x8e\x7b\xe3\x42\x09\x07\x43\x9b\x43\xa0\x9a\x77\x30\xc6\xb9\x34\x91\x8f\x2e\xe1\x6f\x64\x18\xc9\xcb\xc8\x47\xda\x50\x3e\x22\xae\x4e\x14\xb0\x95\x8f\x0c\x6f\xf1\xb0\x3b\xdc\x22\xdc\xde\xd9\x2c\x44\xc2\x55\xb7\x98\xb0\xa2\x37\xcb\x71\x07\xdb\x91\x6b\x54\x1f\x09\x0d\x06\xd8\xf6\xcb\x48\x59\xd7\x43\xea\xe2\x2e\x92\xf6\xf5\x11\xa0\xd6\xc8\x35\xb0\x8f\x26\x97\x33\x3d\x0a\x32\xb3\x8f\x50\x2f\x41\xbd\xd2\x68\x30\x45\x0e\x43\x5b\xdb\x8b\x64\xf2\xc4\x60\x1a\xdd\xf3\xf4\xdf\xcb\x4e\x25\x73\xd3\x7b\x4a\x17\x5e\x21\x4c\x0b\x7c\x4a\xaf\x6f\x8c\x66\x04\x7c\x30\x5d\x03\x86\xcc\xf1\x21\xad\x5e\x44\xda\x04\x3f\x12\xa2\x4e\x65\x85\x2f\x02\x48\x99\x86\xf8\xd1\x97\xe2\x0e\xd5\x2e\x64\x22\xb7\xc6\xc7\xd4\x05\x3e\xc9\xe4\xcf\x0b\x4a\x5b\xf2\xe6\xb5\x25\x3e\xf7\x38\xa1\x1a\xd0\x06\xf9\x3c\x03\x19\xd2\x3a\x03\xed\xf2\x79\x7a\x2d\x7a\xa1\xad\xf3\x45\xba\x1c\xa8\x34\xd2\xe7\xc9\xe2\xb3\xdc\x52\x3f\x5a\xe0\x4f\x64\x98\xe7\x47\x5c\xe8\x1f\x85\x4c\xf4\xa3\x56\x26\x18\x2b\x54\x1b\xe8\x93\x5f\xfa\x23\x05\x15\xd3\x4e\x3f\xea\xf0\x65\x4c\x2f\x3a\x93\xa6\x9c\x72\xe4\x9c\x6b\xb3\x7d\x9e\xae\xc6\x6c\x58\xef\xf3\x1c\x3d\x5d\xdc\x8a\x3f\xba\xc5\x9f\xe8\x11\xae\x95\xd1\x05\x39\x70\x55\xfc\xe5\xa3\x83\x68\x9b\x13\x8d\xf1\xfb\xbc\xbb\x1e\x34\x70\xa0\xd5\x73\x40\xb2\xdc\x3a\x2a\x7e\x8e\xf7\xcd\x65\x8c\x3e\x61\xd9\xbd\xc6\x04\xca\x26\xd5\x50\xf1\x2e\xb5\xe5\x71\xa0\xa0\x65\xb0\x89\x0e\xf9\xf8\xd1\x79\x2a\xd8\xc1\xf1\x7c\x70\x6d\x25\xc0\x77\x07\x7e\x33\xa4\x2d\x8e\x76\x3c\x15\x57\xe6\x31\x5b\x0d\x95\xdf\xda\x0a\xa5\x0e\x74\x0b\xc4\xe6\x41\x4d\x73\xa7\x3d\x25\xa4\x8b\x37\x43\x2d\x3c\x3c\x04\x93\x07\xaa\xa5\x18\x2d\x51\xb9\xf3\x82\xd3\xba\xc7\xdd\x7e\x9d\x75\x68\x2f\x17\xd7\x88\x4a\xcb\xa7\xcc\xf1\x48\x73\xcf\xe6\x9e\xcf\x00\x59\x2e\xb4\xcd\xed\xe2\xcd\x8c\xfc\xf4\x0b\x05\xba\x16\xfd\xf6\xe7\xae\x39\xd0\x34\xd9\xda\xca\xcf\xa6\x68\xa4\x3c\xc5\xf8\x08\x03\xb9\x4a\x76\xc7\xb1\x58\x27\xc9\x6e\x70\x6c\x9e\x08\x45\xd7\x65\xa2\x26\xab\x93\x14\x9a\xa1\xbd\xf4\xc7\xdb\x32\xaa\x63\x83\x5f\xdf\x00\x3a\x2c\xc7\x36\x4e\xc4\x76\x85\x46\xd4\x58\x79\x1a\x0e\x56\x6e\xe6\xcd\x9d\x15\x9d\x14\xa1\x67\xcc\x8f\xf0\x16\x98\xaa\xff\x75\x5d\x74\x6b\x07\xab\xfe\x72\xf4\xe1\xe0\xf8\x97\x8b\x9f\xf7\x3e\x1c\xbc\x3b\x34\x3a\x4f\xe8\xf6\xe1\x41\xbd\xe3\x19\xb9\x1b\xc3\x58\x04\x02\xc6\xa1\xc4\x5f\x33\x16\x1e\xbc\x50\x56\xaf\xc3\x9b\xae\xaf\x32\xc5\xdc\x11\x27\x74\x9d\xd0\xcc\x53\x43\x48\x1c\xa0\xcf\xbb\xf5\x81\x62\x76\x03\x6a\xaf\xec\x88\x5f\x9b\xf7\x83\x2a\x13\xbe\xaf\xd1\x31\xfc\x99\xca\x42\x8f\xf0\xf2\x9d\x3e\x84\x09\x49\x7a\x1d\xda\x19\xeb\x7d\x75\xca\xae\x61\x07\x11\xf7\x1a\x7e\xc9\x44\xf3\x91\xad\x14\x4e\x1a\x3e\x4b\xd6\xfb\x84\xe4\xc7\x7b\xa0\xff\xea\x66\xed\x89\x93\xed\x16\x15\xb2\xc1\xf8\x62\x24\xf1\xfa\xfb\xba\x2a\xe1\x96\x83\x8c\x08\x03\x09\x96\xd3\x78\x73\x21\xad\xe6\x31\x32\xf3\x14\x0e\xeb\x6b\xa3\x5a\x3b\x0a\x7e\x78\xce\x5b\x33\x0a\xa2\xc0\x0a\x28\x3c\x8c\x1a\xdd\x6b\x09\x5c\x7f\xbd\x1f\x87\x7a\x2d\x3f\x0e\xf5\xc0\x78\xb3\x7c\x31\xd4\x96\x72\xbf\xe3\x70\xa1\x1e\xd8\x09\x21\xc7\x0a\xb2\x8c\x99\x08\xb7\x73\x7d\xb3\x98\xff\xd1\x38\x8e\x41\xaf\x01\xfd\x17\x70\x9f\x42\x4f\x7f\xa0\x5c\x97\x3e\x4f\x87\x2f\x7e\xe8\x8d\xe6\x88\x97\x98\xaf\x73\xb8\x4d\xf7\x2a\xc1\x12\x95\x82\x52\x19\x9a\x4f\x24\x0b\x22\x39\xeb\x3c\x7b\x7e\x6d\x6f\x54\x8c\x6a\xb7\x15\x21\xb1\x72\x5a\xe1\x91\x32\x1d\x7b\xf8\xda\x12\xba\x4a\xd5\x0a\xe1\x34\xda\x90\xc5\x90\x0f\xe4\xd1\x82\x4c\x98\x4a\x43\xf2\x12\x97\x21\xb3\x1f\x1a\xc3\x3c\x47\x5f\x4d\x70\x49\x97\x83\x82\x04\x35\xce\x4e\x25\xc9\x31\x56\x9e\xbd\xa6\x31\x46\xb8\x6f\xd5\xba\x41\x38\xfc\x37\xbd\x88\x13\x15\x8f\x53\x21\x5d\x09\xd4\xe6\xe7\x24\x40\xf4\xe7\x44\x50\x52\xf4\x64\xd0\x3e\x3a\x96\x9c\xd2\x70\x29\x04\x14\xf4\xdf\x0e\x97\xc2\xd2\x80\x4c\x43\x35\x54\x3c\x2c\xb4\xbd\x41\x0c\x57\x2a\x10\xd5\x89\x69\x35\xb8\x8c\x2d\x5f\xeb\x8e\xe9\x8e\xd1\xca\x92\x8c\x88\x2c\x33\x1e\x33\x3a\xbb\x92\xa1\x48\xcb\xa0\x3d\xd4\x6d\x54\x12\xa1\xa9\xe7\xe8\x7c\x36\xf0\x44\x5f\x28\x4d\x81\x64\x5f\xfa\x35\x9a\x39\xf1\xe3\xd9\x14\x1b\xb0\xd2\x4a\x76\xcd\xc5\x03\x93\xec\x5e\xf1\xf8\x19\xf2\xfd\x5b\xc1\xe1\x1f\x9b\x8c\x82\x09\xdf\xce\x81\x00\xf3\xa1\x01\xa4\xc3\xef\xbf\x0f\xf8\x22\x7e\xbd\x86\xf5\x48\x50\x40\x65\x32\x55\xa4\x28\xcb\x94\xa5\xe9\xe0\xcc\x65\xf8\x0e\x1e\x54\xac\xf1\x1c\xd9\x2d\xb3\x36\xbe\x7f\x7f\xfc\xf9\xc3\xe9\xe1\x01\x27\xf1\x3f\x7f\x30\x5f\x31\x64\x1f\xde\xd6\x95\xf3\x21\xae\x2e\x1f\xf0\x41\x64\xf0\x10\x2d\x62\x3d\x8f\x37\xc7\x34\xf5\x03\xe2\xe0\x1f\xa1\x8a\x22\xaa\xaa\x10\xff\x1e\x96\x89\x64\xed\x1f\x1d\xa0\xa7\x57\xa3\x15\x36\x1d\xbc\xcd\xc7\x5f\x80\x32\x3e\x3a\xd0\x3c\x4d\xa8\x10\x48\xc5\x4e\xe2\x81\xf3\xae\x9c\x16\xfb\x77\xe3\x59\x91\x2e\x59\xa0\x18\x1f\xa1\x50\x79\x54\x8c\xa6\x00\x2f\x4a\x68\xe9\xc8\xd6\x90\xed\x5d\x10\x29\x26\x60\x43\x57\x13\xdc\xc9\x6e\x80\x2d\xad\x3f\x30\xb8\x40\xa2\x1e\x96\x82\x98\x53\x11\x2e\xf0\x42\x58\x66\x8b\x54\xae\x86\x24\xfc\xe5\x52\x83\x71\x89\x77\xb0\x8a\x2b\x7d\xa1\xd6\x02\x2a\x0b\x98\x05\x9e\xd6\x85\x62\x79\xbc\x83\x4e\x31\xe9\x7b\x04\x5c\xb8\x61\xa0\x7b\xe0\x50\xbf\x00\x69\x8e\x67\x28\x77\x46\x31\x8f\xd1\x8d\xf5\xc7\x80\x9d\x84\x03\x9d\x7b\xed\xe1\xeb\x92\x07\x71\xc6\x9e\x5f\x48\x40\x1d\x21\xe7\xa2\xca\x67\x01\x80\x35\x5f\x0d\xb0\x35\xc7\x00\xa8\x1f\x81\xd9\x28\x60\xae\xe8\xa8\x92\x77\x59\xab\x57\x2b\xf4\x4a\xe5\x61\x01\x44\x72\x2f\x8a\x96\xdc\xf4\xc0\x82\x0b\x66\x39\x50\x9b\xc9\x06\xfd\x3e\x60\xf7\x4b\x58\x9e\xd2\x78\x3c\x30\x4e\x79\x06\x79\x23\x25\x95\x7a\x5b\x18\x16\xf2\x5e\x15\x56\x90\xab\xb3\xd0\xb7\x90\xda\x0b\xa8\x04\x05\x8b\xf2\xf1\x8e\x1a\x44\xad\x5a\x1a\xd7\x7e\x2a\xa6\xa7\x9c\x81\xcb\x6a\x38\x6f\x1f\x5d\x1e\xac\x1a\x8e\x07\x22\x1b\x40\x7a\xb5\xa2\x2e\x91\x2b\xf5\xb3\x1c\x79\xf4\xe8\x00\x16\xfd\x43\xe4\xe3\x2b\xd0\x85\xbf\x08\xf3\x66\x0d\x00\xf1\x8f\x88\x3e\x6e\x4e\x32\x9c\x23\x3e\x4b\x99\x79\x03\x34\x66\xb2\x7f\x19\xe0\x4e\x1e\x17\xa5\xf1\xe5\x35\x76\x73\x70\x1d\x88\x2e\x02\x6a\x43\xf5\x5f\xbe\x98\x8f\xa6\x1f\x0a\x34\x2a\xcb\x1b\xf4\x21\xf0\xc8\xfa\x32\x6d\x9f\x39\x72\xde\x43\x9f\x31\x95\x71\xbc\x6d\x1f\xc6\x73\xa3\xe0\x6a\xae\x98\xb1\x93\xaa\xc0\x4e\xaa\xec\x9d\x14\x58\xf5\x3c\x87\x73\x64\x15\xf8\xb8\x32\xd5\x23\x73\x92\x57\x60\x65\x07\x9d\xc4\xf2\xc3\x9b\x80\x30\xc5\xe3\xc3\x03\x92\x8b\x53\x4a\x81\x5f\x19\x76\x62\x93\xbf\x3e\xbd\x7c\xa8\x18\xeb\xd4\xfa\xe1\x95\x2b\x59\xb9\x77\xe7\x50\x09\x26\x3b\x84\x7c\x25\x7b\xf9\xcb\x63\xd3\xdb\xef\x1c\x89\xd6\xfc\x7e\xf6\xa9\x00\x54\x36\x2e\x67\x05\x59\x0b\xe6\xca\x42\x5b\x50\x7f\x18\xe9\x41\x2c\x8c\xd8\xd8\x73\xde\x47\x98\xdc\x09\x40\x40\xa3\x16\xd9\x8a\xc6\x25\xdd\xd8\x20\xbe\x5f\xab\xcb\x86\xf7\x01\xa2\xaa\xad\x3a\xe4\x0e\x65\x07\x89\xf7\x9a\x5f\x01\x58\x89\x84\x73\x31\x79\x7b\x17\xd2\xab\x36\x57\x51\x26\x3c\x19\x9e\x94\x97\x48\xf4\xbd\xbd\x03\xe8\x06\x9c\x26\x19\x55\x94\x9e\x20\xea\x86\x01\xf8\xdb\x5d\xfe\x73\x56\xf0\x80\x6a\xb6\x06\xe9\x94\xd3\x84\x2b\xee\x66\x01\xf9\xa2\x90\x65\x0e\x87\x5a\x78\x29\xa9\xb7\x74\xf8\x3c\xe0\xa5\x9e\x45\x01\x7f\xaa\xaf\xd7\xf6\x5b\x2f\xc5\xa3\x26\xe5\xe3\x8a\xe9\x48\x82\x4f\x1a\xf1\xed\x72\xee\x90\x96\x52\x86\x57\xfa\x1a\x45\xa6\xa0\x28\xb4\x14\x34\x91\x09\x93\xc0\x4b\x01\x86\x14\x40\x39\xaa\xf0\x2e\x93\x97\x9c\x98\x0d\xda\xb5\x50\x52\x8b\xde\x04\xa0\xd0\xcf\xa7\xef\xdf\x91\xc8\x68\x08\xe4\xe3\x0f\x48\x74\xf6\x7e\x37\xcd\xc3\xe4\x1e\xeb\x23\x2e\xad\x45\x81\x4c\x83\x06\xa8\xd2\x03\xe2\x11\xfb\x64\x6a\x5a\x3a\xda\x44\x5a\x13\x46\x28\x66\x1b\xf2\x73\xe2\x6a\x3a\x0d\x44\xcc\xdd\xb1\x80\x75\x97\xe8\xa1\x26\xee\x28\x08\xcb\x29\x8f\xa8\x3a\x03\x9a\xc7\x7c\x5f\xa0\x08\x54\x04\xa6\x19\xe7\xd5\xa7\x82\x0c\xf9\x28\xb4\x69\x41\xa1\x1a\xa4\x6f\x9b\xd1\xd2\x68\x68\x13\x2b\x3e\x7a\x29\x6c\x8c\x11\x7c\x93\xc7\x24\xb0\xa0\x83\x4b\x26\xfd\xde\x10\x67\xdb\x0b\x26\x1d\xee\x7c\xb7\x4a\xd4\xed\x8b\xb4\x83\xab\x05\x4a\xbc\x66\x4f\x2f\x96\x74\xc8\x75\x12\xfc\x5d\x62\x2d\x15\xb8\x72\xa1\xed\xda\xeb\xaf\xb1\x71\x50\x7e\x7a\x24\xe2\x37\xfc\xec\x10\x4a\x30\xdc\xb1\x3a\xaf\xe4\x41\x63\x96\x93\xa5\xe1\x6e\xb4\x41\xb0\x21\xd3\x19\x61\x5b\xc3\x2d\x64\x37\xea\xe9\xc6\x6f\xd1\x76\x6f\xcd\xed\xe8\xb7\x41\x94\x46\x51\xc0\x01\xa2\xe5\x74\x2e\xe0\x3f\x0c\x3d\xca\xdd\xc6\x01\xcd\x17\x74\x8d\xe4\x32\x4e\xe4\x21\x78\xe4\x07\x5d\xd9\x3d\x3a\xeb\x44\xf4\xc8\x77\xa1\x80\x47\xb7\x71\x05\x6b\xf1\xc3\x00\xcd\xfa\x3f\xa1\x0b\x81\xb7\x7b\x27\x87\xa8\x89\xbb\xa2\xec\xc1\xe1\x4f\x47\x1f\x0e\x2f\xde\xef\x7d\xf8\x0f\x00\xaa\x9b\x74\xf1\xfe\xf0\xd3\x9f\x0f\x0f\x5c\xf3\x3b\x35\x19\x52\x02\x5b\xbc\xb3\x28\xa9\xd1\x2d\x85\x14\x55\xa4\x11\xec\x16\x68\x79\x8f\x93\x90\x47\x1f\xfe\x9c\xb0\x5b\xc1\x04\xb9\x96\x0e\xb0\x30\xa9\xdb\xc4\x42\x82\x06\xc3\x62\x0e\xe3\x86\x36\x18\xfc\xbd\x8d\x37\xaf\xa4\x36\x92\x54\x28\xc4\xa0\xe2\x90\x3e\x71\xb4\x94\x94\x8b\xa6\x8a\x5f\x0b\xb8\x40\x7f\xe4\x4d\xd1\x09\x80\xe4\xcb\x60\x8e\x17\x4e\xe2\xd4\x88\xc7\x64\xe4\xcc\x2d\x69\xb8\x07\xa6\x17\xa9\x92\x13\x45\x8f\x0b\xcd\x7d\xe4\x6e\x00\x55\xf1\x25\xe0\x81\xf0\x0b\x77\x8a\x55\x5a\x31\xb9\xbc\x29\x6f\x78\xa0\x0b\x3f\x75\x99\x95\x5b\x5b\xe5\xe0\x82\x8b\x0e\x0f\x60\x03\xbe\x2d\xab\x09\x60\xdf\xc0\x22\x2b\x01\x21\x2f\xd0\xf4\x02\xfe\xb7\xf0\x7f\x89\x5d\x9b\x26\x95\xac\xbd\xb7\xec\x6a\xac\xfd\x3e\x5f\x90\x1e\xb4\x9f\x4c\x3a\x0d\xa1\x0c\xf4\x88\x58\x92\x67\xaf\xac\x54\xb1\xb2\x84\xb3\xd2\xeb\xec\x08\xc1\x70\x1b\xc3\x77\x29\x26\x4e\x68\x61\x3d\x3c\x78\x39\x09\x0f\xc4\x10\x2a\xbd\x4b\x5f\x1a\xc7\xf8\x83\xd6\x58\x5e\x39\xa4\xff\xb0\xc8\x4c\x16\x49\xb8\x93\x31\xde\xc3\xc7\x47\x97\x1f\x27\x16\x94\xe3\xff\x4f\x5e\x75\xd1\x33\x53\x68\xbe\x2b\xe5\x40\x92\x2a\x7c\x81\x31\x6e\xd6\x89\xe4\x6c\x92\xe3\x49\x4c\x2a\x61\xe7\x21\x17\xb0\x31\x3f\xbb\xb4\x42\x22\xc2\x36\x01\x5c\xb5\xb5\x15\xd5\x44\xa7\xe8\x39\x2b\x02\x69\xb0\x45\x8e\xe1\x60\x50\x18\x93\x50\xcf\x6d\xcc\x2d\x11\x91\xa0\x42\x9f\xaf\xfc\x93\x1d\xcc\x57\x61\xf1\xff\x8c\x8f\x3a\xae\x77\x71\x63\xe4\x8b\xc5\xec\x8e\x93\xb6\xca\xfa\x04\xe9\x90\x2e\x9c\x63\xba\x67\xcb\xb2\x6a\x97\xcb\x9c\xb3\xac\xd9\xad\xd2\x25\xad\x79\x63\xc4\xb3\xbe\x8f\xf7\x7d\xb6\xe7\xa3\x8f\x8f\xdc\x4d\x71\x58\x1d\x7d\x6a\xa5\x4b\x6d\x73\x53\xa3\xdb\xd1\x36\x9f\x04\x99\x79\xf3\xb5\xb5\xcd\x5d\xe5\x2a\x5b\xe1\x9b\xac\x8a\xa4\x66\xbd\xa9\xf0\xed\x6a\x8e\xdf\x05\xb8\x87\x87\x3e\x39\x67\xaa\x7a\x93\xce\x19\x9e\xcd\xd3\xa2\xa1\xf2\x97\x01\xed\xf1\x77\xf5\x58\xd1\x93\xbf\x9b\x83\x72\x0b\x90\xf9\xbd\x35\x32\xc5\xb0\x54\xaa\xe1\x2e\xc7\xf2\x42\x52\x84\x24\x39\x29\xa1\xb4\x37\x1f\xb7\x3e\xd1\xf8\xde\x67\x6a\x9e\xda\x41\x7d\x8e\x45\x47\x85\xa8\x6a\x1f\x88\xa2\xcf\x6d\x21\x3b\x37\xcf\x17\xbc\x23\xd8\xb3\x8f\x82\x02\x25\xb3\x57\xde\x63\xaf\x0f\x27\x1e\xa3\xfa\x34\xbe\xe7\x78\x5d\xb0\x4c\x13\xf6\x21\x7b\x1f\xdf\x0b\x0c\x72\xfc\x61\xff\x90\x33\x1e\x0d\x94\xc2\x13\xac\x13\xd5\x2b\x23\xd0\x93\xe4\xc3\x1e\xa0\xb5\xc9\x51\x26\x3f\x65\x61\x28\xf4\x16\x81\xd1\x9a\x9c\x54\x6d\xd5\x6d\xa7\x0b\xf5\xa5\x60\x16\x32\xb4\xf7\xfb\xf3\x75\x3c\x41\xce\x8c\x0c\x21\x54\xee\x4b\x9e\x54\xe1\xe9\xdc\xee\x2d\xb4\x6f\x7c\x2c\x5c\x48\x68\x99\xab\x3c\x04\xa6\x6d\x80\xc9\x95\x68\xdd\xf1\x89\x02\x07\xe5\x64\x65\x3e\x36\xf0\x89\x73\x64\x02\xc3\x61\x7c\x1d\xa8\xc9\x17\x0a\x62\x2b\x3a\xe3\x96\xf0\x7a\xb3\xba\x80\x69\x50\x6a\x17\x71\xf9\x1b\x0e\x35\xf6\xc8\xbe\x64\xf7\x06\x55\xe9\xf0\x3f\x0a\x93\xe2\x04\x34\xce\xc4\x1a\xb2\x4b\xd9\x87\x56\xb6\x33\xaa\x94\x3f\xce\x51\xb5\xbd\x9d\x10\xb1\x84\xa7\xc1\x63\x60\x95\x38\x76\xef\x44\xc3\x5e\x0e\xcc\x72\x48\x31\x7a\xf5\xb2\x4f\xc8\xa0\x0d\x64\x48\x9e\xec\x93\x5f\x30\x1a\x0f\xb5\xeb\x36\xe9\xae\x5f\x17\x50\x4e\x7e\xe6\xa5\xec\xc2\xb1\xe7\xa6\x41\xd5\xb4\x7b\x34\xb6\x5b\xb8\xaf\x98\x2f\x4d\xca\xad\x5e\xaa\x04\xea\xa2\xdc\xcb\x76\x23\xad\x64\x75\xed\x21\x6e\x91\xb4\xac\x25\xb3\x51\xef\x9f\x0e\xf7\x0f\x8f\xfe\x02\xaf\xe4\x2d\xec\x44\x62\x90\x77\xd9\x7d\x80\xcb\x8d\xae\xfc\x48\x24\xa2\xaf\x28\x3d\x47\xe8\xdd\x9a\xe5\x88\xbd\xd2\x12\xef\xd3\xe0\x8a\x0a\x96\xde\x89\x93\x3e\x96\xe2\x54\x83\x13\x1e\x26\xff\x05\xef\x7b\x95\xdc\x46\x8e\x44\x95\xe1\x82\x54\x6c\x16\xa8\xe9\x95\xad\x6f\x9a\x37\x09\x8f\xc3\x7e\x18\xe2\x00\xd8\x9a\xed\xe2\xe2\x6f\x24\xb8\x97\x7e\xd9\x3b\xbb\x9c\xee\xa2\xb4\xd8\x5c\x0d\x05\xdd\x4b\x51\xd0\xa3\x9f\xe5\x48\xd1\x6d\x99\x4a\xa6\xdb\x68\x1b\x27\x36\xd4\xc5\xd4\xf0\x40\x0a\x62\xff\xc5\x61\xc6\xbf\xda\x69\x06\x27\xd7\xaa\x6e\xc8\x8d\x28\xd7\x5a\x08\xd2\x02\xdf\x3c\x17\x76\x43\x89\x31\x77\x76\x0b\xb7\x2e\x9f\x54\x55\xcd\xc1\x7d\xc3\x71\x99\xab\xb2\x5c\x86\xb9\xbb\xde\x64\xfa\x4f\x75\x33\x16\x42\x20\x14\x70\x0a\xa8\xb8\x07\x0b\x72\x68\xc2\x39\x71\xe8\x3b\xb2\xb8\x31\x66\x2b\xbf\xaf\x6b\xaa\xd3\xfc\xbc\x2b\xf4\x99\x93\x5d\xc4\x66\x8e\x74\x9f\xa5\x0b\xa8\x7e\x38\xf3\x85\x30\x7b\x6a\x29\xd1\x9d\xdf\x94\xc0\x79\x9f\xf7\x59\xb3\xb0\x42\xb7\x87\xda\xbc\xda\x02\x8e\x3c\x6e\x91\x53\x22\x79\x3a\x94\x00\x4f\x93\xbb\x38\x91\xb2\xb7\x38\x5c\x8d\x7a\x8b\xba\x07\xc9\x4a\xc9\xcf\x53\xdb\x43\x63\xc3\xc0\xac\x8a\xe3\x55\x6c\x91\x50\x56\xbc\x0e\xd4\xfa\xa6\xcb\x33\x54\x8b\xfb\x67\x96\x4b\xd4\x05\x4e\x70\xeb\x19\x88\x8b\x84\xcd\x9c\x90\xb2\x8f\x84\xc0\x16\x29\x94\xc7\x25\xf1\x5d\x21\x39\xe6\x5b\x8b\x8e\x1b\x7f\x09\x0a\x49\x2b\x2d\x5a\x47\xe2\x1c\xfa\x2c\x77\x62\x11\xdc\x66\xc5\x6a\xd0\x59\x38\x76\x6b\xeb\xf7\x5e\xa1\xb1\x8d\x90\x02\x1c\x7c\xee\x4d\x2e\x93\xb8\x4c\x71\xd6\xcc\xf3\x9e\xc7\xdd\xbe\xef\xb2\xfb\x47\x9b\xdf\x52\x25\xc8\x4a\xa1\x38\x0d\xda\x89\x81\xfe\xa8\x49\x94\x9a\x5f\x36\x85\x07\x0e\xf1\x2a\x96\x93\x93\x1a\x0b\x2f\x23\x3d\xac\xbf\x87\x87\xde\xb3\xe4\x51\x72\xa4\xc2\x38\xd0\x1a\xb1\x4b\x39\x25\x6e\xe0\x81\xdb\x98\x3f\xac\x51\x53\x40\x83\x93\x25\x38\x15\x52\x97\x48\x83\xc7\x25\x9b\xb4\x7f\x1b\x28\x43\x0e\x6c\x3e\x06\xc9\x20\x47\xe4\xd3\x03\x13\xd5\xf7\xb2\x3f\xd2\x46\x99\x48\x17\x04\xc5\x59\x79\x8e\x11\x88\x59\x4d\xca\x51\xd3\x38\x37\xbd\x05\xd0\x6d\x19\x1d\x83\xf1\x5d\xf4\xb8\xa6\x40\xd4\x92\x78\xf6\x30\x22\x71\x7a\x9c\xc5\xcc\xdf\x1d\xca\x4b\x4b\x0e\x83\x0a\x0e\x81\x3c\x73\x43\x06\x8e\xaa\xc4\x12\x66\x8a\xd5\xce\x04\xfa\xe6\x52\xd5\xb0\x8c\x7f\xd4\xdf\x0f\xe8\x64\x1d\xcc\xd0\x12\x5e\x9b\x3e\xa8\x0d\x62\xa0\x09\xd1\x00\xb5\x45\x00\xf4\x0b\x73\x57\x20\x71\x07\x90\x01\x4c\x6e\xde\xdb\x42\xe8\xdc\xcc\x8f\x51\x86\xb9\xf6\x69\x58\xf6\x4f\x09\xe1\xc8\x51\x00\xf3\xa9\xca\x79\xd6\x37\x77\x0f\x0f\x5c\x2b\x23\x78\xab\x94\xed\x87\xf2\x50\x8f\x05\x35\xf6\xf2\xdd\xb8\xaf\x6d\x45\xc2\x5c\x88\x35\xee\x36\x51\x93\xef\x6d\x74\x83\x92\xa4\x41\x02\x0f\x63\xd0\x68\xc2\xae\x31\x69\xb7\xd2\xa1\xd4\x2d\xc1\x7d\x2d\xc5\xd5\x18\x3d\x2b\xfc\x71\x4f\xf8\xcb\x56\xea\x98\xb0\xdc\x5c\xce\x82\xc8\xe4\x87\xd3\xd2\x5a\xf7\x23\x7f\xd2\xf9\x07\x83\xa7\xbb\x38\x63\x48\xf8\xbc\x52\xe5\x46\x90\xb6\xd6\x35\xc6\x86\x40\x63\x41\xc0\x56\x02\x72\x15\x14\x50\x1d\xc6\x59\xbd\x8a\x0f\x80\xa1\x04\xbf\x8e\x4e\xe2\xf5\xb8\x43\x62\x7e\xed\x62\x2d\x5b\xf2\x0f\x24\x4f\x6a\x97\x50\xb4\xe5\xd0\xd0\xb5\x9f\x46\x31\x99\xe8\x62\x9f\x13\x26\x6e\x93\xf6\x75\x25\xf1\x55\x2f\xd6\xba\x2a\x39\x95\xec\xbb\x92\xbe\x29\x39\xc5\x9c\x6f\x8f\x4c\xbd\x0e\x8f\xbe\x62\xa4\x54\xe2\x2c\xad\xda\x2a\x1d\xa2\xa6\x11\xb7\x7f\x8c\x71\x89\x26\xfe\xe0\xd1\xab\x8e\x21\x5b\x91\xeb\x57\xab\x01\xa1\x99\x8f\xf9\x3e\xf2\x29\xbb\x15\x14\xe1\x45\x5c\xaf\x20\xe6\x47\x5c\x51\x78\x4d\x4a\xbd\x54\x5a\x4c\x5a\xa7\x0a\x09\xf7\x45\x48\x7f\x72\x30\x41\x4b\xb6\xa6\x5e\xb6\xb3\x3b\xa1\x41\x87\xfd\xff\xa5\xec\xae\xb9\xe4\x17\x5d\x3e\xc4\xb0\xd6\x30\x94\x28\x3a\xc8\x90\x78\xe7\xab\x4f\xce\x5b\x4f\xc1\x29\x24\xc5\x73\x45\x76\xd2\x81\xa7\x21\xd7\xeb\xc7\x84\x3b\x2c\x48\x58\xa2\x6c\xbf\x77\xde\xd7\x5b\xb5\xbd\xd5\x8d\xf5\x2b\x6c\x28\x58\x97\x4d\x65\x67\x47\xea\xc9\x39\x4f\x4d\x5a\xf1\x89\x4b\xf7\xb5\xd5\xc4\xa8\x6b\xee\xee\xc5\x05\x93\xf7\x29\xe6\x6a\x46\x28\xb0\xe1\x21\x90\x36\x87\xbb\x71\x91\xcd\x11\xbf\xd8\x42\x85\x38\x21\x17\x28\x3c\x02\xec\x93\xc6\xd5\x68\xf2\x84\x0b\x6d\xcd\xe2\x8f\xd3\xb2\x82\x3d\x7a\x77\x6f\x0c\xd9\xe8\x3b\x71\x70\x94\x94\xca\x93\xaa\xe2\xe5\xbd\x80\x05\x16\xe2\x5c\x98\x37\x40\x2b\x7a\x57\x0f\x13\x84\x64\xaa\xe1\x2c\x3f\xd8\x97\xbd\x76\x7d\x81\x64\x71\x4e\x67\x0d\xc5\xca\xeb\x61\xad\xc4\x37\x83\xab\x65\xde\xa0\xe1\xc1\x2a\x02\x77\x3b\x1a\x44\xdb\x14\xb8\x23\x34\xca\x9e\xed\x44\x31\x83\x38\xce\xd7\x52\x32\x68\xe1\x73\x66\x00\xe5\x71\xf4\x29\xfe\xac\x85\xd1\xf2\x66\x29\xb9\x76\x6c\x5f\xfc\xbe\xe3\x88\xe4\x3f\xb3\x7b\xad\x2d\xbd\xc7\xde\xe6\x6d\x91\x7e\xb6\x7c\xd1\xf8\x7d\xb1\xbe\x66\x58\xb2\x67\xe8\xd2\xeb\x33\x33\x6d\xdb\x8d\xe1\xc3\x0a\x38\x90\xa6\x1d\x71\xce\xc7\xc1\x69\x40\x52\x55\x26\xfd\xe1\xce\x65\xa9\x92\x6a\xcc\xc4\xe4\xc4\x7a\x45\x62\x92\xcd\x9b\x1f\x15\x8e\x7d\xec\x0b\xd0\x51\x62\x14\x39\xab\xd0\x1e\xd2\x4e\xe0\x1c\x18\x09\xd7\x2b\x72\x2b\x24\xe5\xff\x13\xdb\x1f\x11\xca\xfd\x1f\x7d\x2b\x58\xae\x51\x6e\xc2\xeb\x40\xb9\x16\xb3\xf4\xc7\xfe\xf3\x29\xfd\xb1\x3e\x3f\x1a\x5f\xe1\x28\xe3\xab\x5d\x5c\xac\xf0\x82\x60\x08\x1c\xd3\x1f\xf4\xb7\x57\xf8\xbd\x08\x28\xbb\xf5\xf8\xb7\xd0\xb2\x46\xc8\x7b\xce\x56\x4b\x12\xa1\xc8\x8b\xde\x22\x94\xfd\x72\x85\x72\x5d\x9f\x40\x31\x1d\x72\xd0\x3f\xa5\x7e\xc7\x94\x34\x11\xde\x08\x3a\x5a\x6a\x08\x29\x04\x18\x47\xba\x98\x0e\xb9\xaf\x92\x15\xa2\x44\x28\xf2\x2a\x64\x32\xb2\xda\x1d\xa7\xa1\xe8\xe7\x0a\x50\x31\xda\x0a\x5f\x15\x18\x2f\xd3\xf4\x6f\xe4\xab\xc3\xd6\x14\x80\x44\x1e\x50\x8d\xc6\xd0\x78\xf5\x2f\x91\xca\xc1\x23\x06\xc8\xa5\x58\xe3\x74\x5d\xaa\x94\x48\xbc\x0e\xc5\x0b\xf7\x96\x37\x8e\xca\xf3\xa4\x19\x18\x95\xea\x3e\x9d\x13\x23\xcf\xaf\xe4\xf7\xab\xfd\x4a\x06\xbd\x6e\xa0\x11\x55\xf3\xe5\x43\x5d\xf1\x45\x2b\x37\x72\xe3\x6c\x6c\x44\xc9\xae\x97\x5b\x2d\x4f\xaf\xd7\x16\xe0\x3b\x92\x78\xa5\x45\x69\x88\x99\x81\x46\x2c\xe3\xfb\x3c\x8d\xf2\x88\xe5\x97\x97\x0d\x3c\xc0\x5f\x78\x9e\x4c\xb8\xab\x04\xf1\x00\x29\xd0\x45\x78\x85\xbf\xf8\xdc\x95\x88\xaa\x23\xf1\x00\x29\x6d\x39\xc1\x77\xfc\x41\xef\xf3\xe8\xe8\x3b\xa2\x9f\x88\x5d\xa6\xd1\x25\xfc\x45\xa4\x1e\xe1\x5f\x78\x9e\x94\xf0\x38\x29\xf1\xa9\xc6\x27\x2c\x55\x5e\xc1\x53\x79\x05\x4f\xb3\x7a\xfc\xe5\x6f\xcb\x1a\xbd\x21\xe8\x67\x48\xaf\x27\x77\x90\x02\x7f\xe1\x19\xbd\x74\x40\x3f\x85\xef\xf1\x88\xff\x46\x18\x63\xe7\x26\x87\x6e\xf3\xdf\x88\x62\xdd\x23\x72\x8c\xc4\x03\xa4\x94\xe4\x57\xa3\xc4\x16\xc7\xa8\x50\x19\x8d\x49\x2b\x72\x5c\xcf\xf0\x71\x46\x4f\x57\xdc\xff\xbd\x7c\x8a\x78\xb8\x8f\x08\xff\xf2\x67\x8a\x6e\x11\xc9\x27\x48\x43\x57\x19\x93\x08\x6d\x35\xe1\x01\x6d\xc8\x27\x45\x97\x03\xae\xc2\x37\x7a\x80\x94\x29\xf4\x03\xfe\xc0\x53\x99\xcf\x6a\x74\xb7\x41\xbf\xf8\x7e\x83\x2f\x37\xf0\x84\xd5\xb1\x36\xb6\x0e\xed\x16\xf3\x34\x2a\xe6\xf8\x7b\x59\x4c\xf0\x11\x7e\x80\xc0\x43\x87\xd8\x14\xad\x40\x3e\x61\xda\x95\x1a\xac\x7e\xa6\x74\xa0\x24\x29\x8d\xa2\xce\x4c\x81\x40\x2a\x28\x78\x41\x4d\xee\x3b\x28\xdc\x08\x86\x32\x80\xaf\x5c\x0f\xd3\xe8\x7a\x08\xbf\xcf\xe1\xf7\x39\xfc\xbe\x80\xdf\x17\xf0\xfb\x12\x7e\x5f\xc2\xef\x77\xf0\xfb\x1d\xfc\xbe\x82\xdf\x57\xf0\x8b\x8e\xc9\x22\xfc\xcb\x9f\xb1\x5d\xfe\x8b\xb1\x05\x30\xaa\x00\x8f\x96\x80\xa1\x11\xe6\x30\x2a\x98\x75\x98\xf3\x92\x82\x92\xc0\x23\xfd\xc2\xfb\x1c\x40\x01\x7f\xe0\xc9\xf2\xe3\x81\x52\x61\x78\x06\xc8\x7d\xb9\x84\xcf\xc0\x1f\x78\x2a\xee\xae\x0a\xee\xd7\x03\x7e\x23\x11\x7a\x24\xa2\x1f\x78\x2b\xd0\x57\x09\xbc\x16\xdc\x67\xc9\x0c\x3e\x38\x2b\xf1\xb7\xfa\x82\x4f\xd5\x97\x88\xcd\xf3\x12\x1d\x7b\xe4\x68\xf1\x8d\xf6\x76\xf0\xb8\xc0\xa7\xe6\x0b\x3e\x36\x58\x82\xdc\xaa\x70\x7f\x2a\xf8\x17\xa3\x49\xf0\x77\x7c\xc2\x34\x5c\x0b\xf8\x97\x9e\xc9\xbd\x47\x41\xb0\xac\x72\x98\x47\xf8\x03\x4f\x75\x3b\x6e\xca\x05\x0c\x46\x3e\x45\x8c\xb3\x4f\x53\xc9\x46\x65\xb8\xe0\x70\xbd\xd5\x8b\x4e\xac\x37\xf9\x44\x69\x34\x93\xb5\x98\xc5\x7a\xd9\x11\x68\xf8\x6f\xc4\xa0\x30\x94\x5a\xe4\x00\x41\x74\x19\x02\x3f\xf0\x56\x52\x60\x21\x78\x2f\x45\x84\xa1\x05\xbd\xf1\xa7\xfa\x8a\x6f\x68\xf9\x14\xb1\xbf\xa5\xd1\xdf\x22\xd6\x60\x9c\x07\x68\x0b\xfd\x78\xa0\xff\x8e\x66\x79\x09\xbb\x0c\xff\x46\x0c\x8a\x43\xb9\x36\x9f\x43\x19\xfc\x1b\x31\x39\x2a\x39\xa6\x56\x10\x1f\x91\x78\x88\x44\x18\x12\xe9\x99\x04\xde\xe7\x39\x39\x31\xc1\x1f\x78\xab\x97\x70\x3b\x82\x57\xfa\x8d\x78\x2c\x92\x08\xff\xc2\x73\xd7\xd4\x18\x8b\x82\xff\x46\x22\xc6\x48\x44\x3f\x11\x86\x0a\x80\xe7\xe5\x25\x3e\xcd\xe7\xc8\x28\x8d\xc4\x03\xa6\x60\x07\xc9\x8f\x0a\x05\xd5\x89\xe8\x07\xde\x38\xca\xe8\x38\xce\xe8\xd0\xb7\x09\x7a\x35\x81\x53\x88\x63\x33\xf9\x04\x69\xb8\x1d\x20\x01\x7f\xd0\x1b\x1c\x3c\x5e\xe3\x2f\x2d\xf0\x8e\xaf\xf0\x0e\x83\xfc\x44\xf8\x37\x12\xa1\x4d\x22\xfa\x81\x37\x58\x02\x1d\xba\x76\x69\x72\x74\xac\x43\x3f\x11\x83\x45\x04\x2b\x68\x09\x83\x5f\xc2\xc8\x23\xc0\xe8\x51\x4a\x7f\x19\x7a\xd0\x07\xbc\x47\x3f\x11\xbb\x45\x64\x76\x8b\xd8\x6c\x5c\x36\x84\x56\xf9\x2f\xe2\x90\x29\x21\x90\x29\xcc\x42\x31\x9b\x95\x0b\x44\xa1\xe2\x21\x62\x00\xaa\x2b\x5a\xdb\x05\xad\xed\x82\x3f\xe7\xcd\x9f\x31\xce\x02\x9e\x5c\x91\xfd\x8e\xab\xbc\xa5\x55\xde\x7e\xc1\xb5\x83\xa3\xc4\xbf\x91\x8a\x79\x13\x89\x07\x48\xa9\x67\x77\x57\x38\xaf\xe2\x81\xa7\xf0\x6f\xc9\x27\x1e\x2b\x24\x9f\xe9\xef\xd9\xef\x11\xe3\xe1\x4a\x78\x9c\x92\xb6\x43\x1f\x3e\xf8\x17\x9e\x6f\x70\x9a\x6f\xae\xf8\x5c\xf0\x79\x80\x67\xbe\x18\xe8\x27\x7a\x44\x26\xa3\x3e\x74\x73\xd3\x53\xd6\xd7\x12\x95\x61\x12\xd1\x26\x9b\xf0\x44\x5f\xdb\xf5\xec\x9e\x8c\xb9\x22\x9d\x52\x05\xfc\xd1\x2b\xda\x4a\x96\xa9\x5d\xbd\x3e\xd7\x9d\x6c\x19\x3c\xee\x73\xdb\x90\xa2\xcf\x74\xb6\x74\x68\x08\xb8\xdb\xd0\x91\x28\x64\xaf\x63\xb4\xad\xad\x2b\xee\xf9\x69\x73\x87\xd5\x95\xe9\x0a\x8a\x12\xb4\xdb\x23\xfd\x4a\x8e\x7f\xf4\xeb\xe7\x05\x7f\xa1\x5a\xc2\xc5\x83\xd7\x9a\x95\xae\x1a\xf5\x53\xb1\x6d\x3f\xf5\xf3\x42\xa7\xa1\x9b\xb1\xac\x36\xbd\x90\xc6\x96\x62\x51\x24\x81\xf2\x56\x9c\xfe\x42\x95\xe8\xac\x62\xcd\xb9\x54\xd7\x72\x99\x21\xa6\x04\xae\x53\x77\x76\x2e\x23\xd8\xd4\xcf\xbe\x42\xb9\xe0\x8a\xf3\x5c\x19\x25\x63\x6b\x6b\x4c\xf1\x34\x62\x0c\xab\x61\xb0\x8a\xe1\x4d\xdd\xe2\x48\x21\x56\x57\x1d\x0b\x33\x6d\x64\x5f\xf9\xd1\x13\x9c\xa5\x95\xbe\xd4\x77\x89\xf0\xc2\x4a\x5f\x3f\x67\x2b\x96\x95\xe9\xe3\xd0\x75\x5b\xe8\x6c\x24\xcf\xcc\xe7\xfb\xaf\x09\xc8\x8d\xfa\x06\x57\x2a\xe4\x8d\x1c\xa4\x66\xe6\x1a\x5c\xbd\x13\xc3\x52\x22\x61\xba\x12\x61\xfa\x87\x07\x5f\x90\xcc\x73\x12\x2f\x6e\xac\x61\xbb\x35\x1d\xc0\xcd\x60\xa2\x6e\xa8\x64\xac\xf1\x53\xdd\x90\x1d\x0d\x29\xaa\x4b\x2e\x7f\x6d\x1a\xb5\x5c\xec\xd6\x03\x62\x32\x1f\x88\xb8\x7f\x69\x3d\xda\x47\x29\x5e\xf2\x48\x3e\xfc\x3e\x6a\x07\x1e\xff\x46\x4c\x70\xc5\x0e\x37\x72\xa4\x7b\x13\x3b\x06\xd0\x31\x67\x10\x9f\xc2\xf5\x05\x96\xc7\x55\xfc\x9e\xc2\xf7\x11\x5b\xe9\x14\x79\x37\xe8\xbf\xc5\x36\x39\xa0\x20\x1b\x9c\xa5\xd3\xe5\x57\x52\x02\x00\x8f\xa4\x29\x57\x0c\xba\xfa\xf3\x02\x16\xe3\x3e\x9a\xb7\xf1\x0b\x82\xc0\x0d\xfb\x27\x27\x41\x4f\xd8\x6d\x28\x12\xe4\x72\xb5\xf7\xec\xf1\x1a\x98\x6c\xd6\xa3\xa1\xbc\xf0\xeb\x3a\x51\x39\x4c\x1d\x66\x69\xda\x65\x6a\x30\x5b\x5e\xa4\x27\xbe\x92\xf0\x3c\x7c\xd9\x14\x7a\xc9\x45\x0b\x54\x6f\x81\xee\xcf\x60\xe6\x45\x07\xb4\x72\xb2\xa9\xa8\x7b\x27\xee\x50\x01\xaf\x80\xa6\xba\x2e\x2a\x2a\xf7\xe8\xeb\x2e\x1c\x2f\x2d\xa8\xc0\xbc\x18\x48\xdf\x5b\xec\x12\x5e\xfa\x7c\xc4\xfc\x9e\xdd\xb7\xdc\xf9\x2e\xa0\xbd\x6a\x09\x24\x7d\x43\x11\x90\x3e\x65\x77\xf1\xbd\x0e\xac\x86\xbc\xc7\x6c\xc8\x6e\xb3\x7b\x22\x56\xa0\x2c\x5d\xa1\xf0\xb7\xa1\x60\x4b\x40\x3f\xc2\x0f\xbf\x19\x60\x9c\xa5\x86\x87\x5d\xa2\x66\x39\x25\x0d\x0f\x82\x60\x86\x27\x22\x82\xe1\x97\xc8\x57\xf8\xe5\xc4\x23\x06\x61\xe2\x34\x19\x3c\x71\xfa\x05\x1e\x6e\x2f\x79\x97\xde\x67\xcf\xfe\x8a\x71\x25\xf7\xbe\xfd\xdf\xe7\xe2\x37\xbd\xf8\x75\xf0\xeb\xb7\xbf\x4e\x30\xc8\x24\x7a\xad\x7e\x64\xc7\xf0\xc7\x41\x97\xa3\xd2\xd2\xf2\x54\x88\xda\x60\x52\x97\x9c\x05\x98\xdd\x3b\xca\x35\x13\x87\xf9\x6d\xd7\x5a\xad\xd7\x06\xd8\x60\xb6\x8e\x5e\x1b\xda\xc1\x9a\xca\x61\xc2\x1e\xfd\xf6\x4c\xed\xbe\xf3\xdd\x08\x88\xb5\x1f\x9f\x45\xdb\x2a\x69\x3b\x7a\x13\x59\xaa\x46\x17\xfc\x60\x82\xed\x53\x9d\xe6\x57\x5c\x36\xb1\x57\x4d\x0c\xcc\x80\x66\x71\xdb\x66\xd9\x7d\x1e\x82\x52\xd8\xcd\x41\x66\x8d\xb3\xfc\x74\x3b\x7d\xa2\x0d\x2e\x96\xac\xb2\xe8\x47\xa3\xa3\xea\x78\xab\xfb\x0d\x7a\xea\x44\x5b\xf2\xd4\x46\x0c\x8e\x12\x4b\x5f\x06\x4a\x37\x1e\x7f\x1d\x8d\xeb\x95\x04\xaa\x06\x64\xfa\x09\x4e\x00\x0c\xcf\x0d\x6d\x72\x84\x9d\xcd\x49\xc7\x47\x62\x6f\x20\x70\xa4\x4b\x71\x3e\x48\xd8\xa5\x27\x98\xd5\xa2\x1a\x85\x90\x28\x2d\xdd\x12\xba\x13\x68\x4a\x84\xbc\xd8\x6a\x3b\x8b\x36\xa2\x6d\x94\xff\x90\x4a\x46\xd0\x21\xb4\xe4\x4c\xd3\xac\x61\xd3\x63\xbf\xe9\x90\xd0\x60\xa4\x2b\xc2\x37\xc6\x58\xfd\x91\x85\x66\x6f\xe5\x94\xf4\x9d\x76\x1a\xd0\x9d\x69\xed\x3e\xb8\xb8\xc0\x0b\xb2\xec\xb4\x7c\x7f\x54\xc2\xbd\x2a\xfb\xfd\xcc\x54\xba\xb1\x29\x89\xf3\xdd\x40\xa2\x08\x38\x99\x09\x83\x6f\xee\x98\x36\x50\x4e\x77\xa9\x92\xdf\xbf\x11\xfe\x80\x78\x72\xc8\x3c\x5a\xd4\xc5\xa0\x22\x0a\x62\xf5\xe0\x3f\xeb\xb2\x8a\xa3\x48\x85\x63\x89\xa2\x7f\xa8\x14\x78\xf6\x47\xa5\xc0\x4f\xa0\x94\x27\xe4\xbf\x55\x58\x1c\x26\xb4\x4a\x66\x6b\x49\x87\xc5\xb1\xce\x0b\xe9\xa3\xb7\x84\xa5\xdf\x19\xde\x55\xec\x42\x0a\xca\xba\x08\x62\x8b\x40\x23\x21\x17\x03\xb4\x3d\x4d\xed\x05\x42\x0b\x95\x52\x65\xda\xf4\x9c\x34\x56\x09\x06\x31\xf1\x2d\xc1\x70\x25\xe0\xf6\xe6\x0d\x2f\xc9\x0a\x8b\x1a\x23\xfc\xb2\x4c\x96\x3e\xba\x20\x2c\x50\x3e\x3c\x20\xff\x16\xf0\x4b\x86\x8b\x82\xcc\xd4\x3c\xd4\x52\x25\xbb\x87\x3e\x6a\xa9\x92\x34\x46\xc1\x2c\x6c\xe9\x6a\x92\x37\x13\x3c\x45\x48\x5c\x82\x89\x4e\x9c\x64\xec\x22\x2e\x8e\xa0\x28\x99\xce\x68\xf9\x31\x12\x1c\x07\xbe\xa5\x21\x23\x3c\x60\x8d\xb3\x1c\xbe\x86\xf4\x8c\x30\x90\x0b\xc2\x6a\x4c\xa6\xcc\x0a\x3a\xf0\x30\x86\x71\x43\x5d\x13\xfb\x8d\x31\x5e\x07\x97\x12\x12\xb8\x16\xc9\xa6\x27\xf3\xab\x81\x42\x84\xaa\xe3\x50\xba\x07\x47\x0d\xf9\x71\x12\xa8\xb1\xb5\xb5\x80\x82\xd0\xb3\x31\xfc\xb8\xd3\x80\x69\x62\x22\xca\x6c\x3c\xea\x9d\x91\x00\xb2\xaf\xd8\x18\x2d\x0b\xfe\x21\xb3\xc2\x57\xf0\x13\xb3\x02\x90\x7b\x2c\x57\xb7\xc0\x0f\x8f\x70\xfd\x12\x25\xec\xde\x56\xea\xf7\xc5\xc1\x77\x58\xa3\xf1\x6c\x61\xa0\xd7\xc2\xc1\xaa\xb5\x2e\x56\x19\xc5\x2a\xa7\x58\xd9\x7f\xed\xa1\x70\x41\xe1\x2c\x81\xfc\x49\x7b\xa3\xb7\x76\x6f\x96\xac\xdd\x0a\xc4\xdf\x70\xc4\xaf\x47\x00\x17\x00\xe1\x5b\x87\xe7\xe8\x4e\x03\xed\x2f\xea\x48\x6d\xc0\x52\x38\xd9\x82\xc2\x32\x29\x17\xca\x7b\xad\x54\x83\x58\xee\x9a\xaa\x46\x12\x65\x09\x99\x6a\x0a\xcb\x7a\x53\xda\x00\xf0\x22\xdc\x37\x3c\x1d\xa4\x78\x56\x30\xd9\x19\x34\x2f\xae\x57\x94\xdc\xae\xb9\x32\x3e\x74\x61\xb7\x84\xb2\xf9\xea\xb5\xa1\x00\x12\x5e\x1e\xb9\x6c\x6c\x69\x7d\x52\xf5\x7f\xc9\x0f\x92\xa7\x34\xbf\x65\x01\x59\x4d\xdf\x0b\x4c\xcf\x8c\x01\x97\x3d\xb3\x35\x54\xad\x1f\xd9\x3c\x2e\x0d\x21\xba\xa8\x23\x29\x67\x76\x2d\x7e\xc7\x09\xf3\x5c\xca\x87\xaf\x84\xe9\x4b\x62\x06\x04\xe2\xef\xae\x8c\xd9\xd0\x2f\x22\x7e\x9a\x25\xb1\x22\x5c\xe0\x0a\x21\xf3\x1f\x8d\x58\x10\xbc\x01\xa6\x43\x3e\x46\x5f\xb2\x1a\x74\x46\x19\x10\xb0\xfa\xe2\x54\xe4\x8e\xac\x76\xbb\xbf\x46\xa4\xc2\x77\x2a\xf2\xe2\x69\x93\x2f\x42\x7c\xc2\xbe\x1b\xb8\x17\xb2\xca\xe5\x25\xe6\x41\x5e\x62\xeb\xf1\x12\x97\x8a\x24\x97\x8c\x43\xf2\x9f\x39\x57\x6c\xc3\x72\x0d\xf6\xdb\x4f\x24\x3c\x92\xcc\xb7\x3a\xcc\x7c\x53\xcc\x30\xe3\xde\xf5\x18\xb0\x8e\x74\xb7\x98\xe7\xa4\xd6\x89\xe6\x88\x6f\x9f\x30\x9e\x30\x86\x8d\x41\x49\x98\xa0\xa3\xd6\xa9\x77\x42\xe1\x87\x59\xc4\xc3\x10\x47\x0e\x47\x6e\xbc\xca\x87\x6a\x68\xee\xd2\x57\xaf\xff\x8f\x30\xeb\x70\xf1\xad\x76\x97\x6a\x2c\xbe\x3e\xe6\x50\xa3\xf8\x40\x12\x7b\x59\xd9\xf5\x6a\x36\x51\x19\x60\xe4\xe4\x3e\xbf\xa6\xf5\x59\x2f\xcb\xa0\x63\x9d\x71\x76\xdf\x73\xa0\xa5\xd1\x6f\x3d\x39\xbf\x6d\xcc\x81\xe6\xc0\xd8\x95\x18\xe7\x17\x7d\x38\x5f\x6d\xfc\x16\xc2\xfe\xc9\x6f\x03\x25\x4d\xfa\x8d\x7e\x57\x54\x35\x88\x0a\xac\x47\x81\xa9\x7d\x82\x25\xcd\xfd\x3b\x85\xe5\xb0\x46\x5e\x2b\xcc\x4a\xbe\x15\x1e\x97\xf2\x97\x2a\x5c\x08\xdc\xa6\xda\x78\xd3\x23\xeb\x50\x39\x49\xde\xe3\x6a\xf4\x23\x4f\xce\x8d\xcd\xcb\x31\xf7\xa3\xaa\xfc\x02\x87\xf2\xf1\xf2\xe0\xd3\xc3\x6b\x0c\xc4\xaf\xf4\x77\x0d\x64\x55\x1f\x91\x8d\x9a\x30\x77\x22\xd6\x06\xb6\xae\xe2\x5e\xe2\x02\xfd\xab\x4c\x40\x0a\x3e\x84\x00\x53\x60\x11\xad\xdd\x07\xab\x56\xa8\x1b\x95\xdd\x0d\xf4\x26\x61\x7c\xd4\x20\x7a\xbe\xea\xb3\x4e\xbd\x35\x3e\xdc\x04\xc8\x2c\xd1\x95\x75\x34\x70\xd7\x59\x38\x6b\x34\xb3\x56\x47\x9f\x6a\x28\xd0\xef\x8f\x86\x5a\x2b\xe0\x36\xa1\x87\xf5\x75\x9d\x0e\xb7\xe1\xf6\xd8\xb6\x52\x2f\x4c\x2b\x75\xbc\x1d\x0d\x16\x39\xb2\x0d\xb0\xc3\xe6\xb0\x74\x0e\x31\x9d\x06\x42\x0d\x57\x7c\x83\xdb\x57\x27\x81\xe8\xda\x4f\x11\x76\x01\x64\x9e\x7e\xf7\xfc\x49\x12\x6f\x2d\xe7\x59\xeb\xf9\xbc\xfa\x7e\x6d\x37\xc3\xff\x97\xd1\x45\xe5\xfc\xea\xab\xc8\xa2\x23\x54\x69\x11\xe2\x9b\x34\x3a\x7a\xff\xe7\xff\x4f\x69\xa4\x77\x75\x3e\x61\xd1\x0c\xfe\x7e\x0d\x85\x44\x4a\x97\x2c\x2a\xb8\x9c\xf9\xff\x22\xfa\x68\xb5\x87\x42\x43\x74\x29\x40\x68\x18\x01\x88\x1b\xa1\x61\x59\x60\x47\x9d\xf7\xa4\xff\xeb\xd1\x4a\xef\xca\xea\x4b\x31\xa1\x03\x47\xba\xcd\xc9\xd7\x58\xd2\xed\x53\x4b\x7a\x19\x5c\xd2\x63\x6f\x49\xcf\x02\x24\x9b\x29\xb1\xd3\x5e\xbc\xa7\x61\x29\x00\x13\x40\xec\xbf\xdb\xb5\x4f\xcc\x4d\x14\x53\x5d\x6e\x93\xf1\x80\x44\x4f\x62\xa3\xcc\x51\x3e\x74\x93\xb5\xeb\xec\x16\xae\xf4\x25\x77\x48\xa3\xae\xb9\xf9\xb9\xe7\xc3\xc5\x93\xe9\x9b\x9c\x77\xae\x95\x4d\x70\x1e\xfd\x13\xdf\x51\xf7\x22\x18\x2a\xf9\xc5\x2b\x26\xa9\x5f\x5c\xe4\x3c\x3c\x6c\x0e\x65\xe4\x54\x6a\x41\x70\x09\x8a\x5d\x21\x93\x7b\xec\x55\x2b\x98\x2a\x7b\x66\x21\x53\x2a\x9c\xb6\xb9\xad\x61\x61\x75\x50\x9b\xea\x75\xfc\x70\xe0\x51\x2b\xe8\xfe\x0f\x0d\xdc\xa8\x32\x9b\x59\xb7\xdb\xa5\xda\x0a\x6c\x60\x76\x72\x64\x1c\x9a\xe2\x63\xa2\x09\x69\x0e\x3b\x18\x1b\x7d\x20\x69\x40\xa0\x2d\x51\x15\xba\x28\xe3\x4b\x09\xce\x3c\x8f\x91\xc4\x93\xd8\xa4\x4f\x9b\x61\x35\x9e\xe2\x40\x9a\x91\x87\x05\xc1\x8f\xd1\x11\xf8\xd0\x5f\xf2\x5c\x1a\x34\x3c\x86\x7d\xd0\x84\xe7\xdc\x6c\x83\x75\xaa\x7d\xa0\x1a\x38\x91\xb9\x31\x3f\xeb\xce\x1f\x43\x6e\x6f\x9e\x6e\xcf\x34\x53\x95\x83\x25\x08\xa1\xa9\x5c\x88\x08\x2f\x58\x24\x4a\x44\xcc\xaf\x85\x6b\x2b\xe9\x9b\x6b\xf1\xa9\x15\x2d\xd3\x5a\x00\xfa\x24\xda\x26\xab\x74\x73\x4e\x7c\x51\x14\x13\xb4\xee\xb1\x98\x48\xb9\x1c\xd0\x92\x21\x6b\x4c\xe1\x04\xb2\xa7\x61\x8b\xe7\x44\x43\x51\x21\x43\xd8\xc3\xfb\x5f\xa1\x2d\x74\x39\x8d\x49\xbd\xab\x8e\xa4\x37\x77\x9e\x89\xfb\x9c\xb3\x02\xc9\x5b\xb7\x24\x86\xf2\xc0\xf4\xb4\x59\x3e\x6a\x0d\x72\x68\x94\xb4\x99\xf5\x2e\x2b\x2f\x21\xf9\x6f\xcb\xa2\xb9\xe3\xe1\xce\xea\x66\x0f\xba\xcb\xb5\x42\xcf\x2a\x92\x27\x6f\xff\x3f\x27\xc7\x1f\x06\x5c\x8a\x5e\x4e\xef\x38\x7b\x70\xfb\x9b\x73\xe2\xca\x66\xa2\xa3\xe7\xdf\x20\x1a\xdc\x01\x74\xb6\x94\x44\xd9\xf4\xcd\x78\x34\x96\xc1\xaa\x00\x79\x9d\x8d\x89\xbd\x3f\xe1\xfc\xc4\x09\xb1\x3e\x60\x7c\x39\x3d\xf0\x52\x37\x6a\x51\x4d\x92\xd1\x75\x7c\xc3\x01\x74\x95\xcd\xcf\x6e\xce\xe1\xfd\xca\x80\xdf\x15\x5a\x58\x28\x23\x7e\xeb\xac\xbc\x59\xa5\xdd\xb3\x92\x32\xf3\x8e\x8d\xf4\xd5\xab\xbf\x97\x29\xf7\xf7\xe9\x09\xf5\xd1\x8a\xab\x1d\x09\xe3\xa1\xbc\xda\x1b\xaa\xeb\x36\xb8\xef\x44\x6c\x9e\x3a\x11\xeb\xe0\x89\x58\x7a\x27\x62\xee\x79\x4f\xab\x9d\xd3\xac\x1c\x70\x05\x5c\x7e\x9c\xe1\x12\x6e\xd6\x38\xca\x8e\x85\xd2\xae\x52\x47\x3b\x0f\xb9\x09\x33\x0d\x98\xfa\x69\xc1\xdc\xa0\x05\xd7\xd0\x22\x6b\x0d\x3d\xc9\xff\xee\x75\xe0\xd8\x8a\x7c\xbf\xda\x56\xe4\x09\x92\x4b\xf8\xaa\x11\xce\x45\xe2\x7b\x42\x77\xa9\x65\x58\x49\x7b\xe0\xd1\xb1\xb6\xe4\xc7\xe8\x8e\xab\x1a\x66\x48\xd7\x51\x33\x8f\xfb\x6e\x98\x23\x0b\x79\x31\xe3\x8e\xe6\x1d\xa7\x3d\x54\x4a\x69\x0d\x14\xb7\xdc\x63\x43\x1c\x9d\x5e\x17\xe4\x33\x77\x3b\xfa\x6d\x03\x21\xbf\xd1\x2e\x17\x8b\x59\x59\x4c\x36\xba\x7a\xe3\x47\xae\xe4\xfc\x46\x71\x93\x72\x98\x30\x6c\x6e\xa3\x9c\x6e\xfc\x26\x3f\xf7\xdb\x46\xd9\x6e\x74\xcd\xb2\x18\x48\x29\x28\x7c\xfe\xbf\xe5\xeb\x1b\x2d\x60\x76\xc4\x59\x08\x14\xbf\x0f\xd3\x1c\x3e\x8e\x9d\x08\xba\xe3\x45\x53\x78\x12\x59\xf1\x05\x26\x6b\xa2\x1c\x4a\x11\x20\x85\xa0\x18\xe8\x03\x4c\x7a\x24\x93\x18\x5e\x6c\x16\x72\x76\x52\x92\xf7\xb6\x0a\xe9\xbf\x06\x70\x70\x0d\x38\x55\xe0\xe0\xfa\x4d\x33\xda\xde\x6e\x92\xea\x0c\xb0\x76\x7e\xd6\x9c\xa3\x2e\x1c\x97\x45\x56\x19\x26\xd1\x39\xc0\x2b\xb5\x66\xa5\x46\x22\xee\x65\x56\xee\x7a\x2e\x63\x5b\x68\x89\xf7\x2b\x49\xf5\x33\x20\xf3\x6a\xb4\x04\xf4\x4e\x49\x1c\x60\x78\x80\xc7\xd6\x7b\xb6\x14\xbe\x37\xcb\x1e\x0a\x3f\xef\x25\xe1\xdb\x35\x10\xd6\xf2\x29\x84\x35\x0e\x22\xac\x99\x87\xb0\xbe\x92\x5c\x1f\x3b\xd8\x6c\x26\x06\x2c\x88\x73\x4d\xbc\xaf\x42\x66\x27\x42\x8f\x5f\x22\xb3\x92\xe5\x82\x30\x6f\xcf\x0d\x2f\x73\xf7\x26\x59\x9b\x36\x8c\xef\xdf\xe6\x71\x15\xed\x2e\x88\x73\x63\xab\xfb\x24\x3c\x5a\x48\xea\x1c\xb9\x28\x77\xcf\xce\x53\x52\x34\x79\x02\xb1\x06\x50\x05\x77\xdc\xd6\xeb\x9d\xc3\xa2\xa5\x36\x03\x9f\x46\xc9\xad\xea\x46\x10\x69\x9d\x19\xa4\x35\xa5\x9c\x3f\x26\x69\xb0\xa5\xcd\xc2\x78\xe9\x47\x80\x46\x53\x67\x3b\xd0\xd8\x57\x5c\x42\xd4\x05\x60\x15\x49\x6f\x5e\x34\xd8\xf5\x1f\xa3\xef\x45\xd8\x88\xdc\x21\x6c\x93\xd5\xb4\xb7\x52\x9d\x72\xeb\xb1\x2a\xdb\x34\xa0\x03\x38\x64\x33\x34\x19\x23\xa9\x41\xf5\xf0\x50\xc1\x26\x47\x2d\xa1\xda\x70\xdd\xf4\x24\x91\x9c\xaf\x4b\x24\x73\xaa\x78\x24\xed\xb8\xed\x5e\xc0\xe8\xb3\xb3\x73\xed\x2e\x08\x75\x75\xf3\x06\x5a\x96\x08\x11\xb0\xc4\x0e\xe9\xe8\x0b\x6c\xb6\x7c\xd3\x8e\x5a\xc0\x66\xe5\x59\x6b\x22\xa5\x9a\x1b\xea\x52\x2a\xc7\x64\xfc\xb8\xa8\x75\x83\x94\x6c\x6b\x21\x5a\xab\xbb\x76\xa8\x79\xe6\xd0\xa1\x93\x55\x74\xe8\xff\x50\x52\xd3\xa4\x2b\x91\xce\x58\x6d\xbd\x69\x6a\xa5\x4b\x15\x71\xb9\x0b\xf0\x34\x80\x8d\x06\x3f\x8d\x45\x2f\xc8\x55\x38\x11\x5a\xe0\x03\x15\x56\x19\xdd\x0e\x09\x24\xf9\x89\xd6\x48\x42\xae\x3c\xd0\x60\x45\x4c\x26\x9c\x52\xd5\x60\xb2\x84\x53\x79\x4c\x9c\xa2\x51\x3d\xc0\x78\x2c\xa7\xb5\x18\x0a\xb2\xd7\x63\x8a\x4a\x45\xf1\x7f\x27\x1f\xeb\x12\xf5\x19\xe0\x89\x34\x16\xd1\xe4\xaa\x92\x9e\xb5\x6b\xab\xe1\x3c\x2b\xb7\x65\x4c\x90\x7b\x8a\xae\x9c\x96\x0c\xed\xdb\xf2\x47\x47\xd7\x9c\xf7\xfe\xb6\xac\x26\xf5\x2d\xae\x68\x15\x26\x7a\x6b\x2b\x90\xc8\xfd\x8a\x6c\xc2\x9e\xa1\xc8\x5c\x18\x7d\xf9\x0a\xa6\x07\x36\xb4\xa2\x40\x0c\x5f\x7c\x83\xbc\x1a\x5f\xd7\x0d\x85\x61\xa9\xd5\xeb\xf1\x74\x8a\x22\x57\x54\xf5\xa4\x10\xa8\x94\x9d\xcb\x37\x91\x2b\xec\xe4\x09\x70\x7b\x5d\xbc\x83\x27\x21\x6a\xb3\x19\x2d\x3a\xed\x99\xad\x59\x6d\xe1\x19\xb9\xdc\xdd\x49\x91\x29\x29\x22\x47\x27\x12\x4e\x33\xe4\x2f\x61\xc8\x2d\x31\x43\x23\x79\xce\x61\x33\x42\xb2\xd1\xe2\x14\xcc\xc4\x14\xc4\x84\x52\x1b\x6d\x28\xc0\x44\x82\xf8\xd6\x88\xbb\xe1\xae\xf0\xc0\xb4\xcb\xcd\xcc\x72\xf0\x06\xb3\x61\x66\xc2\xab\xec\xee\x34\x5b\x40\x77\x67\x81\xee\x5e\x67\xd3\xed\x31\x1c\xbe\x6a\xb1\x59\xcb\x6b\x34\x11\x67\x40\xd3\x91\xe3\x17\x36\x91\x9d\x86\x83\x97\xf7\x6c\x9e\x4d\x06\xe3\x7a\x36\xcb\x17\x6d\x31\xb1\xd7\xc7\x7c\xf7\x3a\x9d\xd2\x1a\x99\xef\x4e\xd3\xeb\x47\x27\xbc\xa4\x41\xe9\x05\xd6\xba\xdd\x11\x6b\x4d\x47\x4b\x38\x6f\xa6\x30\xca\x89\xe1\xfd\x0d\x87\xbb\x1b\x57\xa4\xed\x0b\x1f\xc7\x8d\x01\xe7\x1c\x7f\x79\x63\xe4\xc2\x03\x39\x5a\xa7\x8c\x24\xb5\x6a\x50\x2e\x6e\x8e\x9e\x3d\x83\xc9\x1c\x18\xd1\xf8\x3a\x6f\x00\x1b\x90\x9d\xe5\xca\xed\x54\xcb\x8a\x08\x35\xb3\x5a\xf3\xad\xa8\x88\x03\x8e\x83\xa1\x17\x02\xdb\x45\xca\xa4\x82\x3b\x09\x2f\xa3\x67\xe3\x38\x39\xd7\xd8\x80\x22\x9a\xcf\x4b\x5c\xe8\x62\x94\x78\xf7\xec\x87\x60\x9d\x1a\x35\x08\x56\x7c\x7f\x56\x80\xb4\x61\xe9\xe2\xb9\xf0\xa6\x94\x5e\xe6\xca\x11\x60\x09\xa4\xa6\x1f\x85\xba\x34\xf4\xbc\x46\x52\x71\xc9\x43\x2d\x60\x70\x82\xad\xad\x19\x2f\xbe\xe8\x5b\x63\x0b\xbd\xc6\x5a\x32\x87\x81\x0d\x50\x8b\x85\x8b\xfa\xb5\x08\xbc\x3d\xa0\x8b\xb0\x38\xba\x69\x85\x0e\xc0\x54\x62\xb0\x28\xde\xc2\x02\x8b\xf1\xde\xc1\x1e\xa1\x06\x66\xb2\x01\x98\xe0\x85\x5c\xb2\x6e\x1e\xb3\xda\x40\x6e\x09\x1f\x05\x97\x06\xfd\x5e\x8c\x97\x08\x55\x33\x82\x8d\x22\x9e\x85\xe0\xec\xa7\xba\xd9\x97\x13\xca\xb7\x9a\x26\x9f\xa1\x88\x21\xcb\xdc\x1b\xa3\x3c\x8d\xac\xe3\x08\x41\xe4\xd5\xe7\x16\x55\x01\xb7\xb6\x02\x58\x7e\x91\xdd\x23\x21\x40\x0d\xb6\xe9\x6c\xb7\x49\x6b\x74\x74\xa9\x13\x4a\x40\xba\xc6\x31\xba\x10\xa2\x8f\x50\x97\x53\x1e\x20\xa6\xbf\xc3\xe9\xf0\xd5\x0b\xd6\xdf\x5f\xc8\x46\x09\xc6\x0f\x6b\xfb\x17\xf8\xff\xa5\x04\x43\x5f\x7f\x16\xe1\xeb\xcf\xd4\x97\x56\x5c\x7b\xfc\x1e\x5f\x7a\x21\x4d\x82\x25\xc7\x67\xb2\x96\xf0\xe2\x54\x19\x12\xff\x43\xe5\x17\xac\xcb\x02\xa4\xb8\x66\x16\xc7\x3a\xd0\x2e\x73\x7c\x10\x27\x94\x2b\x69\x89\x1f\xb3\x21\xb2\xc7\x3b\xb8\x3e\x24\xac\xc8\x88\x89\x2c\x7c\x34\xa1\xdd\x5e\x41\x8a\xc5\x86\x14\xc1\x64\x4d\xdb\x22\x14\x7e\xbf\x83\x06\x62\x2d\x4a\x40\xcf\x32\xbd\x57\x92\x45\xcf\x95\x44\x75\xbd\xdf\x32\x30\x20\x2b\xb1\xef\x2a\xab\xaf\x35\xea\x26\xe3\x4b\x4c\x9e\xb8\x96\xc8\xbe\x7b\xb0\xd0\x4c\x25\xcb\xe6\xc3\x92\x1a\x84\x39\xf8\x9d\xc9\xc1\x27\x80\xfd\x41\x16\x3e\x87\x5e\x98\x93\x3f\xfb\xe3\xb4\xff\xff\x8d\x3c\xe8\xa7\x23\xd7\x39\x2c\xca\x1f\x56\x5b\x78\xfb\x38\xb5\x29\xc4\xaa\x29\xff\xcb\x0c\x16\x16\xfb\xfe\x59\x34\x3e\x12\xb8\xd4\x8e\x44\xb7\x3a\x30\x72\x81\x5e\x8f\x7e\x92\x61\x8d\x10\x63\xde\xeb\xef\xa6\x39\x03\xea\xb6\xb5\x96\xe7\x02\x36\xfa\x5b\x8c\x54\x0f\x83\x13\x5f\xce\x36\x87\x18\x7b\x32\x58\xb3\x19\x4c\x67\x70\xb3\xa4\x1a\x85\x58\xed\x2d\x77\x7e\x85\x21\x0d\xc7\xd9\xd9\x92\xb5\xe7\xa3\x32\xae\x0c\x75\xe3\x5a\xe0\x2f\x3c\x19\x8d\xc1\xfc\xd2\xe4\x68\x85\xda\x06\x78\xd5\x63\x5c\x6f\x08\x98\x19\x39\xe1\xa2\x63\xd5\xeb\x67\xba\x39\x64\x97\x56\x47\x7a\x42\x48\x06\xc6\x38\x0a\x8e\x7b\x87\x35\xbb\xe4\x4c\x33\x01\x7a\x5b\x86\x93\x2c\x18\x57\x41\x47\x8d\xb2\xc0\xc9\xdd\xbf\x72\xdd\x45\x65\xc7\x88\x7b\x41\xca\x0d\xf6\x7c\xa5\xc3\xef\x30\x82\xfd\x0f\x6b\x5b\x4b\x27\xf7\x17\x03\x53\x21\x7a\xc0\x3d\x77\xf1\x75\x8e\xe9\xca\xb2\xf8\x53\xc2\x44\xd1\x8f\xb3\xe5\x55\x59\xfd\xbc\xbc\x14\x85\x8d\xc4\xe3\x06\x7d\xee\xb5\xbd\x45\x8f\x84\x1b\xe2\x9f\x09\xdf\xc4\xb7\xbd\x05\xb9\x2f\xf9\xf7\xeb\x7c\xb3\x7d\x4b\x27\x60\x7c\xff\xff\x92\xf7\x66\xdb\x6d\x2b\x4b\x82\xe8\xea\xd7\xfe\x0a\x0a\xdd\xad\x4d\x96\x52\x34\x29\x0f\xdb\x06\x0d\x6b\xf9\x78\xe8\xe3\x3e\xdb\xc3\xb2\xe5\x3a\x75\x5a\x47\xe5\x82\x48\x48\x44\x99\x04\x58\x00\x68\x5b\x25\xf1\xcb\xfa\xe1\x7e\xd2\xfd\x85\x1b\x43\xce\x48\x50\x94\xf7\xae\xee\x7b\xd7\x7d\xb0\x45\xe4\x3c\x44\x46\x46\x44\xc6\xf0\x29\x5f\xae\x16\x99\x95\x13\x7f\x10\xaf\x30\xbc\xf2\x6f\x59\xfa\xcd\x49\x5f\x0b\x46\x64\x76\x5a\x29\x14\x1a\x40\x22\xca\xca\x48\xc5\xdb\xf2\x3c\x5f\x64\x9f\xd2\x0b\x38\xd2\xe4\x57\xc0\xce\x5e\x09\xa6\xc1\xed\xb4\x13\xf1\xa7\x0c\xb6\x3e\x23\x45\x02\x3b\x03\x7d\xb8\x7f\x19\xbe\x03\x94\x66\x1b\x8d\xf1\x94\xfe\x3b\x2e\x73\x3e\xd5\xc9\x7c\xc9\x2f\xbb\x2b\xb8\x25\x81\x3a\xbe\x96\x2e\x88\xbe\xb1\x27\x9d\x4b\xb2\xc0\xbd\x92\x06\xb8\xaf\x94\x23\x97\x17\xca\x2f\xca\xb9\x71\x3f\xf2\x83\x7d\xe3\xbc\xeb\xb3\x77\x9c\x01\xbb\xd3\xc1\xcf\x8c\x94\x74\xc8\x79\x09\x7c\x92\xf7\x12\x32\xfd\x1a\xb6\x91\xe6\xd0\xf2\xfa\xd6\xbf\xc0\x32\x16\x26\x97\x99\x56\x0a\x10\x9b\x17\xf9\x65\x7f\xb1\x6b\xc1\x4f\x04\x0c\x8e\x53\x36\x05\x0c\xae\x23\x47\xe3\xe7\x06\x6b\x28\x14\xa3\x00\xbb\x1d\x6f\xb1\x3f\xef\x0e\xe2\xda\x6e\x41\x9d\xf9\x4f\x68\x4e\x9d\x5d\x5e\xf5\x67\x58\x06\x43\x34\xbe\x01\xaa\xe3\x87\xda\x1b\x66\x72\xa8\x59\x95\x05\x24\x9d\x26\xfd\x8f\x95\xd6\x96\x5b\x24\x7e\x1f\x4c\xd6\xeb\x6d\x4f\xda\xd0\xf9\xfd\xb9\x73\x09\x84\x61\xcf\x5c\x07\x2d\xd8\x37\x97\x02\x40\x77\x56\x34\x6e\xe7\xe6\x6e\x08\x1f\x10\xcb\xba\x9f\x49\x24\x1f\x1f\x18\xb2\x3a\x78\x1a\x0d\x7d\xdd\xc1\x76\x49\x5a\x1b\x09\xb1\x16\x54\x18\xa2\x7b\xdb\x21\xf5\xcc\xfd\xbb\xb8\x83\xb9\xcf\x1d\x60\x66\x20\x96\xa9\xeb\x0f\x40\xce\xda\x87\x0b\xe3\x22\xa0\x6d\xe8\xe9\x86\x2f\x33\x5e\x43\xdc\xe8\x65\xca\x9c\xc1\x8d\x5b\x26\xb5\xf9\xdc\xc0\x65\x5a\x69\xc9\x0d\x5e\x66\x1e\x80\xdd\xb8\x65\xe6\x2d\x05\xe3\x95\x39\xe9\x9a\x7d\xd0\xf1\xc8\xda\x77\x81\x09\x4a\x46\x79\x6f\x94\xdf\x47\x13\x89\x4c\xa6\xdb\xc8\xbe\x36\x41\xc9\x1c\xbd\x2f\x19\x95\xac\x85\x44\x29\x42\x99\xcc\xaa\xbe\x65\x55\x0b\x28\x65\x50\xb2\x16\xd6\xa7\x58\x64\x9c\xf5\x8f\xff\x3d\x04\x30\xef\x38\x57\xb2\x5b\x70\x35\x7f\x48\x2f\x6d\x26\xd0\xba\xa2\xa5\x23\xcb\x18\xbd\x8a\x5e\x77\x1f\xad\xf8\x01\x51\x82\xed\x83\x15\x3f\xa0\xdb\x3c\x78\xac\xe2\x87\x44\x17\x76\x1c\xaa\xf8\x21\xe9\xb9\x76\x1d\xa9\xf8\x21\x51\xbd\xe1\x03\x15\x3f\x24\xe2\x75\x9b\x48\x20\x7c\x98\xe2\x47\x34\x8f\xad\x47\x29\x7e\xf4\xf8\xae\xa4\x75\xc7\x31\x8a\x7f\x7d\x24\xda\x67\x20\x7e\x3c\x16\xc1\x43\x13\x3f\x3e\x12\xfe\xd1\x88\x1f\xdf\x17\xde\xc1\x88\x1f\x3f\x14\xad\x63\x11\x3f\x76\xba\x92\x87\x22\x7e\xec\x10\xf9\xf2\x48\xc4\x8f\x1f\x8b\xd0\x81\x88\x9f\x18\x16\xa0\xeb\xcc\xc7\x4f\xc6\x7e\x19\x56\x5b\x7e\x62\xc6\xe9\x1e\xa5\x78\x3c\x32\xcd\x9a\x93\x04\xc9\x63\xd1\x75\x90\x20\xd3\x34\xe7\x6a\xbf\x04\x41\x1e\xe8\x47\x2a\xdf\x3e\x63\x90\xf3\x40\x74\x1d\x31\xc8\xa4\xa5\x6c\x9f\x30\xc8\xa1\xde\xba\x8e\x50\x3c\x7e\x80\x4e\x7b\x9e\x6c\x37\x4b\x0b\xfa\xa5\x24\x01\xe4\xc5\xa2\x2c\xab\x3e\xac\xcc\x3f\x64\x83\x7b\xf0\x27\x10\x05\x98\x9c\x1c\x91\xb2\xc2\xcd\xcd\x68\x70\x50\x6c\x58\x57\x2c\xe0\x65\x26\x6f\xe3\x6a\xdc\x93\xe7\x45\xba\xb8\xaa\x73\x5f\x72\xa4\xd0\x92\x2d\x29\x92\x16\x44\xf2\x12\x93\x64\x3d\x6e\xc8\xbb\xf2\x3b\x1b\x0c\x7d\x01\xde\xf7\x2d\x6b\xf3\x53\xb0\xaf\xf8\xf4\x4c\x86\x7c\xff\xd4\xa0\x1f\x93\xd3\x11\x7c\x33\x2e\x41\x0f\x29\x63\xc1\x32\x72\x8b\x6f\x99\x0e\x75\x3e\x19\x31\x2b\x48\x50\x44\x95\x34\x15\x98\x2a\xa3\x01\xe8\x76\xe8\xf7\x2a\x25\x2c\xc9\x48\xd4\xc3\xac\x40\xa7\x50\x32\x37\x41\x07\x2a\xe4\xf5\xcc\xea\xb1\x55\x66\x4c\x2f\xe4\xbf\xa5\x75\xe3\x4c\x25\xc0\x5c\xb5\x7a\xc6\x20\x6f\x39\x30\x11\x3f\xa6\xc0\xdc\x01\xa9\xea\xc8\x10\x32\xf4\xbd\xdd\xae\x63\xeb\x1f\xea\x8a\x9f\xd8\x8f\x1e\x6a\x4d\xa2\xab\xe4\x72\x81\xcf\x8d\x30\xc8\x7e\x33\x5c\xa6\xab\x7e\x3b\xbe\xca\x75\xa4\xc1\xae\x37\x45\x3a\xb8\x87\x6a\x79\x11\x5a\x19\xab\x74\xe4\x0e\x44\x74\x52\x36\xe9\xa2\x97\x17\xb2\xa3\x1e\x3a\xcf\xeb\xf5\x97\xf5\x20\x8a\x0b\x8c\x9f\xac\x32\x06\x22\xd2\xa3\xe9\xd1\x16\xfa\x45\xb3\x1f\xa1\xa2\x32\xbc\xb5\x57\x56\xba\x5e\x16\xd1\x5b\xd3\x12\x00\x90\x8e\xc7\x12\x6a\xf6\x1e\x8e\x1d\x9f\xc0\x44\xf4\xd1\x6a\xb4\xa3\x1a\xf7\x60\xea\x28\x64\x51\xc7\x32\x09\x38\xe1\x81\xdc\x9f\x37\xc5\x4f\xee\x8f\xae\xf8\x13\xfb\x43\xae\x8f\x7b\xcf\x7a\x53\x83\x1e\x5a\x9b\xf3\xa6\x6b\x5b\xf0\xb3\x63\x4e\x42\x0d\x60\x51\x5e\xf6\xe5\xf6\xb2\x5f\x44\x41\x63\xa6\x94\x13\x48\x80\xc1\x0c\x9b\xf2\x75\xfe\x23\x9b\xf5\x8f\x06\x07\x51\x6f\x09\x87\x9e\x60\xdd\x9e\xae\x9c\xd9\xdb\x34\xe4\x4e\xa5\x63\x11\xc4\xde\xc8\x84\xfc\xfa\x5d\x0b\xf0\x57\x38\x75\xa8\x4a\x65\x66\xcf\x73\x0f\x4e\x5d\xee\x26\xd7\xd9\x65\x2b\x85\xbb\x57\xd3\x61\xe7\xdc\xc9\x29\xd8\xef\x5c\x58\x1a\x1c\xe0\xe0\xbb\x02\x19\x5e\xc1\xbb\x83\x17\x57\xbc\xde\xe8\xf5\x3f\x2d\x87\x6f\x5e\x7e\x79\x7e\x72\xf2\xf1\xcd\x9f\x3e\x9f\xbc\xfa\xf2\xee\xf9\xdb\x57\x67\x09\x9c\xec\x99\x60\x35\x23\x54\x5d\x40\x69\x52\x33\x4c\xab\xcb\x3a\xf1\xf4\x76\x33\x4a\x45\x49\xe5\xef\x5f\x81\x2f\x15\xb0\x92\xd5\xec\xaf\x55\x1e\x88\xf2\xa2\x7c\xd8\xb4\x17\xe3\xb4\x13\xa5\x1f\x8e\xcf\x86\xdf\xb1\xb5\x7a\x52\xa2\x72\x3a\xfe\x77\x73\x03\x97\x0c\xfe\x60\x55\x8d\x6b\x9c\x5b\xdc\xb0\x6b\xd0\x02\xe3\x4e\xd6\x28\x6e\xd8\x08\x79\x61\xb4\x44\x5b\xed\x18\xd1\xda\x59\x13\x86\xd4\xcd\xf1\x1a\x49\x74\xf8\x4a\xa5\x2f\x52\x3f\xcb\x27\xf9\xc1\xc1\x40\x2a\x88\xe8\xfc\xd3\xfc\x4c\x0a\xdc\xc4\x4a\x5c\x90\x8e\xb6\x0c\x0b\xf1\x2e\xfb\x8e\x34\x85\xa1\x0e\xf0\xa5\xff\xe6\x26\x0a\xc8\x01\x29\x6b\xd0\x79\xcb\xc8\x89\x6a\x44\x89\xee\xbc\x35\xde\x8e\x8d\xea\x2a\xfa\x3a\xc1\xa3\x52\x93\xbf\x6f\x5a\x36\xfc\x65\x3d\x97\xd0\x77\xa3\x76\x31\x46\xf7\x8e\x17\xc9\x1a\x7d\x26\x24\x85\x1d\xbd\xb3\x0c\x5d\xb3\xdb\xb7\x49\xb7\x8a\xed\x1d\x5e\x88\x15\xad\x45\xd0\xc2\x8f\xa3\x52\x44\xb7\x12\xca\x58\x8e\x9e\x84\xbb\xc6\xb8\x90\x7d\xb1\x4b\xb2\x37\x4b\x20\xc6\xde\x14\x4d\x89\xaf\x00\xbc\xa4\x32\x46\x7c\x2a\xd5\xc7\xcb\xd3\x31\xec\xd6\x74\x68\xc3\x69\x7f\x0e\x60\xb1\x00\x80\x1a\x49\xbf\x2c\x3b\x98\x1f\x62\xdb\xc7\x58\x43\xc7\x31\x08\x9e\x50\x7e\xa7\x80\xe3\x77\x51\x95\x4b\xa2\x2d\x29\x8c\x81\xfe\xb2\x73\x94\x75\x31\x39\x19\x34\x65\xe5\x6f\x93\x6a\x97\x33\x2f\x97\x5c\xd6\x7c\xbb\xb9\x56\x9d\x25\x19\x6b\x9a\xf6\xf9\x3b\xc1\x85\x39\x75\x72\xcf\x08\x02\xec\x75\xca\xb4\xb1\xa4\x90\x08\x65\x41\x16\x92\xb1\x57\x0e\xd7\x85\x96\x94\x9f\xc3\x4c\x38\x86\x1a\x58\xaa\x8c\x9f\x4b\x4a\x31\x1e\xe8\x1b\x64\xb5\xd1\x90\x12\x78\x91\xd8\x63\x60\xf1\x9c\xce\xa1\xcb\xaa\xfd\xfd\x96\xdf\x28\x99\xdc\x1d\x98\x65\xcf\x3a\x68\x1e\x34\x4d\xd8\x20\xc1\xef\x49\xef\x75\xdc\xf2\x60\xb2\x4c\xb6\xf4\x84\xf5\xc4\xb7\x60\x73\xe2\x12\x91\xa0\x21\x93\xc5\xd5\x5d\x91\x22\x9e\xad\xe5\x71\xd5\xbf\xe2\xbb\xb1\x16\x33\x58\xd0\xf8\xdb\xfe\xfe\x25\xe3\x8a\x51\xf7\xb9\x56\x67\x66\x39\xc0\xea\x3c\x7c\xa8\xbe\x60\x2f\x72\xa8\x17\xfd\x8d\x41\xf8\x55\x02\x8d\x95\xab\xfe\x60\x72\x79\x7a\x69\xba\x3e\x48\x16\x02\x6b\x6a\x6c\x84\x95\x0f\x5f\x0d\x28\x51\x63\x25\x6a\x91\x55\xe7\xda\xe9\x6a\xe3\xaf\x6c\x0f\x85\xf5\xe9\xec\xcc\x78\xfc\xdf\x16\x33\x45\x90\x37\x32\xb9\x1d\xf4\xfb\xd8\xfa\xdd\x55\x2b\x8e\x9e\xe2\xd6\xa1\x2f\xb9\x95\x1b\x85\x43\x1a\x51\x06\x5c\xb2\x74\xf2\x4e\xf1\x93\xdd\x4d\x76\x3d\xbe\x29\x1e\x3f\xbe\x8f\x3c\x62\xcb\x7b\x84\xcb\x16\x6a\xff\xb8\x70\x1d\x05\xcc\x9a\xe5\x03\x0d\x39\xc7\x6a\x0e\x92\xca\xa0\x5f\x63\xfd\xe2\xaa\xd7\x99\x06\xe1\x92\xeb\x6c\x11\x65\xa5\xca\xb7\x18\x05\xc7\x2c\xe5\xfd\x3b\x50\x3f\x50\x69\x3b\x84\xf5\x1a\x79\x4b\xe5\xb3\xb8\x12\x74\x27\x4f\x4f\x19\x4f\xc0\x8d\x2d\x11\x06\x5d\xce\x4c\x70\x6c\xd0\xb6\xba\x3d\xd4\xd2\x19\xaa\x50\xca\xeb\x93\xca\x0c\x56\xeb\xa0\x97\x14\xb2\x13\x2e\xec\x1a\xdf\xb7\x4b\x0b\x22\x4b\x8b\xad\xd1\x3a\xa1\x18\x0c\xb2\x97\x0f\x9a\xa4\x74\xc1\x2e\x3d\x53\x71\x2c\x44\x81\xcc\x75\x41\xbc\xf5\xb5\x43\xa8\x02\x7d\x61\x2e\xdc\x91\x30\x37\xf1\x48\xdd\xbd\x23\xbe\x7a\xe1\x4a\x85\xde\x39\x0d\x5a\x46\x57\x89\xd0\x9c\x4c\x38\x48\xac\xac\x81\x3d\x62\xab\xa8\x4e\xc3\xd2\x76\x81\x81\x3d\x2d\xab\x82\x4e\xc3\x0a\x76\x01\xb2\xa5\x21\xf4\x60\x95\xa6\x04\x2c\xa9\x73\x58\x86\x3e\x55\xea\xb3\x0d\x87\x44\x75\xc7\xf2\x0c\x9d\x34\x4d\x79\x87\x0b\xdb\xb1\xf2\x74\x58\xc3\x19\xea\xbb\x90\xac\x39\x03\x5d\xff\xd0\x62\xf3\x80\xe6\x98\xb6\x94\xe2\xb4\x05\x3f\x46\x2d\x81\x25\x84\x2d\x2f\xcd\x96\x97\x6a\xcb\x73\x14\x99\x9f\x96\x67\xa8\x4f\x44\xae\xdd\xac\x4d\x9f\xda\x9b\xde\x90\xdf\xb5\xb4\x3f\x1d\x18\x00\x58\xe1\xcc\x16\x03\xa9\x78\x99\x9f\xae\xce\xb8\xd1\x0b\xc0\xbe\x0e\x44\xac\xce\x26\x45\x72\xc1\x5e\x89\x81\xb6\x7d\xd6\x8b\x0e\x74\xfc\x2a\x51\x61\x88\xa0\x8a\x7c\xae\x79\x30\x52\x30\x0d\x6a\x41\x82\x35\x24\x68\x14\x86\x84\xf5\x88\xbf\x39\x48\xdc\x3c\xbc\x6d\xe5\x8e\x98\x82\x72\xaf\xac\x1c\x69\x23\x31\x57\x9b\x45\x1e\xf3\xaa\x81\x6e\x96\xf6\x69\xce\xfb\x84\x89\x7a\x9f\xe6\x5b\xf7\x09\xab\x1e\x32\xe3\x05\xbb\x33\x77\xb4\xf2\x0c\x3d\x03\xa7\x51\xbe\xd9\x7e\xcd\xae\x6a\xa0\x07\x24\x66\x80\x2d\xab\x39\x70\xbd\xd9\x8c\x2c\x74\x02\x4b\x1e\xed\xb5\xd1\xd2\xde\x1b\x8b\x14\xb6\x3a\x7d\x5a\xa8\xad\x4e\x51\x27\xfb\xa2\x8f\x6a\xb1\x05\x1e\xcd\x1c\x89\x91\xf7\x17\xe4\x2d\x35\x47\x2b\x95\xf3\x2a\x4b\xbf\x6e\xf6\x72\x34\x02\x90\xeb\x52\x9e\x3d\x1b\x21\x35\x83\xfe\xf5\xd0\xa7\xb3\x46\x2b\x96\x6a\x9b\xff\xec\xbf\x4e\xc6\xc3\x23\x14\x61\xb5\x49\x47\x0c\x9c\x80\xa7\x40\x39\x55\x10\x6f\xde\x7d\x7a\xf5\xf1\xe4\xcb\xdb\xe7\x1f\xff\xf2\xf9\x43\x2b\xf7\xed\xfb\x7f\x7c\xf5\xe5\xd5\x3f\xbd\xf9\x84\x91\xe9\xe2\x08\x15\xf7\x22\xf1\xf1\x15\x25\xbf\x7b\xff\xf2\x15\x7a\xdf\xe7\xc4\x93\x57\xff\x74\xf2\xe5\xc5\xfb\x77\x27\xaf\xde\x9d\x70\x33\x16\x91\x16\x89\x80\x8b\x1b\x49\xe0\xf4\x52\xe5\xd3\x2f\x0a\xf9\x8f\x91\xee\x61\xec\x52\x2d\xff\x2d\xaa\x25\xf2\xbd\x53\x47\x41\xff\x2a\xfe\xcc\x76\xf2\x41\x12\xc9\xd0\xd0\xec\xa6\x27\x20\xd3\x8a\x4b\x11\x10\x22\xc4\xb9\x70\x58\x5f\xb8\x34\x6c\x06\x33\x2e\x02\x8e\x37\x42\x81\x84\x9e\xec\xec\xea\x42\x12\x98\x1c\x3a\xcb\x33\x61\xb4\x83\x67\x99\xf0\x3e\x46\x49\xed\x1a\x20\x1e\x9d\x32\x57\xd9\x05\x3b\xc5\xcf\x13\x9f\xbd\x45\xcb\x2d\xe5\x0b\x82\x98\x6e\x56\x7c\x82\x8a\x2a\x76\x28\x54\xf6\x82\xa5\xaa\xc0\xa1\x2a\x90\xa8\x13\x73\x35\xdf\x4c\x2c\xd7\x73\xc9\xf5\x97\xbc\xb6\xd5\x70\xc8\x39\xb4\x7a\x4d\x55\x21\x4b\x9d\x41\x49\x4f\x9a\x35\x6a\xa4\x6c\xa4\x67\x41\xd8\x23\xd2\x2c\xb7\x9d\xe0\x2e\x92\x6f\x65\x3e\xeb\x49\x4d\xf4\xec\x42\xfa\xa9\xc5\x9f\xb2\x16\x66\xc0\x44\x38\x03\x35\xd7\xf0\x8b\x8e\x75\xcd\xfe\x8d\x5b\xce\x8d\xeb\xc1\xfe\xfe\x5e\x19\x4a\xed\xaf\x4f\xeb\xb3\xa4\x81\xff\xf8\xe2\x59\xb5\x78\xed\xc3\x23\x1c\xde\x38\x41\xd7\x9e\x6b\xad\x72\x97\xa4\x9a\x40\x5d\x3d\x1b\x1b\x24\x72\x91\xb0\xba\xdd\x0a\xdf\x31\x47\x93\xd5\xb3\xf9\x64\x0e\x38\xe4\xe2\x74\x7e\x66\x5a\x3e\x9d\x1f\x1c\x9d\x4d\xac\xc6\x2e\xc8\x6f\x31\xb9\x80\xb4\x42\xc8\x29\xa3\x64\x37\xd5\x4c\x74\x36\x08\xe9\x10\xe3\x84\xd4\xbc\x66\x34\x2f\xcb\x8a\x10\xef\xb7\x29\x30\x43\x95\x21\x32\xf4\xaf\xf5\xc0\xec\xa0\x54\x7f\x4c\x42\x32\x38\x67\x8f\xad\x80\x79\x99\x25\x84\x53\x30\x47\x2d\xa2\x26\xfe\x73\x74\xc5\x4f\x27\x93\xe3\xe5\x85\x7c\xfc\xc8\x01\x32\x71\x96\xe1\xa6\x8a\x8c\xb6\x5d\xc7\xb0\xcd\x34\x70\x0a\x3b\xd6\x20\x74\xe2\xc6\x6a\x0c\x8c\x7b\xaf\xbf\x87\x31\x8e\xa1\x05\x17\x70\xcd\xa0\x37\x6d\xa7\x89\xce\x21\xbd\x2d\xbe\x9d\xaf\x5a\x76\x07\x87\x23\x52\x31\xd2\x44\x3c\x93\xe6\x29\x7c\xab\x74\xc4\x67\xe7\x63\xd2\x32\x73\x85\x19\xd6\x50\x96\xd4\x22\x99\x0b\x54\x9e\x3a\x69\x49\x31\x32\x45\xab\x04\xaa\x4c\xe5\x7d\xc0\x9d\x30\xb5\x2f\x50\xe8\x8b\x9a\x8b\xf8\x05\x29\xeb\x1e\x01\x2a\xb9\xc3\x55\xe6\xac\x1c\x39\xae\x37\x4f\xbf\xa1\x95\xe9\xba\xc8\xff\x6d\x9d\xf5\x30\x08\x53\x44\x66\xa9\xc3\x5f\xc8\xcb\xb1\x6f\x58\x4a\xba\x5c\x2a\xec\xc1\xfe\xbe\xee\xb2\x80\x73\x01\xcb\xe2\x76\x1d\x91\x9c\xa3\xc7\xb1\x1f\x6a\xa7\xc7\xa2\x2c\x0e\x65\x9d\x1e\xde\xfe\xbd\xba\xec\x95\xf8\x22\x8b\x6e\xdb\xf2\x1a\x86\x90\xd5\xf8\x96\x36\x1b\x46\x5e\x24\x86\x9c\xdd\xc2\x9b\x18\xcf\xa8\xb2\x9f\xba\x44\xb8\xa8\xd1\x45\x6e\x0a\x88\x6a\x8e\xb1\x35\x91\x42\x6b\x79\x34\xae\x81\x00\xa0\x23\x86\x4e\xf2\x0f\x92\xfc\x38\xea\x91\xb7\x8c\x5e\x33\xd7\x8f\x10\x4b\x8a\x9a\xd9\x83\x33\x19\x1d\xe4\x18\x5a\x33\x6e\x17\xb2\x9e\x4d\x80\xbd\x96\x8e\xe7\x9e\x46\x07\xe9\x41\xf4\x6c\xa8\xfc\x94\x13\x8e\xac\xe4\x21\xd8\xdf\x57\xbf\xd0\xdb\xb0\x02\x19\xf2\x33\x5c\xdd\xc2\x74\xe2\x48\xa3\xde\x9b\xa6\xf7\x3d\x85\x35\x42\x6d\xa5\x19\x6c\x1e\x6f\x2e\x8a\x7e\xd8\xbf\xf9\x10\xdd\x01\x61\xc1\x4f\x59\xd6\x9b\x37\xcd\x2a\xbe\x77\xef\xe2\x7c\xb8\xcc\xee\xd1\x66\x1d\xca\x0d\x3a\xa4\x85\x07\x64\xd4\x5b\x02\x2c\x01\x70\x10\x5b\x49\x8f\x65\x91\x00\x6c\x26\x0c\x3d\x1a\xd7\x46\xb9\x96\x8e\x4c\x3c\xdd\x18\xe9\x2e\xb6\xd7\x6f\x06\x1b\x9b\xce\x53\x47\xa2\xc0\x08\xbc\x51\x34\x99\xb5\xa3\xa2\x02\x20\xcf\x38\x6c\x86\xb8\x50\x70\xc4\xb0\xf2\x65\x99\xae\xbe\x28\xdc\x1a\xd9\x40\x58\x6b\xb3\x0e\xcf\xda\x7a\x30\xd8\xe2\xb4\x4b\x42\x0a\x71\xa2\x53\x3f\x2a\x6c\x0e\x70\x5c\xf5\x73\x94\x3d\xa9\x0b\xa1\x55\x06\x9a\x0f\x9e\x39\x7d\x85\xc0\x41\x6f\xc7\x38\x19\x5c\xc3\x3a\x68\x6a\xb5\x66\x3f\xdd\x65\xbf\x16\x19\xc0\x9d\x70\x16\x6c\x6d\xa4\xda\x77\x71\xf5\x4f\x51\x14\xd9\xe1\x7f\x1f\xdd\x83\x67\xd0\xc0\x66\x8a\xb2\xe0\x7e\x8a\xf4\x6d\xba\xc9\xf5\x5b\x17\x8c\x88\x4c\xd0\xe1\x22\xed\xe7\x00\x0c\x75\x0d\x34\x2a\xf6\xb1\xc4\x5b\x74\x79\xaa\xd3\xdc\x1d\xb9\x48\xf3\x45\x36\xfb\x32\xcb\x58\x17\xac\xac\xbe\xe0\xf4\xbe\x90\x07\x94\x48\x5c\xcb\x3a\xb1\xae\x8d\xaf\x64\x92\x03\xbc\xcd\x02\xba\x1d\x68\xd3\xb5\x87\xf6\xc8\x28\xa9\x7a\xd4\x8a\xdb\xd1\xb6\x01\xb8\x6e\xe1\x41\x96\x6a\x77\x60\x2a\xc8\x44\x4f\x73\x48\xd5\x48\xef\x46\xf7\xfe\xf9\xef\xb3\x83\xff\x7a\x4f\x5c\x26\xd7\xce\x65\x19\x78\xd2\x9a\x7a\xd7\xa9\x25\x1d\xd3\xe4\x82\xd6\x32\xb7\xa4\x85\x8d\x09\x23\x9b\x1c\x01\xc0\xb6\x5e\x08\x10\x70\x6b\xeb\x61\xa0\x38\x13\x1c\xf7\x26\xd3\xd2\x1a\x1b\x35\x4c\xd8\xca\x9f\x4c\xb7\xf7\xf7\xd7\xe8\xc7\xdf\x24\x08\xe5\x6f\x7e\x41\x7f\x51\x0f\x5f\x5e\xc3\x4e\x79\x3b\x4d\x98\xf0\xd0\x50\x4b\x05\x8a\x36\xbc\x90\x70\xe8\x8c\xc0\xc2\x5c\xde\x8d\xce\xb0\xe9\xf3\x4b\xfb\xf2\xbe\x4b\x20\xda\xee\xd0\xad\x1d\xf1\x53\xfd\x2b\x7f\xbb\x3b\x13\xe7\xca\xd7\x9e\xdd\x52\x0c\x33\x3c\xf0\xc4\x63\x53\xc6\x6c\x9e\x24\x4a\x32\x56\x98\xe9\x45\x0a\x52\xf2\x0f\xcc\x21\xe9\x92\xa3\x39\x61\xce\xcf\xba\x6d\x03\x33\x45\x98\x5d\x28\x1d\x2b\x57\x89\xd3\xd9\x97\x54\x1b\xbe\x98\xb0\xa4\x9b\x0d\xaa\x74\x77\x86\xe0\x66\x66\xcb\x6b\xb3\xb0\x42\x14\x2f\x44\x5e\xfb\x75\x72\xd1\xd5\x5a\x15\xd0\xdb\x0e\x6d\x66\xcb\xcf\xcc\x93\x5d\xa2\xd6\x5e\x53\x84\x6c\x67\xca\x8a\x0e\xdb\x04\xc2\xbd\x3e\xd9\xdd\xea\x18\x1a\x52\x51\xa2\x48\x7f\x87\x6c\x4f\xb5\x87\x47\x4a\x92\xc1\xa4\x6c\x05\x52\x57\xe3\x9a\x18\xc1\x6b\xb6\x10\x39\x91\x4e\xf9\xdc\xc7\x44\xe2\xf8\xd8\x28\xb0\x42\x5b\xbc\x4a\x69\x39\xd5\x3a\x7b\x52\x00\xb8\x39\x93\x29\x2d\x97\x7d\xa6\xaf\xf8\x11\xae\xda\x78\x74\x97\x88\xb6\x7c\x6c\x8d\xbf\x2d\x51\x24\xf4\xc2\x6d\xd4\x99\x5e\xbe\x06\x1a\x83\x1f\x2b\xe0\xbe\x07\x96\x77\xd1\x19\xa2\x0b\xcd\x32\xb9\xad\xd7\x79\x55\x37\xea\xdd\xae\x5f\x99\xe0\x22\x2d\xc2\x97\x99\x5d\xcb\x5f\xa1\x62\x7a\x0b\xd2\xdb\xa6\x29\x2a\xe6\x97\xde\xf2\x01\x86\xeb\xe4\xf4\xac\x4b\xdc\x1b\xea\x7f\x0e\xc4\xb3\xd5\xdc\x00\xa8\x10\xb6\x02\x45\xcb\xd5\x49\x35\x81\x7b\x5e\x37\x2d\xe5\x5e\x64\x1f\xde\xb7\xe2\x7e\x97\xc9\x88\xbc\xaa\x98\x82\x12\x65\xe7\xcf\x4a\x96\x2d\x36\x76\x2e\x46\xe3\xe1\x5d\xd5\xbe\xd2\x98\x26\x5a\x2a\xeb\x26\x05\x0e\xc8\x3a\x59\xd3\x47\x9e\x5b\xb8\xc3\xdd\x78\x68\x43\x1a\xb9\x4b\x23\xd7\xc1\x24\x43\x3a\x8c\x3b\x33\x20\x68\xe9\x9b\xee\x64\x98\xf9\xa1\x04\xaa\x6e\x46\xda\xf0\x9e\xd1\x5e\x5b\x15\xf5\x8f\x72\x41\x88\x58\x86\x5c\x4b\x92\x53\x04\xa3\x1a\x0c\x1f\x9f\x8b\xf3\x12\xd9\xe4\xd9\xa7\x69\x55\x2e\x16\x1f\xa4\x96\x27\xc6\xcd\xe8\x57\x96\x75\x0b\x60\x31\x45\x33\xb7\xdd\x69\xda\x50\xc5\x66\x24\x3e\x60\x99\x54\x7f\x5f\x93\x11\xd2\x07\x6b\x34\x74\xc5\xa5\x81\xfb\xe2\xa4\x84\xfb\x72\x3d\x6c\xbe\x97\xcf\xe5\xfd\x4c\x6b\x56\x29\x6b\xee\xeb\x2f\xac\x13\x46\x51\xbc\xbc\x4d\xe6\x40\x12\x7f\x7d\xf3\xee\xe5\xfb\xbf\x7e\xf9\xf3\xf3\x77\x2f\x7f\x7b\x15\x5b\xc6\xac\xc7\xbc\x95\x5c\xaa\xce\x9a\x3f\x77\x21\x8c\xc1\x75\x0b\x7e\x92\x6c\x23\xc8\x4e\x97\xfb\xf6\xca\xca\x21\xa1\x17\x0e\x60\xb8\xeb\x56\x29\x8d\x2d\x4d\xd9\x8d\xf0\x3d\x8a\x76\x58\xf6\x50\xcc\xa1\x4a\xd1\x36\xa9\x8c\x9a\x46\xfe\x9f\x97\x44\xa5\x20\x4d\x4a\x0d\x38\x74\xc0\x80\x3b\x90\xf1\x21\xef\xd4\xc3\x94\xeb\xec\xd2\x85\xbc\xfb\x19\x7c\xd8\xda\x31\x24\x16\x71\x08\x14\x3d\x05\x89\x1d\x30\x3c\x6e\x89\xe1\x6e\x01\xef\xb5\xf2\x80\x59\xcd\xff\x1d\x83\xc6\x0e\x58\x3b\x42\x8f\xc4\x0b\x4e\x82\xaf\xac\x7a\x6d\x95\xd0\x84\xa3\x12\xd2\x91\xa3\x52\x44\xd3\xaf\x86\xae\x41\x55\xbf\x24\x26\x58\x47\x4a\xaf\x80\x90\xc0\xa0\x81\x68\x0a\xe5\x5c\x07\x4b\xeb\x3a\x30\xca\xb1\x0f\x9f\xdc\xa6\xc8\x1c\xb4\x9e\xb2\x11\x41\xfc\xeb\xe8\x67\x14\x69\x83\x06\x58\xde\x61\x8f\xc7\x8f\xc6\x62\xfb\x59\x87\x22\x8f\xe8\x42\xdb\x39\xa0\xab\xab\xbc\xda\x7d\x23\x07\x4c\x15\xee\xec\x75\xd8\x21\x8f\xc2\x1e\xa4\xbc\xa8\x89\xb6\x7d\xb4\x67\x95\xe4\xa1\x5c\xa9\x34\x6b\xe3\x59\x5b\x7b\xbf\x0b\xd7\x5e\x1b\x72\xad\x34\x5a\xb0\xa2\x3d\x17\xe0\xdc\x4c\xb6\xb5\x68\x71\x61\xa5\x7b\x04\x60\x6a\x67\x39\x4b\x1a\x57\x7e\x96\x9c\x73\x6c\xe9\xe2\x0a\x6f\xc6\xf1\xda\xca\xc3\xf9\xc6\x53\x2b\xc1\x18\xf5\x2c\xac\x54\x65\x68\xb8\x32\x69\xf6\x31\xb8\xe8\x7c\x83\x6f\x13\x4a\xbf\x33\xb0\xc9\x2d\x56\xaf\x1e\x70\xc4\x4f\x4c\x96\xbf\xf1\x70\x66\x9e\x84\xdf\xfc\x5b\x1a\xe5\xe3\xc7\xc1\xc3\x45\x47\xe4\x2e\x21\x5e\x15\x2d\xd6\xd7\x1e\x14\xd4\x0f\x49\x91\x63\x84\x32\xdf\x30\x56\xeb\xf8\xb3\xad\x8a\x3c\x43\x53\x26\x00\xc9\xd3\x8b\x39\x41\xda\xf9\x8b\x39\x33\x70\xcc\x9f\x4f\xe9\xde\xb5\xbc\x75\x03\x61\x5c\xeb\x46\xe1\x3e\x48\xcf\xf3\x45\xee\x05\x42\x33\xe4\xfc\xfe\x7e\x3f\x7a\xf3\xee\xc3\xe7\x13\xd2\xe9\x22\x97\x14\xc8\x03\xef\xef\x73\xdc\x69\x4a\x44\x9a\x00\xc8\x2c\x7c\x24\x7b\xfe\xf1\xd5\x73\xb7\x24\x64\xa0\xfb\x3e\x4e\x9c\xf2\x8b\xd9\xab\x59\x4e\x4a\x92\xac\xd3\xaa\x07\xf3\xc6\xc8\xc5\xda\xe6\xe4\x28\xe0\x91\xfa\xa9\x34\xd3\x8c\x44\x46\x71\x26\xb4\x23\x0a\x72\x8d\x11\x53\xf0\xe1\xe0\xfc\x60\x5a\xc7\xb5\xeb\x82\x24\x1b\x18\xcf\xc4\x24\x73\xd2\x59\x21\x37\x5b\xec\xb1\x64\x68\x75\x8f\x3b\x32\x74\x07\x30\x69\xd0\x97\xd6\xfe\x3e\xd2\xb1\xe8\x2a\xaf\x7b\x38\x98\xcf\x4e\xcb\xf4\x78\xc8\x69\x4d\x0e\x39\xde\xca\xb4\x47\x43\x3a\x7a\xba\x67\x76\xde\x42\x52\xaf\x26\x91\xee\x6c\xac\x81\x51\x36\x79\xb6\xb1\x12\x5f\x15\xb3\x8d\x96\xaa\xb5\xdd\x7a\xc0\x0e\x07\xf6\x5d\x5d\xa5\xb7\x39\xc0\x99\x14\x52\xe7\x4c\xc9\xf5\x06\x09\x7b\x4b\xd0\xc3\x3b\x2c\x3a\xfc\xd3\x1c\x4a\x2f\x05\x92\x24\x1c\xd0\xb8\x65\x69\xdf\x29\x8d\x5f\x76\x23\x25\x8b\x0d\xdf\xf5\xd2\x05\x49\xdf\x12\x83\xdc\xdc\xc8\xfe\x47\xd4\x2e\xd0\x9b\xa2\x0e\x2f\xb4\x15\xe3\x4c\xfa\xa2\x29\xd9\xe3\x0e\x2d\x7d\xe0\x35\xa9\x84\xe9\x95\x09\xb0\x63\xc1\x7d\xf1\xb7\x23\x29\x84\xbb\x19\xc6\xf7\x4d\x29\xbc\x69\xfd\xe4\x36\x21\xe7\xc4\xbb\x82\x26\x41\x6a\x67\x72\xed\xff\xa8\xbf\x37\x02\x68\xeb\x76\x13\x94\x07\xd7\xbc\x3c\xa4\x2c\xed\x08\x88\x55\xc5\x86\xb5\xb5\xdc\x24\x71\xed\x70\xac\xea\xa0\xb4\xf8\x31\xa1\x61\x07\xa1\xc5\x63\x76\xaa\x60\xf0\x59\x3c\x7e\xf8\x50\x84\xd0\x19\x64\xfc\x4a\x88\xf8\x27\xcc\x76\x2e\x0e\x32\xe3\x5f\xea\xfe\xa3\xb6\x0f\x54\xcb\xfd\x77\x5a\x3d\x6f\x80\xdd\x83\x25\xbe\xb8\xb9\x69\x68\xa5\x79\x67\x3c\x7e\x58\x45\xee\x64\x35\x59\x5d\x73\x44\x35\xe9\x81\x8a\x13\x32\xad\x94\x37\x00\x64\x71\xd1\xd2\xa9\x91\x5d\xf3\xbb\xae\xd2\xa3\xc8\x48\x7a\x0e\xc7\x58\x03\xbb\xab\xec\xa1\xc6\x7b\x0c\x60\xb5\x3e\x87\xb9\xf7\x47\x58\x36\xad\xf9\x2a\x83\x16\x2e\x06\x83\x38\x8a\x42\x22\xfe\x55\xbf\xa4\xf6\x4b\x0a\x32\xb3\xea\xf3\x38\xd0\xdb\x89\x25\x47\xcd\x2c\x39\xaa\x1a\xc4\x01\x7a\x5a\x2b\x26\xe9\x53\xe5\x2c\x65\x7f\x7f\x0f\x07\x99\x0e\x48\x1f\xc4\x48\x1f\xf5\x90\xd2\x81\x27\x8b\x57\xa7\x4c\x83\xbf\x6a\x5b\x34\x1a\xfe\x95\x5e\xc9\x40\xad\xb0\xe5\x2f\x70\x44\x8a\x28\xc5\xb3\x24\x55\x2a\x28\xb8\x81\xa9\x5c\xad\x74\x30\xc8\xad\x07\x68\xbd\x05\x29\xae\x7c\x63\xbe\x06\xa4\x9d\x22\xe3\xe8\x5a\x2b\x98\x1b\x65\x57\x58\xa3\x1a\xdd\x18\x9b\xf1\x4f\x2d\x15\x82\xb5\xb4\x18\x88\x22\xf4\x15\x43\x7f\x57\x1c\xa0\x75\x20\x9f\xa6\x72\xdc\xbc\xc1\x64\xd5\x9f\xde\xdc\xc8\x05\xd6\xd3\x58\x90\xab\xed\xe9\x71\x1a\xd7\xc8\xa7\x4f\x26\xf3\xe4\x02\xf5\x9b\xe5\xf3\xc3\x92\xa2\xb0\xef\xef\xcf\x19\xb2\xd6\xfc\x0b\x7a\xe9\x2f\x93\x02\xca\x4d\x05\x5c\x19\x02\xbd\x6f\xef\x8d\x6f\x6e\x28\x4f\x4e\x68\xd5\x5f\x1c\x1c\x3c\x9d\xc9\x97\x82\x5b\x68\x5b\x5b\xd6\x79\x91\x44\xc3\x08\xfd\xad\xa9\xdd\x98\x25\x68\xf8\xb7\x54\x72\x7a\x4b\x56\x15\x60\x6c\xd1\xfd\x5b\xc8\x2e\xbc\x4f\x4e\x2d\x4d\x86\x5d\xd9\x39\x75\x07\x0d\xdd\x80\x41\x89\x98\x73\x1b\x2a\x6d\x80\xd6\x59\xe3\x61\xa3\xc2\x01\x5f\xdf\x99\x3e\x49\x17\x62\x6c\x20\xf3\xd9\xe1\xd8\x3e\x31\xcd\x20\xd6\x8a\x98\xec\xed\x14\xd8\xe6\x6f\x59\x55\x03\x1e\x54\x96\xab\x2d\x03\x09\xf3\x44\xca\x10\x3d\xc1\x18\x8b\x30\x2a\x84\x8f\x9c\x0a\xec\x8d\x05\x21\x5b\x56\x73\x9e\xe2\x23\x98\xc0\x67\xa4\xbd\x11\x64\x0d\x4c\x27\x27\xdf\xcb\x0f\xf3\xb4\x6e\xdb\x3e\xe0\xdd\x39\xed\x03\x50\x71\x97\x5c\x4f\x60\x07\x51\xc4\x29\xd4\x83\xd5\xd4\x73\x25\x5b\x69\xb5\xd5\x6a\x67\x23\xbe\x28\xf1\x1d\xd0\xc8\xc0\xc4\xab\xba\xb0\xd6\x6b\xca\x7b\x07\x17\xc8\xcb\xac\x9e\xc2\xf5\x97\x92\x7c\xb9\x16\x79\x6d\x4a\xbd\xbf\x88\x73\xf1\xe9\xd5\x87\xe7\x1f\x9f\x9f\xbc\xff\x18\x5f\x04\xf8\xe4\x0e\xc2\xba\x25\x7f\x1e\x8f\xb6\x47\x67\x73\x5d\x54\xd2\xfe\x47\x2a\xcd\xf2\x0e\x67\x1e\x29\xbb\x1f\xf7\x8a\x81\x12\x79\x34\x32\x54\x6d\xa0\x25\x6d\xfd\x52\xb1\xd8\xa2\x31\x87\x36\x97\x3a\x7c\x7e\xbb\xf8\xce\xd9\x2f\x4f\x73\xd4\x36\x44\x23\x13\x7c\x0d\x4d\x4a\xbe\x28\xe9\x77\xb5\x91\x94\x7e\xbf\xf3\x09\xce\x3f\x8f\x46\xb7\xa9\xf5\x2a\xe7\x3f\xc9\x91\x92\xd3\xf5\x06\xd0\xe2\xf5\x66\x92\x0e\xbf\xa3\xd8\xe7\x16\x4d\x15\x9d\xa2\x4f\xa0\x59\x89\x3d\xbd\xa6\xe8\x28\x06\x9d\x14\x4a\xad\x90\x77\x65\xf1\x5b\x76\x99\x4e\xaf\x64\xbb\x98\xcd\x9e\xbf\x4c\x99\xce\x02\x1b\x4b\x97\xc4\x1e\x63\xb7\x56\x8a\x3d\x46\x67\xab\xcc\x00\xf5\x4d\xd5\xf1\x36\x48\xf0\x60\xee\xa4\xae\x79\xf4\x8b\x64\x8b\x05\x84\x6e\x4f\xc0\x81\x2e\x4e\x47\x67\x49\xa3\xd4\x70\xac\x5e\x01\xb6\xba\x56\x01\x16\xe1\x0b\xfa\x9b\x9b\x7e\x55\x5e\x70\xd8\x08\x04\xfb\xf9\xb2\x2c\x31\xdc\x05\x43\x04\x4a\x83\x5e\x18\xf5\x84\x04\xcd\x41\xfe\xa8\x91\x71\x02\xc9\xe0\x76\x6a\x71\x0c\xa8\xa5\xb5\x65\x21\x80\xaa\x42\x87\x28\x53\xb1\x3b\xda\x37\x45\xc7\x5e\xe9\xce\x0a\x22\x79\xd8\xe9\x76\x78\x41\x51\xf9\xce\x35\x97\xc3\xf1\xa1\x45\x8c\xbf\xb3\xee\x40\x55\xff\x1d\x60\x90\xe4\x22\xc3\x86\xa4\x82\x42\x77\x13\xa1\xf9\xe2\x05\x14\x1c\x6b\x82\xcf\x48\xba\x51\xda\xe2\xd0\xa8\xfc\x6e\xf1\xfd\x10\xaa\x01\xdc\x70\x73\x2f\x60\x77\xfe\xca\x47\xfe\x95\x12\x36\x8f\x2c\xa5\xac\xf4\x96\x77\xdd\xb6\xb7\xaf\xdd\x9e\x6d\xc7\xa3\x9d\xb5\x36\xd3\xd9\x22\xab\xee\x1f\x91\x48\xf0\xfa\xc5\x9f\x5f\xbd\xf8\xcb\xa7\xcf\x6f\xc9\xda\x91\x0c\x1d\xe3\x68\x96\x36\xe9\x21\xeb\xc9\x90\x8e\x43\xbd\x5e\x46\x22\x9d\xcd\x5e\xc8\x8f\x93\x92\x95\x55\x03\xac\x78\x61\xb1\x74\xa8\xf7\x46\xda\x72\xfd\xe8\x59\x24\xa2\x5e\x74\x50\x0d\xdb\xdd\x1d\xfc\x92\x44\xbf\x1c\x34\x07\xbf\x44\xcf\x7e\x41\x12\x24\x2d\x3e\x66\x30\xf0\x56\x0f\x8a\x1e\x2d\xd9\xfd\xae\x09\xc9\x1d\x6a\x74\x30\x29\x31\xec\x32\x70\xba\x35\xea\x20\xa3\x71\xd4\x48\xb9\x23\xb6\x87\x98\xd3\xb6\xdb\x97\x62\xc5\xfb\xa3\xd6\x08\x78\x9e\x31\xad\xee\xce\x8a\x70\x7a\x29\x5e\xd9\xdc\xed\xfe\xfe\x1b\xfd\xf0\x15\x74\xd2\x8c\x64\x3e\x39\xe2\xc6\x0b\xf1\x6d\x20\xc2\xa4\x22\xc6\x4f\x9b\xb3\x49\xc1\x54\x4c\xff\xbc\xbf\x57\x53\x94\xc0\x81\xc0\xf4\x44\xb9\xd6\xe6\x0f\x83\x15\x42\xcc\x10\x1f\x05\x7b\x25\xfd\xef\xfe\x77\x7a\xa3\x0b\x7b\xdb\xe5\x01\x17\x4c\x36\xc9\x37\xfd\xb7\xa4\xa0\x81\x0c\xa7\xd5\x06\xbe\x16\xf0\x78\xc2\x6c\x51\x6b\xae\xc8\xee\xd4\xfd\xb7\xa7\x19\x2a\x7b\x00\x21\x8d\xbf\x92\x37\xe6\x95\x15\x49\x4d\x0a\x64\x9a\xd1\xb4\x6d\x35\x02\xc3\x37\x41\xfb\xe7\xc4\x3a\x25\x9a\xce\x2f\xec\x46\xbc\xa7\xda\x86\xd5\x53\xf6\xf7\x2f\x61\x39\x33\x15\xb3\x62\x6f\x24\x09\xce\xbd\xb1\xc3\x1a\x69\x25\x06\xb7\xf7\xa9\xd9\x4d\xcc\xb0\xf6\xbe\x26\x06\xe3\x18\x95\x1d\xfb\x2f\x61\x3c\xb1\xdd\xe0\x02\xab\xbd\xe4\xb7\xb7\xe5\xb0\x45\x24\xa2\xb2\xab\x42\xd2\x2f\x55\x9b\xb2\x78\x23\xd5\x7d\x03\xd2\xfe\x80\x93\x22\x4f\xfe\x3e\xbf\x8d\xc8\x71\xd5\x2e\x5c\x4f\x45\x8c\xec\x8c\xf4\x72\xb9\xf5\x85\xf4\x5b\x5b\x98\x7f\x19\x94\x98\x4a\xef\x44\xb3\x6c\x55\x65\xe8\xa4\x79\x66\x9c\x13\xd9\x3c\x87\xec\xf7\x4d\xa1\xb7\xd1\x78\x2b\x62\x5d\xaf\x26\x57\x8c\x8c\xfd\xa8\x70\xde\xe6\xa6\xa4\xcf\x22\x56\xcc\x64\x39\x72\xab\xda\xc7\x96\x76\xd5\xac\x4d\x18\xf5\xe7\xae\xb2\xcf\x00\x3d\x1b\x2d\x87\x9a\xf6\x16\xdf\x93\x55\xdb\xaa\x5c\xbc\x45\x82\xf0\x24\x19\x8b\xf7\xc9\x13\xf1\x01\x3f\x3e\xe1\x7f\xef\xd0\xa4\x4c\xee\xf2\x1b\x54\x54\x57\xb6\xfb\x7f\xba\xb2\xf9\xbb\x0f\x82\xdf\xe4\xde\xf2\x1d\xe1\xa1\x4b\x14\x02\x89\x2f\x6c\x96\xe0\xd8\x4d\x77\x1a\x92\x4b\x1d\x29\x05\x66\x6f\x86\x4e\xf3\x70\x36\x2c\x32\x41\xa3\x77\x52\x86\x06\x14\x5b\xa1\x37\xb7\x8c\x4c\xd6\x59\xf5\x25\xdc\x1f\x9e\x4c\xb6\xae\x45\xa1\x18\xbd\x46\x27\xc9\xc9\xcd\x8d\xf3\xfd\x1e\x96\xef\x62\x98\x15\x68\xa8\x69\x3d\x5a\xca\x81\x90\xe7\x71\x7d\xa8\x4d\x77\x12\x18\xfa\x46\x21\xfa\x03\x52\xf5\x99\x28\x68\x54\x21\x13\xf2\xf8\x9b\x17\x3b\x95\xdf\xee\x44\xa7\xc9\x79\x47\x90\xe0\x17\xd2\x37\x23\xb2\x03\x6f\x86\xed\x25\xa0\x20\xbc\xda\xcf\xe9\xd0\x35\x61\x55\x66\x32\xb0\x88\xd8\xa4\x40\xdf\x7e\xbe\xe7\x59\x52\xf9\xc5\xb5\x9b\x07\x34\x33\x65\x78\x33\x98\x2d\xcc\x9d\x18\x26\xcd\xf8\x96\xc3\x2f\x52\xbd\x56\x96\xc7\xdc\x1f\xc0\xe7\x6a\x34\x07\xdb\x1c\x02\x12\x94\x76\x52\x9f\x93\x37\xc3\x75\xe1\x0e\xf8\x39\xc7\x7b\xd5\x8a\x16\xaf\x50\x17\xa6\xc6\x68\x63\x6f\x88\xba\xc2\xa1\x67\x33\x09\xab\xa8\x1d\xb6\x4e\x6a\xb4\x5e\x10\x53\x5e\x9c\xd0\xca\xd2\x0c\xd7\xb6\x2f\x58\xe9\x08\x76\x8a\xd6\x6d\x42\xab\x03\x93\x16\xbe\xa3\x76\xdc\xf1\x5c\xfe\x91\x59\x7e\x3d\x49\xee\x16\x36\x82\xc3\x7e\x74\x36\x47\x36\x38\xe1\x26\xb5\x98\x17\x9f\x6f\x79\x39\xa1\xf4\x0c\x18\x56\xd5\xcd\x39\x2a\xcb\xbc\x19\x6e\x69\x5e\xee\xe4\x46\xb4\xe0\xf6\x16\x7a\x8a\x0e\x0d\xa0\x94\x2d\xfa\x48\x40\x89\x63\x68\x19\x28\xd4\x92\x05\xf5\x21\xf3\x13\xdd\xc3\x48\x86\x87\x37\xb4\x63\x00\x40\x27\x7e\x40\xb2\x43\xed\xcc\x71\xbf\x0d\x11\x6a\x18\xa8\x44\xa9\x22\x72\xf7\xb0\x96\xfa\x8d\x7d\xa3\x20\x04\xef\xbe\x56\xf7\xaa\xb6\x87\x28\x90\x9f\xcf\x5a\x5d\x61\x4c\x44\x07\x57\xd0\xba\xb4\x9e\xed\xd0\xf9\x1a\x0a\x59\x49\x03\x7f\x32\x68\xa4\x07\x78\xfa\xec\x5b\x59\xb0\x13\x1d\x64\x41\x60\x39\xb6\xac\x3e\x69\x8b\x7d\xb2\xd6\xa9\xb0\x1a\x56\x44\x4b\xa0\xc9\x6e\xaa\x24\xb3\x80\x17\xcb\xe8\x15\xc0\xbe\x89\xa4\x40\x25\x16\xef\xb4\xf9\x32\xb8\xf1\x9e\x7a\x7f\xc0\xe5\x52\x94\xcd\x78\xa2\x3a\xd7\xa1\x25\x15\x94\x1d\x37\x8e\xc8\xee\x4b\x2c\xbd\x39\x39\x4a\x64\x4e\x2f\x46\xdb\x2c\x43\x2b\xd1\xc6\x8a\x7e\x88\xf4\xe1\x84\xc6\x11\x42\x0c\xcd\xc0\xa8\x02\xe3\x0e\x9a\x7a\xae\xa4\xaf\x35\xf9\xe0\x6b\xd0\x3b\x19\x93\x6b\x41\xca\x65\x2c\x14\x27\x66\xbb\x84\xd5\xab\xe4\x6e\x0b\x65\x16\x99\x8c\x27\x95\xb1\x91\xb4\x2c\x28\x51\x6e\x7e\x5a\x1d\x1c\x9c\x4d\xd2\x89\x34\xf7\xd2\xcb\x94\x0e\x26\xf5\x31\xbe\x33\xd4\xc7\x79\x92\xc6\xcb\xa1\x2b\x6b\xeb\x63\x84\x1e\x34\x0b\x56\x7d\xe0\x80\x0a\xe9\xde\xc4\x1a\x04\x30\xfa\xa1\x54\xe8\x39\x1d\x16\xd9\x8f\xe6\x53\x7e\x8e\x2a\x56\x1b\x8a\x38\xa6\x5d\x2b\x68\x97\x5c\xf9\xc6\xfa\x00\x1e\x60\x3c\xf0\x45\xb2\x71\x41\x06\x82\x2f\xe3\x0a\x1f\xd1\x48\x1f\x55\x7a\xee\x8f\x53\xb1\x5a\x57\x97\x28\xac\x5d\x6f\x26\x0a\x29\xea\xc5\x4d\xae\xbc\x6b\xd0\xcb\xd7\x29\x1c\x0b\x54\xa8\x06\x06\x16\x8b\xfb\x66\xbb\xf1\xff\xad\x2a\x06\x77\xd1\x76\xde\xaa\x86\xe3\x12\xa9\x90\xf5\x20\xac\x5a\x10\x7c\xe5\xb2\x68\xd0\x78\xcc\xfe\x15\x6f\x21\x41\xe3\x31\xeb\x11\x75\x53\xa0\x50\xa2\x83\xc9\xdf\x42\x7f\x02\x83\xff\x28\xc8\xf0\xef\xac\xa8\x2d\xaf\xb0\x99\x74\x27\xa0\x7c\x8e\xc4\x99\x30\x07\x8e\x95\xed\xd8\xc9\xc0\xd0\xb1\xce\x15\x96\x0b\x13\x80\x78\x6a\xa3\x19\x1c\x8e\x85\x65\x69\xcb\xb5\xb5\xe7\x15\xd9\x58\x29\x3f\x36\xfe\x1b\xde\xdd\x46\xe3\x58\x03\x3b\xa3\xe1\x52\xdd\xc3\x68\xc2\x63\x90\xf1\x01\x77\x1f\x81\x65\x7a\xfc\xb3\xfd\x23\x1e\xf3\x4d\xb8\xee\x32\x04\xdb\xd0\x79\xfb\x18\x9a\xce\x7d\xf0\xc6\x80\x16\x4a\x33\xfd\x3a\xd8\x5f\x0f\xff\x94\x4e\xbf\xc2\x69\xb6\x1d\x0b\x0d\x6f\xf5\xdc\xd3\x9f\x89\x25\xd0\x7e\x7d\xd7\x44\xc9\xb4\x0c\x28\x6a\x69\x94\x48\x11\x9d\xb6\x02\x07\x06\x54\xbe\xde\x62\x10\x32\xea\x89\xbb\x21\x7b\x0c\xa3\x03\x76\xb1\x48\x01\x6f\x14\x2f\xb4\x7d\x94\x79\x28\xeb\xe6\xfe\x2e\x76\x60\xf5\x70\xb8\x33\xe4\xbd\x96\xf8\xdf\xb7\xe4\x9a\xfc\x90\xc6\x6c\xd2\xae\xba\x0b\xde\x3e\x0b\x26\x94\xd0\x91\x56\x32\x9a\x48\xc7\x36\xf2\xbe\x53\x15\x93\xc2\x7d\xa2\x28\x94\xae\x7b\x71\x9a\x13\xd5\xde\x8a\xff\x98\x0f\xd4\x15\xb4\xea\xa7\xcc\x60\x4c\xb0\x70\xc2\xee\xce\xd6\x89\xef\x41\xe7\x00\xfd\x39\xd4\x1e\x7f\xd1\x5f\x0b\xa9\x33\xce\x2e\x72\x5e\x66\xab\x66\x7e\x30\x86\xcb\x4c\x26\xb0\x47\xa4\x12\xf5\xf9\x11\x1e\x81\xe2\x2e\x0f\x0e\x74\xd4\xdf\x6a\x23\x6d\xdb\xad\xc0\x2e\x0e\x01\x30\x3f\x38\x90\xf4\xc4\xde\x88\x74\x37\xa5\x7a\x46\x70\x11\xf4\x12\x54\xd2\x2d\x86\x3f\xe7\x4a\x45\x7a\xf9\xa2\x28\x3f\xac\x29\x5d\xb3\x17\xe8\x9f\x04\x78\x92\xff\xac\x02\x0b\x5a\x63\xc2\x1d\x68\xd0\xf9\xa4\x52\x12\x9d\x1f\x1e\x8a\x39\x12\xc4\xc7\x00\x91\x71\x8a\x30\xaa\xa6\xd2\xb1\x97\x6a\x26\x85\x9a\x89\x1c\x88\x53\x87\x8a\x62\x2c\xbf\x76\x4f\x85\xdd\xd3\x97\xad\x5d\x39\x60\xd3\xb1\x54\x08\x12\x37\x37\x8a\x3d\x17\xea\x4d\x1d\x57\xb0\xe4\xd5\x0b\x01\x4d\xa9\x81\x06\x99\x28\xf4\xed\x41\xec\x57\xed\x73\x82\x68\x8a\x8e\x9a\xf9\xe8\x0e\x0c\x40\x64\x3a\x18\xd0\x30\x0c\x95\x5c\x8b\x54\xe4\xf8\x68\xc5\x2a\x00\xe9\x8f\xbe\x03\x30\x98\x87\x36\xf8\x14\x67\xd2\x00\xdb\x14\x57\xc7\x85\x2c\x7e\xe7\xbf\xae\xc9\x85\x48\x77\x63\x9d\xbb\x8e\x6e\x96\x98\xc9\x9d\xc3\x41\x98\xca\x83\x60\x41\xb4\x55\xf8\xb9\x7c\xd0\x9e\x8b\x12\x86\x0f\x2c\x6a\x0a\xa0\xac\x57\xac\x1a\xec\xb5\x9e\x05\x4b\x20\x17\x8b\xfd\x7d\x5c\x8b\x9b\x9b\xce\x31\xd0\x42\x96\x04\x41\x45\x07\x3a\x70\x02\xdf\x74\x03\x7e\xc3\x66\x90\x12\x02\x32\x92\xe8\xb6\xb8\x1c\x18\x4f\x80\xf3\xd9\x74\x21\x16\xa2\x93\xf5\xce\xb5\x5f\xa9\xed\xa5\x7e\x5a\x90\x0a\x86\xef\x7b\xcb\x29\x43\x8a\xdc\x32\x44\x50\xab\xc5\xc1\x75\xd1\xae\xde\xb8\x0d\x10\x83\x1b\x1a\x90\x8a\xaa\xd9\xdd\xf7\x80\x54\xbf\xba\x90\x4d\x1e\xa8\x8d\x72\xae\x0e\x38\xe8\x96\x75\xf9\x98\xb3\x21\x8b\x16\x6f\xc5\x01\x27\x06\x31\xa7\x33\x60\xe5\x83\xc2\x5a\x2f\x0a\x5c\x26\x3a\x76\x2b\x9c\x7c\x73\xa3\x62\x0a\xb5\xb2\x58\x7e\x2e\x02\x60\xe9\x8b\xfc\xd8\x2b\x86\x39\xc2\xd9\x40\x78\x43\xe5\x10\x43\x01\xa6\x5a\x32\xea\x9d\x23\x70\xb5\xec\xbf\x39\xde\x05\x42\x5a\xc1\xe1\x3b\x1c\xc8\x70\xd2\x2f\xf0\xaf\x70\x20\xb2\x77\xa4\x9e\x6f\xa1\x95\x89\x36\xde\xc5\x56\x8e\xa8\x81\xaf\xd9\xd5\xdb\x1c\x6d\x82\x23\xb6\x71\xba\x76\x3d\xd3\xd0\x6a\xb9\xee\x68\x28\xc9\x76\x46\x43\x09\x8e\x23\x1a\xa6\xb4\xda\xaf\x4a\xa6\x33\xa0\xfb\x79\xa0\x77\x0b\xfb\xa9\xe4\x50\xa9\xf5\xbe\xc0\x46\xb5\xd5\x71\xbf\x04\x6a\x41\x28\x07\x19\x18\xb2\xae\x40\xa5\xa4\x50\x3a\xfc\xae\xe8\x45\x56\x49\xf0\xaa\xb0\x61\x52\xd9\x96\x97\xe7\x0c\x40\xa8\xc2\x20\xb4\x53\xfb\x60\xbc\x11\xf7\xd0\x22\xf8\x86\x63\x8d\xb8\xda\xcd\x40\xe5\x90\x45\xe6\x5a\xa9\x33\x29\x0e\xef\x75\x59\x9d\xa4\x97\x8e\xe1\x65\x6d\xc3\xe3\x7a\x4b\x08\x9c\xb6\x2e\xcb\x78\xbb\x55\xa0\x05\x20\x14\x15\x87\x5b\x35\x46\x14\xf6\x8a\x94\x18\x0e\x88\x04\xb2\xec\x16\xa0\xfd\x68\xcc\x6e\x3b\x02\x7a\x11\xd9\x10\xce\x40\x3a\x9d\x7f\xcc\x2e\x3a\xf2\x67\x99\xcc\xc7\x57\xe6\x99\x11\x82\x3c\xaf\x21\xed\xa4\x6c\x7b\x62\xed\x97\x43\x7b\x34\xa8\x4a\x83\xf1\x09\x55\x37\x52\x6a\x24\x31\x84\xd3\x1a\x8a\xb2\x76\x6d\xaf\xca\x2e\x6a\xc4\x49\xf4\x0c\x59\x98\x51\x22\x3c\x09\x49\x32\x6b\x11\x68\xcb\x12\x0d\x6b\xa3\x05\xaa\x1e\x95\xaf\x6a\xd6\x47\x7d\x02\xec\x0f\x90\x9c\x8c\xb8\x3c\xb1\x90\x36\xd5\x4f\x92\xe2\xd8\x7c\x5d\x6f\x62\xfd\xc1\x7e\x6d\x9b\x8d\xd0\xc3\x72\xf6\xc4\x46\x73\x34\x8f\xcc\xc3\x6c\xd2\x9c\xd4\xde\x78\x40\x4e\x81\x58\x5c\x04\x48\x3b\x07\xdf\x72\x7d\xe5\x16\xf2\xdc\x5d\x3b\x9e\xd3\xd9\x9f\x7b\x09\x78\x57\x25\x14\xb7\x39\xdd\x2d\x36\xd6\x89\xb8\x76\x5c\xbc\xbb\xa0\x38\x74\x1a\x86\xf3\xd8\x7a\xf7\xa6\xf9\xfc\x84\xe9\x84\x51\x00\xe2\xfb\x15\x95\xb6\x92\x80\x52\x17\xaa\x19\xe1\x13\x71\x35\x88\xab\x4d\x4b\xad\xf7\x4e\x7a\x61\x53\xd4\x0b\xab\xd0\x81\x5e\xbb\x17\x6c\x0f\x2e\x64\xf4\xd5\x16\x67\xed\x7c\x74\x1e\x43\x03\xc4\x02\x8a\xc5\xc9\x6c\xa7\xff\x3e\x1a\xcc\xc3\xf1\xcc\xd2\x36\x2e\x90\x56\x4f\xff\x5a\xe6\x85\xc4\x6e\x64\xe8\xe4\x3f\x1f\x16\x61\xaf\x71\x25\x05\x15\xc4\x03\x3a\x20\x93\x76\xe5\xfe\x23\x06\x9e\x0e\x5b\x63\x97\x78\x18\x13\x8b\x5c\x8e\xc5\x6b\xb2\x79\xa7\x10\x43\x17\x59\x25\x23\x47\xa0\xbd\xc8\x14\x80\xa6\xba\x6c\x85\x7e\xb7\xba\x82\x73\x4d\xfe\xe5\x06\xc2\x3a\xb1\x8d\x6c\x89\xea\x39\xc8\xc5\xa8\xbf\xf4\x95\x1f\x23\x7c\x58\xa7\x78\x7c\x28\xa2\x67\xcf\x0a\x56\x3c\x44\xe1\x81\x57\x97\xbb\xb1\x70\xdc\xb1\xb0\x8c\xcc\x5e\x55\x48\x7b\x18\x12\x8a\x8d\xb7\x2b\x9c\x4b\x23\xf9\x80\x25\xfc\x78\xbc\x5d\xbb\x71\x1b\xc9\x80\x53\x66\x2a\x40\xfa\x88\x90\x1f\xb8\x7d\x2f\xac\x94\xdd\x48\x82\xf1\x76\x45\x1e\xf7\x04\xea\xaf\xa6\x6f\xb9\x4c\xc3\xf7\xbf\xa4\xbc\xb9\x79\x21\xbd\x14\x23\xd3\xac\x55\xf0\xfa\xaa\x98\xb4\xc8\xbe\x44\xd9\x83\x16\xfe\x23\x6d\x40\x3e\x52\x50\x0e\xfc\x6f\xeb\x1c\x30\x46\x8f\x3c\xf9\xf4\xfe\x25\x3a\xa8\x0e\xa2\x7f\x21\xbf\x3b\x45\xd9\xf4\xea\x55\x36\xcd\x2f\xf2\x8c\x7c\x2a\x45\x07\xfd\x08\x0a\x94\x50\x60\x18\x01\x89\x21\xfd\x3a\x29\x33\x0d\x63\x57\xba\x67\x34\x7c\x0b\x7a\x11\xe0\x3e\xdc\x32\xa8\x25\xe7\xfb\x5a\x6d\x4d\x54\x3d\x70\x12\x4a\x49\x93\x59\x9f\x03\x05\xa7\x7b\x89\x8a\x63\x59\xc3\xdc\x88\xf9\x5d\xf6\x8d\xb6\xb8\x35\xc1\x37\x05\x39\xb2\x81\xc1\xd7\x3c\xbf\x02\xe7\x87\xfa\x8a\x70\xfd\xe2\xf7\x1a\xbf\x71\x6a\xf5\x7a\xb5\x5a\xe0\x54\x9b\x52\xad\x83\xe8\xc1\x4e\x52\x90\x0d\x4c\xc9\xe4\xc4\xb5\xcc\xa4\x70\x14\x7d\x4a\x5b\x01\xfb\xd5\xb0\x99\xa7\xcd\x47\xfa\x74\xe5\x66\xf9\xed\x33\x25\x4f\x4e\xae\xe3\x1f\x25\x23\x4a\x79\xba\x35\x2f\xc5\xb6\xe9\xa6\x81\xe9\xca\x1d\xac\x31\x6d\xfb\x74\x95\xff\x2c\x9a\xaf\xc2\xda\xeb\x64\x34\x59\x3f\xcd\xd5\x7b\xca\x5a\xb9\x1c\x42\xa1\x5e\x2e\xd6\x34\x0d\x1c\xfb\xb4\xe5\x8c\x47\x3b\x69\xef\x58\x3b\x14\x53\xea\x8f\xcc\x70\x71\xb8\x10\xdf\x5a\x6f\xe1\xe8\x49\x55\x71\x78\x97\x00\xf6\x5b\xd7\xa1\xe4\x75\x68\xfc\x39\xcb\xb5\x28\xbc\x79\xf7\xec\x67\x08\x6f\xb7\x33\xd7\x43\x53\x78\x1b\x71\xc8\x74\x05\x5a\x6b\x90\x29\x47\x46\xbc\x7b\x29\x3e\xd6\x91\x75\xde\x8b\xad\x43\xcf\xad\x2d\x0c\x0c\xdd\xdb\x32\x1d\xec\x03\x3a\xfc\x17\xda\xff\x6d\xd0\xba\xee\x1a\xbf\xb1\xed\x90\x87\x0e\xfd\x8c\x6a\x37\x53\xd2\xc8\x03\x75\xea\xc8\x57\x2e\xb7\x3d\x71\x4e\xa2\x1f\x29\xe1\x4e\xc7\x92\x4c\xaf\x30\x21\xdf\xed\x5c\x02\x6d\xcb\x8e\xcb\xd6\xe4\x10\x6c\x10\x9e\xed\xf4\x4e\xe8\x45\xb9\xb8\x02\x2c\x93\xda\x58\xe6\xce\xe8\x45\x6e\x54\xba\xd3\x79\xe3\x4e\xdd\x03\xc7\xbe\x97\x71\xc1\x7d\x1a\x67\x3d\xf8\xa3\xce\xde\xe2\x76\x48\x18\x4d\x72\x03\x02\xb9\x3a\xf6\x00\xc6\x4a\xa4\x4d\xec\x69\xaa\xab\xca\x2e\x37\x3f\xb1\x74\x1d\x70\xde\xbd\xb5\xab\x2d\xa8\x63\xfe\xbf\x03\x57\xa0\x64\x69\x0b\xa2\xb8\xf8\x3f\x03\x7a\x0a\xec\x76\xb8\xd9\xb8\xcb\x7f\x69\x43\x5e\xa6\x41\xec\x74\x4d\xfb\x3c\xe5\x84\x45\x32\x75\x60\x6e\xa1\x40\x6c\xb1\xb1\x61\x4c\x44\xad\x3e\x22\x6b\x61\xe6\xb8\x30\xf5\xf7\x1c\xbd\xb8\x19\x57\x72\xd3\xb4\xce\xa2\x62\xbd\x3c\xc7\xc7\x56\xfa\x60\x4c\x12\xc5\x4a\x5f\x73\x42\xa9\xe7\xe8\xb3\x21\x2d\x74\x72\xc6\xc9\x72\xf9\xe2\x90\xe7\x3c\xad\xb2\x9c\x7d\xcb\xaa\xab\x3e\x5b\xb6\xb5\x6f\x17\xa3\x19\xea\x0b\x73\x6d\x90\xd2\x3a\x16\xba\xb0\xf4\x7d\xaa\x06\x34\xb6\xb8\x9f\x99\xd1\x04\x51\x33\x55\x1b\xea\x8f\xf2\x38\xa2\x7b\x37\x8a\x33\xfb\x20\x7f\xcc\x2e\x5f\xfd\x58\x1d\xeb\xe9\x59\xea\xbe\x4b\xdb\x3f\x4e\xe6\x00\x11\xc7\xf2\x40\x4d\x59\xbb\xad\x97\xc0\x41\x28\x53\x3e\x14\xaf\x45\x13\xbf\x04\xf7\xa6\xca\x54\xd9\x25\xec\x63\xe4\xba\x87\xb6\xb5\x3d\x8d\x86\xa8\x1d\x8e\xd2\xf7\x51\x46\x3e\xc2\xb7\xab\x7f\xfa\xcc\xd7\x8b\x24\x7a\xfa\x34\x2d\xca\xe2\x6a\x59\xae\xeb\x67\xcf\x22\x71\x4e\x76\xe0\x3f\x12\x38\xf4\xe2\x63\x72\x4d\x4b\x15\xc3\x59\xe0\x35\xc3\xc0\xb3\xe5\x02\xbf\x15\x74\x0c\x48\x93\x2f\xb6\xcd\x22\x30\xaa\x07\x42\x17\x26\x4a\x38\x1b\x08\x5e\x30\x4c\x2a\x95\x14\x88\xc1\x0e\x93\x24\x00\x02\x33\x58\x5c\xc5\x25\xba\xe1\xc4\xde\xc8\xea\x2a\x93\xfe\xf2\xce\x85\x5a\x3e\x48\xae\x05\x6a\xe2\xc4\x3f\x64\xab\x90\x32\x15\x70\x4d\xc1\xdf\x35\xff\xc5\x65\x89\x17\xa2\x9e\xa7\xf0\xf7\xc2\xb8\x9c\x8c\x95\x62\xc6\x50\x2d\x5e\x1d\x89\x68\x6a\xe9\x65\xc8\xfe\xa4\x62\xc6\xb9\xd2\x20\x44\xe9\x42\xb8\xb2\xc9\x87\x0f\x1c\x96\xac\xfa\x63\x60\xf3\x47\x1f\xbb\x5d\x94\x6d\xd9\xcb\x18\x38\xb1\x0e\x2d\x8a\x60\x98\xe9\xf1\xf8\x0e\x9e\x66\x89\xcf\x5c\x48\xcf\x2e\xc0\xa8\x7e\x58\x63\x04\x06\x5b\x90\xe9\xba\x6f\x2a\x6f\xd5\x85\x0e\x07\x32\xf7\x42\x87\x5f\x4b\xf7\x67\xd0\x9d\x72\x2b\xd3\x12\xca\x04\x86\x26\x9f\xf8\xcd\x43\x03\x3e\xf2\xc3\xa2\xfd\x25\xbb\x8a\x1b\xfa\xc5\xfe\x78\x0a\x8a\xc6\x65\xda\x76\xc2\xe5\x29\x6c\x93\xc1\x7d\x9b\x3d\x0d\xf5\x22\x6f\xe0\x4c\xdd\xc0\x4d\x12\x28\x85\x62\x63\x0c\xb7\x64\x62\x71\x37\x43\xfb\x09\x67\x28\x07\x26\x7f\xd1\xc0\x06\xec\x84\x21\x6b\xcb\xf1\x82\x23\x48\x46\x28\x78\xeb\xf4\x42\x45\x2d\xf5\x07\xe8\x4d\xaa\x72\xbd\x49\x15\xb6\x0e\x51\xb1\x45\x5e\xd0\xe5\x92\xa7\x43\xb1\x88\xa0\xeb\x0e\x4e\x0d\xe5\x30\x4d\xc0\x79\x3b\xbe\xf3\x40\xf9\x1d\xc7\xa3\x73\x52\x7e\x6a\x00\xe6\xa7\x6c\xab\x82\x9e\xf7\x65\xa6\xd2\x9f\x82\x61\xcd\xae\x1c\xef\x46\xac\x22\xcc\x82\x12\xb3\x0b\xe4\x38\x2f\xa9\xad\x72\x8e\x58\x1e\x6d\x8a\xce\xd3\xe9\x57\x2a\x66\xe0\xd9\x05\xf2\xfc\x56\x20\xb7\xfd\xf5\x50\x2c\x53\xdb\x83\x89\x13\xa4\xd2\x1b\x99\x71\xd6\x63\x87\x8d\xd7\x0a\x1b\xbe\xb8\x8c\xfc\x30\xaa\xc5\x8b\xd3\x61\x87\x27\x11\x31\x5d\x94\x35\xe6\xfb\x1e\x3e\xc8\x1d\xa3\xd5\x42\xeb\x79\x15\x3d\x65\x4b\xe3\xaa\xbe\x31\xe5\x19\x1a\xb7\x5f\xa8\x12\x87\x9a\xe8\xdc\x83\xf3\x0e\x61\x97\x22\xd0\xbe\xe8\xea\x2b\xb4\x97\x1a\x7c\xfd\xa6\x3b\x8a\x17\x65\x03\x6c\xce\xf3\xc5\x02\x21\x5e\xcc\xb7\x76\xe5\xc3\xc3\x6d\x7d\xb5\xca\xdb\xb8\x83\xfa\x9b\x25\xa7\x73\x41\x41\xd4\x50\x9f\x05\x03\x09\x58\xfb\xf7\xd7\x2a\x5d\xad\x3c\x2c\x23\x97\x72\x66\xd4\x09\xcd\x5c\x02\xe5\x42\x53\xa6\xaa\x3e\x00\x75\xd5\xf5\xa7\xd0\x85\x39\x8c\xb3\xaf\x50\x97\x83\xf0\xb1\x63\xef\x71\x6e\x4d\xbf\xc3\xae\xa3\xc8\xbe\x67\x26\x53\x07\xff\xaf\x87\x24\x27\x45\x75\xa7\xf2\x76\xd4\xe5\x1e\xda\xf8\xc1\xe3\x3b\xbb\x18\xbb\x4d\x51\xd2\x3b\xc3\xf1\x78\x64\xa2\x1a\xb7\x8e\x30\x5c\xc8\xa4\x45\x68\x9f\xe0\x78\x7c\xff\x31\x61\xc7\x9d\x3c\x8b\x76\x47\xa3\xf7\xde\x19\x42\xee\x05\xf0\xb9\x01\xcd\x0d\x83\x91\xea\x69\xa7\xcc\x23\x46\x11\x7c\x97\xb8\x8b\xa7\xd2\xa9\x79\xb5\xf2\x8d\x24\x1a\x4b\x3f\x29\x0f\x69\xc9\x6b\x51\xa8\x83\x8f\x11\xa1\xc0\x9d\xc8\x71\xa7\xfa\x1e\x46\xaa\xc8\xbb\x80\xb2\xfe\xf0\x8d\x3b\xd0\x40\x4f\x98\xe0\x9e\xe9\x30\x60\x49\xd9\x2f\xe1\x98\x53\x03\x5a\xa3\xc8\x82\xdc\xc1\xc6\x13\x86\xfe\x07\xcc\x6f\xb4\xdb\xfc\xba\x2c\x58\xe4\x24\xb7\x4f\xc2\x7a\x62\xf1\x98\x83\xdc\xb9\x9a\x7c\xf3\x31\x27\xa8\x32\xad\x97\x5a\x3f\xef\xe2\x52\xb1\xa7\x0b\xf6\xa2\xef\xde\x56\xeb\xdb\x35\x04\xa7\xad\x17\x1d\x3b\x80\xbb\xb9\xf4\x89\xfa\x2f\x44\x88\x0a\xc0\x97\xad\xed\x04\xf3\x76\xcf\x81\xee\xf4\x20\xcf\x54\xdc\x32\xbb\x78\x7c\x34\xfa\x19\xd5\x63\x3c\x59\x47\x77\x71\x90\xfb\xd3\xc4\x51\x16\x46\xd2\xe5\x8e\xb4\x51\xde\x45\x1b\x05\x29\x7d\x9f\x60\xca\xb7\x13\x37\x69\x88\xb8\xe9\x0c\x72\x14\x64\x47\xa7\xbf\x87\x8a\x58\x6f\x3c\x9a\xe9\xae\xa4\xc1\x1a\x49\xa6\xd3\x85\x98\x9e\x21\x39\xb3\xf3\x3d\xbf\xfa\x7f\xdb\x3d\x5f\xfe\xf4\x3d\x9f\xff\xae\x7b\xbe\x76\xee\xf9\x54\xde\xf3\x17\x3b\xb1\x28\xbf\xff\x9e\xdf\xf9\xae\xee\xe6\x9e\x8f\x7e\xc6\x27\xa8\x15\x3e\xd6\x8b\xdd\x64\xa1\xc4\xad\xf8\xda\x3f\x1c\xf2\x20\x65\xf5\x34\x5d\x91\xb2\xf0\xeb\xb2\x92\x54\x0c\x9d\x28\x6b\xab\x37\xc0\x5c\xd7\xd6\xa2\x57\x72\xd1\xaf\xdd\x7b\xc5\xf3\x0e\x8e\xe4\x05\x95\xf3\xae\x1f\x36\x14\x24\xe9\x05\x97\x93\xb6\xfe\x69\xdf\x7a\x93\x36\xfe\x45\x42\x18\xea\x38\x8f\xa3\xa7\xf5\x2a\xc5\xb7\x4c\xe5\x33\x8f\x73\x94\x31\xd6\x41\xf4\x8c\x9e\x1e\x9e\xde\xc3\x62\x18\xf5\xd2\x57\x7d\x0d\x58\x77\xc9\xb7\x71\x72\x3e\x68\xc6\x82\x16\x6b\x26\x2c\x55\x03\xb3\x0f\xe9\xde\xb7\x94\xae\xc9\xec\xbd\xad\x78\x89\xf2\xe5\x81\xd4\x07\x0f\xbc\xd9\xa3\x5c\x18\x43\x6e\xd0\x41\xf1\xfe\x03\x16\x68\xb2\x66\x1f\x1d\xb5\x68\x29\x53\x85\x81\x25\x7e\xd8\xed\x2e\x77\x8b\x3a\xa0\x77\x17\x06\x81\x04\xe0\x99\xf8\xf5\xa3\x9d\xb5\x50\x06\xd7\xb3\xfe\x97\x21\x53\x38\xd9\xb4\x2c\xa6\xf9\xc2\xbe\x93\xf6\xf7\xaf\x1c\xe3\x93\xdd\x6e\xb0\x59\x5e\x59\x0e\x4b\xeb\xdf\x58\xb0\x61\xbc\x63\x4f\xed\x33\xcf\x1e\xe2\xd5\xdd\xa4\x70\x54\x7b\x28\xc9\x96\x61\x3a\xb7\x9b\x6b\xa7\x82\xef\x15\x38\xb0\x2b\xdf\x1d\xb2\x34\x23\xf5\x4d\x4a\xb4\x24\xdb\x52\x58\x3d\x6c\xec\xaf\x60\x2c\xc2\x2c\x3c\xe9\xc9\xac\x8f\xe6\x6e\x4b\xed\xf3\x71\xc9\x51\x0f\xf3\x81\xe5\x73\x6e\x34\x69\x9e\x15\x76\x0c\xd5\xa5\x7c\xa8\xae\x86\xe8\x4e\x07\xfa\xc5\x79\x19\x77\x4d\x5f\x56\x00\xe9\x80\x51\x15\xea\xac\xb9\x6c\x2b\x99\x57\xbc\x52\x64\x29\x4f\xfc\xcd\xc5\xbb\x0c\xcd\x50\x28\xb6\x7b\x70\xa1\x01\x69\x69\x27\x53\xfc\x44\x59\xda\x4f\x94\x99\xbb\x7d\x2a\xa8\x41\xbf\x3c\x4d\x51\x35\x69\xb3\x69\xf9\x93\x50\x6c\x31\x05\xb9\x0c\xfa\xb4\x12\xbc\x43\x79\x4d\x41\xc8\x61\x0e\x72\x93\x8e\xfb\xd2\x60\x0a\x6e\x20\xf2\xfe\x80\x36\xbc\x59\x7b\xa6\xc7\x81\x34\x65\x69\x15\x07\xf2\x12\x7a\x67\x90\x6a\x16\x2d\xc8\x20\x24\xd8\xf6\xe6\x37\xeb\x07\x46\x08\xe3\xd2\x2b\x40\x66\x0d\x97\x18\xb2\x43\xbd\x1e\x06\x68\xa9\x45\x88\xee\x5a\xed\xe4\x4b\x82\x5d\x3f\x68\x43\x1c\x97\xde\x9a\x87\xaf\x94\x59\x5b\xc9\x6a\xd9\xd2\xa7\x3a\x3d\x43\x1f\x13\xee\x39\xbc\x44\x79\x9c\xa4\x0e\x5e\x6d\xa5\xae\xc2\xa7\x5d\x81\x7c\x97\xf8\x25\x58\x6b\xcf\x1c\x15\xdc\xfa\x7a\x85\x1e\x9b\xd0\x79\x5d\x67\x8d\x81\x40\xd7\x7b\xb1\x65\x22\xb5\x11\x2f\xb6\x0e\xd7\x85\xde\x5b\x84\x44\x6e\x61\x57\x1c\x75\x9e\x9c\xbe\x12\x2f\xce\x26\x73\x27\x84\xc0\x85\xba\x88\x77\x26\x23\xcf\xb7\x0a\x7c\xb7\xe0\xd2\xa9\x4b\xb4\x39\x63\x1d\x84\x30\x2d\xd5\xda\x86\x46\x3d\xf2\x31\x84\x1b\xba\xf1\x33\xdb\x50\x48\x64\xd3\xa5\x6e\x29\x97\x47\xe1\x24\x8b\xf0\xe8\x6c\x58\x95\xed\x2e\xc1\x3e\xff\x48\x28\xbe\xf0\x42\x2c\xf0\xbd\xfe\x23\x59\x79\x6e\x2a\x94\xcb\x6b\x11\x5d\x2c\x00\x4f\xfc\xc9\xc1\x00\x91\xed\xa7\x03\x51\xe1\x44\xc1\xd7\xcd\xcd\xe5\x44\x3a\xe1\x97\x18\x5d\xca\x54\x6d\x21\x35\x5a\x37\x28\x51\x40\xaa\xe8\x04\x61\x84\x70\x40\x34\x40\x0b\x97\x83\x6b\x3c\x63\xd2\xf0\xeb\xdb\xc4\x3f\x80\x8d\x0d\x6e\xf6\x5e\x23\x8a\xa5\x27\x3a\x16\xf9\x84\x36\xd2\x55\xd8\x45\xec\xb9\x65\xd7\x8d\x6a\xb9\xc2\x6d\x52\x15\xf2\xaa\xdd\xcc\x2c\xe8\x04\xcd\x43\xa0\x54\x4c\x3d\x13\x5a\xa5\x02\xc8\xf3\x8a\x04\x5b\x5f\x92\xeb\xce\xd1\xb1\x74\xcb\xed\x20\x2e\x85\xc4\xb9\x9c\x10\xd7\x22\xb0\x8b\xf1\x0f\x4b\x28\xf6\x51\xa4\x75\xba\x42\x9b\x6d\x43\xa5\x7d\xf9\xa3\x38\x90\x4e\x93\x6b\xc7\x4c\x3a\xc4\x8e\xb4\xb5\x34\x7d\x8d\xcc\xa3\x5d\x34\x32\x83\xe1\x0a\x2c\xef\xfb\xc3\xb7\x9f\x3f\x9d\x7c\xf9\xfc\xe9\x95\x71\x9f\x83\x7a\xf7\xb2\x38\xaa\xbc\x5e\x4f\x7f\xc4\x95\x98\x62\xd0\x5b\x8c\x96\x3e\xc3\xaf\x19\x7e\x5d\xe4\x8b\x85\xfc\xf3\x7e\x95\x4e\xf3\x86\x12\x81\x9e\x7e\x9d\x2e\xf3\x85\xfa\xf8\x84\x98\x16\x7e\x62\xb5\x0b\x8a\x9c\x5b\xa5\xb3\x1c\xd6\x84\xb5\x6b\x11\x21\x98\xb4\xcf\x80\x9c\x6b\xf8\x46\x33\xdc\xac\x7a\x55\xcc\xf4\xef\xb7\xb9\xf9\x4d\x9e\x9b\xe1\xab\x24\xe7\xcb\xf8\x43\x77\xbf\x42\xd3\x97\xaa\x90\x54\xbd\x6a\x4e\xa6\xea\xcf\x32\x2f\xf8\x87\x0c\x04\xf9\x1c\x35\x2e\x9b\x8f\x48\x85\x43\x6a\x85\xff\x70\xb8\x14\xe8\xb7\x86\x42\xe9\xec\x2d\x05\x6b\xc4\xcf\xa6\x5c\xbd\x28\x17\x65\x25\x7f\x9b\x99\xc3\xba\x97\x5f\x33\xfd\xe3\x65\x5a\xcf\xe5\x4b\xb9\x4c\xf9\x2d\x2f\x32\xa0\xcc\xf5\xb7\x5f\xf5\xaf\xf9\xac\x99\x63\x3c\x7a\xa0\xdc\x9f\x17\xd3\x39\xf5\xd1\x58\xab\x84\xee\xab\x10\x62\xe1\x57\x9e\x7d\xff\x53\x89\x63\xfc\x31\xc6\xff\x8e\xf0\x3f\xf8\x77\x85\x5f\x57\xf8\x05\xcd\x6e\x30\xe2\x82\xf6\x17\x46\xaf\xc7\xf1\xb5\xbd\x5b\x11\x7e\x1c\xca\xc5\x8b\xec\xad\x8b\xf0\xf7\xe1\x05\x7d\x44\x66\x1b\x39\x99\xc3\x91\xb4\xb7\x31\x6a\x25\x45\xde\xc6\x46\xce\x67\x64\x6d\x73\xc4\x3f\x0f\x81\x1a\x8b\xac\x1d\x57\xc9\xcb\x5c\x27\xf3\xe6\xab\x0c\xf2\x52\x1e\x05\xb7\x3d\x0a\x24\x46\x2e\x28\x44\xf6\x57\x14\x04\x87\x28\x90\x18\xb9\x40\x11\xd9\x5f\x91\x05\x21\x11\xfe\x3c\x9c\xe2\xef\xc8\x01\x16\xce\xd0\x0b\xef\x03\x4c\xc4\x09\x87\x33\x95\x12\x79\x10\xa4\x0a\x2c\xf8\x3b\xf2\x00\x4a\x65\x7b\x1d\x30\x7c\xa9\xcc\xef\xf8\x15\xd9\xc0\x46\xe1\x0d\x0e\x53\xfa\x88\x34\x88\x45\xf2\x47\x14\xb2\xe4\xf0\x3c\x51\x10\x56\xda\xdd\x97\x2d\x3b\x35\x0d\x78\x8e\xdf\xdf\x4f\xb7\x85\x34\x90\x3a\x32\x77\x71\xfa\x0f\x1d\x71\x3c\x1d\xe7\xcd\x54\xb1\x68\x81\x2c\x13\x7a\x81\x17\x84\xdc\x06\x34\x43\xf3\x21\xf8\x27\x3b\x80\xd7\x39\xfc\x29\xb4\x23\x77\xc8\xd0\xbf\x39\x55\x57\xb0\xbe\x36\x9b\xa0\xa3\xfb\x9d\x23\x0f\xc8\x91\x3a\xe1\x07\xe2\x56\x38\x02\xc1\xea\xf2\x43\x0e\x90\x8c\x8a\xf5\x43\x8a\x87\x43\xf4\xd0\x4a\x2c\xb2\x8b\xc6\x4a\xfa\x0d\x3e\x37\xfe\xf3\x08\xea\x62\x5d\xee\xef\xb3\xee\xfb\x6c\x7f\x7f\x96\x24\x6b\xc5\x7f\xa2\x47\xa3\x19\x69\x42\xed\x7d\xbb\xb9\xd9\x5b\xf5\xbf\xb1\x2f\xef\xa4\x99\x30\xef\x6a\xbf\x8a\xcc\xe5\x5c\xc4\xd2\x0a\xd8\xc8\x96\x73\x89\x84\x88\x08\xe8\xa2\x86\x62\xf8\x24\x33\x91\x0f\xd3\x29\x2c\xc2\x7a\x81\x62\x1b\xe9\x30\xfa\xa5\x0c\x86\x44\x71\x25\x44\xb5\x71\x9e\x41\xe8\x6d\x8f\x3c\xc9\xc2\x15\x6a\xbd\xe2\x73\x84\x16\x80\xd9\xf4\x32\x45\x27\x80\x3b\xbe\xde\x7f\xba\x2a\x9a\x79\xd6\xe4\x53\xaa\x6f\xa4\xd5\x81\x70\x23\xea\xa9\xa3\x46\x09\x0c\xb5\xd7\x0a\x50\xfa\x35\xbb\x7a\x7f\x61\x5c\x2b\xc0\x29\x5f\x2c\xca\xef\xaf\xfe\x6d\x9d\x2e\xc8\x9b\x42\xe9\x84\x14\x43\xf7\xe8\xd7\xbc\x26\xf1\xf5\x0a\x67\x3e\xfb\x48\x0e\xae\x2a\xa3\x16\x14\x5f\x9f\x73\x1c\xad\x78\xd1\xbf\x86\x83\xc0\xa5\xd9\x34\x42\xc8\x68\x56\x4e\x9e\x8c\x8a\xa5\x5c\x57\x00\x9f\x81\x9c\x70\x06\x34\x16\x34\x76\x7a\x81\x03\xf8\xd3\x62\x0d\x57\xf6\x90\xd0\x19\x99\x5a\xbc\xcd\x8a\x35\x27\xbc\x46\xd8\xe5\x9f\x7f\xc9\xae\x5e\x96\xdf\x0b\xfe\x78\x5b\xc2\x59\xf7\x3e\x3f\xaf\xf8\xc3\x9c\xe6\x39\x82\xed\x19\x3d\xa3\xb3\x6f\x46\xfe\xf3\x8d\xff\x48\xf6\xf2\x3a\xa3\x20\x4e\x38\xff\x78\x2e\x9c\x80\x85\xbe\xe1\x71\xa9\x35\x1a\xa5\x2a\x63\xcf\x0c\x32\xee\x4f\x39\x22\x9e\x8a\xc8\xd2\xb4\x22\xb2\xec\xef\xf7\x67\x49\x83\xa3\x90\x43\x18\x4c\xd8\x91\xbc\x69\x0a\x97\x22\x0e\x8d\xb6\x55\x52\xaf\x40\x8c\xec\x7e\x2b\xdb\x5a\xc9\xd8\xab\xf4\x79\x25\x95\x18\x7b\xb4\x02\x55\xbf\x1c\x58\x15\xbd\xd5\xb3\x2a\xcb\x0d\x70\x53\x4c\x63\xd8\x8e\x6b\x31\x74\x65\x45\xf1\x32\x27\x24\x7e\xf8\x58\x84\xce\x47\xfc\xe8\xd6\x77\x71\xef\x70\x00\x05\xab\x9c\xfa\xb8\x67\x03\x63\x57\x88\xf0\xd1\x00\x1a\x97\xba\xe1\x93\x01\x5f\xbf\x0a\xff\x60\x00\xd9\xfb\x90\x2e\x98\x5d\xdc\xf1\x92\x27\x84\x55\xf9\xbd\x7f\x24\x1e\xde\x1f\x74\xbe\x8f\xb7\x59\x6e\xaa\x38\xcd\xf2\x45\x9f\x7e\x01\x25\x33\x2b\x97\xfd\xc1\x3f\x14\x83\xa0\x51\xdf\xd1\x76\xe5\x3a\x8b\x06\x6f\x21\xa4\x76\xd4\xb0\xcf\x4d\xbe\xb0\xde\xda\x02\xa8\x2a\xf7\xb0\xd1\x8b\x45\xbe\x3a\x2f\xd3\x6a\xa6\xd0\x52\xda\x81\xae\x7c\x34\x46\x67\xc3\xc3\x65\x3a\x13\xe0\xc7\x69\x74\xea\xe5\x13\xb8\xaa\xcc\x85\x97\xf9\xb2\x4a\x2f\x55\xde\xca\xcb\x3b\x29\xd7\x32\x76\x9d\x71\x1a\xa3\x33\x3f\xbf\x51\x39\x73\x2f\xe7\xaf\xf3\x2c\x5b\xa8\x4c\x13\xba\x91\x57\x14\x28\xa4\x17\xec\xe2\x74\xd9\x16\x68\x7d\x73\xf1\xed\x65\xdb\x5e\xd0\xc5\xb4\xc8\x76\x5e\x9f\xe3\x61\xbf\x1d\xd1\x7e\x43\x64\x4a\x88\x61\x6f\x64\x23\x59\x9d\xae\x50\x2c\x66\x6f\x50\x8c\x94\x4f\xbf\xee\xda\xee\x0b\x2a\x1c\x68\x98\x32\xfc\x96\x2d\xa4\xb2\x6b\xfb\x56\x95\x50\x2f\x26\xbb\xd5\xd7\xea\x6a\xf7\x4e\xa0\x6c\xb0\xf5\xd5\x95\xdf\xec\x7a\x97\xbb\x8d\x6b\x43\xd1\x50\xa3\xeb\xc6\x6b\x73\x56\xae\xa1\xd6\x8b\xbb\x2c\xfb\x4b\xab\x4a\xa0\x0f\x2b\xdb\xef\x0b\xa0\x7e\xe7\x4e\xb0\x6c\xa8\x75\x48\x0f\x34\x8b\xec\xd1\x1d\x5a\xc6\xe2\x1d\x8d\x43\x56\xb0\x7d\x8c\xa0\x77\xa7\x1e\xb0\x42\x67\x1f\xe8\x77\x33\xd0\xcb\x8f\x7c\xe7\x1d\x7e\xa9\xca\x77\xf5\x01\x79\x81\x2e\x38\x50\xc9\x1d\xfa\xe0\x0a\x1d\x9d\x50\x66\xa0\x97\xf7\xdf\xee\xb6\x5a\x54\xbe\xa3\x0f\xcc\x0b\x74\xc1\x2c\xee\x1d\xfa\xe0\x0a\x1d\x9d\x50\x66\xab\x17\x20\xff\x77\xee\x00\xca\x06\xdb\x2e\x57\x5e\xb3\xc4\xd2\xec\xda\x2e\x93\x67\x81\x86\x29\xc3\x6b\x39\x47\x62\x61\xd7\x96\x89\xb2\x08\xb5\x4c\x19\x5e\xcb\x5f\x25\xf9\xb4\x63\xdb\x8a\xda\x0a\xb4\x2e\xb3\xda\xed\x7f\xa8\xb2\x7a\xe7\x65\xf9\x8b\x2a\x1f\xee\x81\xf2\xda\x5d\x7c\xde\x79\x3b\x99\x38\x0c\x37\xfe\xd9\xdf\xd0\x45\x99\xee\x8c\x7c\x7e\xc3\xb2\x81\x76\x31\xdd\x6b\x36\x43\x5b\xaa\x5d\xdb\x25\xc3\xab\x50\xc3\x94\xe1\xb5\xbc\xd4\xe4\xf7\x8e\xad\x1b\x7a\x3d\xd0\x83\xce\x0c\xf5\xf2\xb6\xdc\x1d\xdb\xbc\xd5\x15\xba\x7a\xc1\xcc\x50\x2f\xef\x77\x07\xfb\xb7\xaa\x7c\x57\x1f\xef\x5b\xc0\xcf\x5d\xdc\x01\xa3\xbd\xd5\x15\x3a\x3b\x69\xe3\xb4\xa5\x64\x6f\xee\xd2\x47\x18\x46\x65\x96\xd7\xfe\x2a\xad\x9b\x9d\xb7\xe2\x03\x15\x0e\xb4\x4d\x19\x5e\xcb\x6c\x9d\xb1\x63\xcb\x1f\xa9\x70\xa0\x65\xca\xf0\x5a\x66\xf7\xef\xbb\x36\xcd\x8e\xda\x43\x6d\x73\x8e\xdf\xf8\xfa\x7c\xb9\xfb\x75\xfb\x89\x4b\x87\x1a\xa7\x1c\xaf\xf1\x06\x89\xf8\x17\xa8\x67\xb9\xf3\xf0\x4f\xac\x2a\x81\x6e\xac\xec\x50\x5f\x77\x20\x80\x4e\x54\xf9\xae\x5e\xda\x24\x10\x75\x71\x97\xb3\x7c\xa2\x2b\x74\x75\x12\x38\xcb\xd4\xcb\x9d\xee\xf5\x13\x53\xa3\xab\x9f\xd0\xcd\xfe\x1d\x79\xa5\x5d\xfb\x20\xc6\x2a\xd4\x3c\x65\xb8\x2d\x6f\xf0\xad\x5f\x89\x42\xae\x86\xc8\x24\xa1\x10\x91\x69\xe5\xab\x21\x71\x37\xc2\x93\x70\x5c\x0d\x2d\xd6\x84\x33\x81\x23\xc0\xd4\xd5\x15\x7d\x02\xb2\x82\xaf\x35\x89\x23\x6d\xda\xfb\x6a\x68\x11\xef\x94\x89\x34\x33\xa4\xc2\x1f\xf5\x89\xdb\xcc\x29\xf0\xcb\x24\x22\x6d\xaa\x92\xe1\xb7\xce\x40\x7a\x52\xa6\xc3\x4f\x95\xcc\x24\x20\xa7\xd3\x6f\x95\x41\x38\x8e\xd3\xf1\xa7\x4a\xe6\x0d\xe1\x74\x96\x36\x53\x06\x50\x48\x98\x56\xae\xf0\x93\x2f\xac\xab\x21\xdd\x72\x42\x0b\xa2\xae\x58\xe2\x8b\x09\x4c\xa0\x5c\x0d\x89\xaa\x11\x96\x0c\xe7\x6a\x28\xc9\x11\x99\xc8\x94\x00\xa5\xd2\x4f\xa1\xa5\x3b\x94\xf6\x99\xfa\xa3\x8b\xf7\x6a\x88\x77\xb5\x70\x24\x50\x57\x43\x7d\x1d\xea\x0c\x02\x5c\x99\x81\xbf\x75\xc6\x7b\x1a\x91\xba\x73\x4c\x32\xaf\x83\xbe\x28\x84\x25\xae\x92\xc9\x3c\x0a\xc6\xab\x57\x43\x42\xc6\x98\xc0\xe8\x50\xaa\xe4\x62\x82\x44\x62\x57\x32\xf4\x05\x25\x31\xea\xb9\x1a\x32\xc6\xc2\x24\x1b\x57\x5c\x0d\x2d\x64\xa3\x33\x79\xe3\x15\x6a\xd0\xc9\x72\x66\xfa\x3c\xeb\x0c\xb5\x67\xe6\x0c\x62\x16\xc3\xfe\xd5\x90\x0e\xcc\x46\xeb\x5c\xbd\x40\xa3\xe3\x57\x83\x57\xa7\x2f\xce\x86\xb6\x4c\x34\x81\x04\x12\xe7\x9c\x3b\x92\xc9\x2b\x91\x51\xdc\x7b\x2d\x8c\x0e\x86\x37\x40\xd5\x2c\xaf\x9c\xcc\x9e\x94\x14\xc0\x92\x74\x97\xf0\x51\x48\x89\x7b\x58\x65\x0e\x55\x1c\xa9\xb3\x97\x6c\xe5\x4c\xa1\x24\xb7\x8a\x42\xa5\x0f\xc6\x6f\xc9\x2b\x34\x48\x24\x59\xbc\x76\x73\x8e\xe2\x4a\xcc\xbc\x9a\x78\xd2\xd2\xcb\xa1\x86\x49\xf3\x4d\x50\x65\x3e\x19\xa8\xcd\x37\xef\xae\xf9\x56\x3b\x99\xa4\xb6\xcc\xf3\x72\x68\xc3\xb1\x0c\x69\x3a\xc3\x60\xcf\xf6\xa0\x9c\xa2\x46\x96\x79\x69\x64\x99\x57\xc9\xba\xd5\x2c\x21\x22\xf3\x29\x0f\x59\x52\xb7\x0a\x32\x4a\x81\xce\x8f\xa0\xf3\x6a\x78\xbe\x6e\x9a\xb2\xe8\x18\x40\x4b\x3e\x4b\xa9\x36\x6a\x32\xa9\xe6\xa0\x79\x69\x04\x89\x5e\xda\x7b\x67\x71\xcd\xd1\xf2\xd2\x68\xae\xd3\xd6\x14\x08\xfd\xb9\x9f\x78\x0a\xfc\x94\xc6\x69\x50\xa3\x3d\x37\x89\x51\x9e\x9b\xe6\x0d\xc5\x60\x3a\x3b\x0d\x91\x5c\xb2\x68\x8d\xcd\x3e\xb0\x5e\xaa\x3b\x46\x73\x4a\xbd\x34\x79\x40\x93\x55\xab\x6d\x85\x32\x92\x8b\x56\x96\x3c\xbf\xc9\xbc\xbd\xdf\x78\xc9\x58\x9f\xce\xca\x4b\x34\x95\xe4\x9b\x65\xff\x8a\x55\x80\x5e\x24\x57\xd6\xcb\xd4\x37\x3a\x45\xea\x49\xaa\xdc\xfe\xee\xf4\x62\x20\x5e\x38\x72\xe1\xf3\xdb\x65\xeb\x96\xa8\x37\x7e\x74\xb4\x4d\xe6\xde\x25\xe6\x8d\xc7\x47\xbf\x8a\xb0\xcc\x15\xb2\x9e\x6c\x11\xc9\x87\xe4\xbf\x90\x37\x16\xdd\xe2\x5f\xc8\x76\x07\x63\x49\x7f\x21\xef\x81\xe8\x10\xf0\x42\xde\x43\x11\x92\xef\x42\xc6\x23\xd1\x21\xde\x85\xbc\x5f\x45\x48\xba\x1b\x8f\x1f\x76\x68\xc5\xb8\x2f\x06\x2d\x1d\x99\xbb\xba\xf2\xaf\x3c\x85\xf7\xc2\xb1\x89\x69\xc9\xd5\xcb\xe4\x7a\xaa\x36\xe7\x65\xda\xa4\x01\xcf\x6e\x91\x53\x80\xde\xb7\x8f\xb3\xa1\x5b\x4b\x3e\x40\x3b\x89\x00\x57\xd5\x30\x5d\x5f\xe2\xfb\x08\x29\x16\xf5\xf1\xa5\xab\x6d\x26\x11\xd8\x6a\x9a\xf9\x76\xd3\xc3\x3f\x62\xe6\x18\xcd\x90\x1f\x10\x7f\xdf\x48\xef\xea\xa9\x75\xc7\x91\x3a\xcf\x14\x72\xb8\xca\xa5\xdf\x4f\x0d\xdb\x83\x7c\x1c\xfb\xfd\xdd\x4d\xbc\x2c\x37\x06\x33\x89\x41\x00\x43\x5c\xe4\x97\xca\x82\x4b\xa5\xbe\x25\xd5\x96\x44\xfa\x95\x2f\x52\x7a\x42\xc3\x5e\x93\x42\xbe\xa4\xb3\x02\xa7\x09\x93\x3a\x7c\x83\xa8\xff\x22\x9d\x9a\x78\xe5\xd2\x25\x37\xa9\x7f\x77\x38\x31\x4f\x13\x74\xbc\x4d\xbe\xbe\xe1\x6f\x92\x1e\xa7\xfd\x62\x10\xa3\xaf\x6e\xe9\x42\x48\xba\xb8\x1b\x4a\x1f\x2b\x1f\x98\x16\xc9\x66\xc7\xed\xa4\x18\x35\x44\x11\xda\xc9\xb1\x01\xd1\x34\xec\x44\x3c\xaf\x5f\x7a\x45\x31\xc2\x8b\xed\xa7\xed\xa4\x5a\x67\xb1\x93\xf2\x3a\x5d\xd4\x72\x4d\xf2\xda\xa2\x88\x3e\x01\xfe\x5e\x41\x03\xed\xc2\xb7\xda\xad\xdd\xcd\xf1\xa4\x42\x3f\x27\xa4\x7e\x40\xcf\x67\xd7\x14\x2d\x82\x0d\x15\x28\x35\x4e\x85\xf4\xf9\xce\xa5\xdc\x29\xbc\x23\xd5\x4e\xc2\xeb\x14\xdb\x9a\x55\x15\x89\xf7\xaa\xa5\x0f\x43\xba\x31\xc9\x87\x08\xb7\x9a\x2f\x33\xb8\x08\x97\xab\x00\x0a\xe9\x65\x43\x9d\x7d\x73\x83\xae\x64\x86\x45\xf9\xbd\x4f\xcf\xf6\xfe\x3e\x90\xcd\x16\x2e\x6a\xad\x3e\x37\x93\xd2\xf5\xb6\xe1\x12\x95\x6d\xbd\x62\x7f\xc3\xf6\x46\x13\xcb\xfb\xba\x05\x90\x13\x9f\x40\x3d\x6e\x53\xac\x71\xe6\x40\x86\x72\xe5\x10\x80\x8b\x16\x54\x6c\x84\x47\x12\x77\xf8\x83\x77\x47\xe4\xd5\x39\x0e\x10\xd6\x31\x5a\x2a\xe0\xf2\xff\x89\x76\x84\xe2\xc8\xee\x06\x6d\x3c\x2c\x54\xd7\x06\xc6\xba\xb5\x72\x50\x9f\x73\xf0\xb0\x06\xea\xd9\xf9\x21\x90\x0f\x2b\x7b\x5b\x33\xdd\x7e\xe6\xa5\xc3\x24\x3a\xd0\xcd\x19\xeb\x27\x84\xf0\x8d\x31\xb7\xf1\x50\x8e\xc9\x70\xb0\x0e\x99\xf2\xe1\x5b\xa9\xee\x32\xa9\xd1\xf5\xb1\x85\x3a\x13\x17\x09\x9a\x28\x15\x70\xd2\xe4\xd9\xe3\x07\x78\x1b\x12\x81\xfb\xc1\x68\x79\x56\x82\xfd\x91\x38\x59\xf6\xd4\x13\x0c\xef\x6c\xc6\x42\xfe\x56\xad\xc1\xa1\xad\x45\xe6\x8e\xce\x1d\xac\x6f\x7c\x88\x36\x72\xcd\xbc\xca\xb2\xe7\x32\x16\x33\xa1\x10\x0a\x24\xe7\x59\x29\x76\x14\xfc\x79\xf7\x2a\x61\x0f\xad\x1e\xfe\x89\xc7\x8f\xc8\x16\xf1\xfe\x9d\x3d\x22\xef\x76\x51\x9a\x97\xf7\x12\x6d\xb1\x91\xd6\x9d\x49\xa4\xf6\x33\xd7\xa4\x4d\xe8\xd1\xb0\x77\x77\x7c\xfc\x7f\x98\x12\xb9\xbf\x5d\xa3\xfa\x0f\x59\xe0\x2e\xed\x85\xdc\xcd\x01\x22\xbc\x7d\x1f\xbd\x2d\x67\xe8\x17\x16\x75\x60\x9b\x8c\xaf\x25\x20\x7f\xe3\x5c\x2c\xa4\x8b\x28\x79\xb5\x34\xd5\x02\x7d\x20\xb1\x9f\x8e\x79\x7e\xd1\xe8\xaf\x74\x61\x7e\x2f\xb3\x26\xd5\x1f\x55\xb6\x82\xe3\xc9\xbf\xb1\x35\x75\x2d\x41\xd7\x4e\xaf\x78\xed\xc9\x41\x87\x68\x5d\x18\x0e\x2a\xcc\xd6\xa8\x69\xc5\xa1\xc9\x8f\x31\x56\x70\x3c\xa2\x57\xaa\x2d\xb5\x80\xfc\x2d\x4c\xa5\x9b\x1b\x4c\x5b\xaf\xac\x66\xb2\xa1\x6a\x60\x84\x52\xce\xdc\x11\xb5\xdc\xda\xff\x9d\xbb\x08\x00\x52\xbd\x2b\xd0\x6f\xe5\x60\xec\x0d\x86\xb4\x27\xa2\x73\x7f\xe1\xd8\x33\x54\xee\xae\x51\xfb\xfb\xa0\xf2\x1f\xf3\xec\x3b\xce\xee\x6d\x86\x4d\xd7\x6d\xa0\xf4\xe1\x2f\x4d\xae\x6b\x40\xeb\x59\xf1\x4f\x12\xd6\xe8\xe3\x6f\x12\x0a\x17\xa8\xe9\xfd\x4f\xf6\xc7\xdf\x7e\x1e\x3e\x5b\x70\x98\x0b\x16\xe4\x04\x2d\x83\x39\x4b\x32\xf1\x11\x41\x0b\x33\x5e\x4d\x8c\x42\xa0\xe6\xf8\x28\x7e\x40\x7f\xc7\x08\x4d\x5c\xba\x56\x07\xc1\xc6\x7f\x41\x5a\xcc\x29\x82\x4e\xcf\x87\x18\x17\x4c\xaa\xb2\x11\x38\xd5\xd5\x54\x7e\x02\x50\x35\xa5\x52\xc9\x75\x0a\xa2\x4f\xb2\xf4\x32\xfb\xa7\x10\x18\x53\x86\x62\x15\xb9\x14\xb1\x8c\xb8\xa0\x07\xe5\x50\x12\x9e\x2c\x1d\x21\x45\x5d\x6a\xea\x6f\x5d\x4d\xfd\xcd\x6e\xea\x6f\xba\xa9\xbf\xf9\x4d\x9d\x94\xab\x10\xe0\xa7\x77\x01\x7c\x1f\x88\x20\x7d\x17\x18\xdf\xdd\x35\xf7\x1f\x83\x79\x7d\x50\xce\xf1\x71\x63\x8d\x42\x1d\x9b\xc8\x3f\xb1\x93\xa6\xa4\x79\x39\x73\xd2\x3a\xe1\x75\x0b\x8c\xb7\x40\xb9\x0c\xac\x79\xfe\x33\xc8\xa6\x63\x6d\x77\x76\x00\xf8\xb3\xf7\x6f\x98\x69\x82\x25\x45\xdb\x01\x3f\x6c\x6a\x36\xc4\x54\xe3\x17\x14\xbf\xa4\xa9\x5b\x29\x5d\x69\x32\xe3\x49\x01\x4f\x59\x32\x42\x3e\x35\x75\x40\x53\xe5\xfb\x9c\xbc\xe5\xbf\x94\xca\xf1\xda\x57\xab\xe1\x4e\x11\x14\x6f\x6e\x94\x1e\xfc\x5f\xa9\x25\x29\x6a\xe1\x10\x16\xf9\x22\x7c\xc0\x39\xef\xe6\x26\x78\x0d\x6c\xdd\x99\x96\x06\x6c\x90\x8e\xfb\x0f\x12\x4a\xb5\x04\x1e\xd9\xa2\x49\x83\xf8\x85\x73\x14\x56\x90\xe5\x22\x7a\x0a\x79\x69\x65\x1d\x66\x43\x2b\x2d\x26\xff\x83\xf0\x2b\x88\x67\x38\xc7\x69\xf2\x6f\x76\x93\x7f\x0b\x34\xe9\x14\x08\xe4\xeb\x1e\xff\x27\x9f\x1c\xfa\xfd\x56\x05\x70\xfc\x23\xc4\x37\x3b\x47\x33\xb2\xb5\x4a\x2b\xa4\x92\x83\x6e\x0e\x5a\x1c\x61\xd3\xb6\xf3\x65\x4e\x2e\x6c\x03\xac\xbc\x1c\x7c\xe7\xef\x37\xd0\x07\x8a\x02\x8f\x43\x89\xda\xae\x39\x0e\xe5\x62\xb8\x44\xf6\x67\x91\xd7\x6f\x0a\xdb\xa6\x13\x83\x0e\xfb\x89\x18\x1d\xa5\xc3\x2a\x59\x0a\x14\xdc\xe2\x2d\xbd\xe9\xbd\xbd\x60\x67\x1d\x46\xbf\x14\x25\x41\xa4\xa2\x16\x6b\x74\xc1\xb0\x27\x99\x67\xa7\x6a\x5f\xba\xdd\x9a\x8a\x85\x15\x2e\xb0\x35\x99\x91\x98\x1a\xf6\x5d\x6f\x09\x5a\xc6\x8e\x48\x37\x59\x9e\x1c\xa7\x4b\xac\x62\x02\x0c\x62\xe3\xe4\x65\x59\xf7\x42\x06\xdf\xdc\xc4\x66\x4a\x8f\x75\xab\xc1\xf5\x06\xe3\xec\xf5\x5a\xf9\xba\x95\xae\xb5\x56\x1e\x7c\x17\xa8\xc4\x66\x8d\xaf\x23\xce\x73\x17\xd4\x08\x80\xc3\x49\xf1\x54\x7b\x23\xb5\x7c\x42\x50\xf0\x02\x3d\x78\x0f\x0e\x30\x1e\x4b\x39\x7c\xff\xa7\x4f\xaf\x3e\xfe\xe3\xab\x97\x5f\x5e\x7d\xfc\xf8\xfe\x63\x10\xc6\xb0\x60\x65\x2d\xe1\xb1\xfd\x61\xf0\xcf\x80\x8f\x9e\x9a\x36\xc6\x92\xe9\x68\x2c\x69\xf5\x6b\x56\xd8\xdd\xa9\xe2\x60\xac\x16\x3a\x87\x85\xde\x6c\xa4\xcd\xbd\xbf\x4a\x32\x34\x5e\x00\x50\x76\x58\x3f\x40\x96\x93\xca\xac\x5f\xa5\xd6\x0f\xa3\x52\x37\x18\xfa\x52\x1e\x4c\x7f\x26\x15\xaf\x6d\x8e\x50\x56\xef\xb5\x27\x85\xb6\x6a\x34\x5a\xfd\xc3\x42\xd6\x35\xde\x82\x16\xac\x51\xd8\xe9\x36\x9c\x55\x66\x01\xd6\xb4\x00\x5b\xcf\x3b\x2c\x4f\xa9\xc2\xa7\x56\xc2\x1d\x4d\x7c\x1d\x32\xd3\x6b\xbb\x26\xbb\xbf\x5d\xe6\x6e\x21\x3e\x40\x0b\x9f\x0b\x32\x0a\xcb\x66\x4c\x25\x7e\x28\xeb\x5c\xca\x4b\xd1\xae\xc2\xa7\x45\xe3\x91\xf0\x89\x4a\x48\xaa\xb2\x0b\xe0\xcb\xe6\x9c\x44\xa2\xc0\xba\x2d\xe3\x2a\xa4\x91\xde\x00\x30\x7b\xab\x5d\x38\xcb\x3f\x44\xd5\x22\x58\x21\xf9\xaa\x65\x9a\xb1\x7d\xdc\x70\x0f\x93\x60\xe2\xc1\x5d\x84\xf7\x44\xbb\x54\x8a\x34\x19\x08\xf6\xbe\x9f\xf9\x54\x89\xef\x59\x1c\xb6\xca\x4d\x6a\x4c\x60\x86\xfd\xfd\xf2\x18\x43\xfc\xac\xeb\xf9\x10\xb6\x7a\x71\xc5\x7e\x42\x80\x5d\x2d\x54\x7a\x9f\xbf\xcb\xe3\xd3\xec\x0c\x45\x60\x00\x24\xe8\xb8\xe4\x14\x0a\x3a\x6e\x99\xc3\x8e\xf5\x8a\xae\xed\x7f\xb0\xbb\x24\xc9\x46\x4e\x63\xc0\x42\x23\x8a\xc2\x5b\x9a\xc8\x04\x25\x9c\xa4\x26\xe9\x37\x07\xd9\x50\x49\x06\x9e\x37\xf8\xc8\xf0\xdf\x2a\x28\x0e\x87\xbb\x81\x5f\xda\x43\xd4\x4d\xf1\xf4\xe9\xf8\x91\x1c\xfa\xa3\x87\x0f\x8f\xc6\x81\x88\x41\x0f\x5a\x12\x23\x77\x44\x16\x27\xb6\x5a\xa4\xd3\xac\x5f\x09\xb7\xb8\xf6\x47\xd5\x94\x9f\xf1\x0c\xbd\x40\xf7\x08\x83\x8d\x22\x9b\xee\x1d\xf6\x87\x83\x7b\x97\xa1\x9e\x77\x97\x00\x59\x11\x9f\xcc\x40\x4a\x11\x2d\xeb\x43\xf4\xe9\x6f\x6d\xce\x34\x5d\x66\x88\xeb\x88\x2a\xbb\xf7\xcf\x87\x50\xe2\x5e\x7b\x97\x74\xa9\x18\xe6\x4f\x63\x69\xf1\xfd\x3e\x44\xaa\x75\x00\x42\xf9\x38\x23\x7e\x76\x6f\x14\xa3\xa1\xe6\xf1\xde\x18\xfe\x36\x83\x63\x2a\x38\x34\x91\xaf\x49\xf4\x2d\x83\xb2\x1f\x9b\x9f\xec\x0c\x07\x7d\x9e\x43\x49\x45\x51\xab\xf3\x72\x00\x4a\x3f\xb5\xc0\xbc\xb7\xd7\x1f\x3f\xda\xef\xcc\xef\x63\xe4\x43\xe8\x10\xf0\x9c\x0d\x91\x64\xe4\x45\x81\xdf\x43\x20\x69\x72\x01\x26\x89\x16\x7b\xd0\x62\x01\x43\xab\xbd\xb7\x07\xb3\xb5\x7c\xed\x2b\x17\x12\x41\xf7\x41\x68\xdb\x17\x31\x98\x4a\xbb\xe2\x3d\xb4\x37\x6e\x48\x54\xfc\x2d\x5d\x50\x22\x96\x91\x2e\xe9\xad\xf0\x80\xe8\xb5\x1d\x55\x7c\xa0\x33\xff\x48\x43\x57\x88\xe1\xb3\x8c\xaa\xc3\x57\xde\x64\x4b\x6e\xca\x33\x97\xb5\x42\x53\x1c\xb7\x42\x0e\x64\xc3\x9a\x7c\xd8\xc0\xe9\x46\x09\x15\x06\xcb\xb3\xec\x57\x9b\xf2\x39\x7b\xd7\x6f\x63\x36\x95\x15\x8f\x1f\xff\x4a\x0b\xb7\x3b\x7f\xa7\x24\x24\xa5\x94\xc6\xbf\x4e\x51\x9e\x4e\x78\xaa\x48\x94\x7f\x59\x26\xa6\xaf\xf1\x6d\x60\x91\x72\x28\x54\xf6\x8c\xf2\x1a\x50\xde\x87\xf4\xd2\x78\x65\x8b\x0e\x32\xe3\x47\xff\xaf\xf9\x62\xf1\x99\x63\x9f\xda\x98\x3d\x47\x0f\xaf\x1b\xe9\xd1\x33\xe4\xc6\xd0\x76\x24\x87\xde\xd6\xbc\x30\x7e\x9e\xf3\x3c\x00\xb9\x6c\x67\x2f\x7a\x5b\xb1\x62\x57\x9b\x31\x6b\x12\x84\x3c\xab\x05\x10\x69\x8b\x95\x0b\x2d\x77\x36\x5c\xd2\xe5\x3e\x35\x9e\xf2\xe0\xc8\x9e\x8e\xcf\x00\x3f\xfd\x56\x7e\xd7\xf8\xc9\x86\x1e\xf5\x8c\x52\x25\xeb\x49\xdd\xdf\xdb\x5b\xab\x40\x8d\xd8\x2e\x50\xb0\x25\xd0\x1b\x7d\x19\x7d\x06\x39\xc4\xbc\x00\x66\xf8\xcf\x27\x6f\x7f\x4b\xa6\xd0\xf0\x41\x76\x30\x3d\x3d\x3a\xd3\x84\xd1\x02\x52\x47\x67\x93\xc5\xe1\xe1\x64\x50\xc1\x4e\xc3\x16\x73\xac\x5b\x26\x6b\xed\xea\x19\xf5\xb3\x62\xbf\x35\x72\x01\xea\x3f\x5d\x9d\xa4\x97\x14\xac\x39\xaa\xa7\x55\xbe\xc2\x15\x5d\x99\x08\xf7\x88\x40\x44\x0e\x64\xf2\x10\x3a\x7c\x95\x62\x6c\x11\x8b\x2a\xbb\x48\xf2\x3e\x00\x17\x76\x87\x27\x1e\xfd\x05\x9a\x01\xc0\x78\x9c\xb0\xba\x56\x96\x5e\xad\x0b\xc7\xb2\x9b\x14\xe9\x72\x34\xec\xff\x96\x57\x65\xe1\x6e\x39\x83\x30\x1d\x10\x0c\xbb\xe9\xc8\xd0\xd9\xe9\x20\x52\x84\xc6\x22\xd2\xe6\xeb\xd6\x78\x2e\xd2\xe2\x73\x9d\xbd\x7c\xff\xf6\x58\x5b\xdd\x73\x93\xca\x8c\x3e\x9a\xe5\xdf\xa2\x81\x14\xf2\x00\x36\xff\x7b\xfd\x0f\x4f\xfb\x7f\xff\x7e\x30\xb8\x37\xf9\xcf\xad\xa3\x1a\x1c\x6b\xfc\x88\x94\x66\xfc\x91\x02\xda\x7f\x28\x5a\x03\x05\x5a\xa5\x23\x3e\xe6\x83\x16\xef\x1a\xc2\x97\x6d\x4c\x79\x2c\xdf\xa6\xbe\x66\x57\xe8\x4c\x61\x78\x91\x2f\x00\x1b\x1a\xcf\xc4\xd6\xbd\x82\xa1\x89\x07\x43\x8c\x0e\xd8\x8f\x7a\x30\x69\xc6\x61\xe6\x4d\x0e\x73\x98\xda\x4d\xe5\x83\x58\x2d\xb0\xe0\x26\x70\xb1\xde\x45\xc9\x43\x3d\x20\x32\x8d\x85\xae\xe1\x5a\x3e\x83\x30\x91\xcc\xb9\x49\x5e\xa4\xa2\xa6\x44\x52\x41\x22\xaf\xdf\xa5\xef\x2c\x52\xab\xba\xb9\x41\xcd\x43\xa8\x54\xfa\xda\x10\x88\xff\x31\xac\xe9\x71\x14\x1d\x34\xb1\x8e\x3b\x62\x3a\x42\x8f\x92\x09\x50\x12\x55\xbe\x04\x56\x43\x34\x07\xd1\xea\x47\xe4\x46\x11\xf8\xf4\xc9\x72\xaf\x83\xca\x9e\x79\x8d\x2e\x45\x16\x59\x5d\xbf\xa3\x9b\xa5\x8d\x7d\xec\x3a\xf1\x03\x22\x47\x1f\xb6\xc8\x51\x5f\x12\xc4\x21\x8c\x94\x6a\xda\x26\xa8\xd9\xe0\x1a\xb8\xb6\x3b\x0e\xbe\x4c\xfa\x6a\x53\x0f\x5b\xf4\x61\x90\xf2\x69\x63\xf3\x6c\xe3\xfa\x84\xdc\x54\xf6\x2b\x77\xc2\x0f\xa8\xee\xab\x37\x20\x34\xf4\x01\x5e\xf9\xcf\xe5\x98\x3e\xf2\xd2\x51\xad\x02\xd2\xd9\x9f\xb1\x5b\x03\x2e\x91\x24\x70\xbb\x40\xf2\xc6\x2d\xa9\xde\x6e\x43\x0e\x3d\xb3\x8d\x68\xdb\x78\x3f\xdc\xfe\x7e\xf9\xad\x3b\xf2\xe5\xc3\x9f\xa0\x26\x11\x16\x83\x64\x44\x1f\x00\x14\x8e\xab\xa2\x34\x73\x25\x05\x04\x5e\x30\xda\x8f\xe2\x68\x3f\x5d\xae\x26\x91\x88\x9e\xe1\xef\xcb\x06\x7f\x3e\xc5\x9f\x0b\xfc\xf9\x4b\xf4\x0b\xfc\xfc\xb7\x75\x49\xe9\xbf\x60\xfa\x7f\xf9\x71\xf4\xeb\x24\xda\x00\xe2\xbc\x77\xba\xff\xec\x69\xf4\xcb\x99\x43\x11\xeb\xd9\xdf\xf5\xf5\x49\x1e\x0c\x64\x7c\x5b\xaa\x47\x05\xdd\x57\xb9\xf2\x20\x22\x0f\x7a\x8a\xbc\xb7\x3c\x6d\x93\x34\x31\x47\x30\xa9\x8f\x4b\x24\x4d\x15\x7d\x26\x53\xf0\xa4\x0e\xe2\x46\x54\x28\x66\x48\x03\x3e\x4a\x3c\xde\x2c\x93\xe2\x65\xd8\x23\x15\xd2\x82\x03\xd9\xc2\x69\xde\x5c\xfb\xbe\xd3\xd9\x2b\xac\xa1\x30\xe4\xc5\xd2\x54\x29\xfa\x5f\x42\x7e\x5d\x47\x56\x1f\x4c\xdc\xd3\xb6\x69\x5d\x00\x81\x16\xe3\xf1\x11\x3d\xf2\x87\x1a\x84\xf3\xf7\x38\x78\x1e\xef\x12\xb9\x14\xe5\x0b\x19\x1b\x1b\xf4\x95\x58\xa1\x41\xb1\x42\x00\x40\x77\x71\x5f\xe0\x6b\xb4\x07\x28\x59\x7d\xeb\x43\x7e\x8c\xec\x08\xdf\x0a\x05\x79\xc1\x0d\x74\xbb\x8d\x6a\xe2\x09\x28\xcf\xa0\xea\x12\x4e\x6d\x4f\x12\x37\x37\x3a\xfd\xbc\x9c\x5d\xc9\x39\x9a\x33\xe4\xe6\x86\xe6\xbd\xbb\x72\xa4\xa4\xe1\x50\xfe\xa6\x9e\x87\xd5\xbb\xa2\x62\x77\x59\x72\xdd\x47\x3a\x4f\x25\x09\xba\x6e\xf6\xf7\xc7\xf7\x31\x9c\x36\x5d\x21\xe3\xfb\xc0\x26\x35\x80\x02\x9b\x67\xc9\xfd\xa3\x9b\x1b\xca\x6a\x8e\x9b\x78\x14\x1a\xe0\x5d\x82\x32\xd0\xa3\x0a\x8c\x4d\x53\xf7\xa7\xf4\x79\x76\x73\x43\x7f\x29\x38\x19\xdc\x47\x33\x58\x11\x0a\x2b\x8b\x71\xee\xcc\x73\x0a\xfa\x1e\x0a\xbc\x9b\xab\x3b\xb8\xb2\x42\x49\xf2\x6c\x8e\xa3\x57\x05\x45\xcc\x60\x77\xfd\xf4\xa6\xa9\x9e\xb9\xe1\x84\x6f\xee\xf0\xa8\x9f\x9f\xea\x45\x85\xd1\xba\x83\x8c\xa3\xc8\xbe\x64\x03\x2a\x13\x80\xf9\x5e\xd5\xd3\x38\x7a\x45\x0e\x8f\x23\xf1\x69\x05\x88\xf1\x3c\xad\x62\xa0\x41\x04\x89\xa2\x22\x80\xd1\xf2\x3b\xfe\x8c\xc4\xe7\x95\xfc\xfc\xbc\x8a\xc4\xc7\xfc\x72\xae\xb2\xe9\x77\x24\x48\x93\x9f\x53\xf0\x27\x24\x64\x8b\x38\x7a\x49\x31\xcd\x23\xf1\xd7\x1c\x32\xdf\x7f\x8a\x04\x99\x06\x44\x96\x9d\x40\x24\x9e\xaf\x56\xb5\x97\x24\x15\xd7\x23\x29\xbe\x2a\xa7\x5f\xa1\x66\xf9\xef\x1f\x60\xc1\xc8\xe9\x0c\x3e\x06\xba\xd3\x45\x44\x7c\xfd\x38\x8e\xd0\x5d\x75\x8d\x13\x89\xc4\x93\x38\x3a\x49\xcf\x23\x31\x3e\x82\xd6\x81\xfc\xa9\xe0\xe7\xfd\x58\xae\xbe\x18\x3f\x82\xe6\xf1\x61\x11\x7e\xfe\xca\xdd\x43\x5f\xf0\x01\x8d\x3c\x5f\x60\x2a\xd4\xff\x90\x02\xd8\x44\xe2\x68\x04\x05\xd2\x55\xcd\x03\x39\xfa\xd5\xac\xd9\xfd\x23\x5a\xad\xfb\xf7\xb1\xec\x65\x86\x6b\x73\xff\x01\xff\xe6\x55\xb8\xff\x10\x7b\x9c\xc1\x0f\xe8\xef\xcf\xe5\x12\xeb\xfc\xea\x2c\xec\xfd\xc7\xd6\xc2\xde\x7f\xe2\xae\xea\x83\x91\xb3\xa6\xc0\xe4\x47\x6f\x8a\x3a\x43\xa7\x6d\xc0\xb7\xea\xe5\xc5\xe8\xe8\xd1\xeb\x71\x44\x71\xa6\xa3\xd7\x47\x11\x85\x8d\x8e\x5e\xdf\x8f\x28\x6c\x73\xf4\xfa\x41\x44\x91\xcc\xa2\xd7\x0f\x23\x0a\x3a\x15\xbd\x7e\x14\x51\x7c\x95\xe8\xf5\xaf\x11\x05\x31\x89\x5e\x3f\x8e\x28\xe6\x42\xf4\xfa\x49\x44\x8e\xdb\xa1\xc1\x51\x44\x2e\xaf\xe1\x17\xb6\x7d\x84\x6d\x8f\xb1\xf1\x07\xd0\x38\x90\x66\xbc\x1e\x28\x7a\x70\x76\xea\xe8\x08\xb2\xdf\x66\x4d\x1a\xf9\xd8\xab\x4b\xb3\x03\xcf\xec\xa3\xbb\x84\x7b\x30\xd2\x6a\x81\x4f\x99\xb6\x0a\x23\x5e\x60\x43\xff\x91\x58\xdb\xab\xb4\x72\xf0\x7c\xf2\x39\x41\xd2\x41\x53\xbc\xc7\x7b\x7b\x18\x9c\x1a\xa5\x32\x0e\x45\xe6\xb0\xd7\x70\x82\x00\x54\xe2\x88\x9f\xb1\x23\x21\x81\x28\x8e\xe4\xf3\x35\x82\x7b\x93\xc6\x91\x7c\xda\x06\xb8\x46\x80\x8b\x23\xf5\xa0\x1d\x85\x7c\xe2\x3c\xba\x8b\x70\x51\x31\xc8\x8d\x54\xa6\xb0\x75\x27\x6e\x6e\x58\x1c\xac\xe6\x44\x08\x53\x4b\x66\x8e\x6d\xb9\x56\xdc\x04\x90\xe8\xa3\xdd\xc4\x88\x25\x70\xd7\xf9\x40\xac\xda\x9c\x01\xea\x76\x24\xd1\x3f\x20\x13\x19\xcc\xcc\x2d\xb6\x19\x8a\x21\x5e\x3b\x8e\x9e\x2e\xf2\xe2\x6b\xef\x1e\x92\x61\x4f\x29\x7c\xf5\xb3\xa7\xf7\xf8\x6f\x24\x52\xd8\xa1\x64\x2f\x07\x9e\xab\x52\x3c\x2e\xa5\x1d\xaf\xe0\x3f\x7e\x59\xb1\x50\x5e\x07\xa7\x5b\xb6\x39\xd7\x1c\x85\x37\x77\xe1\x5c\xd3\xe4\x7a\x9a\x57\xd3\x05\x5a\x77\xa2\x12\x31\xba\x1b\x10\xd9\x62\x91\xaf\x6a\x4a\x42\x07\x25\x02\xdd\x0b\xaa\xbf\x69\xf5\xdf\xa5\xef\x46\x4c\x59\xa5\xcd\x9c\xfe\x96\x8b\xab\x4b\x7c\x3e\xe4\x9f\xaa\x02\x96\x4c\x17\x76\x85\x0a\xdd\x91\xe1\x0b\x4a\x43\xce\x24\xd8\x15\xdd\xde\x68\x03\x94\xdf\xe9\x58\xfc\xf2\x94\xdd\x9b\xf5\x96\xeb\x45\x93\xaf\x16\xb0\xe8\xe4\xae\xeb\xd9\x2f\x02\x63\x02\x50\xde\xb3\x08\xa3\x1c\x43\xe1\xe8\x29\x61\xd0\x67\x48\xdf\xde\x93\x3f\xcf\x80\x15\x3f\xbd\xaf\xb3\x9e\x36\x78\xf1\xc3\x9f\x4a\x96\xaa\x60\x0f\x64\x9a\xa9\xb2\xe0\xd6\xea\x6f\x97\x5c\x8a\x7e\x9c\x61\x88\x34\xd8\xcb\x18\xf3\x8e\x9f\xc2\x92\x71\x26\xfd\x38\x13\x00\x70\x29\x65\x3d\x5d\xa6\x2b\xce\xa1\x1f\x30\x00\x38\x36\xa7\x47\xad\x21\xa8\x6e\x21\xfb\xb2\x2a\xd7\xb2\x8e\xfe\xb2\x87\x93\x5d\xa2\xe7\x42\x6a\x1c\x0e\xf7\x62\x56\x67\x0d\x97\x36\x5f\x30\xba\xb4\x4a\x97\x5c\x88\x39\x7b\x2e\xa2\x7e\x9f\x89\xa6\x0a\x0c\x83\x57\xc1\x5f\x80\x72\xd5\xd0\x28\xe2\x1a\x7f\xe2\xbb\x6e\x4d\x76\xc0\xf8\x6b\x2d\xd4\x18\xe1\x27\xd5\xc4\xbf\x17\x65\xd9\xe0\xdf\x79\x96\xce\xf0\xef\x2c\x9e\xc2\x07\xfc\x27\x81\x69\xc1\xb0\xb4\xd0\xa0\xb4\x00\x48\x5a\x30\x20\x2d\x7c\x38\x5a\x30\x18\x2d\x34\x14\x2d\x0c\x10\x2d\x7c\x18\x5a\x30\x08\x2d\x18\x82\x16\x0c\x40\x8b\x00\x7a\xde\x26\x72\x69\x0b\x51\x1e\xdd\x85\x43\x23\x7f\xcf\x40\xdd\x66\xd6\xf9\x9d\x0c\xb2\xc4\xf9\xd6\x9c\xa4\xcb\x95\x70\xdd\x89\x24\xd6\x0a\x18\xfd\xa7\xfc\x1c\xd5\x8a\x8d\x22\x8c\x95\x38\xc1\x46\x0d\x76\xdb\x78\x91\x0b\xcc\x9b\x8c\x14\x07\xe6\xc9\x88\x62\x86\x97\xdc\xc1\x7d\x7c\xa6\x54\x78\x92\x52\xd2\x24\x3f\x28\xc9\xf3\xa3\x74\x87\x2a\x65\x77\x48\x8c\x02\x3b\x96\x3e\xd3\x04\xe1\x35\x85\x51\x2d\x95\x73\xdd\xe6\x30\xdf\x4c\x72\xe0\xb2\xb0\x27\xf4\x25\x37\xb0\xe9\xe9\x52\x61\xda\xbb\x38\xfd\x54\x13\x3e\x36\x52\x76\x34\xcc\x44\xad\x11\x89\xb8\x2c\x7d\x39\xbd\xb0\x36\x76\x7c\x12\xe0\x29\x1e\xed\xcc\x22\xe9\xa7\x84\x72\x7f\xdf\x42\x9b\x40\xa4\x97\x49\x64\x2d\x11\x92\xf5\x1a\x95\x7a\x43\x3b\x76\x0a\xc6\x11\xdd\x03\xc8\xe7\x21\x7e\xde\x09\x87\xb3\x76\xfe\xae\xd0\x4b\x33\xbc\x8b\x9c\x5f\x2d\x32\xac\x2c\x5f\xa2\xc7\xd7\x3f\x94\x99\x19\x29\x14\xb2\xe7\x51\x8b\x93\xf2\x66\x28\xad\xb4\x91\xc4\x13\x57\x76\xcd\xbf\xed\x58\x13\x95\x09\x63\xe8\x34\x73\x5b\xca\xac\xec\xd0\x9d\x7d\x8b\x40\x3d\xf0\xf4\x17\x1d\xfe\xd7\x71\x34\xf0\x44\xe9\xf2\xa1\xaf\x7f\xfa\xfc\xf0\x7f\x9e\x85\xdf\xfa\x1e\xdd\x85\x09\x34\x6f\x7d\x03\xfb\xb1\xef\x90\x5e\xfb\xec\x0d\x9f\x5f\xad\xe6\x59\xc1\x4a\x85\xf8\xda\x17\x7e\xec\x33\xa5\x62\x98\x32\x8d\xe6\x27\x04\xa4\xfa\xad\x24\x69\x89\x2d\x25\x83\xa5\xde\x74\x54\x68\xb4\xd7\x65\x75\x92\x5e\xf6\x39\x57\xc8\x10\x3a\xd0\x5e\x8c\xa1\x6c\x38\xb5\x2f\x53\xd1\xe0\x43\x1b\x5d\xd0\x0b\xd1\x46\xca\x76\x7c\x27\x7a\xa1\x17\x18\x93\xf6\x5b\x76\x99\x4e\xaf\x42\x39\xef\x88\xe8\xb5\x64\x2d\x52\x9e\xc2\x4d\xa1\x65\x84\x95\xb7\x09\x3f\xe0\x84\xe2\xc0\x79\x55\xe3\x27\xe6\x41\xc7\x1d\x4c\x3c\x1e\x3d\x10\x5d\xa3\x81\xcc\xa0\x6c\xf4\xd7\xed\x64\x7e\x48\x66\x62\xb4\x8f\xd8\x85\xae\xa4\x7b\xd7\x14\x0a\x1d\x03\x8d\x90\xb4\x60\xb0\x4e\xac\x40\xf3\x6f\xf3\x82\x18\xc3\x5e\xf6\x63\x9a\xad\x18\xf7\x4f\x49\xf9\x61\x36\xe9\xad\x49\x15\x29\xeb\x15\x65\x71\xb8\x54\x05\x67\xd9\xb7\x5e\x66\xd0\x46\x0f\xee\x08\x2a\x74\x01\x98\xa6\x47\xce\x28\x7a\x4b\x0c\xef\x72\x99\xf5\xd2\x62\xd6\x4b\x67\x33\x7a\xbe\x4d\x17\xbd\x79\xb6\x58\x41\xa9\x9e\x9c\x6a\x3d\x44\xc9\xd6\xa2\xce\x64\x20\xfa\x53\x6b\x02\x48\x36\x8d\x26\xce\x48\xdf\xa8\x5b\xb5\xf7\x8f\x79\xb9\x60\x3b\x84\x5e\x74\xd0\xe8\x73\x72\xef\xbf\xd5\xf7\x2e\xed\xc0\x09\x12\x6c\xa7\xa7\x8b\x83\x83\xb3\x0d\x5c\x29\xcd\x1c\x38\xc4\xde\x7a\x78\x51\xa1\x97\x92\x93\xf2\x43\xb9\x4a\xc6\x62\xbd\x09\x09\x8f\x7e\xbd\x8b\x15\x0c\xaf\xb7\xf5\xac\x73\x73\xd3\xd0\x2b\x30\xcc\x9e\xb8\x2d\x15\x1f\xcc\x46\xf6\x56\x9c\x79\xde\xcd\xa8\x2c\xf0\xa9\x33\x4f\x8a\x9e\x55\x8c\xdc\x2b\xe4\xca\x96\x72\x2b\xd1\x3d\x49\x31\x3a\xae\xf6\xc5\xde\x2f\x30\x46\x38\x76\x31\x21\xe2\x3d\xf0\x74\x8d\x2a\x54\x52\x92\xb2\x07\x17\x74\xb5\xbf\xcf\xaa\x92\xc4\x64\xc0\x55\x95\x9b\x0e\xf3\xe5\x8a\x3b\xa3\xa5\x47\x46\xe5\x35\x8c\x80\x02\x5a\xb0\x93\x08\xd6\xa8\x04\x1a\xf0\xfe\x70\x84\x51\x62\x72\xc6\x57\x62\xeb\x83\xda\xa4\x74\xae\xc6\xaa\xab\xbf\xfd\xfd\xdb\x07\xb2\x4b\x99\x7e\x04\x03\x8c\x06\x7b\x49\xc2\x11\x33\xef\x70\x31\xfe\xba\x13\x9f\xb7\x07\xe7\xee\xe6\x66\x2f\x14\xa6\x02\x69\xac\xe3\xac\xa7\xa2\xc9\xcb\x94\xb8\xfd\x76\x66\x54\x05\x92\x90\xaa\x40\x00\x0b\x63\x26\xbe\x9b\x0e\x42\x8f\x62\xbf\xfe\xc4\xfb\x00\xa9\x3f\xbc\x79\xf7\xe1\xf3\x09\xcb\xd1\x54\x07\x00\x23\xa7\x8c\xc0\x51\x92\x76\xf2\xea\x9f\x4e\x9e\x7f\x7c\xf5\xdc\x2d\xa3\x2e\xaa\x6b\xf2\x49\x4f\xac\x5f\xda\x64\xea\x2f\x9a\x98\xe2\xef\x48\x7d\x1c\x92\x21\x50\x44\xac\xe1\x12\x95\xa5\xe1\xc7\x12\x48\x1e\x62\xfd\x78\x1d\x98\x19\xac\xeb\xef\x65\x35\x63\xce\x0f\x9d\x13\x23\xa3\x07\x94\xfe\x74\xce\xac\xde\xc2\xe2\xf8\x84\xea\x65\x5d\x51\xf2\xf7\x2c\x23\x57\x9b\xa1\x83\xbe\x55\xff\xc5\xb9\x92\xf7\xf7\xef\xab\x79\xe2\x4e\xb8\x7a\x28\xdd\x3a\x28\x4a\xff\x84\xd4\x6d\x7e\xbd\x8b\x8c\x3d\x63\xd1\x40\x24\x43\xc3\x8a\x22\xd1\x2f\xa0\x4a\x2f\x0a\xc5\x38\xcf\xc6\x3a\x5e\x56\x95\x8c\x27\xc5\xb3\x8a\x14\x0f\x1b\x53\x1a\x35\x0f\x29\x74\x15\xdc\xaa\xc7\xd9\x41\xd4\x43\xb9\xe7\xe0\xc0\x3c\x5d\x66\x21\xb8\xd9\xd9\xeb\xb0\xab\xb6\xdc\x32\x95\x41\x05\xbe\xcd\x04\xbe\x6d\xd8\xe7\x17\x42\xc0\x92\xbe\xa0\x9f\x5f\xf4\xa5\x95\x69\xe6\x4b\x44\x1a\x74\xa4\x5d\xa1\xe1\xa9\xf5\xee\x1a\x50\xcc\x6b\x33\x61\xbf\xb6\x68\x3e\xff\x12\x95\xc3\xb5\xfb\x27\x3e\xaa\x35\x04\xa3\x8e\x67\xf9\x77\x09\x02\xd7\x5d\xdd\x23\xf0\xbd\xed\xfb\xd2\x29\x71\xfd\xd4\x16\xe7\x3c\x32\xa9\xad\x0f\xf7\x05\xae\x48\x79\x9a\x9f\x25\xe6\x3d\x04\xbe\xe0\x22\xc5\xb5\xd4\xcf\xb8\x0c\x1d\xf2\x5d\xd6\x3c\xae\xbb\x73\x0b\x4d\xe1\x2e\x6f\x04\xfe\x0b\x98\xae\x58\x58\xda\x72\xad\xd7\xba\x63\xd4\x2d\x8e\xf1\xbf\xc4\x56\x6b\x2d\x06\x21\xd2\xfd\xf1\x5d\xe4\x9f\x70\x6a\x01\xc2\xee\x9d\xfe\x73\x7a\xf8\xef\xa3\xc3\x27\x5f\xce\xee\x01\x77\x5a\x53\xb4\xe5\xdf\xa1\xd7\xf8\xf8\x2e\xa2\x47\x2d\xfe\xab\x02\x21\x9f\x45\xd6\xd2\x3f\x32\x24\x6c\x5b\x02\xd7\xa1\x5e\x74\xab\xfe\xd0\xe3\x1d\xde\x96\xc5\x56\x56\x72\xe2\xb2\xb0\x85\x0a\x66\x21\x15\xef\xf1\x4c\x2b\x39\xea\x70\x89\xf6\xe7\xad\xd4\xef\xd9\xf9\xd7\xbc\xb1\x72\x9c\xeb\xf7\xe6\xe6\x7a\x73\xfb\x15\xfc\xb8\x75\x93\x59\x48\xc8\x1a\x0a\x8c\x17\x28\x86\x02\xdd\x17\x00\x06\x2d\x12\xf4\x65\xa0\xc4\xd7\x94\x3a\x3c\x87\x41\xe1\x3b\x71\x0b\x6f\xd8\xad\x00\x2d\x4e\x38\xfb\xf1\x76\xb9\x83\xed\x7e\x3d\xcc\x87\x03\x8b\xf8\xcf\xa7\xbd\xbf\x57\x7f\x2f\xfe\xde\xfc\xfd\xe2\xec\x1e\xb2\x6c\x4f\xfb\x7b\x87\x87\x37\x28\xc5\xbd\x29\x4a\xd6\x76\xba\x41\x01\xf8\x8d\xfc\x5d\x37\x57\x8b\x6c\x60\x6a\xfd\xfd\xde\x33\xa8\x98\x7b\x26\xf0\x99\x25\x1b\x6e\x36\x2c\xd4\xd7\x1b\xb5\x2b\xd1\x68\x89\x97\x7b\x48\x1e\xc1\x6d\x6e\x25\x12\x19\xe8\xf6\x4a\x58\xd1\x08\x8e\x50\x56\x65\xbe\x14\x41\xce\x8a\x56\x19\x87\x1e\xa3\x53\x47\x11\x12\x9e\x92\x3e\xcd\xe9\xe8\x6c\x7f\xbf\x54\xc9\xee\x3c\xa2\xff\xfb\x7f\xfd\x5f\x40\xd8\xab\x75\xb5\xc5\x5e\x63\x7c\x19\x1c\xce\x8c\x9e\xfa\x71\xe6\xa8\x75\xa1\x67\x11\xb4\x0a\xca\x9a\x0c\x95\xd9\xfb\x23\x31\x1e\xb0\xee\x99\xbb\x50\x36\x99\x94\xef\x00\x77\x77\xb1\x1b\xe4\xe5\xb1\x6c\xc9\xa4\x63\x8b\x82\x30\x78\xd1\x7d\xaf\x14\x88\xc8\xf7\x02\xf8\xf1\xe6\x26\x03\xdc\x88\xcf\xa9\xf0\xc7\x62\x1b\x74\x7b\x0d\xb6\x17\xa8\x08\xb8\x2f\xd0\x8b\x69\x40\x8d\x2f\x84\x66\xef\x62\xce\xe7\xe8\x08\x23\x34\x34\x2c\x6d\x6b\xe8\x07\x26\x7c\xcd\xae\xe8\x1b\xfe\xe2\xe7\x17\x32\xaa\xa3\x14\xfe\x89\x2a\xc5\x7b\xe3\xd0\x38\x76\x54\x7d\x34\xe4\x50\xd5\x6f\x91\x14\x77\xd1\xe5\x05\x68\xed\xb7\xc8\xef\x06\x53\xa5\x6e\x57\x73\x38\xe6\x3d\x14\xfe\xda\x0e\x2c\x95\x02\x5f\x89\x8d\xb4\x70\xe5\x95\xad\xd4\x25\xe0\x52\xdc\x18\x11\xab\x52\xdc\x47\x31\xeb\xa4\x79\x96\x4f\x72\xa0\xe1\xe8\x5e\xc7\xeb\xdc\xbf\xc8\x7f\xea\xde\xfa\x09\x51\xd4\x85\xaf\x28\xe4\xee\x36\x6b\xd8\xd0\xfe\x1e\xe7\x52\x3f\x20\x46\x85\x78\x7e\xb5\xef\xdf\x7f\xe4\xc6\xc3\xed\x50\x33\x9a\xe3\x65\xaf\xcb\xe5\x96\x62\xe1\x7f\x8d\x0e\xb0\x9a\x13\xf3\xd6\x09\xe8\x28\xb5\x70\x8e\x47\x31\x22\x1b\x60\xef\x46\xc6\x74\xb1\x0e\xde\xab\x6b\x27\x12\x0f\x13\xa4\x7f\x4e\x8b\xd9\x22\xab\xad\xc0\x3a\x16\x49\xbb\x48\xd6\xc3\x4f\xaf\x3e\x3c\xff\xf8\xfc\xe4\xfd\x47\xb1\x4a\x80\x78\xc6\x38\xed\x11\xfe\x48\x46\x80\x31\x87\xf8\x63\x0c\x3f\x62\xfc\x71\x14\x6d\xc4\x3c\xb9\x77\x9a\x0c\xe3\xb3\x7b\x97\x62\xe6\x8b\x69\x4a\x91\x4a\xc9\x8c\xb8\x80\x82\x23\x04\xda\x16\x11\xac\xe0\x62\x09\xf9\x4b\x63\x06\xb1\x54\x06\x45\xdf\x00\x2a\x96\x67\x93\x75\xd2\x1c\xf4\x9b\xe3\x55\xbc\x18\x1c\x40\x05\xb1\xc4\x88\x17\xc5\xc1\x5c\xcc\x0f\x12\xf4\x32\x87\x5d\x60\x7f\x1b\x2d\x68\xb9\xd4\xa0\x2e\xae\x12\x56\x6e\x14\xaf\x92\xab\xe3\xc5\x01\x6e\xee\x08\x76\x6f\x62\x74\x9b\x1c\x9d\xc8\xe4\x72\x50\xaa\x78\x92\xaf\x60\x89\x61\xec\x63\x12\xe0\xf4\x28\xc0\x96\x56\xa7\xba\x84\x5a\x46\x95\x0a\xbe\xea\x00\xe5\x83\x2d\x65\x81\x66\xf4\x31\x85\xde\xae\xa7\xc4\x4c\x8f\xf7\x6c\xae\x6b\xe0\x3a\xd1\x0c\xb0\x08\x2f\xf0\xbc\xdb\x0b\x93\x43\xd2\xc1\x0a\xe7\x77\xfa\xe2\x0c\xa6\x68\x2f\x11\x25\xa9\x55\x1a\x68\x3b\xba\xb9\x4d\xcd\xa7\xb7\x48\x02\x7d\x20\x8a\xc7\xa3\xfb\x1d\x84\xd8\xce\x06\x51\xbe\xcf\x28\x20\x5c\xda\xc4\x4a\x38\x98\xfc\x93\x16\x85\x6c\x2a\x52\xdb\x8b\xfc\x9c\x07\x1e\x0d\xb8\x1d\x93\x10\xff\xca\x4d\xb4\x28\x5c\xaf\x89\xba\x9a\xaa\xca\xf8\x33\x3e\x1a\x51\xd4\x9c\x27\x77\x75\xc2\x42\x5a\xf9\x17\x85\x72\x4e\x26\x1d\xf9\x2a\xaf\x64\x25\x2c\x2a\xd2\x86\xbe\x76\xc1\xc6\x0a\x78\x3b\xfc\x42\x9e\x9d\xea\x84\x45\x9c\xc2\xce\x5a\x48\xb1\x5b\xed\x30\x79\xc8\x63\xb1\x21\x25\xd7\x84\xf6\xed\x4f\x40\x78\xf2\x86\x3c\x25\xdf\xa6\x5e\x1e\x8c\x56\x65\xb7\x73\xce\x2c\x1b\xc1\x91\x60\xdf\x44\x76\x09\xf9\x1c\x56\x91\x60\x93\xcf\x3a\x10\xa1\xc5\xb3\x66\xd2\xc0\xc1\x66\xb6\xd6\xad\x02\x49\xd0\xae\xe1\x74\x9d\xf9\x65\xcb\xbc\x09\x0a\x81\xef\x30\x49\x29\x7e\x24\x9b\x55\xbf\x73\x40\x86\x21\x81\x43\xe0\xde\x5c\xe3\xb2\xa8\xf8\x58\x6b\xda\x38\x20\x05\x38\x5e\x2e\x92\x67\x4a\x00\x0a\x83\xc4\xa2\x02\xa5\x6f\x53\xe9\x18\x76\xac\x82\x48\x61\x0e\x5f\x91\x6b\x05\x09\x03\x28\xc9\x4e\x37\x8f\xb6\x94\x12\x56\xb9\xfb\x5b\xcb\x21\xbe\x51\x25\x1f\xdc\x52\x52\x54\xa6\xec\xc3\x5b\xcb\xa2\x55\xb8\x2a\xfd\x68\x87\xd2\x68\xe1\x0f\x94\x17\xc2\x4b\x9d\x8c\x45\x6a\x81\xc4\xf4\x70\x3c\x98\x4c\x9f\xd5\x93\x1a\x80\x22\x3d\xad\x0f\xc7\x67\x96\x28\xa7\x06\xac\x8f\xcd\xb2\x2d\x9f\x69\xd7\x46\xf2\x0b\xb8\xa5\xd6\x6a\xc7\xb8\x8b\xd1\x64\x25\x5b\x54\xbb\x04\x2d\x6d\xdf\x28\x2c\xd0\xda\x2b\x99\x2a\x67\x85\x1f\x6a\xab\x6c\x17\xa9\x47\xdd\xe5\x84\x5b\xf2\xfe\xb6\x92\xe8\xbb\x98\xcb\x4a\x67\x0b\xe8\x60\x77\x2f\xa5\xdb\x71\x11\x5e\xb5\xc5\x64\x41\xab\xb6\x70\x57\x6d\x01\xab\x26\xfb\x91\x0b\x67\x77\x94\x6a\xcc\x8f\xda\x22\xf6\x11\x2b\xbd\x57\x96\x4a\xf9\x5a\xc6\x8e\x0b\x34\xf9\x06\x8a\x10\x2d\x96\xb5\xcd\x8d\x73\xe8\x1c\xec\x91\x5c\x6f\xa4\xe5\xbd\x39\x62\xc7\x6d\x24\xe2\x27\x25\x3e\xa2\x11\xe5\x59\xec\x57\x23\x33\xce\x72\xe0\xa7\x27\xa5\x50\xca\xe9\xf6\x9c\x00\xad\xee\x34\x2b\xdc\xfb\xff\x0f\x4d\xcc\x05\xe1\x96\x4a\xf1\xce\x38\x91\xe6\x6a\x7b\xc1\xb4\x87\x98\xc8\x6b\x01\xe5\x90\x30\x29\xf9\x67\x8f\x78\x03\xf8\xda\xab\x68\x7d\xd1\xde\x83\xc7\x8e\x58\x04\x4b\x18\x9a\x8e\xf5\x28\x2a\x75\x3e\x53\x49\xeb\xf7\x2b\xa0\xf3\xdd\xa6\x30\xc1\x6b\x0d\x92\x2c\xbf\xc1\x92\x0b\xf6\x17\x67\x4c\x76\xf1\x32\xb3\x04\x66\x3b\x2e\x63\x66\x8b\x7b\xfe\x7c\xba\x56\xf1\xf9\x62\xf1\x5b\xf0\xfa\x0c\x80\xc3\x71\x3f\x3b\x0e\x37\x1f\x7b\x60\x22\xd8\xba\x3f\x00\x93\x17\x17\x49\xf7\x56\x3a\x45\xd3\xd9\x4c\x6f\xb1\x0b\xd6\x4e\xb1\x1a\x2d\x9c\x7e\x04\xe6\xd0\x32\xdb\xa0\xf7\xab\x57\x70\x97\x36\xd8\xa2\x97\x70\xd4\x4a\xb9\x0f\x29\x6d\x7d\xc4\x27\x2d\xd9\x54\xdf\x5e\xb5\x3d\x2b\x8f\x1c\xa8\x17\xb8\x4f\xf8\xdf\xcd\x0d\x90\x34\x22\x42\x13\xf2\x8b\xbc\x20\xbd\x69\x63\x14\xa4\xfb\x39\xb6\xf8\x3b\x5c\xd7\xc0\x1d\xcc\xf5\xf7\xf7\xf9\xef\x30\x5d\xce\xd4\xef\x7e\x7b\xee\xd8\xc8\x66\xb0\xe9\x47\x40\x36\x2f\x73\xd4\xde\x0d\x8d\x20\x3b\xce\x68\xaf\xec\x67\xd5\x30\x45\x97\x49\xe6\x1c\x77\x87\x0d\xcc\x57\x80\x24\x56\x40\x61\x5f\x60\x18\x83\x1c\xc0\xdf\xd0\x70\x8d\xad\xf0\xae\xba\x9a\xb8\x0c\x1d\x30\x11\x92\x17\xd8\x43\xd5\x76\x33\xdf\x3d\xa4\x08\x49\x0d\xbe\x99\x67\x70\x9d\x07\x56\x02\xf5\xdd\x6d\x9a\x11\x87\xad\x0e\x5f\x06\x37\x61\xf6\x94\xa9\xcd\x39\x8c\x4b\x9d\xc2\x0c\x09\x30\x16\x3c\xe3\xe9\xa1\x02\x35\x6a\xbe\x1e\x9b\xb2\x88\x8f\xea\xf5\x74\x8a\x6e\xe6\xdd\xd4\x8b\x34\x5f\xac\x2b\x45\xc5\xca\xd4\xc1\xa4\xd5\x4d\x32\x72\x99\x69\xed\x4b\x1f\xe8\x01\xf2\x00\x51\x90\x57\xdb\x63\xb4\x56\xc4\xc9\x03\x4b\xbd\xac\x2f\x07\x71\x1f\x50\x33\xe6\x8c\x8e\x29\x21\x96\xb7\xa5\xa4\x79\xb9\x90\x28\xc9\xf3\xfc\x8a\x37\xd4\x34\x81\x5c\x93\x7c\x44\x97\x9b\x7d\x48\x43\xea\x4d\xaf\xa6\x8b\x2c\x1a\x40\xeb\x79\x42\xb6\xf4\xc7\x39\x37\x5b\x0a\xac\x5c\x97\x8b\x6f\x99\x50\xcd\x0c\x62\x9d\x46\xfa\x59\x2c\xc2\x48\xd1\x28\x54\xf6\x83\x97\xa8\xc5\xeb\x57\xca\xec\x66\x0d\x64\x24\x21\x54\xc4\xbf\x53\x34\x71\xbb\xbc\xcc\xaa\x6c\x06\x24\x85\xf9\x20\x1f\x2b\xe8\x52\x09\xf0\xe9\x34\xa1\x5f\x03\x5a\x90\x7e\x0a\x63\xab\x60\x6c\x7d\x56\x07\xa8\xfb\x53\x54\x94\xa5\x71\x56\x36\x5c\x96\xea\x62\x17\xfa\xd6\x07\x0e\xc5\x2a\x90\x87\x0a\xe0\xec\xa7\xb8\x7c\x70\xa8\xa7\xbc\xe1\x40\x57\x4c\x9d\x4d\x7b\x36\xda\xdf\xc7\xd7\xf4\xa9\x9e\xf6\x02\x5b\x63\x7a\x05\x30\xb5\x1a\xd5\x62\x60\x87\x32\xce\xfb\xda\xb6\x96\x66\x5f\x99\xc9\x02\xfc\x56\xee\xd4\x2b\x39\x75\xc4\x68\x38\x75\x48\xc0\x31\xc1\x45\x2c\xc7\x74\x84\x4e\x29\x02\x63\xaa\x06\x6d\xd9\x08\xc2\x94\x91\x2b\xa1\x1b\x85\xc6\x76\xa3\x60\x50\x51\x89\x82\x57\xb5\xa9\xcd\x69\x79\x36\xa0\x33\xe5\x20\x2e\x28\x85\xf6\x35\xd0\xe6\x06\x63\xbc\xea\xbe\x6a\x32\x02\x92\x9e\x7c\x15\xff\x66\xcd\xc9\x3a\x7e\x6b\x5d\x54\xc2\xa6\x2a\xce\x53\x1b\xb5\xeb\x5a\xe7\x48\xbb\x18\xc2\xf5\x60\x78\x37\x2d\x63\xd4\xdd\x6b\x87\x23\x31\xc8\x73\xc0\xea\x1e\x16\xf4\xbf\x2b\x9b\x5e\xaa\xdf\xa4\x22\xb2\x12\x1b\xed\xc9\xb3\xfe\xe5\xcb\xbb\x0f\xef\xbf\x7c\xe9\xaa\x25\x47\x1e\xc9\x33\x2d\x4b\x27\x63\xf5\xaa\x00\x30\xb0\x66\xd7\x35\x5c\x00\xd7\xd1\x5c\x39\x0d\x5a\x54\xf2\xd5\x7f\xad\x10\x48\x17\xde\x1a\x09\x89\x4c\x42\x25\xca\xe3\x12\x31\x9b\xb6\x30\xd3\x2b\x8a\x03\xf0\x9d\xf7\xf6\xdd\xfb\x28\xbc\x4e\x8e\x1c\xf4\x6e\xab\xa7\x40\x07\xcd\xf0\x24\x12\x40\xd9\xba\x86\x54\x22\x58\x80\xcd\xc1\x35\x96\x70\xac\x80\x56\xe8\x91\x33\x49\x70\x1a\xd1\xc1\x8a\xce\x3a\x49\x0d\x02\x4c\x85\xef\xd0\xde\x0b\xfd\xdb\x38\x58\xd0\xae\x59\x2a\x04\x91\xd9\x38\x20\xd3\xc7\x96\x32\x2c\x24\xa6\x93\x11\x89\x49\x0e\x8a\xa4\x73\xad\x07\x53\x25\xda\x14\xb3\x24\x74\x63\xa2\xdf\x87\xe5\x32\x9b\xe5\x78\x73\x04\xe6\x62\xe7\xa3\x5c\x33\x86\x84\x93\x7c\x99\x95\xeb\x86\xa6\x24\xfb\xe3\x76\xb5\x48\x0b\x08\xa7\xe8\x47\x24\x90\xcc\x5e\xb4\x18\x7e\xdd\x76\xb8\x2e\x96\x02\xd8\x5b\xac\xb3\xb8\x10\xdf\x2b\x0e\x47\x8d\x60\x36\x25\x3f\xcd\xeb\x8a\xbe\x2b\x54\x89\x19\x63\x08\x26\x5e\x93\xe5\xe0\xda\xef\xc9\xb1\xd8\x4e\x0a\x81\x0a\xc3\x36\x55\xe5\xd3\x02\x9e\x6c\xa7\xce\x16\x17\xda\xdd\x3c\x0a\x79\xe4\x61\x96\x74\x80\x50\xde\x5b\xae\x81\x82\x30\x1e\x1c\x48\x98\xc1\xe7\x2b\xa3\x0f\x81\xae\xf7\xa8\x7e\x15\xc3\x3f\xf4\x28\x21\x2a\xd5\x96\x20\x52\x23\xe0\xd6\x9a\xdf\xf4\xe1\x0e\x5d\xc9\xa2\xa8\x25\x9d\x69\xae\x33\xa3\xd1\x0d\x04\x2a\x44\x63\xdb\x80\xc7\xfb\xfc\x60\xf8\x2d\x59\xd0\xea\x5b\xc7\x2a\x12\x53\xb1\x37\xd6\x44\xf8\xd4\x72\x26\xfd\x4d\x00\x34\x8a\x48\x62\x07\x94\x45\xa3\xd1\xf1\xa2\x3f\x45\x4d\x2c\x3a\x2b\x91\x03\x8d\xc6\x3e\x67\x62\x64\xea\x21\x85\xa0\x31\x69\xd8\xc8\x76\x81\x28\xa3\xe3\x6e\x59\xd3\x4b\xf6\x26\x74\x92\x83\xe7\xbb\xd8\xe1\x7c\x23\x95\x06\x00\xa1\xc7\x4f\x83\x12\x01\x98\x56\xb8\xe7\x3f\x78\x3c\x85\x33\x1e\xd8\xb6\x5b\xd6\x32\x3a\xe5\x85\x64\xf9\xc0\x19\x74\x36\x57\x0f\x30\xc7\x4d\x80\x38\xa2\x0e\xe1\x12\x65\x8f\x28\x83\x78\x44\x6b\xae\x38\x2c\x7d\x4f\x9e\x9e\x0d\xfc\xe5\xa7\x43\x18\x9e\x6e\x11\x9c\x6e\xb5\xc3\x74\xa5\xc5\xb0\x92\x19\xe6\xf2\x81\xa8\x44\xa7\x12\xa3\x49\x0a\x6b\x9c\x79\xfe\x88\x72\x64\x29\x1a\x71\x70\x50\x23\xfb\xb7\xbf\x5f\x00\xf2\xa5\x8b\xdb\x6c\x22\x59\xfc\xfd\x87\xae\xda\xff\x8e\xa5\x09\x4d\x1e\x5d\x4a\xe8\xc9\x4e\xf1\x7f\x4b\x95\x24\x84\xa9\x2f\x17\xe5\x79\xba\x38\xe6\x3f\x71\x18\x97\x2f\x2e\x8e\xf1\xbf\x60\xae\x54\x78\xe7\x3f\x31\xa0\x66\xc5\x08\xb6\xb4\x05\x0c\xeb\x46\x4a\x0e\x54\xc8\x7b\x51\xc6\xf3\x52\xc8\xf7\xf9\xd9\x27\x40\x32\x18\x0b\xec\x4c\xe8\xa4\xe7\x54\x52\xa6\x51\xac\x33\x07\xf3\xa2\xd9\x87\x57\x5d\x51\x7c\x03\x3f\x7d\x55\xae\xfa\xfc\x88\x32\xf1\x9b\x6f\xd7\x51\x19\x54\x49\x0f\xbe\xf5\x36\x6c\x3d\x5c\xac\x65\x78\x79\xf9\x44\x89\xce\x3b\xe0\x73\xa8\x34\xbf\xfe\x07\x7c\xbf\xc0\xb6\x4b\xd4\x0c\xb5\x21\x51\x4b\xce\xc9\xfd\x17\xab\x8c\x3d\xed\x67\xec\xd1\xa5\xca\x00\x5a\xe0\xe4\xa9\x11\x1e\x1c\x00\xc6\x48\x4c\xe6\x69\x71\x26\xf0\x5a\x52\xca\x61\xf8\xdb\xd2\x0f\x73\xf4\x26\x2c\x35\x25\xad\x36\xc7\x4f\x49\x52\x5f\x22\x63\x47\x7d\x25\x10\x06\x62\x9d\xe4\x7d\xa4\xe9\x20\x29\x49\x75\xf9\x29\x96\x5f\x73\xf9\x45\xb2\x3e\x9d\x9e\x61\x89\x03\xbc\x4d\x56\x70\xc1\xa2\x83\x2d\x60\x08\xce\x92\x85\x7e\x50\x6a\xec\x07\xa5\xeb\x79\x5a\x2b\xc1\x44\xd8\x43\x23\xcb\x88\x89\x76\x67\x49\x5b\xbd\x3e\x67\xc5\x10\xdc\x0e\x6f\x29\x4a\x92\x2c\x55\x00\x1c\xda\x79\x5b\xab\x0a\x10\xf7\xf2\x39\x04\xaf\xfb\x81\x68\xf0\x91\xf9\xa9\x96\x41\xe1\xf3\x03\x3e\xfb\x25\xb8\x7a\x02\x59\xcd\x0c\x7d\xda\x5a\xe3\x44\x7d\x1a\xeb\x13\xdf\xf0\xb4\x7a\x83\x7a\x49\xd8\x08\xee\xe2\xa4\x7c\x9b\x16\x57\x01\x9f\xd9\xf8\xb2\xeb\x2e\x7a\xa3\x25\x8f\x74\x5c\xcf\xd3\xe9\x57\x72\x00\x54\xa1\x4b\x1d\xa2\x0c\xcb\x33\xa0\x79\xe9\x57\x75\x76\x5c\xc5\xf2\xfa\x4e\xa5\xd4\x5a\x75\xd8\x27\xef\x8a\x29\x13\x93\xe5\x41\x24\xe3\x7e\x44\x67\x2c\xc8\x3c\x4d\x9d\x24\xa4\xf2\xc4\x37\x7c\x92\x04\x20\xe7\x29\x01\x49\x17\x74\xd3\x2b\x65\x01\xc7\x91\x9a\x79\x2f\xaf\x7b\x05\x62\x24\x58\xc7\x5e\x53\xf6\x78\x04\xf8\x2b\x6f\x10\x59\x44\xc0\x9c\xe7\xf5\x6b\xdd\x94\x1c\x22\x3a\x30\x70\x96\xd3\xf9\x64\xd6\xc1\xea\x64\x9a\x16\xd8\x89\x69\x1c\x0b\xf4\xcc\x0e\xf6\xce\xb3\x29\x5a\x5d\xf7\x00\x13\xa1\x59\xdc\x7a\x81\xa0\x58\x96\xab\x48\xae\x50\x8c\x6a\x9e\x50\x05\x68\xec\x1a\xe6\x06\x08\x54\xb6\xb5\xcc\x9a\x79\x89\x96\xe0\x6a\xe9\x3c\xaf\xa9\x5a\x1e\x21\x52\xe5\xad\xd2\x81\xa4\x40\x12\xc2\xa3\x16\xdf\x0c\x09\x7f\xbf\x91\x0f\x67\xad\x45\x26\xb5\x37\x26\x0d\x33\x20\x34\xdf\xb0\x8f\x4e\x69\x63\x8c\x9c\x01\xdd\x79\x54\x9a\x5a\x00\x78\x84\x2d\x64\xb9\xa1\x7d\x8c\x15\x69\x87\x6e\x3e\x67\xd9\x8f\xf7\x17\x70\x5a\x27\xa6\xf3\x43\xa2\x98\x44\x74\x52\xa1\xd1\x02\xac\x1f\x0b\x14\xd5\x22\xa4\x0b\xc0\x41\xb3\xab\xde\x65\x59\x64\x3d\x74\x2d\xd0\x73\x26\x44\xc5\xf6\xd0\x7f\xd3\xb0\x5e\x91\xff\xb4\x4c\x00\x21\x57\x62\x30\x1c\x74\x47\x8f\xd6\x81\xb9\x30\xbb\x11\x63\x14\x19\xe6\x77\x00\x67\xa4\x1c\x52\x46\x4f\xd9\x59\x62\xfb\x90\x57\xe4\xe7\xb0\x6b\x3d\x9f\x96\xb6\x1b\x51\x14\x39\x27\x25\x29\xf2\x5a\x07\x39\xb1\x9d\x43\x52\x08\x9a\x3e\x5a\xd4\x98\x55\x20\x5f\xa2\x6a\x85\x9a\x81\x88\x5e\x03\x73\x19\x5a\x91\x2d\x8b\xe0\x9c\x70\x6f\x66\x8e\xf7\x54\x4b\xca\x26\x9a\xae\x79\x01\x35\xae\xef\x19\xd4\x03\x6b\x8f\x5a\xe5\xe3\xbb\xff\xe1\xf8\x67\x86\x0c\x3c\x9f\x0f\x5c\xb1\x77\x27\x93\xe3\x6f\x0d\x5f\x96\xb0\x9f\x95\xe8\xac\x13\x8c\x2a\xc7\xde\x91\xbe\x44\xef\x7e\xa6\xed\x81\x42\x62\xad\x1c\xb8\x69\x4b\xaf\x76\xc9\x72\xcb\xe3\xd2\x93\xb5\x20\x9d\xc0\x02\xaa\xca\x11\x50\xc5\x8d\x45\xc8\x94\x88\xb8\xf0\x4e\x3d\x01\x46\x07\x6d\x38\x63\xa0\x8f\xd0\x95\x19\x6c\x13\x26\xff\x06\x50\x2d\x53\x49\x6d\x4e\x26\xbf\xa0\x6b\x01\x53\x91\x6c\xe6\xb4\x4f\x24\xc2\xc5\x34\x29\xcc\x1d\x48\x0d\x4c\xbe\xb2\xe3\xa3\x11\x79\x7d\xe7\xfb\x3c\x3e\x1a\x93\x02\xc3\x93\x0e\x25\xea\xd0\xd5\xaf\x70\xd9\x5b\x42\x38\xb5\xab\xa3\x04\xbf\x20\x73\xd6\xbf\x0e\x7a\xf6\xab\x86\x6d\x30\x23\xe2\x8e\x06\xe8\x37\x1c\x03\x45\x12\x18\x6a\x4b\xdb\xa9\x3d\x54\xfb\x4e\x5e\x55\x19\x0a\xf8\x6d\x68\x06\x68\x9f\x97\xeb\xc5\xcc\x4f\x37\x4f\x85\x0c\x89\x6d\xd8\xe2\x5b\xc7\x37\xd3\x2a\x50\xde\xc6\x7b\x4c\x3a\x4a\xa2\x72\x78\x3f\x3a\x30\x19\x3f\x32\xd8\xaf\x1c\x8c\x49\xe9\x0d\xe5\xb7\xf4\x3c\x5b\xe0\x23\xb6\x3d\x1a\x5d\xc7\x7b\xc2\xad\xdc\x3a\x18\xc3\x9c\x65\x2e\x81\x9b\x59\xf9\x88\x60\xb9\x1b\x13\x55\x1a\x6f\x44\xb8\x49\xf8\xbc\x33\x8b\x06\xcf\x92\x91\xbc\x7a\xdb\xc5\x2e\xe8\xa0\x52\x19\x12\xf6\x2a\xae\xce\x98\x71\xfd\xf2\x61\x7d\x0e\x6b\x36\x87\x1b\x6e\xb9\xae\x9b\xde\x3c\x85\xe3\x6c\x35\x4f\x36\x63\xaa\x9d\x1e\xf5\xd0\x5b\xa9\x2a\xf5\x2f\x83\x49\xd6\x96\x50\x6a\xf4\xa7\x9b\x21\x46\x11\xe8\x41\x25\x54\x0a\x17\xe7\x5e\x98\xa9\x94\x1b\xf9\xbc\x98\x7d\x68\x2d\x91\x1b\x6a\x4a\x6f\x96\xda\x64\x61\xd1\x21\xf6\x69\x66\x55\x7e\x7f\x01\xa2\x57\x3f\x56\xc0\x41\x01\x3a\x33\x1c\x4d\x8f\x9b\xe4\x5b\x5a\x6e\x51\xef\x7c\xdd\xc0\xed\xd4\xf4\x50\x4f\x4e\x62\x27\xe3\xfe\x0e\x31\x8d\x82\x23\x13\x46\xb4\x50\x32\x35\x65\x07\x00\xd8\x42\x20\x57\x24\x45\xab\x6d\xb9\x88\x69\x51\xa2\x6b\x79\x08\x54\xe3\x38\x3d\xe8\x3e\x4b\x8c\xfd\x20\x0a\x1f\x48\x51\x4d\xd6\x44\xff\xaf\x4d\x6c\x91\x9e\xf2\x76\x37\x27\xc7\x6d\x4c\x02\x8f\x02\x59\xfc\xdb\x82\xef\xcc\x8c\xf9\x79\x7d\x55\x4c\x6f\x1f\xf8\x84\x65\x42\x27\xf9\xf4\xab\x8b\x51\x65\x33\x7a\xb5\x78\xb7\x65\x6a\x6b\xaf\xed\x30\x68\xc2\xb2\x9f\x11\xd5\x1f\x7c\x32\xaa\x3f\xfe\x64\x68\x32\x9a\x38\x37\x39\x35\x8f\x11\x57\xb7\x94\x6e\xb6\x05\xb7\x28\x3b\xed\xa3\x97\x4d\xb8\x90\xf9\x18\xe5\xa8\x82\x4d\xdd\x6e\x2b\x5c\x51\x61\x3c\x9e\xd6\xbe\x59\xfe\xa6\x37\x96\x29\x8a\xbc\x67\x3c\x74\xdd\x52\x8d\x6b\xb3\xcd\x47\xa3\x2d\xaa\x6d\x6e\xba\x22\x44\x0a\x8b\xc9\x90\x4e\xec\x03\x62\xf5\x0a\x5f\x5a\x43\xea\xd8\x19\x3b\xac\x27\x73\x01\x34\x1a\x31\x0e\x08\xe5\x80\x5a\x8a\x72\x8e\x59\x14\xec\xbe\xb9\x0f\xdb\x77\x8e\x5b\x53\x8a\x3f\x3d\x0a\x22\xe0\xcc\xb6\xda\x4e\x8c\x1c\xdb\x87\xb5\x4d\x90\xc0\xe5\xca\x12\x9e\x3e\xb2\x7a\xa7\x81\x12\x67\x03\x74\xf0\x6e\x7c\xee\xbe\xcc\x67\x6f\x7d\x87\xbb\x95\xba\xc0\xf9\xe2\x18\x7a\x77\xb2\x02\x47\xca\xcd\x6d\xf4\x21\x65\xc1\x8d\x4f\x94\xa1\xcc\x5e\x25\xf7\xbd\x21\x9e\x0d\x50\xe0\xef\xb0\x7b\x68\xf7\xb4\x09\xbb\x05\xb6\x06\x83\xde\xeb\x87\xa1\x42\x0a\x06\x79\x8b\x50\x7d\xb1\x45\x40\x1c\x8d\x5a\xca\x8c\x3f\xbb\xb7\xb6\x3f\xcd\xa4\x72\x69\x4b\x40\x9e\xa5\xd8\xb6\xe9\x14\x5c\xf5\x16\xea\xd3\x2f\x63\x4c\xd4\x4a\x3b\xa8\x4b\x7b\xab\x07\x92\x44\xb9\xb5\x98\xba\x62\x8e\xdd\xad\x29\x18\x56\x24\xe8\xfe\x21\x40\x93\x33\xd0\xa4\xbe\xce\xa6\x3f\xc1\xdc\x80\x8b\x1c\x3d\x5b\xbc\x69\x25\x38\x3d\x2b\x4c\x9f\xe4\x5d\xd0\x85\x26\x15\x9b\x36\x78\xa5\xff\xe1\xe0\xb5\xcd\x98\xc9\x23\xa5\x15\xb4\x49\x93\xb0\xbf\x64\xd9\x8a\x43\x1f\x29\xa2\x75\x6c\x53\xaa\xe3\x8d\xb7\x7a\x19\x4a\x73\x28\x7c\x65\x5e\xf3\x23\x91\x72\x3b\x75\xcd\xf1\x2b\xc8\xfd\x76\xb6\x19\xb8\x41\x3e\xab\x21\x8b\xff\xd4\xf6\x90\x25\x3a\x09\xd9\xaa\xa1\xbe\xad\x64\x26\xca\xdb\x5a\xb4\xce\x0b\x16\x62\x00\x4d\x5a\x55\xf9\x2c\xeb\x3d\xff\xf0\x46\x8a\x1f\xd0\x72\x1f\xe5\x13\x45\xef\x63\x76\xb1\x58\xff\x70\x7b\x1a\xf6\x3e\xd7\xe8\x3e\xa0\x6c\xe8\x3a\xe4\x1a\x05\x8c\xb1\x57\x56\xa6\xb5\x1c\x5a\xd6\xf5\xfd\xf1\x90\xa9\x29\x30\x43\xe8\x64\x40\x4d\xaa\xd6\xb6\x37\x30\x8d\x3a\x3c\x8d\xfa\xae\xd3\xa8\x79\x1a\xa9\x7c\x90\xc6\xcb\x17\x7e\xfc\xc1\x33\x30\x82\xce\xc4\x15\x88\x62\x08\x52\xbc\x69\x3f\x66\xf5\x7a\x41\x16\xbe\xa1\x92\x8a\x36\x3b\xb5\xe8\x09\xa1\x68\x89\x33\xcb\x87\xf6\x3a\xc1\x48\x37\xd7\x9b\xc9\xfa\xa9\x55\x5b\x72\xeb\x6b\x65\x7b\xb0\xb0\x05\xaf\xeb\xb3\xc9\xf4\x74\x71\x96\xa4\xfd\x05\x1b\x5d\xac\x2c\xe6\xce\xd0\x74\x71\xc4\x2b\x14\x09\x49\xf9\xd1\x43\x41\xe1\x28\x56\x61\xc0\x20\x86\x83\x98\xd5\x30\xfd\x25\x11\x1e\x44\xa2\x6d\x99\xfb\x04\x79\x7a\x31\xc4\xe5\x38\x8e\x24\x19\x12\xc5\x91\x4d\x90\x44\x67\x92\x24\xb9\xb0\x59\x6c\x43\x3f\xcb\x71\x5f\x88\xa9\x58\xc1\x69\x6b\x49\xc1\x51\xc0\x73\x01\x7d\x06\xac\x03\xe8\x4c\x02\x27\x2a\x4d\x30\xb7\x9c\xfb\xd6\xfb\xc0\xdd\xcf\x3d\x7d\x2d\xf3\x1f\x30\x41\x8a\x8f\xd8\x85\x06\xa4\xb6\x3e\x92\x2f\x21\x2e\xdc\x91\x4a\x19\xe5\x2c\x63\xb6\x3d\xd2\x0a\xf0\xae\x08\x50\xe9\x64\xc8\xbd\x4c\x02\x7b\xe9\xd1\xf4\x49\xc4\x81\xed\x22\x51\x2b\x4e\xc0\x84\x53\xf2\x24\x24\x3a\x5d\x31\x0b\xf8\x5b\x05\xad\x32\xb2\xaf\x7a\xc0\x8f\xba\x9e\xd8\xdb\x2e\xe0\xc7\xe2\x71\x90\x3c\xca\xa8\x49\x6c\x3c\xd8\x48\x04\x69\xce\x01\xa3\x3f\x7a\x31\xb1\xb1\x5f\x0a\xe0\x4e\x0a\x9f\x2d\xbc\xb1\x46\x3d\x3e\xff\x42\x83\xd4\xc1\x1d\xd1\xc9\xda\xc1\x8a\xf6\x00\xfe\x08\x94\x72\x4f\xe5\x78\x03\x0d\x61\xcb\xa9\xc1\x96\xe9\xe9\xb4\x63\xda\xd3\xe0\xb4\xa7\x77\x9e\xf6\x94\xa7\x5d\xe3\x7c\xff\x50\x24\xba\xcb\x8c\x33\x7a\x97\x10\xfa\xf8\x5b\xea\x1e\xa2\x35\xb9\x30\x5a\xb2\x37\x4a\x48\x86\x7d\xc1\x4a\x39\x46\x59\xd7\x7b\x87\x43\x64\xb2\x18\x88\xc5\x26\x80\x40\xec\x13\x0b\x68\x64\xd4\x46\x2a\x7c\xfa\xe1\xeb\x49\x00\xc5\x04\x5f\x17\x1d\xd4\xc9\x88\xc1\x49\x8a\x06\x6d\x92\xac\x43\x92\x07\x05\xfd\x45\xe0\x92\x7e\x2a\x15\xb5\x17\x47\x06\x13\xb4\x52\xa8\x88\x0c\x53\x40\xc3\x71\x42\x2c\xc8\x27\x5f\x5d\x84\x6a\xda\x25\x28\x21\x92\x6e\xa4\x0a\x54\x41\xe2\x4c\xfe\xb0\x33\x5e\x53\x08\x02\x27\x9b\x93\xdc\x89\x23\x51\xe7\x4d\x1b\x93\xa8\x90\x42\x1d\xca\x8e\x8a\xbf\x9c\x2c\xc4\x2a\x6e\x36\xa6\x44\x4a\x86\xe3\x3c\x8a\xa2\x4a\x54\x3e\xb5\x9e\x44\x27\xc5\xd0\x16\xee\x62\x44\xf1\xc5\x22\x31\x22\x5e\xce\x96\x42\xde\xc4\x12\xf2\x72\x06\x8b\x74\x13\x4b\xa4\x2b\x33\x58\xfe\x9b\x28\xf9\xaf\xd2\x2d\xb0\x39\x17\x77\x0f\xea\xdd\xdf\x4b\x73\x7e\x2f\x4d\xf1\x9d\x41\x51\x97\xf9\xe0\xb8\x8a\xf3\x49\x73\x9a\x9e\x25\x6e\xc3\xa8\x92\xa0\x9f\x44\x61\x74\xb5\xf4\x73\xab\xd4\xaf\x8d\x0a\x49\x50\x5e\xeb\x5e\x32\x89\x6a\x42\x4a\x3b\x6e\xaf\xad\x0a\x7a\x15\x65\x84\x9a\xdb\xeb\x3b\xc2\x15\x6e\x45\xc9\x9d\x6e\xaf\xac\x4b\x52\xbd\x2f\x5f\xbe\xc2\x89\x77\x2e\x76\x75\x03\x5a\xea\x66\x88\x08\x6e\x6e\x50\xfb\xa8\x5c\x64\xc3\x8c\x51\x69\x47\x39\x7e\x96\xfc\x06\xb0\x83\xb7\xdf\xb0\xf7\xea\xd3\xc3\x5e\x3d\xcf\x97\xbd\x2a\xfb\xb7\x75\x5e\x65\xb3\x61\x6f\xde\x34\xab\x3a\xbe\x77\xef\x32\x6f\xe6\xeb\x73\xe4\x5d\xee\xd5\xab\x32\xff\x9a\xdd\xab\x08\x4d\xfe\x6b\xfd\x5f\xb2\xfa\xa1\x32\xed\x73\xd1\x03\xe0\x26\xf2\x63\xe6\x20\xaa\x2e\x59\xbc\x7b\x76\x20\x95\xbc\xa3\xb5\xd0\x03\x64\x90\x2b\x7a\x07\x21\x40\x22\x21\x35\x75\x86\x01\xc9\x8d\x45\xeb\xd0\x42\xea\x91\xf0\x11\x05\x24\xde\x17\x1e\x6e\x80\x34\x1a\xb7\xfb\xae\xa1\x0f\x2f\x24\xfc\x2a\xfc\xe3\x0a\x89\x8f\x03\x78\xf5\x51\x1b\xaf\x3a\xea\xdc\xb6\x96\x9c\x27\x54\xc4\xe7\xfc\xc2\x25\xa3\x80\x90\x2b\x8f\xcd\xeb\x5c\x36\x88\x0f\xd9\xa8\x7f\xed\x3e\x63\xe6\xed\x67\x4c\x9c\xcb\xce\x8f\x98\x48\xc7\xf9\x84\x10\x1c\x59\x7c\x9b\x52\xcf\x9b\x39\x3a\x4a\xf0\x2c\xb5\x33\x9b\x94\xe2\x13\x37\xb3\xec\xad\xb2\x21\x1b\xf9\xbe\xbf\xf8\xcd\xa2\xb8\x90\x21\xa9\x2e\xeb\x5b\xcb\x39\xd6\xde\x96\x4d\xb9\xb7\x6a\x45\x52\x7b\xa1\x5f\x48\x6b\xb7\x09\x0c\x0d\xc5\x44\xd2\xb4\x0d\x5f\x42\x2b\xd8\xff\xcb\x2b\x36\x5b\x53\xe8\x30\x6e\x11\x25\x8c\x31\x79\x39\x99\x1f\xd2\x0f\xeb\xca\x78\xb4\xa7\x15\x93\x7b\xcd\x77\x34\xe2\x87\xb3\x4c\x8d\x12\x4e\x8e\x1b\x9a\x2f\x19\x73\x58\x66\x6d\x84\x67\x4d\x1e\x5f\xf6\x85\xf4\x45\xd1\x31\x7a\x8a\x30\xaa\x5b\xa3\x16\xc8\x43\x82\x9a\xcb\x31\x7a\xc9\x29\x50\xf9\xc9\xde\xaa\xd4\x0d\x9e\x87\x5a\x1d\xc1\x15\x57\x2a\x1e\x7b\xa1\x6d\x45\xee\x5d\xba\x8a\xcb\xb4\x1e\x86\x92\xde\x6a\x33\x5a\xb9\xb7\xf8\x0e\x9e\x29\x03\xfb\xa0\x9f\x03\x65\x62\xaf\xb8\x99\x69\xe8\xc2\x5e\xe0\x3b\x3a\x3d\x41\x46\xe6\xee\x8a\x04\xdd\x68\x9c\x24\xef\xb9\x48\xe0\x4a\x73\x92\xba\x19\x23\x91\xa2\xe3\x7b\x73\xb7\x45\x1b\x40\xb0\xad\xfb\x34\xa4\x4d\xec\x41\x58\x13\x80\x30\xa5\xd9\xd9\xbf\x46\xce\xc3\x0f\xb7\x7b\xba\x80\xfd\x39\xb3\x5f\x35\x1a\xc5\x80\xb8\xcc\x26\xca\x95\xf0\xd5\xad\x08\x69\x3f\xdd\x32\x34\x83\x02\x7c\x0b\xdc\xa7\x80\xe0\x24\x2d\xcd\x0b\xda\x4b\x19\x7e\x01\xf6\xe7\x3d\x8c\x06\xd4\x6b\x80\xd5\xea\x1d\x59\xda\x22\xf5\x9e\xf1\x21\x06\x37\x75\x6b\xc6\x68\xe8\xcb\x3a\x5e\xb0\x2d\xca\xb7\x0a\xfa\xa8\x0e\x00\x52\xbc\x10\x0a\x42\x58\x2d\x07\x79\x80\xa9\x50\x40\xc2\xf6\x42\x0a\x66\x51\x31\xe2\x02\x2d\xe6\x98\x55\x1b\x4d\x16\xd2\xd6\x79\x7d\x9b\x9a\x48\x8a\x30\x39\x68\xd5\xbb\x90\x5a\x16\x68\x17\x2d\x9f\x23\xf2\x7e\x83\xdc\x3a\x69\x88\x98\x57\x86\xfe\x0a\xa3\xcd\x5d\x5b\x3a\x1a\x29\xdd\xf9\x4d\xb9\x02\x3a\xa8\x10\x17\x52\xa5\x24\xc0\xdd\x76\x6a\x5c\xc9\x5d\x2e\xd0\x4b\xa9\xa4\xda\x43\x17\x8d\x77\x69\x6c\x7b\x32\x97\x0c\x7e\x97\xdc\x58\xeb\x76\x5f\x6f\x95\xab\x6a\x63\x0f\x24\xcb\xda\x62\x55\xc9\xc3\x9f\x96\xe8\x43\xa6\x95\x8d\x66\x1f\xd7\xa6\x08\x33\x6e\x08\x61\xbf\xc8\x47\x28\x66\xbf\x56\xf2\x5d\xa4\xf7\x4b\x74\x50\x1e\x44\xbf\xf4\xbe\xcf\xb3\xa2\xb7\x26\xdd\x22\xc9\x62\xa9\x1b\x74\x2f\x9a\xc8\xc6\x82\xbd\x6d\x7c\x51\x6b\x43\x2f\xfb\xb7\x09\x5b\x25\x17\x1c\x50\x0c\x68\x09\x5b\x69\xd9\xb7\x3d\xff\x6f\x5b\xf6\xbb\x2d\x79\xb3\x7d\xc9\x9b\xf0\x92\x37\xd6\x92\x37\x3b\x2d\x79\xb3\x7d\xc9\x91\x68\x51\xcb\xde\x84\x96\xbd\xf1\x96\x9d\x84\x1f\xd9\x7f\xc0\xb2\xb7\x9e\xf1\xb6\x6a\x5d\x04\xb8\x0c\x42\xb9\xa7\x67\x42\xc9\xb4\xe0\xa7\x25\xd4\x3a\x3d\xdb\x58\x2e\x06\x99\x50\x61\xce\xca\x78\x9d\xcb\x86\x4b\xa4\x3a\x6b\xd4\xb1\xe3\x5f\x3a\x74\x90\xdd\x9f\xe6\xf7\x2b\xba\xd0\xf0\xad\xd3\x4a\xca\x06\xc2\x0e\x61\xd7\x0c\xda\x6d\x90\x3a\x47\xe0\xd5\x10\x5f\x19\x19\x4d\xe1\xf3\x21\xb6\x5b\x6d\xac\xf8\x36\x0d\xc9\xb3\x94\x1d\xd7\x98\x04\x2b\x98\xd2\xd6\x6d\xd3\x08\x7a\x22\xeb\xb4\x86\xd0\x18\xad\x21\x29\x55\x93\x26\xb6\x68\x90\xad\x5f\xf3\x9d\xae\x64\x62\xc8\x1e\x56\x57\x00\x62\x67\x3d\xcd\xfa\xa1\x8d\xf4\x75\x03\x64\x5d\xfd\xc2\x57\x1c\x67\x31\x7a\x95\xe5\x37\x53\xc6\xb1\xb6\x3a\x13\x0c\xcb\x52\x0d\x70\x46\x66\xd2\xb7\x2d\x85\x54\xbe\x71\x9a\xa9\xcb\x65\x16\x88\x2d\xb8\xd7\xb9\x36\xb7\x6d\x2d\x80\x07\x59\x81\x1a\xa7\x1d\xa4\x59\x8c\xfa\xf5\xe8\x94\x63\x24\x77\x35\xf0\x90\x0d\xff\xb7\x99\x04\xe5\x7a\x4e\x31\xc8\x01\xb8\xf7\xcc\x60\xed\x47\x6a\x8a\x4d\x68\x1c\xe3\xa0\xd3\xcc\xbd\x0c\xe9\x1d\x06\xd6\x96\x73\x13\x4b\x39\x17\xda\xb3\x75\x8a\xcb\x64\x0c\x4c\x47\xdb\xa7\xc7\xb3\x92\x2c\x03\xaf\x6d\x97\xa1\xe5\x99\xed\x60\x8c\x1e\xc2\x1b\xe3\x2e\x18\x83\xd8\xd9\x42\xdb\x00\x02\x0d\xb9\xd7\xc2\x4a\x0e\x07\x0f\x78\x81\x84\xc4\x52\x92\x7c\x9f\x44\x16\x6d\x96\x1a\x1a\x35\x86\x52\xe4\xa7\x08\x5b\x32\xda\xd6\xc1\x30\x7b\x14\x27\xeb\x79\xd3\x1f\x0d\xdc\x08\xcd\x07\x2a\x28\xee\x58\xb6\x62\xf4\x8e\x43\xd3\x40\xb7\xcc\x8e\x66\x77\x46\xd5\x4a\x7f\x27\x1d\xb5\x03\xb4\x75\x67\xbe\x2b\xb3\xf9\xae\xe2\x14\x85\x25\x67\x14\x0b\xde\xc4\xa0\x15\x46\x30\x01\xeb\xc1\x51\x7a\x0e\xa5\x2e\xcf\x61\x59\x2c\xae\x2c\x01\x58\x4b\xd4\xe1\xda\xe1\xe8\x96\xe4\x28\x2d\x4d\x9d\xe0\xdc\x02\xbe\x87\xad\xb0\xc3\x41\x4f\xc4\x3c\x9d\x8d\x51\xd8\x0c\x78\x07\x94\xe2\x5f\xe6\xb2\x30\xe0\x0e\x29\x17\x3a\x3b\x0d\x5c\x3e\xf0\xef\xa1\xc9\x42\xce\x7d\x3a\x49\xdb\xfd\x6c\xea\x8b\x85\x45\x17\xc4\xe8\xa2\xd3\xf8\x45\x39\x4b\xeb\xb9\xf4\x01\x3f\xbc\x57\x97\xd3\xaf\x19\xba\x7d\x17\xa5\x27\x8b\xaa\xfb\xa7\xc4\x41\x44\x22\x5a\xa5\x18\x2b\x0a\xe6\xfc\x2d\xc7\x40\x51\xd1\xd7\x1c\x23\x34\xa1\xff\xee\xcf\x35\x86\xc1\x8a\x98\xef\x6e\x7d\x3c\x47\x2b\x24\xf8\x46\xa9\xb4\xcc\x04\x38\xc5\x5f\x35\xff\x3c\x29\x57\xf9\x94\x7f\xbe\x45\x3f\xc0\x02\x86\x97\xe2\xa3\x1b\xf0\xde\x14\xd8\xb4\x85\x8e\x99\x1b\x1e\xd6\x78\x0d\xc9\xe1\x01\xec\x57\xdf\x90\xb4\x16\xf8\x88\x52\x00\x13\x89\x8f\xb5\x1b\x51\xa2\xdb\xc5\xe6\x96\x26\x78\x6a\xdd\x4d\xf0\x9c\x83\x8d\x90\x34\x43\x36\xa3\x96\x46\x35\x54\xa8\x86\xa0\x49\xd8\x95\x4a\x35\x87\x2b\x77\x6b\x63\xbc\xbc\xdb\x9b\x72\xe3\x7f\x58\x3b\x19\x1f\xdd\x3f\x12\xbc\xc9\xf1\x43\xc1\x9b\x0f\x20\x33\x26\x90\xd9\x25\x8a\xa6\x0b\x32\x6d\x98\x80\x5d\xa7\x4d\x85\x3d\x23\x98\x80\x7c\xf2\xf9\x25\xa2\x59\xa6\x7e\x9f\xf9\xbe\x43\xbd\x71\x6c\xf7\xb9\xfd\x87\x80\x2e\x2e\x25\xc3\x28\xfc\x7f\x5e\x01\x58\x4d\x51\x22\x81\x23\x46\x17\xa6\x11\x1a\x2d\x2e\x97\x29\x15\x82\xa9\x60\xa0\xdf\xbf\xe6\xb3\x66\xce\xc0\x87\xb5\x6f\xdd\x27\xd8\x97\xc6\xde\xa7\xa6\x84\x2d\x92\xee\xfd\x7f\xcf\x2e\xed\xe8\x50\x75\xeb\x2e\x01\xc1\x85\x27\x77\xba\x28\xeb\xec\xd6\xed\xd8\xee\xc0\x73\xb7\x0e\x8b\xf4\x5b\x7e\x89\xc1\x34\x6e\xeb\x6c\x47\xbf\xd9\x56\x67\xee\x76\x07\x77\x5b\x09\x43\x01\x08\xf3\xda\x7c\x7c\x9f\x97\x39\xa2\x9a\xf4\x7b\x7a\xc5\xfb\xfc\x8e\x51\x97\x41\x33\xb2\xf0\xed\x9b\xad\x1a\x55\xfb\x9d\x89\x22\x47\x26\x9f\x0e\x25\x62\x38\xe0\x0b\xd4\x4f\xb4\xc9\xd0\x2e\xd9\x01\x8b\xc9\x9f\xb0\xd1\xe9\x42\x16\x55\x3f\xc9\x7c\x03\xf0\x0d\xdc\x17\x0b\xf4\xb9\x33\x16\xb2\x00\x67\x4a\xbc\x61\x66\x15\x18\xa8\x19\xe4\xbf\xad\x73\x7b\x84\x5c\x97\x16\xe1\x16\x34\x28\x17\xca\xe0\x41\x1b\x69\xe1\xea\xdd\x52\x9f\x17\xd8\x54\x77\x4e\x01\xa9\xae\xbd\xeb\xc2\x7c\xa6\x91\xc2\xc1\x7b\x0d\x5c\x7f\xd9\xf7\x68\x97\x83\xe4\x41\x58\x4b\xa4\xb0\x13\x84\xdd\xab\x80\x78\xca\x3a\xe0\x8b\xe3\x9f\x29\xdc\xb0\xe8\x02\x18\xe6\x5b\xa5\xc9\x61\xf4\x5f\x94\x33\xdf\xc9\x00\xa3\x57\x2b\xaa\x6a\x52\x0d\xd5\x61\xe9\x47\x1c\x96\xee\x1e\x46\xd3\x55\x61\xe0\xdd\xcc\xc0\xe4\xe5\x48\x81\xa4\x6e\xa1\x0e\x87\xad\xf7\x26\xfe\x9f\xa5\x37\x58\x0b\x91\x4a\xce\x93\x1e\x96\xeb\x7b\xf2\x9e\x31\x2b\xc2\x4a\x29\x76\x46\xe9\x66\xc8\x6d\x36\x5a\x17\x2a\x83\xf7\xd0\x44\x7e\x57\xe9\x4d\x7a\xce\x61\x2d\x18\xf7\xb6\x75\x66\xd1\xd1\xde\x40\xc6\x3c\x31\x84\x28\x09\xe2\x1b\x0a\x80\x2e\x16\xc9\x14\xed\x62\x9c\x50\x43\x13\x29\xda\x5e\x48\x89\x36\x41\x52\x3c\x3d\x1d\x9f\xed\xef\xe7\x0a\xfa\xfa\xf8\x0d\xad\xdb\x82\x68\x3a\x30\x71\x6e\x9d\xaf\xbe\x5b\x80\x48\x0c\xd9\x12\x30\x61\x14\x87\xfd\x14\x3f\xb1\x25\x91\x4a\x60\xe8\xaf\x05\xa6\x0d\x9c\xaa\x44\x5a\x50\xd5\xe3\x8a\x48\x11\x53\x31\xae\x51\xbd\x8a\xd3\x6a\x7f\x4c\x4b\xd8\xda\xa9\xc5\xfb\x95\xf2\x78\xfc\xa7\xe7\x2f\x4e\xde\xbc\x7f\x87\xfa\x00\x66\x61\x74\x60\xf8\x83\xe8\x3f\x45\xb4\x78\x76\x53\x0d\xd1\x57\xb1\x52\x3c\xba\x94\x14\x17\x0c\xb7\x1e\x4c\x56\xc7\x25\xf9\x23\x52\x07\x6e\x8d\x17\x58\xad\x8f\xee\x6a\x33\x88\x91\xfe\xc1\xdb\x12\xad\x8c\x7b\xd4\x58\x8f\xae\x7d\xaa\x6f\xf5\x23\xc9\x1f\xb9\x4e\xd3\xd3\x23\xf8\x7f\x7d\x5c\x49\xea\x89\x17\x1e\x53\x71\xea\x5c\x86\x16\xc0\xce\xf6\x87\xfe\xd5\xda\x42\x2a\xfc\x55\x6f\xa1\x5f\x74\x59\x5f\x46\xe8\xfa\x4e\x2f\xda\x11\x43\xd0\x45\x42\xc5\xe7\x89\x5a\xaf\x23\x6b\xbd\xe4\x25\xdf\x9f\x8b\x0b\x68\x6e\x63\x35\x57\x03\x2a\x73\x9a\x1b\x73\x73\xa6\x9d\x71\xb0\x9d\xda\x6b\x87\x71\xaa\x86\x42\xfa\x0c\xc1\x20\xe1\x4e\x80\x41\xfc\x1b\xca\xc7\xc8\x40\x91\xd9\x8a\x53\x40\x07\x14\x38\x16\xf0\x03\x49\xb6\x9f\xca\xe3\xf9\xac\x77\xd8\xfb\x1f\xf4\xf2\xd5\x33\x07\x36\xba\x87\x50\xd6\x3b\x95\x29\x67\x50\xe6\xb7\x0c\x85\x68\x18\x95\x88\x42\x19\x15\x0d\x2a\x8c\x20\xeb\x81\x8f\x38\xaa\xa6\xb0\x7a\xc1\xd3\xd4\x7b\x8a\xff\x63\x17\x2f\x48\x53\xa9\x47\x47\x0c\xdb\xc7\x23\x04\xc9\x2f\xf5\x09\xe2\xc7\x36\xbb\x7d\x89\x0d\xec\x36\x97\x59\xef\xa9\x84\x34\x6c\xf4\x53\x86\xd1\x90\x58\x6a\x65\x90\x4a\x74\x8f\x61\x0e\xf2\xe7\xc0\x2f\xf1\x87\x0a\xa9\xa4\x1a\x0f\x8d\x18\x20\xa2\xf7\x94\xc3\x99\x3e\x6b\xf7\xa3\x22\x30\x91\xdd\x68\xe6\x4f\x1d\x57\x03\x6f\xbf\x68\x60\xb7\x08\x40\x71\x6b\x43\xd6\x88\x1a\x1a\x3d\xee\x68\xef\x54\x96\x3a\xa3\x5a\xb4\xd8\x53\x0c\x24\xdc\xa3\x5c\x35\xd9\x33\x3a\x53\x9b\x8d\x7c\x5b\xf6\x31\x2f\xe0\x7a\x7a\xe4\xf5\x11\x2f\xa4\xdf\x17\x6d\xbc\x0b\xc9\x8f\x84\x87\x76\x21\x8d\x5e\x72\x3d\x64\x0f\x17\xe8\x7d\x4d\x89\xd2\x1d\xb2\xa3\x17\xde\x8a\x7d\xe4\xf2\x5d\xa1\xef\xd2\x52\x67\x1d\xd2\x2d\x55\xd1\xdd\x50\x0e\x3f\xe2\x07\xbb\x00\xae\x48\x1b\xe2\x1d\xdf\x72\xd0\x89\xd2\xc3\x3b\x49\xcf\x51\x86\x3a\xfc\xd7\xfa\x87\xf6\x43\x6d\xa6\xa0\x6e\xe7\xa9\xbe\x9d\x5f\x2c\x80\xac\xea\x5f\x03\xea\x5e\x2d\xd2\x2b\x52\xd2\x8d\x9e\xaf\x56\x91\x60\xa9\x66\x7c\x9a\x8a\xca\x08\xd2\xd7\xfa\x5e\x15\x86\x56\x1d\x9c\x09\xf5\xdb\x51\xb6\x97\x2e\x97\xd2\xa2\xa6\xf0\x5c\x27\xf4\xa4\x07\x77\x6d\x31\x73\xed\x84\xb4\x6a\x64\x20\x76\x00\xbb\x82\xf6\xb3\x6a\x4a\x1e\xb4\xd2\x73\x4e\x47\x08\xb0\xc8\xe7\xa9\x24\x76\xdc\x45\xa0\x8b\xdf\x5b\xb0\xf8\xe8\xe8\x57\x41\xeb\x0e\xb4\xc0\x48\xb8\x5b\x10\xdf\x1f\x79\x84\xc2\xd1\x2e\x01\xd4\x9c\x4d\xee\xdb\xbb\xdc\xda\x63\x4d\x19\x00\x76\x68\x4e\xf2\x66\x91\xc9\x6d\x94\x74\xc1\x5b\x86\xd7\x3f\x95\x3f\x64\x7a\xea\xa4\xbf\x29\x56\x6b\xb5\xf1\x12\x1a\x50\x4a\xb0\x05\x1c\x88\x90\xb8\x05\x18\x5e\x10\x7f\xa6\xa0\x01\xd5\xd0\xa0\xe0\x99\x2b\xd3\x6f\x3d\x5d\xa0\x88\x50\x06\xe5\x40\x26\x01\x1d\xb1\x19\xab\x27\xbc\x41\x3f\x60\xf4\xd7\xba\xcf\x6a\xc7\x74\x86\x8e\xd7\x8a\x0c\x40\x4f\x39\x78\x00\x05\xd0\x7e\x07\x3a\x7f\x10\xab\x74\xb8\x15\xfd\xa2\x28\xfa\xf9\x23\x00\xab\xec\x04\xac\x6b\x7c\x83\x80\x49\xaa\x00\x24\x6a\xc9\x31\x71\xd3\xae\x90\x76\x34\x54\xef\x04\xa1\x36\xa6\x71\x61\x01\x20\x94\x50\x98\x07\x0a\x90\x7c\x5f\x84\x20\x01\x32\x08\xca\x1d\x40\x80\xc4\x27\x77\x01\xf3\x9d\x65\x64\x9d\xb8\x6c\x18\x20\x8f\x73\x37\x83\x77\x34\x9b\x9d\x10\x4c\xa6\xb7\xc2\x24\xad\x89\x0d\x98\x8a\xf4\x2c\x45\xa4\xe4\x4f\x11\x39\x0a\x93\xe9\xb9\x88\x9c\x3e\xce\xc4\xad\x66\x50\xd7\x5a\x90\x55\x22\xd0\x4a\x4b\x15\x61\x35\x03\x14\x87\xc9\x08\x02\xa1\x05\xf7\xe4\x9e\x6c\x68\xd5\x16\x4d\x42\x0d\x93\x30\xcf\xc0\xbd\x81\x79\x2d\xd7\xdd\x06\xc9\xd7\x53\x5c\x22\x5e\x19\xbc\x35\x0f\x1b\x5c\x9a\xc3\xf3\xb4\x8a\x36\x2d\x00\xdc\x02\xfc\x51\xbd\x4a\x8b\xae\xe6\xa0\xa9\x8c\xb8\xe9\x41\x1b\xa8\xbb\x2a\x22\x01\x30\x45\xd4\x00\x95\xd1\xdd\x6c\x00\xf2\x53\xc5\x88\x06\xee\xd3\x0e\xe0\x80\xbc\xc7\x16\xf4\x7a\xb0\xba\xb3\x70\xce\x82\x55\xcd\xc9\x95\x1e\x7e\xd4\x0c\x58\xee\x65\x18\x28\xbe\x05\x50\x95\xbc\xe3\x76\x50\xab\x81\x38\x7b\x4f\x9a\x00\x29\xc0\xdb\xde\x18\x80\x69\x4e\x37\xfd\xa7\xf5\xb9\x63\x1b\x4e\x6a\x53\xc0\x37\xa3\xa0\x5b\xfa\x1b\x91\x8e\xc4\x4c\xf8\x79\x64\x49\x60\xdd\x48\xe9\x61\x4d\x06\x93\xcb\x3e\x31\xaa\x2a\x1f\x09\x4f\x37\x13\xbd\x05\x5f\x90\xda\x1b\x70\x68\xcb\x74\xd5\xd7\x65\xd5\x21\x90\xe5\x25\x17\x29\xe8\x70\x61\xe5\x01\x5e\x37\xd7\x24\x70\x31\xed\xc3\x97\xdb\x3e\x8a\x67\x74\x76\x5d\x2f\xa0\xd9\x6c\xfa\x35\x9b\x49\xb3\x28\x79\x36\xec\x45\x00\x5e\xb1\xd6\x12\x1e\x33\x74\x95\xe2\x36\x5f\x6b\xb1\x91\x29\xa9\x52\xfc\x92\x4a\x92\x64\x4a\xaa\x14\xa7\x24\x92\xae\xda\xba\x76\x18\x0d\xd0\x1f\x26\xfa\x62\xd6\xe2\x2e\xb4\xb0\x17\xf8\xf6\x68\x39\xcc\xcc\x99\xa9\x49\x01\xf4\x06\x7a\x07\x61\x56\x2f\x16\x28\xe7\xf2\xd4\x7c\x8c\xbd\x98\xbf\xfd\x5d\x6b\xb2\x09\x52\x50\x8c\x63\x28\x96\x9b\x6d\xe7\x1f\x5e\xd3\x2c\xb9\x0b\x4e\xc8\xf1\x2a\x81\xb3\x4d\xdb\x1b\xa9\x15\x05\x3e\xe1\x6a\x05\xdf\xe8\xd9\x3c\x12\x14\x60\x65\x5e\x2e\x70\x54\xd1\x67\x55\x24\x70\x2b\x7a\xad\xa9\x55\xdf\xd2\xda\x07\x55\xe4\xf6\xd6\x14\x5c\x6c\x69\xed\xa3\x2a\xb2\x19\x84\xd0\x58\x1b\x9b\xca\xe3\x1b\x40\xa3\x2c\xfe\x46\xb1\x6c\x2c\x7f\xb7\xeb\x1d\x72\x46\x59\xc8\x23\x4c\x9b\x62\x1f\xea\x40\xbb\xf3\xb1\xdc\x09\x8d\x3b\x6e\x9d\xf8\x2d\x93\x7e\x47\xd9\xd2\xb9\xfd\x3f\x92\x93\xc6\xe8\x75\x95\x65\x18\xed\x64\x87\x65\x95\x98\x64\x4b\x07\xcf\x55\x09\xb7\x8f\xbc\x9a\x0e\x2f\x64\x3f\xc3\x22\x6b\x76\xe8\x8b\x65\x97\xdd\x33\xc1\xec\xdb\x5b\xd1\xb7\x7f\x77\x4b\x2f\x54\x11\xf4\xe1\xd0\x6e\x6f\xd5\x75\x1a\x16\x68\x67\xb4\xdb\x51\x01\x14\xa7\x06\x40\x98\xee\xbc\xfc\x81\xbd\x45\x9f\x3e\xfd\x16\xdc\x52\x17\xf2\x72\x00\xa1\xc3\x6c\xb1\xc8\x57\x35\x8a\x94\xcb\x82\xf1\x87\x0d\x41\x0a\xa9\x6c\x42\xa0\xac\xc6\xc2\x03\xa8\x09\xda\x22\xc1\x2e\x3a\x35\x64\xe1\x29\x08\x5f\xc7\x1d\x9c\x73\x98\x45\xb6\x5e\x60\xe4\xa5\x4c\x37\xf1\xce\xcf\x53\x61\xaa\xd1\x7f\xab\x62\x22\x35\x2f\x2e\x50\x4b\x25\xa3\xe8\xbf\x58\x23\x5d\x37\x25\x46\xb8\xb3\xe5\xa4\x92\x0a\xfe\x73\x06\x9c\x47\xe5\x30\x44\x9a\xa0\x90\xf4\xfb\x6f\x79\x91\x59\x7c\x51\x90\x14\x9d\x7a\x77\xbf\x91\xac\x2c\xb6\xde\xfd\x86\x44\x0f\x51\xa9\xb5\x88\x64\x43\x2e\x95\xba\xfe\x09\x2a\x55\x35\x14\xd7\x5d\x54\xea\xda\xce\x98\x67\xf9\xe5\x5c\x73\x32\x1c\xb3\x8e\x92\x0e\xc7\xa3\xd1\x6d\xf6\xd5\xb2\x96\x1f\x75\x1a\xf7\xa7\xce\xff\x1d\xf1\x90\x01\xd1\x8f\x94\xd4\xa5\x00\xd6\x6e\x94\xdf\xbc\x7f\xba\xdd\xd5\xcc\x5b\x1e\x8b\xf4\x06\xc0\x62\xc5\x34\x5c\x88\x97\xef\xdf\x62\x14\xc1\xbe\xf4\xa3\x8c\x20\xf4\x69\x5a\x95\x0b\x34\x3a\xad\xe9\xc7\x49\xb9\x3a\xa0\x80\x01\x70\x41\xf3\xda\x90\xa3\x4e\xce\xe4\x04\x77\x9d\xda\x9d\x2b\xab\xc6\x35\xe5\xd0\xab\xa8\xb2\x2f\x34\x1d\xee\x32\x46\x6b\x4c\xfe\x10\x14\x81\xc1\x0b\xd2\xa2\x2e\x02\x5d\x1b\x82\x63\x3b\x14\xc0\xe2\x5a\xb5\xef\xb4\xa8\x56\x30\x45\xb9\x82\xd4\x06\xaf\xf5\x77\xfc\xb9\xc7\x91\xbf\x4d\x42\x92\xa1\x63\x74\xeb\xfd\x98\x74\xe5\xee\xce\x4c\x69\xc6\xe9\xe6\x46\x33\x53\xe8\xb3\x50\x50\x5c\x88\x75\x72\xbd\xc2\x58\xf1\xc5\xe5\x6f\xd9\x85\xbc\x8d\x51\xff\x91\xdd\xbb\x15\xcd\x41\xb4\x02\x14\x6d\x24\x12\xfb\xfb\xfc\xf8\xa4\x13\x4e\x47\x67\x37\x37\x48\x93\x12\x40\x8c\x2c\x3b\xc6\x64\x34\x99\x3e\xb5\x86\xa5\x4e\xa4\xe2\xdf\xa6\xc6\xae\x39\x50\xea\x74\x7a\x86\x21\xdf\x14\x62\x11\x17\xc9\x42\x8e\xfe\xa0\x39\x98\x4e\x16\x32\xc4\x61\x7f\x75\x90\x44\x4a\xd6\x79\x18\x1d\x70\x3a\x22\x0f\x56\xfd\x6f\x89\x20\xae\xbf\x66\x57\xf1\x85\x7e\x8b\x58\x6c\x2c\x33\x6c\x8c\x88\x36\x7f\xba\x80\xed\x2b\xcc\x30\xe7\x18\xa0\x20\xdc\x1a\xde\x89\xdc\xde\x41\x04\x7d\xcf\x2d\x72\x67\x25\x28\x90\x68\xbc\x0e\x90\x33\x92\x33\x9c\xa1\xb4\xbb\x2a\xd7\xf5\xe2\xea\x13\xa2\x33\x19\x26\x33\xbe\xfe\xf2\x65\xde\x2c\x17\xc0\x45\x23\x0e\xef\xcb\xe1\x9c\xce\xcf\xf0\x5e\x32\xbe\x50\xc6\xe4\xdd\x5b\xba\xc9\xbd\x9d\x6c\x93\x13\xc6\x1b\x57\x0e\xad\x6e\x0f\xad\x94\xc4\x1b\xc2\x6f\x84\x8e\xaa\x9b\x34\xd7\x67\x20\xb6\x76\x89\x0f\x8a\xc8\xb8\x9e\xcc\x3f\x7a\x80\xbe\xc2\x30\x14\xe8\x1f\x32\x18\x59\xcd\x0c\x88\x5a\x77\xef\xe6\x85\x77\x37\x7b\xd2\xeb\xe0\xd5\x06\xbc\xf2\xa3\xad\x7c\x74\xf0\xb6\x8c\x8f\x8e\x1e\x08\x73\xb1\xc6\x47\x81\x2b\x5e\xf8\x17\x72\xfc\xc8\x67\xc5\x77\xd6\xc0\xe8\x92\x8e\xda\x77\xbb\x61\xce\x51\x15\x32\xc0\x92\xaf\xaa\xfc\x1b\xde\xc4\xfc\x6c\x90\x06\x25\x9d\xf5\x2e\x17\x36\x2f\x44\xa4\x78\x37\xc2\x41\x2d\xee\xcd\x42\x44\x8c\x42\xe4\xaa\x4f\xf2\x21\x2a\x8d\xd8\xb2\x1c\x7c\xc8\xb1\x1e\x39\xfd\x9c\x5b\xd0\x9c\xd3\x3a\xa0\x38\x22\x3d\x73\x83\x2c\x8c\x42\x32\xb6\x86\x58\xb5\xcd\xde\xb5\xc5\x33\x0a\x89\xd4\xd4\xb5\x02\xcc\xeb\x25\x70\xc3\x68\x13\x73\xa1\xef\x05\x54\x6f\x24\x8c\xcc\xc8\x31\x48\x88\x9a\x15\xda\xa8\x49\xa1\x8d\x96\x44\x5a\xb9\x8b\xb4\x32\x89\xb4\x82\xf8\xc5\x8c\x30\xef\xc6\x25\x81\x69\x34\x39\xf2\x74\xa2\x1c\xe2\x0f\x38\xb5\x4b\x92\x5e\xe4\x24\xac\x6a\x7e\x1a\x29\x45\xbd\xe8\xa0\x62\xc4\x94\x49\xc4\x34\x62\xc4\xe4\x1e\xcc\xda\x3b\x98\x36\x24\xc2\xe1\x7c\x20\x3a\x44\xbb\x12\x94\x01\x97\x8c\xdc\xd3\xd6\x29\xdc\xda\x59\xc5\x68\x07\x41\x2c\x71\x08\x7f\xce\xf1\xeb\xea\x76\x69\x6c\x17\x09\x5c\x7b\x39\x5e\xab\x3f\xf3\xe0\x60\xcb\xb0\x43\x94\xb3\x2f\xc7\x15\x8e\xe8\x77\xae\xfb\x76\x9e\xad\xb8\x86\x88\x60\x00\x9f\x64\xe5\xdd\x68\xeb\x2e\x59\xaf\x90\x1d\xb9\x92\x61\xc9\x60\x45\xb7\x51\xd1\x86\x7c\xa2\x05\xf3\xe8\xa7\x72\xba\xae\xd1\x0d\xac\x35\xd8\xbb\x57\xe6\xc3\xf9\x97\xcc\xf5\x91\x0c\x54\xe9\xf8\x3e\xd1\x34\xdf\xe7\xf9\x74\x4e\x81\x94\x59\x04\x46\x43\xb7\x5d\x35\xb6\x29\xac\x49\x74\x8f\xe9\x21\xbb\x0a\x9c\x89\xe3\x54\xa9\xa2\xf4\xdd\x3c\xa1\x85\x87\xa8\x92\xcf\x2f\x35\x71\xca\x4f\xfd\xb7\x97\x14\x35\x47\x7a\x72\x47\x28\x6a\x76\x4e\xde\xa6\x68\xf5\xe2\x4b\x25\xa0\xfb\x8f\xcd\x44\x8f\xfb\x6d\x99\xa9\xc0\x05\x94\xca\x96\x7d\xb8\xcb\x1f\x8c\xac\xf2\x18\x73\x46\xe7\xc5\xd1\x9f\xd2\xe9\x57\x40\x1b\xd3\x8c\x17\x00\x08\xa1\x9b\x9b\xe8\x25\xc5\x23\xd3\x29\xc7\x7a\x64\x71\xf4\xb9\xc8\x91\xa4\xcc\x2f\x72\x00\x34\x55\x60\x7f\x5f\x97\x50\xfb\xc3\x7a\x00\xed\x67\x53\x7f\x56\xee\x22\x84\xa5\x80\x3b\x3f\x12\x28\xb4\x49\xe0\x73\xf8\x1d\x88\xee\x90\x84\x4b\x89\x10\x88\x28\x91\x1f\x5d\x8d\xb8\xa2\x16\x1e\xb2\x4d\x42\xf1\x59\x61\x67\x96\x32\x8d\xb7\xbd\x2c\x00\x42\x5f\x96\xdf\x0b\xfb\x46\x81\x24\xbc\x68\x78\x69\xac\x74\x4e\x69\xe1\x5f\xff\xf5\xcc\xc1\x41\x80\x6b\x8f\xc4\x56\xb2\x29\x88\x99\x43\x48\x12\x08\xa6\x07\x3f\xf7\x28\xb1\xb3\xb6\xa6\xc2\xdb\xdb\xf0\x23\xdc\x55\x0d\xf0\x30\x75\xf4\x87\xbc\x78\x5a\x02\x47\xdd\xb0\xbf\xc0\xac\x7f\x6a\xcb\x76\x76\x56\x0e\xec\xbc\x88\xb4\x68\x27\x77\xf4\x16\xde\x34\xd9\xd2\x79\xdc\x0e\x3c\x1c\x7a\xa2\x1c\x97\xf0\x6b\x89\x72\xe4\x0b\x8e\x2f\xc5\x51\x9a\x10\xdb\x65\x38\x72\x54\xa1\x6b\x88\x04\x35\xd8\xb8\x2b\xbf\x49\x3b\x5e\x1f\x6b\x11\x59\x03\xad\x77\xbd\x7c\xa8\x03\x57\x7c\xa3\xdf\x24\x53\x3b\xd5\x6e\xdc\x91\x03\x69\x21\x81\x94\xfa\xb5\x48\xd9\xa9\xa5\x2b\xa9\x5d\x9a\xe8\xa7\x0b\x09\x13\x5b\x6b\xd5\x1a\x70\xb6\x13\xb3\xf4\xdc\x89\x4f\x4b\x16\x1a\x50\xb3\x31\xde\x86\xb5\x7f\xf8\x54\x95\xf6\xc2\x70\x74\x00\x79\xae\x95\x5e\x2b\x4b\xd9\x9f\x84\xb1\xcd\xc6\x76\x0e\x3a\xcc\xd0\x0e\x2b\x93\x03\xb0\x17\x0e\x9d\x8c\xb8\x7d\xa5\x61\x6e\x78\x7b\x5f\x68\xb8\x95\x0e\xd7\x45\x3d\xcf\x2f\x9a\x9d\xea\xf2\xd1\xc4\xea\xb4\xd5\x32\x3c\x01\x4a\x76\xd3\xcd\x60\xf7\xd7\x5f\x8c\xbb\xc4\xdc\x63\xab\xec\xf9\xba\x69\x4a\x8f\x7c\xe6\xb4\x43\xad\x94\x1d\x20\xee\x6d\xa0\xd9\xd8\x6f\x12\x01\xb2\xba\x35\x9c\x1a\xee\xc0\x43\xee\xa4\x0e\xde\x30\x01\x99\xf7\xb4\xbc\x0c\x8b\xbb\x6d\x40\x6c\x0b\xae\x7d\xe6\xd8\xd1\xf1\xb9\xf5\x79\xd9\xa5\xd8\xef\xff\x2a\xda\x18\x04\x92\x9f\x88\x00\x9e\x02\x5e\xf9\x71\x88\x3d\xf6\x6e\x80\x96\xa5\xf0\xef\xa0\xdc\x5d\xea\xd7\xe7\x83\x9b\x1d\xf4\x27\xac\x49\x04\x35\x28\x76\x41\x4e\x3d\x9b\xf0\xd5\x38\xc6\x47\x13\xb9\x62\x7b\x2d\x66\x56\xf2\xbf\x56\x8a\x52\x77\xe8\x46\x1f\x26\xf8\x43\xbb\x1a\x0a\xfb\xe8\x94\x22\xfc\x1f\x6a\x8c\xdf\xea\xd1\x09\xb9\xa9\x75\x89\xda\xed\xb9\xe5\xb4\x30\x50\x75\x52\x6b\xfe\xe1\x36\x26\x36\x33\x0a\xae\xc1\xb3\xc5\x87\xca\x1a\x00\xe9\x57\x6c\x7f\x91\x09\x51\x29\xbb\x13\x22\xbf\x5f\x2b\xd1\xbd\xb7\xfd\x47\x19\xf5\x02\xa3\xd4\x8d\xac\xeb\xbc\xee\xba\xce\x6f\x79\x7c\xd9\x06\xc7\xaa\x9b\x8e\x07\x96\xe0\x45\xfc\x33\x0f\x2c\xfa\xca\xfd\xff\xdb\x03\xcb\xd6\xe7\x85\x3b\xbc\x25\x74\x1f\x6b\xd1\xc5\x6c\x0a\xdb\xdc\xbe\xf1\x65\xf2\x8d\x25\x93\x3f\xce\x24\xa1\x50\x1b\x5d\xaa\x46\x63\x19\x8d\x5c\x82\x61\xe5\xc2\x32\xf3\x8c\xf4\x63\x8c\xf9\x0e\x3a\xb4\x96\x80\x97\x44\x05\x2c\x74\x24\x50\x24\x9d\xed\x2e\x92\xc6\xa6\x58\xd2\xcc\xa2\xb6\xaa\x7d\x1d\x02\x5d\xf0\x33\x52\xe8\x6c\x27\x29\xf4\x0e\xfd\x5b\x4c\x42\xd6\xc5\x62\xdd\x55\x4d\x2b\x84\x0a\x20\x63\xf4\x53\x02\xe5\xfb\x77\x56\xb7\xdd\x82\x58\x7c\x55\x2f\x97\x8b\xf8\x99\x4b\xd5\x9e\x68\xd4\x75\x1f\x32\xd8\x57\x84\x2d\x08\x40\xc9\x43\x16\x8b\x8c\xed\x9b\x00\xf7\x8b\x80\x10\xc3\x98\x2a\xc9\x71\xb8\xc0\x5d\x44\x01\x78\x3f\xed\x74\x13\x51\xf3\xdc\xee\xbb\xdb\x2f\xa5\xdd\x25\x9e\xb7\xde\x58\xb4\xd1\xe3\x2d\x06\x58\xda\x2f\x47\xe3\x70\x03\xd9\x41\xbf\x39\x8e\x7a\x7d\x72\x63\x32\x88\xe2\x08\x98\x11\xe3\x17\x44\xdf\x5a\xd2\x26\xcb\x32\x83\xb4\x6d\xb7\x42\x94\x55\x50\xe7\xaf\xc3\x7e\xab\xee\xb0\xdf\x5a\xbb\xe9\x92\xf7\x9c\xb4\x8d\xba\x36\xd5\x10\xa6\x2c\x4d\xb2\x1d\xb9\xdd\x50\xda\x89\x03\xdf\x82\x7b\x23\xda\xca\xa2\x24\x9d\x06\xbe\x43\x5a\xb8\x70\xb9\x83\x88\x1c\x37\xa1\x63\x31\xb4\xad\x50\x56\x1e\x1d\xb5\x29\xb0\x2e\x0e\x80\x0d\xba\xdd\x01\x18\x8b\xf4\x9d\xc7\xd0\x98\x51\x2c\xb2\x8b\xc6\x1f\x03\x6c\x7a\x5d\x16\x83\x5b\x47\xc3\x06\x99\xf6\x68\xd2\xa1\x36\x46\xb6\x3b\xe1\x82\xc1\x86\xb1\xc4\x40\xd8\xb3\x78\x4e\x41\x59\x9d\x89\x98\x2e\x59\x13\xa9\xab\xcb\x6c\x58\x2e\x66\x07\x51\x8f\xfd\x0d\xcf\xc8\x8c\x07\xed\x57\xa2\x83\xec\x94\xec\x2d\xcf\xec\xae\xa1\x2c\xf7\xac\x2c\xf8\xb9\xbe\x68\x95\x35\xdd\x9b\xa7\x60\x67\x04\x24\x0e\xb5\x76\x69\x79\x4b\x81\x65\xd9\xcc\xdc\x22\x85\x62\x7e\xf1\xaa\x01\x94\x60\xb1\xdd\xaa\xbe\x36\x7c\xd5\x57\x68\x69\x7e\xab\xb7\x64\xe2\xa8\x75\x3f\x6b\x76\x46\xe0\xc2\x4b\x6d\xf4\x9a\x29\x3f\xb0\xcd\xa6\x05\xb6\xb1\x6b\xb7\xc0\x96\x76\x18\x12\x19\xfe\x6e\x6d\x61\x49\xae\x0f\x5a\x0d\xa0\x47\x04\x7b\x49\xa4\x8d\x6e\xdb\x39\x8a\xcd\xce\x4c\x34\x04\x9f\x92\xd2\x59\x8c\x3b\xcb\x34\x81\xd6\x6f\xe4\x34\xa5\x10\x29\xb4\x6e\x21\xa7\x2b\x65\x44\x11\xfd\xb9\xac\x1b\x4e\x9b\xc3\x2f\x94\xb2\xd1\xea\x52\x8a\xb2\x73\x50\xea\x68\x9c\xaa\xce\xc0\x99\x08\x50\x31\x7a\x22\x4a\xf8\xe4\x4c\xc5\xb1\xb9\x40\x67\x7f\x78\x9d\x27\xa4\x6e\xb1\x0e\x89\x79\x44\xfd\xff\x94\x76\x65\xbd\x6d\x23\x49\xf8\xaf\x48\x04\xd6\x20\x43\x4a\x91\x92\x19\xef\x40\x5a\x46\xbb\x40\x1e\x76\x17\x48\xe6\xc1\x33\xd8\x07\x43\x08\x68\x89\x4e\x08\xc8\xa4\x40\x52\x89\x0d\x47\xff\x7d\xeb\xe8\xbb\x9b\x3a\x30\x79\x88\x2c\xb1\x8f\xea\x66\x75\x77\x55\x75\xd5\x57\x54\xd6\x9c\x20\xed\x3d\x67\xcf\xa5\x2e\xd7\xa9\x70\xef\x40\xb2\x16\x35\x73\xd2\x56\x00\x4a\xfb\x74\x3a\x8d\x44\x56\x9c\xbf\x12\x96\x65\xc7\xed\x5c\x13\xac\x65\x44\x39\x87\x37\x7b\x3a\x83\xcc\xf8\xad\xf7\x97\xf8\x91\x9b\x58\x5d\xf2\x54\x2a\xcf\xe6\x86\x21\x55\x44\x65\xc5\xc6\x97\xd4\xb2\x31\x9c\x62\x63\x65\xf6\x6c\xf8\x3d\x39\x86\xb2\x6d\x57\x65\xc7\xd9\x6e\x5c\x40\x3f\x3b\x51\x77\x8d\x69\xd0\x4d\x94\x69\xd8\x0e\x5b\xfa\x0d\x13\x20\xf6\x98\x7c\x3a\x6b\xfd\xb0\xeb\x50\x36\xe5\x9b\x1b\xe4\x22\x4c\x62\x6f\x20\x6e\x1b\xb9\x73\xef\x0e\x40\xd7\x08\x64\x03\xf4\x02\xc5\x39\xa0\xe4\x42\x65\x45\x00\x63\x0f\xe5\x08\x6b\x63\xc0\x9e\xce\x46\x95\x11\x8c\x2c\x1c\xd5\x32\x13\xfc\xb2\x34\x32\x5c\x8b\x51\xb3\xe8\x12\x63\x0e\x3d\x63\x18\xaf\x46\x96\xec\x85\xbc\x1c\xc9\xca\xfa\xf0\x54\x72\x96\xf1\xf1\x7c\x38\x03\xf9\x18\xb4\x2f\x18\x3c\xe5\x30\xf8\xf2\x85\x1a\xfd\xf2\x25\xc7\xf4\x55\x8d\x3f\x15\xe3\xb8\x1c\x49\x50\x45\x22\x32\x3c\x7a\x89\x93\x58\xc0\x20\x8b\x11\x89\xdc\xa3\xa2\xb3\x92\x09\x1f\x59\x94\xa0\xdb\x27\xc4\x64\xb6\x40\xec\xed\x34\x1a\x86\x74\x63\x5a\x4e\x97\x8d\x40\x81\x14\x66\x8d\x1f\x8c\x7e\xfa\xbf\xf2\xe1\x8e\x78\x1b\xf6\x35\x84\xdc\x8d\x52\xb5\x01\x6c\x18\xde\x1c\xf7\x9c\x34\x7a\xfb\xa3\x8b\x54\x4d\x58\xe5\x28\x6f\x06\xc0\xb9\x4a\x4e\x95\x65\x5a\x81\x75\x1d\x02\xc1\x38\x51\xc9\x80\x8c\xb0\xea\x89\xd5\x1c\x80\x2e\xfe\xef\xdd\xef\x9f\x31\x7c\xbb\x43\x46\xdd\x16\x7d\x81\x6c\x40\x8d\xd5\x53\x66\x59\xbc\x2d\x03\xbd\xb6\x43\xf9\x53\x26\x26\xa2\x04\x5b\x19\xb2\xfb\x2b\xde\x23\x4a\x1e\xb0\x5f\x9f\xec\x9e\x6e\x1a\xa9\x1f\x5c\xb9\xf5\xd7\xea\xf1\x25\x66\x9f\xd8\x32\x43\xc4\xe2\x12\xf6\x66\x32\xd8\x12\x5f\x1c\xe3\xca\x4a\x20\x08\x33\x5c\x48\x48\xa1\x6e\x41\x78\x41\xef\x4f\x7b\xb5\xaa\xd7\x27\x1e\x22\x07\x8d\xf6\x2b\x42\xf0\xdb\xdf\x97\xe8\x3e\x86\x1f\x88\x9f\xf7\x4a\x87\x22\x82\xcd\x25\x0b\xfa\x11\x5d\xd4\x02\x0f\x35\x0c\x6b\x6b\x09\xbc\x55\xfc\x4a\xd0\x19\x65\xa6\xc5\x74\xf8\x82\xc7\xe0\x02\xc1\xbc\x22\xb3\x6a\x63\xc0\xab\x2d\xa3\x7f\x4a\x48\x85\x55\x9d\x47\x0d\xc8\xca\xa9\xfc\x01\x56\x06\xfc\xf4\x1d\x4d\x5b\xe4\x4a\xa2\xf1\x16\x50\x98\x22\xfb\x57\x4b\x79\x05\x6d\x70\x5d\x83\x19\x34\x31\xf9\x84\x75\x64\xa4\x48\xc7\x51\x34\x51\xb2\x02\x02\xc4\x71\xba\x08\x96\xf9\x8e\x65\x52\x55\x46\x9c\xbc\xa5\x05\x48\x8b\xc3\x11\xb3\xc5\xe2\xc5\xb4\x83\x97\xe6\xc0\xc9\xa9\x04\xbb\x26\x5d\x36\xe8\x01\xda\x1f\x86\x1f\xf2\x54\x95\x34\x33\xf0\xf7\x58\x4c\xdb\x64\xbe\xd0\x93\x28\x9f\xd0\x4d\xf8\x5c\x4c\xa6\xa8\x92\x5a\x55\x8c\x69\xe6\x27\xa2\x4a\xff\xa1\xc4\xe7\xe5\x87\x1e\xbe\xa0\xbd\x84\x71\x6f\x4d\xdb\xdb\xc1\xd2\x62\xdc\xcb\x2c\xad\x9a\xec\x86\x22\x98\xf6\xc8\x5e\x8f\x08\xcb\xda\x2a\x34\xd1\x30\xf6\xac\x8d\xdf\xb8\xb1\x72\x62\xfc\xd1\xc4\x3b\x79\xfa\x13\x2c\xd0\x9d\x65\x6d\x35\x0a\xe9\xed\x40\x62\x59\x0d\x16\x45\xc9\x82\xc1\x64\xee\xe4\x85\x1a\xac\x04\xd0\x40\x9c\x45\x7d\x10\xb2\xab\x25\x98\x6c\xe9\x0e\x1e\x16\x57\xbf\x06\x6e\x38\x8a\xd6\x05\x46\x6e\xbc\xc7\x64\xba\xac\x38\xd9\x29\x88\x1b\xca\xe6\x0e\x1f\x19\xd5\x6c\x24\x13\x09\x16\x47\xc7\xa1\x82\x9f\x7b\xed\x69\x0d\xc2\x6e\xb2\x46\x86\x84\xb6\x6a\x5c\x45\x07\xa1\x68\xc4\xe2\x27\x21\x02\x8b\x25\xeb\x93\x69\xb5\x6b\x25\xbc\x35\x87\x8e\x8d\x59\x12\xbb\xea\xa6\x77\x3b\x08\xcd\x84\xd6\x40\x3c\xca\x55\x07\xb5\xd1\x41\x8b\xd3\xc4\xbc\x78\x98\x3e\x22\xd6\x62\xeb\x76\xb3\xe4\x28\xad\x9a\x20\xe7\x33\xcc\x63\x0e\xf3\x86\x59\x21\x83\x04\x48\x95\xc0\x4b\x07\xcd\xb7\x7e\x22\x37\x17\x4d\x59\xbb\x5e\x56\xdc\x19\x1a\x09\x83\xaf\xbe\x89\x2b\xa9\x59\xd0\x8d\x9b\x10\x6d\x02\x9d\x92\x16\x31\xf4\xb6\x58\xb7\xc8\xcb\x60\x4d\x54\x1f\x02\xa9\x4c\xc5\x74\xc0\x06\x24\x24\x74\x60\x3e\x29\xa2\x3b\xef\x9a\xbe\xa1\xf5\x84\xb8\x42\x68\x5f\xfc\xd6\xac\xd1\xf4\xb4\x09\xe6\xfc\x01\x05\x28\x5e\x05\x48\x45\x43\x46\xa2\x26\x00\x35\xb4\x40\xb5\x34\x47\x9e\xaa\x30\x33\x66\x11\x8a\x23\x0d\xb0\x1b\xae\x37\x6b\x64\xc1\x39\xb6\x3c\x19\xe9\x7a\x42\x44\x1a\xda\x43\xc7\x27\xeb\x65\xaf\x5f\x58\x2f\x67\x55\x68\x6e\x8a\x7e\x9e\x1b\xfb\x35\xf6\xf6\x6b\x74\x7b\x1c\x58\xd4\x42\x91\xb2\xe2\x22\xe9\x9c\x15\x87\x2c\x6e\x78\x43\xab\x2c\x50\x57\x6d\x24\xe5\xda\xef\xce\xd8\x9c\xce\xcf\x59\x29\xa3\x2f\x0d\x6a\xe4\x4f\x48\x55\x70\x40\xa0\x7c\x2a\x2d\x30\x60\xa8\x46\xb2\xa8\x90\xbf\x7e\xac\x32\x37\x37\xe2\x50\x5c\x59\x87\x23\x61\xda\x7e\x0d\x2d\x84\x33\xb5\xe9\xed\x71\xe8\x2e\x5d\x52\x53\x2b\x43\x37\x82\x7b\xdb\x4a\xf8\xf8\x17\x83\x89\x2c\xdb\xef\xf5\x70\x6e\x01\xb0\xbb\xb0\x97\x22\x5a\x01\xe7\xef\x7e\x03\x21\xfd\x1e\x73\x8c\x4c\xe6\x59\x97\xa3\x00\xbd\xc3\x43\x12\x44\xd7\xa9\x59\x9c\x36\xbc\xca\x94\x5d\x3b\x91\xe1\xf0\xa0\xac\xc3\x17\x1f\xae\x2d\x73\xb2\x13\xdb\xcb\xd1\xa7\xa0\xab\x81\x84\x50\xb1\x50\x56\x29\x6f\x82\x12\x4d\x49\x22\xdc\xb4\xc1\x70\x53\x01\xa9\x3e\x44\x6f\xee\x48\xbf\x15\x2f\x02\xd8\xda\x4c\xd2\x48\x0c\x2b\xa0\x23\x1a\xbe\xc5\x9c\xd5\x7d\x81\xd9\x0b\x33\xe5\x2a\x67\xd6\x2b\x90\x44\x41\xce\x04\x11\x76\x8b\x34\x0d\x57\x57\xde\x74\xe1\x6e\x27\x93\x70\xb5\x61\x6e\xe3\xba\x2b\x2c\xc8\x9c\x69\xf1\xde\xe1\xac\x4f\xd8\x10\xa3\x9d\xf6\xb1\x75\x05\x7c\x04\x22\x25\x4f\x63\xd2\x16\x3e\x02\xa5\x19\x7b\x11\x0a\xb5\x47\x0b\xb5\x02\x78\x2a\x4a\x14\x5c\x35\xb9\x4a\x2f\xf9\x83\xfd\xba\xd9\x39\x3a\xd7\x79\xec\x64\x33\x79\x9d\xea\x26\x59\x24\xff\x7b\x72\x94\x1b\x25\xee\x33\x3b\x56\x32\x76\x7a\x5b\x5e\x19\x7f\xe3\x52\x66\xb4\xe8\x64\x61\xff\x9c\xc3\x42\x5f\xc4\xc6\x6f\xb8\x6d\xfa\x45\x58\x26\xbd\xc0\x8f\xcb\xc5\x2c\xf3\xdd\xb6\x7c\xb3\xb9\xeb\x25\x3c\xe8\xb4\x65\xca\xb9\xa8\x2d\xe5\xed\xb5\x2b\xae\x73\xc5\xcf\x83\x25\xa9\x9a\x4a\xac\x53\x70\x43\x48\x63\x02\xc6\x95\x84\x83\x7a\x1b\x90\x63\xb4\x6f\x0f\xbe\x56\x76\x19\x26\xdc\x34\x14\x4d\x6c\x68\x4b\xa5\xcd\x4b\xa6\xdf\x05\xb6\x03\x15\xd7\xdf\xa0\x9b\x83\xc1\x31\x37\x37\x42\x77\xc2\x2f\x56\x9c\x3a\x69\x6e\xca\xa6\x9c\x31\xa7\xfa\x3d\x29\x73\xb6\x37\x0a\xe1\x21\x45\xfe\x65\xf2\x50\x42\xd1\x42\x95\xab\xb2\x22\x79\x8d\xc7\xed\xcf\x9f\x2d\x22\xab\x91\x2c\x54\x59\x62\x0f\x48\x3c\x40\x87\x9e\x8e\x1e\x07\x5f\xe8\xc1\x0b\x7f\x51\xb4\x15\x46\x47\x4c\x84\x1a\x20\x90\x0d\x89\x01\xea\x10\x70\x98\xd2\xbe\x24\xab\x26\x2c\xb4\x58\xdd\xb6\x43\xdd\x02\xfd\x98\x35\x7a\x71\x55\x79\x9f\x4e\xcd\x34\x21\x81\x62\xe7\x09\x14\xbb\xb0\x7a\x13\x1c\x8a\x6a\x24\xa8\xde\xec\x78\x87\xfc\x24\xe3\x3f\x83\x07\xfb\x8e\x0e\xf6\x9d\x38\xd8\xc5\xa7\x14\x08\x86\x8e\x72\x67\x3b\xdd\x5f\x7a\x94\x0f\x7a\xd7\x3a\x66\x5a\xe7\x06\xd9\xf2\xb2\x1a\xda\x99\x4f\x7b\xd1\x1a\x3b\x73\xf2\xba\xc9\x69\xe1\xc9\x89\x89\x65\x3c\x5d\xb6\xd3\x4e\x43\x3b\xb5\x42\x9a\x29\xfa\x40\xab\xc2\x20\xad\x66\x2a\xee\x45\xf2\x02\x23\xfd\x84\xb7\xc1\x80\xa4\xc1\x41\x4a\x3a\x8f\xa6\xda\xeb\x0a\xb9\x4d\x9a\x37\x8d\xa7\xb6\x46\xd3\xa9\x82\x03\x29\xdd\xd0\x9c\xbc\x11\xe7\x3b\x87\x4e\x46\xa3\x28\x8b\xe6\xb7\xfb\xe7\xd1\xc7\x16\x11\xf3\xef\x8a\xba\x1b\x7d\x6a\x6a\xcc\x21\x17\x42\x2f\xca\x6f\xdf\xa8\xa6\x48\x90\xd9\x50\x82\x16\xe3\x36\xa4\x16\xf8\x22\xd7\xed\xb7\x71\x67\x85\x74\x3a\x00\xc1\xee\xf6\x5a\xe9\x78\x68\x76\xf3\xde\x7a\x45\x0a\xcb\x73\x47\x95\x22\x3d\x4d\x35\x6c\x8b\xe7\xa0\xd5\x5d\xf1\x72\xed\xc5\xb5\x81\x96\x1d\x92\xcc\xb1\xd6\x71\xa0\xbc\x4f\x9f\x45\xcf\x0e\xe8\x09\xd6\x3b\xb1\x12\x37\xa7\x57\xa2\xb7\xe0\x74\x4c\x91\xc1\x77\xb0\xae\x7e\xcd\x1c\xb6\xb3\xee\x3c\xdc\xb5\x76\xda\xc1\xdb\x95\x82\xa4\x9d\x8d\xf2\x6b\xb2\x20\x82\x09\xa6\x56\xe3\xf9\x22\xee\xa4\x49\xf3\x98\x8d\x67\x09\x7f\xc7\x2f\xf6\xef\x43\xe2\xc5\xc5\x1e\x1a\xee\x0a\x0b\x48\x13\x22\x08\xf8\x6a\x99\xa1\xf1\x78\x95\xb4\x70\xc9\xaf\xff\xda\x6e\x43\xcc\x3a\x28\x57\x1c\x33\x34\xbf\x3b\x7b\x35\x7f\x08\x6f\x44\xc9\x19\x1d\x7a\x76\xa1\xd9\xdd\x29\x2c\x55\x55\x3d\x21\x3c\x97\x99\x57\xdb\x24\xd1\xd5\x32\x40\xa0\x18\x92\x20\x44\xa0\x46\x30\x92\xf1\xdc\x79\xd7\x79\xe7\x5d\x77\x9a\xc1\xbb\xd3\x92\xfb\xe0\x89\x72\xd2\xe9\xc4\x3c\x6e\x1c\xd6\xbe\xd8\x15\xd7\x04\x36\x76\x20\xa2\x86\x91\xa1\xfa\x60\xc0\xdc\xb0\x14\xec\xf8\x88\x84\xa0\x1a\x51\x20\xbf\x5e\xb7\xac\x7c\x8e\x34\x05\xd8\xcc\xdd\xab\x2f\x14\x83\x0b\xe9\x88\x92\xd1\xad\xff\x10\xf3\x6b\x9b\xae\x82\x5a\xf1\xbb\x0c\x18\x7e\x3d\xe9\x3c\x84\x37\x29\xf7\xd9\x80\xa0\xac\x72\xc4\xe8\x24\x23\xf3\xf5\x8a\xcc\x17\xe6\x2f\xcb\x8d\xf4\x09\x46\xe4\x01\xe9\xf7\xdb\x67\x1b\xb2\x38\xe5\xfd\xaa\xe7\xb8\x3e\x72\xc4\x2f\x03\x1b\x76\x40\x7e\x43\x88\x08\xd9\xac\x12\xce\xe5\xaa\x52\x9d\xa0\x74\xae\x3a\x27\xa5\x4f\xf7\x2f\xbe\x12\x09\xf4\xb7\xd3\xed\xf0\xda\x2b\xad\xbe\xe3\x8d\x67\xfb\xa2\xca\xea\x85\x79\xa6\xd0\x8d\xf6\xaf\xb4\x87\x81\x0d\x37\x4a\x87\xc1\x1d\x8a\x06\x56\xdb\xf7\x24\xfe\x30\xed\xe7\x3c\x68\x35\x4c\x35\xc6\x00\x8d\x26\xcb\x04\xde\x2f\x5d\x86\xb6\x61\xab\x9b\xf2\xf2\x36\xc8\xa7\x8e\xc6\xf8\x93\x1a\xa0\x78\x33\x04\x0c\x36\xf0\x7a\x24\xa5\x5c\x4a\x92\x2b\xbe\xf5\x16\xc1\x27\x8c\x83\x4c\x71\xcb\xea\x51\x99\xbd\x0a\x13\xe0\x42\x92\x87\xdb\xde\x6a\xa3\x05\xd2\x58\x72\x9f\xe8\xc7\x99\x9b\xc5\xd0\x6b\x0d\x82\xaf\x52\x56\xcf\xd2\xd5\x0b\x4f\x72\x9e\xdf\xb2\xf2\x52\x0c\xc9\x25\x72\x14\x86\xe9\x32\x58\x4c\xf4\x71\x5e\xc8\xd9\x85\xfc\x49\x2c\xc3\x96\x21\xbe\xb8\x76\x2d\x36\x13\x0f\xc6\x83\x0c\x2a\x2c\x4e\xa0\x48\x58\x5d\x19\x70\x2b\xb9\x40\x67\xb9\xd8\xe1\xfe\xc4\x61\x73\x01\x1e\xa1\x3c\x75\x50\xae\xba\xfe\xa8\x68\xc8\x83\xdc\xdd\x55\xcc\xb4\x52\x06\x23\x2d\xa2\x64\xd9\x22\xd2\x5d\x5c\x2a\x6c\xf9\x19\xa2\x55\x64\x05\x49\x76\x92\xcb\x55\x66\x07\x27\x13\x83\xcd\x66\x85\xe9\xdf\x7a\x56\xb6\x28\x3c\xd9\xa2\x60\xf1\xff\xb3\xe5\x66\xcb\x91\x5b\x68\xf3\xa2\x7b\xa9\xd2\xaf\xe2\x5d\x7e\x04\xb7\x94\xc2\xb4\xdb\x7b\x97\x76\x05\x2f\x10\xa7\x6b\xc5\xd2\x48\xeb\x0a\xff\xe3\x4b\x6c\x65\x3c\xa7\x7b\xfa\xd3\xe5\x69\xc2\xce\x19\xdb\x8b\xd3\x20\x04\x67\x19\x78\x80\x63\x7f\x09\xa4\x16\xf3\x78\xd6\xe2\xd2\x65\x3d\xfd\xf3\xcf\xff\x7c\xf4\x5d\x43\xa2\x67\xf1\x6f\x42\xff\xfd\x82\xff\xbd\xc8\xaf\xf2\x5f\xa4\xae\xba\xde\xde\x3f\xbf\xac\xdf\x7e\x0d\xb8\xe6\xcd\x6f\xdf\x7c\x2a\xfa\x6f\xd3\xb6\x00\xed\xf5\x29\x4e\x7e\xce\xb2\x3a\x8f\x9e\x23\xd8\xe0\xe0\xa0\x7e\x7f\xd3\xff\xfc\x4d\xc7\xc8\xf5\xcd\x1d\x6d\x0a\xf1\xfc\x96\x76\xe7\x5a\x83\x42\xe4\xf6\x91\x09\xec\x28\x8d\xb6\x4b\xb9\x57\xef\x8b\x2d\xc2\x5f\x80\xd4\x0b\x53\xff\xef\xe6\xd0\x76\xa0\xae\xbd\xcb\xa2\x19\xba\x44\xb8\xcf\x3f\x55\x35\x6c\x1e\xba\x84\x8a\x56\x48\xd1\xa7\x82\x72\x6e\x99\xba\xa7\x97\x15\x45\xa5\x3a\x0f\x89\x2d\xef\xd7\xab\xd9\xc2\xfc\x0a\xbb\xc1\x0c\x17\xbe\x97\x51\x8d\x63\x25\xcb\xfb\x06\x71\x8e\xe2\xdb\x14\xc4\x2f\x94\xd4\x57\xfc\x21\x8a\xa7\xf3\xc5\x2c\x49\xde\xd4\x98\xda\xb8\x4b\x0b\x65\x4c\xe6\xa7\x6f\xea\x7f\xf4\x49\xc1\x20\x17\xf9\xbd\x7a\xba\x5e\x62\x20\xfd\x2b\xdf\x6e\xe8\x3a\x46\x1e\x89\x4d\x1e\x45\x20\x9d\x62\x2e\x45\xa0\xee\x31\x1f\xcf\x97\x07\x03\x0d\xb3\x10\xa6\xca\x2e\x3d\x60\xba\x09\xd9\xd9\x07\x4c\x30\x17\xef\xd8\x24\xbd\x41\xa1\x78\x66\x22\x13\xcd\xb2\x6d\x2e\x5b\x59\x6e\x3f\x30\x2e\x11\x51\xf1\x94\x1f\xee\xbf\xad\x97\x8f\x50\x1b\xfb\xca\xba\x34\x47\x9c\x80\x34\x7f\x52\x6d\x67\xfb\x34\xcd\x3a\xe8\x61\x15\xe3\x41\xbf\x5f\x19\xfd\x20\xf2\xd4\x76\x32\x5f\xc1\x49\xfa\x94\xa2\x9d\x04\xe6\x4b\x4f\x50\x82\x95\xf3\x79\xb2\x10\x15\x9e\xf0\xcc\x55\x7f\x23\x91\x38\xc8\x04\x47\x09\x8a\xac\x6e\x2b\x95\x8d\xa5\x79\x8d\xa7\x34\x7c\xcf\x54\x9f\xc9\x51\x4e\x2b\x66\xb3\x24\x3e\x6b\xf2\x6d\xb3\xa1\xd7\xea\xba\xe7\x6f\x8a\xfa\x7b\xd1\x45\x0c\xf6\x8e\xc7\x2a\x3a\xe9\x3e\xc3\x83\x77\x5b\x5a\x67\x86\x99\xc7\xcd\xfe\x22\x9c\x82\xa6\x8f\x50\x05\x6f\xe2\xe1\x65\x15\xdd\xa1\x2d\xff\xc0\xfa\x65\xc2\x38\x5b\x94\x9d\x96\x00\xc4\x1e\xa4\xed\xc8\x58\xb5\xec\x6e\x36\x44\x1b\x46\x87\x10\x18\x19\xc6\x8f\x4c\xbf\x57\x5d\xf5\x50\x01\x1b\xbc\xe4\xd1\xb7\x0a\x64\x4a\xba\xad\xe0\x67\x0c\xe9\x15\xcd\x67\xb3\xfd\x73\x94\xa9\xf6\x1e\x9a\xed\x0b\xe6\x4a\x2c\xeb\x2d\x81\x83\xc5\xa5\x46\xad\x35\x71\xc2\x64\x33\x0d\xec\x5f\x8f\xbb\xe6\x47\x1e\x31\xc9\xf2\xb8\x3c\x4d\x60\xed\x11\xf1\x37\xa4\xcc\xec\xb7\x4e\x96\x32\x59\xa2\xd9\xaf\x72\x61\x02\xd9\x1e\x1a\xfc\xcc\xd7\xf0\x78\x5b\x2c\xc9\xcd\xfa\x09\xe5\x63\xd4\x8e\xa2\xf0\xe5\x98\x61\xce\x92\xe5\xff\x01\xeb\xd0\xc3\x9d\x15\x51\x04\x00\x01\x00\x00\xff\xff\x98\x15\xca\xa2\xb8\x3f\x01\x00" func dist_bundle_js_gz_bytes() ([]byte, error) { return bindata_read( @@ -106,7 +106,7 @@ func dist_bundle_js_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/bundle.js.gz", size: 81846, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/bundle.js.gz", size: 81848, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -126,7 +126,7 @@ func dist_css_fontello_css() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/css/fontello.css", size: 689, mode: os.FileMode(436), modTime: time.Unix(1430087392, 0)} + info := bindata_file_info{name: "dist/css/fontello.css", size: 689, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -146,7 +146,7 @@ func dist_css_fontello_css_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/css/fontello.css.gz", size: 329, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/css/fontello.css.gz", size: 329, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -166,7 +166,7 @@ func dist_css_style_css() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/css/style.css", size: 3166, mode: os.FileMode(436), modTime: time.Unix(1430087392, 0)} + info := bindata_file_info{name: "dist/css/style.css", size: 3166, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -186,7 +186,7 @@ func dist_css_style_css_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/css/style.css.gz", size: 1024, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/css/style.css.gz", size: 1024, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -206,7 +206,7 @@ func dist_font_fontello_eot() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.eot", size: 5288, mode: os.FileMode(436), modTime: time.Unix(1430087392, 0)} + info := bindata_file_info{name: "dist/font/fontello.eot", size: 5288, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -226,7 +226,7 @@ func dist_font_fontello_eot_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.eot.gz", size: 2704, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/font/fontello.eot.gz", size: 2704, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -246,7 +246,7 @@ func dist_font_fontello_svg() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.svg", size: 1571, mode: os.FileMode(436), modTime: time.Unix(1430087392, 0)} + info := bindata_file_info{name: "dist/font/fontello.svg", size: 1571, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -266,7 +266,7 @@ func dist_font_fontello_svg_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.svg.gz", size: 812, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/font/fontello.svg.gz", size: 812, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -286,7 +286,7 @@ func dist_font_fontello_ttf() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.ttf", size: 5120, mode: os.FileMode(436), modTime: time.Unix(1430087392, 0)} + info := bindata_file_info{name: "dist/font/fontello.ttf", size: 5120, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -306,7 +306,7 @@ func dist_font_fontello_ttf_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.ttf.gz", size: 2652, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/font/fontello.ttf.gz", size: 2652, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -326,7 +326,7 @@ func dist_font_fontello_woff() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.woff", size: 2912, mode: os.FileMode(436), modTime: time.Unix(1430087393, 0)} + info := bindata_file_info{name: "dist/font/fontello.woff", size: 2912, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -346,7 +346,7 @@ func dist_font_fontello_woff_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/font/fontello.woff.gz", size: 2862, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/font/fontello.woff.gz", size: 2862, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -366,7 +366,7 @@ func dist_index_html() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/index.html", size: 369, mode: os.FileMode(436), modTime: time.Unix(1430087392, 0)} + info := bindata_file_info{name: "dist/index.html", size: 369, mode: os.FileMode(436), modTime: time.Unix(1430343952, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -386,7 +386,7 @@ func dist_index_html_gz() (*asset, error) { return nil, err } - info := bindata_file_info{name: "dist/index.html.gz", size: 248, mode: os.FileMode(436), modTime: time.Unix(1430087402, 0)} + info := bindata_file_info{name: "dist/index.html.gz", size: 248, mode: os.FileMode(436), modTime: time.Unix(1430343962, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/client/src/js/components/Connect.jsx b/client/src/js/components/Connect.jsx index d4b0344e..71827075 100644 --- a/client/src/js/components/Connect.jsx +++ b/client/src/js/components/Connect.jsx @@ -19,7 +19,7 @@ var Connect = React.createClass({ var channels = _.filter(_.map(e.target.channels.value.split(','), _.trim)); var opts = { name: e.target.name.value.trim(), - ssl: e.target.ssl.checked + tls: e.target.ssl.checked }; if (this.state.showOptionals) { diff --git a/irc.go b/irc.go index 1f179e95..0fdc0d22 100644 --- a/irc.go +++ b/irc.go @@ -227,8 +227,8 @@ func (i *IRC) writef(format string, a ...interface{}) { func (i *IRC) send() { i.ready.Wait() - for message := range i.out { - i.conn.Write([]byte(message)) + for { + i.conn.Write([]byte(<-i.out)) } } diff --git a/main.go b/main.go index 7dade88c..6a5efa0d 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,8 @@ import ( "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/julienschmidt/httprouter" "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/net/websocket" + + "github.com/khlieng/name_pending/args" "github.com/khlieng/name_pending/storage" ) @@ -26,35 +28,37 @@ type File struct { func reconnect() { for _, user := range storage.LoadUsers() { + session := NewSession() + session.user = user + sessions[user.UUID] = session + go session.write() + channels := user.GetChannels() for _, server := range user.GetServers() { - session := NewSession() - session.user = user - sessions[user.UUID] = session - irc := NewIRC(server.Nick, server.Username) irc.TLS = server.TLS irc.Password = server.Password irc.Realname = server.Realname - err := irc.Connect(server.Address) - if err != nil { - log.Println(err) - } else { - session.setIRC(irc.Host, irc) + go func() { + err := irc.Connect(server.Address) + if err != nil { + log.Println(err) + } else { + session.setIRC(irc.Host, irc) - go session.write() - go handleMessages(irc, session) + go handleMessages(irc, session) - var joining []string - for _, channel := range channels { - if channel.Server == server.Address { - joining = append(joining, channel.Name) + var joining []string + for _, channel := range channels { + if channel.Server == server.Address { + joining = append(joining, channel.Name) + } } + irc.Join(joining...) } - irc.Join(joining...) - } + }() } } } @@ -106,7 +110,9 @@ func main() { File{"/font/fontello.woff", "application/font-woff"}, } - //reconnect() + if !args.Development { + reconnect() + } router := httprouter.New() diff --git a/message_handler.go b/message_handler.go index 293f81ac..ccb2dd60 100644 --- a/message_handler.go +++ b/message_handler.go @@ -88,6 +88,10 @@ func handleMessages(irc *IRC, session *Session) { }) } + if msg.Params[0] != "*" { + session.user.LogMessage(irc.Host, msg.Prefix, msg.Params[0], msg.Trailing) + } + case QUIT: user := msg.Prefix diff --git a/session.go b/session.go index b3797c9b..e47a83be 100644 --- a/session.go +++ b/session.go @@ -16,7 +16,7 @@ type Session struct { wsLock sync.Mutex out chan []byte - user storage.User + user *storage.User } func NewSession() *Session { diff --git a/storage/init.go b/storage/init.go deleted file mode 100644 index 4e87a010..00000000 --- a/storage/init.go +++ /dev/null @@ -1,36 +0,0 @@ -package storage - -import ( - "log" - "os" - "os/user" - "path" - - "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" -) - -var db *bolt.DB - -func init() { - var err error - currentUser, _ := user.Current() - appDir := path.Join(currentUser.HomeDir, ".name_pending") - - os.Mkdir(appDir, 0777) - - db, err = bolt.Open(path.Join(appDir, "data.db"), 0600, nil) - if err != nil { - log.Fatal("Unable to open database file") - } - - db.Update(func(tx *bolt.Tx) error { - tx.CreateBucketIfNotExists([]byte("Users")) - tx.CreateBucketIfNotExists([]byte("Servers")) - tx.CreateBucketIfNotExists([]byte("Channels")) - return nil - }) -} - -func Cleanup() { - db.Close() -} diff --git a/storage/storage.go b/storage/storage.go new file mode 100644 index 00000000..560c7116 --- /dev/null +++ b/storage/storage.go @@ -0,0 +1,53 @@ +package storage + +import ( + "log" + "os" + "os/user" + "path" + + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" + + "github.com/khlieng/name_pending/args" +) + +var ( + appDir string + + db *bolt.DB + + bucketUsers = []byte("Users") + bucketServers = []byte("Servers") + bucketChannels = []byte("Channels") + bucketMessages = []byte("Messages") +) + +func init() { + var err error + currentUser, _ := user.Current() + appDir = path.Join(currentUser.HomeDir, ".name_pending") + + if args.Development { + os.RemoveAll(appDir) + } + + os.Mkdir(appDir, 0777) + os.Mkdir(path.Join(appDir, "logs"), 0777) + + db, err = bolt.Open(path.Join(appDir, "data.db"), 0600, nil) + if err != nil { + log.Fatal("Could not open database file") + } + + db.Update(func(tx *bolt.Tx) error { + tx.CreateBucketIfNotExists(bucketUsers) + tx.CreateBucketIfNotExists(bucketServers) + tx.CreateBucketIfNotExists(bucketChannels) + + return nil + }) +} + +func Cleanup() { + db.Close() +} diff --git a/storage/user.go b/storage/user.go index 006e460c..fba1fd94 100644 --- a/storage/user.go +++ b/storage/user.go @@ -3,7 +3,12 @@ package storage import ( "bytes" "encoding/json" + "log" + "path" + "strconv" + "time" + "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/blevesearch/bleve" "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/boltdb/bolt" ) @@ -24,12 +29,24 @@ type Channel struct { Topic string `json:"topic,omitempty"` } -type User struct { - UUID string +type Message struct { + ID uint64 `json:"id"` + Server string `json:"server"` + From string `json:"from"` + To string `json:"to"` + Content string `json:"content"` + Time int64 `json:"time"` } -func NewUser(uuid string) User { - user := User{ +type User struct { + UUID string + + messageLog *bolt.DB + messageIndex bleve.Index +} + +func NewUser(uuid string) *User { + user := &User{ UUID: uuid, } @@ -42,17 +59,22 @@ func NewUser(uuid string) User { return nil }) + go user.openMessageLog() + return user } -func LoadUsers() []User { - var users []User +func LoadUsers() []*User { + var users []*User db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("Users")) b.ForEach(func(k, v []byte) error { - users = append(users, User{string(k)}) + user := User{UUID: string(k)} + go user.openMessageLog() + + users = append(users, &user) return nil }) @@ -63,7 +85,7 @@ func LoadUsers() []User { return users } -func (u User) GetServers() []Server { +func (u *User) GetServers() []Server { var servers []Server db.View(func(tx *bolt.Tx) error { @@ -82,7 +104,7 @@ func (u User) GetServers() []Server { return servers } -func (u User) GetChannels() []Channel { +func (u *User) GetChannels() []Channel { var channels []Channel db.View(func(tx *bolt.Tx) error { @@ -102,7 +124,7 @@ func (u User) GetChannels() []Channel { return channels } -func (u User) AddServer(server Server) { +func (u *User) AddServer(server Server) { go db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("Servers")) data, _ := json.Marshal(server) @@ -113,7 +135,7 @@ func (u User) AddServer(server Server) { }) } -func (u User) AddChannel(channel Channel) { +func (u *User) AddChannel(channel Channel) { go db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("Channels")) data, _ := json.Marshal(channel) @@ -124,7 +146,7 @@ func (u User) AddChannel(channel Channel) { }) } -func (u User) SetNick(nick, address string) { +func (u *User) SetNick(nick, address string) { go db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("Servers")) id := []byte(u.UUID + ":" + address) @@ -140,7 +162,7 @@ func (u User) SetNick(nick, address string) { }) } -func (u User) RemoveServer(address string) { +func (u *User) RemoveServer(address string) { go db.Update(func(tx *bolt.Tx) error { serverID := []byte(u.UUID + ":" + address) @@ -157,10 +179,116 @@ func (u User) RemoveServer(address string) { }) } -func (u User) RemoveChannel(server, channel string) { +func (u *User) RemoveChannel(server, channel string) { go db.Update(func(tx *bolt.Tx) error { tx.Bucket([]byte("Channels")).Delete([]byte(u.UUID + ":" + server + ":" + channel)) return nil }) } + +func (u *User) LogMessage(server, from, to, content string) { + go u.messageLog.Update(func(tx *bolt.Tx) error { + b := tx.Bucket(bucketMessages) + messageID, _ := b.NextSequence() + id := server + ":" + to + ":" + strconv.FormatUint(messageID, 10) + + message := Message{ + ID: messageID, + Content: content, + Server: server, + From: from, + To: to, + Time: time.Now().Unix(), + } + + data, _ := json.Marshal(message) + b.Put([]byte(id), data) + + go u.messageIndex.Index(id, message) + + return nil + }) +} + +func (u *User) GetMessages(server, channel string, count int, fromID uint64) ([]Message, error) { + messages := make([]Message, count) + i := count - 1 + prefix := []byte(server + ":" + channel + ":" + strconv.FormatUint(fromID, 10)) + + u.messageLog.View(func(tx *bolt.Tx) error { + c := tx.Bucket(bucketMessages).Cursor() + + for k, v := c.Seek(prefix); i > 0 && bytes.HasPrefix(k, prefix); k, v = c.Prev() { + var message Message + + json.Unmarshal(v, &message) + messages[i] = message + i-- + } + + return nil + }) + + return messages[i:], nil +} + +func (u *User) SearchMessages(server, channel, phrase string) ([]Message, error) { + serverQuery := bleve.NewMatchQuery(server) + serverQuery.SetField("Server") + channelQuery := bleve.NewMatchQuery(channel) + channelQuery.SetField("To") + contentQuery := bleve.NewMatchQuery(phrase) + contentQuery.SetField("Content") + + query := bleve.NewBooleanQuery([]bleve.Query{serverQuery, channelQuery, contentQuery}, nil, nil) + + search := bleve.NewSearchRequest(query) + searchResults, err := u.messageIndex.Search(search) + if err != nil { + return nil, err + } + + var messages []Message + u.messageLog.View(func(tx *bolt.Tx) error { + b := tx.Bucket(bucketMessages) + + for _, hit := range searchResults.Hits { + var message Message + + json.Unmarshal(b.Get([]byte(hit.ID)), &message) + messages = append(messages, message) + } + + return nil + }) + + return messages, nil +} + +func (u *User) openMessageLog() { + var err error + + u.messageLog, err = bolt.Open(path.Join(appDir, "logs", u.UUID+"_log"), 0600, nil) + if err != nil { + log.Fatal(err) + } + + u.messageLog.Update(func(tx *bolt.Tx) error { + tx.CreateBucketIfNotExists(bucketMessages) + + return nil + }) + + indexPath := path.Join(appDir, "logs", u.UUID+"_index") + u.messageIndex, err = bleve.Open(indexPath) + if err == bleve.ErrorIndexPathDoesNotExist { + mapping := bleve.NewIndexMapping() + u.messageIndex, err = bleve.New(indexPath, mapping) + if err != nil { + log.Fatal(err) + } + } else if err != nil { + log.Fatal(err) + } +} diff --git a/websocket.go b/websocket.go index 5c874cdb..aa9a418b 100644 --- a/websocket.go +++ b/websocket.go @@ -18,7 +18,7 @@ func NewWebSocket(ws *websocket.Conn) *WebSocket { } func (w *WebSocket) write() { - for data := range w.Out { - w.conn.Write(data) + for { + w.conn.Write(<-w.Out) } } diff --git a/websocket_handler.go b/websocket_handler.go index 9f4ac2db..a3c02d49 100644 --- a/websocket_handler.go +++ b/websocket_handler.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "log" + "strings" "github.com/khlieng/name_pending/Godeps/_workspace/src/golang.org/x/net/websocket" "github.com/khlieng/name_pending/storage" @@ -84,25 +85,32 @@ func handleWS(ws *websocket.Conn) { irc.Password = data.Password irc.Realname = data.Realname - err := irc.Connect(data.Server) - if err != nil { - session.sendError(err, irc.Host) - log.Println(err) + if idx := strings.Index(data.Server, ":"); idx < 0 { + session.setIRC(data.Server, irc) } else { - session.setIRC(irc.Host, irc) - - go handleMessages(irc, session) - - session.user.AddServer(storage.Server{ - Name: data.Name, - Address: irc.Host, - TLS: data.TLS, - Password: data.Password, - Nick: data.Nick, - Username: data.Username, - Realname: data.Realname, - }) + session.setIRC(data.Server[:idx], irc) } + + go func() { + err := irc.Connect(data.Server) + if err != nil { + session.deleteIRC(irc.Host) + session.sendError(err, irc.Host) + log.Println(err) + } else { + go handleMessages(irc, session) + + session.user.AddServer(storage.Server{ + Name: data.Name, + Address: irc.Host, + TLS: data.TLS, + Password: data.Password, + Nick: data.Nick, + Username: data.Username, + Realname: data.Realname, + }) + } + }() } else { log.Println(addr, "already connected to", data.Server) }